pinme 2.0.0-beta.8 → 2.0.0-rc.1

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 +1471 -1231
  2. package/package.json +31 -30
package/dist/index.js CHANGED
@@ -1519,11 +1519,11 @@ function checkNodeVersion() {
1519
1519
 
1520
1520
  // bin/index.ts
1521
1521
  var import_commander = require("commander");
1522
- var import_chalk22 = __toESM(require("chalk"));
1522
+ var import_chalk23 = __toESM(require("chalk"));
1523
1523
  var import_figlet5 = __toESM(require("figlet"));
1524
1524
 
1525
1525
  // package.json
1526
- var version = "2.0.0-beta.8";
1526
+ var version = "2.0.0-rc.1";
1527
1527
 
1528
1528
  // bin/upload.ts
1529
1529
  var import_path7 = __toESM(require("path"));
@@ -4399,11 +4399,11 @@ var {
4399
4399
  } = axios_default;
4400
4400
 
4401
4401
  // bin/utils/uploadToIpfsSplit.ts
4402
- var import_fs_extra4 = __toESM(require("fs-extra"));
4403
- var import_path5 = __toESM(require("path"));
4402
+ var import_fs_extra5 = __toESM(require("fs-extra"));
4403
+ var import_path6 = __toESM(require("path"));
4404
4404
  var import_form_data2 = __toESM(require("form-data"));
4405
4405
  var import_ora = __toESM(require("ora"));
4406
- var crypto = __toESM(require("crypto"));
4406
+ var crypto2 = __toESM(require("crypto"));
4407
4407
 
4408
4408
  // bin/utils/uploadLimits.ts
4409
4409
  var import_fs = __toESM(require("fs"));
@@ -4584,709 +4584,331 @@ function getUid() {
4584
4584
  return getDeviceId();
4585
4585
  }
4586
4586
 
4587
- // bin/utils/uploadToIpfsSplit.ts
4588
- var IPFS_API_URL = "https://pinme.dev/api/v3";
4589
- var MAX_RETRIES = parseInt(process.env.MAX_RETRIES || "2");
4590
- var RETRY_DELAY = parseInt(process.env.RETRY_DELAY_MS || "1000");
4591
- var TIMEOUT = parseInt(process.env.TIMEOUT_MS || "600000");
4592
- var MAX_POLL_TIME = parseInt("5") * 60 * 1e3;
4593
- var POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL_SECONDS || "2") * 1e3;
4594
- var PROGRESS_UPDATE_INTERVAL = 200;
4595
- var EXPECTED_UPLOAD_TIME = 6e4;
4596
- var MAX_PROGRESS = 0.9;
4597
- var StepProgressBar = class {
4598
- spinner;
4599
- fileName;
4600
- startTime;
4601
- currentStep = 0;
4602
- stepStartTime = 0;
4603
- progressInterval = null;
4604
- isSimulatingProgress = false;
4605
- simulationStartTime = 0;
4606
- constructor(fileName, isDirectory = false) {
4607
- this.fileName = fileName;
4608
- this.spinner = (0, import_ora.default)(`Preparing to upload ${fileName}...`).start();
4609
- this.startTime = Date.now();
4610
- this.stepStartTime = Date.now();
4611
- this.startProgress();
4612
- }
4613
- startStep(stepIndex, stepName) {
4614
- this.currentStep = stepIndex;
4615
- this.stepStartTime = Date.now();
4616
- }
4617
- updateProgress(progress, total) {
4618
- }
4619
- completeStep() {
4587
+ // bin/utils/webLogin.ts
4588
+ var import_crypto = __toESM(require("crypto"));
4589
+ var import_http3 = __toESM(require("http"));
4590
+ var import_url2 = require("url");
4591
+ var import_chalk3 = __toESM(require("chalk"));
4592
+ var import_child_process = require("child_process");
4593
+ var import_fs_extra4 = __toESM(require("fs-extra"));
4594
+ var import_os4 = __toESM(require("os"));
4595
+ var import_path5 = __toESM(require("path"));
4596
+ function openBrowser(url2) {
4597
+ const platform = process.platform;
4598
+ let command;
4599
+ if (platform === "darwin") {
4600
+ command = `open "${url2}"`;
4601
+ } else if (platform === "win32") {
4602
+ command = `start "" "${url2}"`;
4603
+ } else {
4604
+ command = `xdg-open "${url2}"`;
4620
4605
  }
4621
- // Start simulating progress to continue display after 90%
4622
- startSimulatingProgress() {
4623
- this.isSimulatingProgress = true;
4624
- this.simulationStartTime = Date.now();
4606
+ (0, import_child_process.exec)(command, (err) => {
4607
+ if (err) {
4608
+ console.log(import_chalk3.default.yellow(`Unable to open browser automatically. Please visit manually: ${url2}`));
4609
+ }
4610
+ });
4611
+ }
4612
+ var CONFIG_DIR2 = import_path5.default.join(import_os4.default.homedir(), ".pinme");
4613
+ var AUTH_FILE2 = import_path5.default.join(CONFIG_DIR2, "auth.json");
4614
+ var DEFAULT_OPTIONS = {
4615
+ apiBaseUrl: "https://pinme.dev/api/v4",
4616
+ webBaseUrl: process.env.PINME_WEB_URL || "http://localhost:5173",
4617
+ callbackPort: 34567,
4618
+ callbackPath: "/cli/callback"
4619
+ };
4620
+ var WebLoginManager = class {
4621
+ config;
4622
+ server = null;
4623
+ resolvePromise = null;
4624
+ rejectPromise = null;
4625
+ loginToken = "";
4626
+ constructor(options = {}) {
4627
+ this.config = { ...DEFAULT_OPTIONS, ...options };
4625
4628
  }
4626
- // Stop simulating progress
4627
- stopSimulatingProgress() {
4628
- this.isSimulatingProgress = false;
4629
+ async login() {
4630
+ console.log(import_chalk3.default.blue("Starting login flow...\n"));
4631
+ this.loginToken = this.generateLoginToken();
4632
+ console.log(import_chalk3.default.blue("Starting local callback server..."));
4633
+ await this.startCallbackServer();
4634
+ try {
4635
+ const loginUrl = this.buildLoginUrl();
4636
+ console.log(import_chalk3.default.blue("Opening browser..."));
4637
+ console.log(import_chalk3.default.white("If browser does not open automatically, please visit manually:"));
4638
+ console.log(import_chalk3.default.cyan(` ${loginUrl}
4639
+ `));
4640
+ openBrowser(loginUrl);
4641
+ console.log(import_chalk3.default.yellow("Please complete login in browser..."));
4642
+ console.log(import_chalk3.default.gray("Browser will close automatically after successful login.\n"));
4643
+ const authToken = await this.waitForCallback();
4644
+ const authConfig = this.parseAuthToken(authToken);
4645
+ this.saveAuthConfig(authConfig);
4646
+ console.log(import_chalk3.default.green("\nLogin successful!"));
4647
+ if (authConfig.email) {
4648
+ console.log(import_chalk3.default.green(`Welcome, ${authConfig.email}`));
4649
+ }
4650
+ console.log(import_chalk3.default.gray(`Address: ${authConfig.address}`));
4651
+ return authConfig;
4652
+ } catch (error) {
4653
+ console.error(import_chalk3.default.red(`
4654
+ Login failed: ${error.message}`));
4655
+ throw error;
4656
+ } finally {
4657
+ this.closeServer();
4658
+ }
4629
4659
  }
4630
- failStep(error) {
4631
- this.stopProgress();
4632
- this.spinner.fail(`Upload failed: ${error}`);
4660
+ generateLoginToken() {
4661
+ return import_crypto.default.randomBytes(32).toString("hex");
4633
4662
  }
4634
- complete() {
4635
- this.stopProgress();
4636
- const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
4637
- const progressBar = this.createProgressBar(1);
4638
- this.spinner.succeed(
4639
- `Upload completed ${progressBar} 100% (${totalTime}s)`
4640
- );
4663
+ async startCallbackServer() {
4664
+ return new Promise((resolve, reject) => {
4665
+ this.server = import_http3.default.createServer(async (req, res) => {
4666
+ try {
4667
+ const url2 = new import_url2.URL(req.url || "", `http://localhost:${this.config.callbackPort}`);
4668
+ if (url2.pathname === this.config.callbackPath) {
4669
+ const authToken = url2.searchParams.get("token");
4670
+ const error = url2.searchParams.get("error");
4671
+ const loginToken = url2.searchParams.get("login_token");
4672
+ if (error) {
4673
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4674
+ res.end(this.getErrorHtml(error));
4675
+ if (this.rejectPromise) {
4676
+ this.rejectPromise(new Error(error));
4677
+ }
4678
+ return;
4679
+ }
4680
+ if (!authToken) {
4681
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4682
+ res.end(this.getErrorHtml("Auth token not received"));
4683
+ if (this.rejectPromise) {
4684
+ this.rejectPromise(new Error("Auth token not received"));
4685
+ }
4686
+ return;
4687
+ }
4688
+ if (loginToken !== this.loginToken) {
4689
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4690
+ res.end(this.getErrorHtml("Login token invalid or expired"));
4691
+ if (this.rejectPromise) {
4692
+ this.rejectPromise(new Error("Login token invalid or expired"));
4693
+ }
4694
+ return;
4695
+ }
4696
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4697
+ res.end(this.getSuccessHtml());
4698
+ if (this.resolvePromise) {
4699
+ this.resolvePromise(authToken);
4700
+ }
4701
+ } else {
4702
+ res.writeHead(404, { "Content-Type": "text/plain" });
4703
+ res.end("Not Found");
4704
+ }
4705
+ } catch (err) {
4706
+ console.error("Callback error:", err);
4707
+ res.writeHead(500, { "Content-Type": "text/plain" });
4708
+ res.end("Internal Server Error");
4709
+ }
4710
+ });
4711
+ this.server.on("error", (err) => {
4712
+ reject(err);
4713
+ });
4714
+ this.server.listen(this.config.callbackPort, "127.0.0.1", () => {
4715
+ console.log(import_chalk3.default.gray(`Local server: http://localhost:${this.config.callbackPort}`));
4716
+ resolve();
4717
+ });
4718
+ setTimeout(() => {
4719
+ if (this.rejectPromise) {
4720
+ this.rejectPromise(new Error("Login timeout, please try again"));
4721
+ }
4722
+ this.closeServer();
4723
+ }, 10 * 60 * 1e3);
4724
+ });
4641
4725
  }
4642
- fail(error) {
4643
- this.stopProgress();
4644
- const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
4645
- this.spinner.fail(`Upload failed: ${error} (${totalTime}s)`);
4726
+ buildLoginUrl() {
4727
+ const callbackUrl = `http://localhost:${this.config.callbackPort}${this.config.callbackPath}`;
4728
+ const url2 = `${this.config.webBaseUrl}/#/cli-login?login_token=${this.loginToken}&callback_url=${encodeURIComponent(callbackUrl)}`;
4729
+ return url2;
4646
4730
  }
4647
- startProgress() {
4648
- this.progressInterval = setInterval(() => {
4649
- const elapsed = Date.now() - this.startTime;
4650
- let progress;
4651
- if (this.isSimulatingProgress) {
4652
- const simulationElapsed = Date.now() - this.simulationStartTime;
4653
- const simulationProgress = Math.min(simulationElapsed / 6e4, 1);
4654
- progress = 0.9 + simulationProgress * 0.09;
4655
- } else {
4656
- progress = this.calculateProgress(elapsed);
4657
- }
4658
- const duration = this.formatDuration(Math.floor(elapsed / 1e3));
4659
- const progressBar = this.createProgressBar(progress);
4660
- this.spinner.text = `Uploading ${this.fileName}... ${progressBar} ${Math.round(progress * 100)}% (${duration})`;
4661
- }, PROGRESS_UPDATE_INTERVAL);
4731
+ waitForCallback() {
4732
+ return new Promise((resolve, reject) => {
4733
+ this.resolvePromise = resolve;
4734
+ this.rejectPromise = reject;
4735
+ });
4662
4736
  }
4663
- stopProgress() {
4664
- if (this.progressInterval) {
4665
- clearInterval(this.progressInterval);
4666
- this.progressInterval = null;
4737
+ parseAuthToken(authToken) {
4738
+ const firstDash = authToken.indexOf("-");
4739
+ if (firstDash <= 0 || firstDash === authToken.length - 1) {
4740
+ throw new Error("Invalid token format");
4741
+ }
4742
+ const address = authToken.slice(0, firstDash).trim();
4743
+ const token = authToken.slice(firstDash + 1).trim();
4744
+ if (!address || !token) {
4745
+ throw new Error("Token parsing failed: address or token is empty");
4667
4746
  }
4747
+ return { address, token };
4668
4748
  }
4669
- calculateProgress(elapsed) {
4670
- return Math.min(
4671
- elapsed / EXPECTED_UPLOAD_TIME * MAX_PROGRESS,
4672
- MAX_PROGRESS
4673
- );
4749
+ saveAuthConfig(config) {
4750
+ import_fs_extra4.default.ensureDirSync(CONFIG_DIR2);
4751
+ import_fs_extra4.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
4752
+ import_fs_extra4.default.chmodSync(AUTH_FILE2, 384);
4674
4753
  }
4675
- createProgressBar(progress, width = 20) {
4676
- const percentage = Math.min(progress, 1);
4677
- const filledWidth = Math.round(width * percentage);
4678
- const emptyWidth = width - filledWidth;
4679
- return `[${"\u2588".repeat(filledWidth)}${"\u2591".repeat(emptyWidth)}]`;
4754
+ closeServer() {
4755
+ if (this.server) {
4756
+ this.server.close();
4757
+ this.server = null;
4758
+ }
4680
4759
  }
4681
- formatDuration(seconds) {
4682
- if (seconds < 60) {
4683
- return `${seconds}s`;
4684
- } else if (seconds < 3600) {
4685
- const minutes = Math.floor(seconds / 60);
4686
- const remainingSeconds = seconds % 60;
4687
- return `${minutes}m ${remainingSeconds}s`;
4688
- } else {
4689
- const hours = Math.floor(seconds / 3600);
4690
- const minutes = Math.floor(seconds % 3600 / 60);
4691
- const remainingSeconds = seconds % 60;
4692
- return `${hours}h ${minutes}m ${remainingSeconds}s`;
4693
- }
4694
- }
4695
- };
4696
- async function calculateMD5(filePath) {
4697
- return new Promise((resolve, reject) => {
4698
- const hash = crypto.createHash("md5");
4699
- const stream4 = import_fs_extra4.default.createReadStream(filePath);
4700
- stream4.on("data", hash.update.bind(hash));
4701
- stream4.on("end", () => resolve(hash.digest("hex")));
4702
- stream4.on("error", reject);
4703
- });
4704
- }
4705
- async function compressDirectory(sourcePath) {
4706
- return new Promise((resolve, reject) => {
4707
- const tempDir = require("os").tmpdir();
4708
- if (!import_fs_extra4.default.existsSync(tempDir)) {
4709
- import_fs_extra4.default.mkdirSync(tempDir, { recursive: true });
4710
- }
4711
- const outputPath = import_path5.default.join(
4712
- tempDir,
4713
- `pinme_${import_path5.default.basename(sourcePath)}_${Date.now()}.zip`
4714
- );
4715
- const output = import_fs_extra4.default.createWriteStream(outputPath);
4716
- const zlib2 = require("zlib");
4717
- const gzip = zlib2.createGzip({ level: 9 });
4718
- output.on("close", () => resolve(outputPath));
4719
- gzip.on("error", reject);
4720
- gzip.pipe(output);
4721
- const stats = import_fs_extra4.default.statSync(sourcePath);
4722
- if (stats.isDirectory()) {
4723
- const archive = require("archiver");
4724
- const archiveStream = archive("zip", { zlib: { level: 9 } });
4725
- archiveStream.on("error", reject);
4726
- archiveStream.pipe(output);
4727
- archiveStream.directory(sourcePath, false);
4728
- archiveStream.finalize();
4729
- } else {
4730
- const fileStream = import_fs_extra4.default.createReadStream(sourcePath);
4731
- fileStream.pipe(gzip);
4760
+ // HTML templates
4761
+ getSuccessHtml() {
4762
+ return `
4763
+ <!DOCTYPE html>
4764
+ <html>
4765
+ <head>
4766
+ <title>Login Success - PinMe</title>
4767
+ <style>
4768
+ * { margin: 0; padding: 0; box-sizing: border-box; }
4769
+ body {
4770
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
4771
+ display: flex;
4772
+ justify-content: center;
4773
+ align-items: center;
4774
+ min-height: 100vh;
4775
+ background: #000;
4776
+ overflow: hidden;
4732
4777
  }
4733
- });
4734
- }
4735
- async function initChunkSession(filePath, deviceId, isDirectory = false) {
4736
- const stats = import_fs_extra4.default.statSync(filePath);
4737
- const fileName = import_path5.default.basename(filePath);
4738
- const fileSize = stats.size;
4739
- const md5 = await calculateMD5(filePath);
4740
- try {
4741
- const response = await axios_default.post(
4742
- `${IPFS_API_URL}/chunk/init`,
4743
- {
4744
- file_name: fileName,
4745
- file_size: fileSize,
4746
- md5,
4747
- is_directory: isDirectory,
4748
- uid: deviceId
4749
- },
4750
- {
4751
- timeout: TIMEOUT,
4752
- headers: { "Content-Type": "application/json" }
4753
- }
4754
- );
4755
- const { code, msg, data } = response.data;
4756
- if (code === 200 && data) {
4757
- return data;
4778
+ .bg {
4779
+ position: fixed;
4780
+ top: 0;
4781
+ left: 0;
4782
+ width: 100%;
4783
+ height: 100%;
4784
+ background:
4785
+ radial-gradient(ellipse at 20% 80%, rgba(120, 0, 255, 0.3) 0%, transparent 50%),
4786
+ radial-gradient(ellipse at 80% 20%, rgba(0, 200, 255, 0.3) 0%, transparent 50%),
4787
+ radial-gradient(ellipse at 50% 50%, rgba(255, 0, 150, 0.15) 0%, transparent 60%);
4788
+ animation: bgPulse 6s ease-in-out infinite;
4758
4789
  }
4759
- throw new Error(`Session initialization failed: ${msg} (code: ${code})`);
4760
- } catch (error) {
4761
- if (axios_default.isAxiosError(error)) {
4762
- throw new Error(`Network error: ${error.message}`);
4790
+ @keyframes bgPulse {
4791
+ 0%, 100% { opacity: 1; transform: scale(1); }
4792
+ 50% { opacity: 0.8; transform: scale(1.05); }
4763
4793
  }
4764
- throw error;
4765
- }
4766
- }
4767
- async function uploadChunkWithAbort(sessionId, chunkIndex, chunkData, deviceId, signal, retryCount = 0) {
4768
- try {
4769
- if (signal.aborted) {
4770
- throw new Error("Request cancelled");
4794
+ .grid {
4795
+ position: fixed;
4796
+ top: 0;
4797
+ left: 0;
4798
+ width: 200%;
4799
+ height: 200%;
4800
+ background-image:
4801
+ linear-gradient(rgba(0, 200, 255, 0.03) 1px, transparent 1px),
4802
+ linear-gradient(90deg, rgba(0, 200, 255, 0.03) 1px, transparent 1px);
4803
+ background-size: 50px 50px;
4804
+ transform: perspective(500px) rotateX(60deg) translateY(-50%) translateZ(-200px);
4805
+ animation: gridMove 20s linear infinite;
4771
4806
  }
4772
- const form = new import_form_data2.default();
4773
- form.append("session_id", sessionId);
4774
- form.append("chunk_index", chunkIndex.toString());
4775
- form.append("uid", deviceId);
4776
- form.append("chunk", chunkData, {
4777
- filename: `chunk_${chunkIndex}`,
4778
- contentType: "application/octet-stream"
4779
- });
4780
- const response = await axios_default.post(
4781
- `${IPFS_API_URL}/chunk/upload`,
4782
- form,
4783
- {
4784
- headers: { ...form.getHeaders() },
4785
- timeout: TIMEOUT,
4786
- signal
4787
- }
4788
- );
4789
- const { code, msg, data } = response.data;
4790
- if (code === 200 && data) {
4791
- return data;
4807
+ @keyframes gridMove {
4808
+ 0% { transform: perspective(500px) rotateX(60deg) translateY(0) translateZ(-200px); }
4809
+ 100% { transform: perspective(500px) rotateX(60deg) translateY(50px) translateZ(-200px); }
4792
4810
  }
4793
- throw new Error(`Chunk upload failed: ${msg} (code: ${code})`);
4794
- } catch (error) {
4795
- if (error.name === "CanceledError" || signal.aborted) {
4796
- throw new Error("Request cancelled");
4811
+ .container {
4812
+ position: relative;
4813
+ z-index: 10;
4814
+ background: linear-gradient(135deg, rgba(20, 20, 40, 0.9) 0%, rgba(10, 10, 30, 0.95) 100%);
4815
+ padding: 3.5rem 4rem;
4816
+ border-radius: 32px;
4817
+ box-shadow:
4818
+ 0 0 60px rgba(0, 200, 255, 0.15),
4819
+ 0 25px 50px rgba(0, 0, 0, 0.5),
4820
+ inset 0 1px 0 rgba(255, 255, 255, 0.1),
4821
+ inset 0 -1px 0 rgba(0, 200, 255, 0.1);
4822
+ text-align: center;
4823
+ border: 1px solid rgba(0, 200, 255, 0.2);
4824
+ max-width: 440px;
4825
+ backdrop-filter: blur(30px);
4797
4826
  }
4798
- if (retryCount < MAX_RETRIES) {
4799
- await delayWithAbortCheck(RETRY_DELAY, signal);
4800
- return uploadChunkWithAbort(
4801
- sessionId,
4802
- chunkIndex,
4803
- chunkData,
4804
- deviceId,
4805
- signal,
4806
- retryCount + 1
4807
- );
4827
+ .container::before {
4828
+ content: '';
4829
+ position: absolute;
4830
+ top: -1px;
4831
+ left: -1px;
4832
+ right: -1px;
4833
+ bottom: -1px;
4834
+ border-radius: 32px;
4835
+ background: linear-gradient(135deg, rgba(0, 200, 255, 0.5), rgba(255, 0, 150, 0.5), rgba(120, 0, 255, 0.5));
4836
+ z-index: -1;
4837
+ opacity: 0.5;
4838
+ animation: borderGlow 3s ease-in-out infinite;
4808
4839
  }
4809
- throw new Error(
4810
- `Chunk ${chunkIndex + 1} upload failed after ${MAX_RETRIES} retries: ${error.message}`
4811
- );
4812
- }
4813
- }
4814
- async function delayWithAbortCheck(delay, signal) {
4815
- return new Promise((resolve, reject) => {
4816
- const timeoutId = setTimeout(() => {
4817
- if (signal.aborted) {
4818
- reject(new Error("Request cancelled"));
4819
- } else {
4820
- resolve();
4821
- }
4822
- }, delay);
4823
- if (signal.aborted) {
4824
- clearTimeout(timeoutId);
4825
- reject(new Error("Request cancelled"));
4826
- return;
4840
+ @keyframes borderGlow {
4841
+ 0%, 100% { opacity: 0.3; }
4842
+ 50% { opacity: 0.7; }
4827
4843
  }
4828
- const checkInterval = setInterval(() => {
4829
- if (signal.aborted) {
4830
- clearTimeout(timeoutId);
4831
- clearInterval(checkInterval);
4832
- reject(new Error("Request cancelled"));
4833
- }
4834
- }, 50);
4835
- });
4836
- }
4837
- async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, deviceId, progressBar) {
4838
- const fileData = import_fs_extra4.default.readFileSync(filePath);
4839
- const abortController = new AbortController();
4840
- let completedCount = 0;
4841
- let hasFatalError = false;
4842
- let fatalError = null;
4843
- const uploadTasks = Array.from({ length: totalChunks }, (_, chunkIndex) => {
4844
- const start = chunkIndex * chunkSize;
4845
- const end = Math.min(start + chunkSize, fileData.length);
4846
- const chunkData = fileData.slice(start, end);
4847
- return async () => {
4848
- if (abortController.signal.aborted) return;
4849
- try {
4850
- await uploadChunkWithAbort(
4851
- sessionId,
4852
- chunkIndex,
4853
- chunkData,
4854
- deviceId,
4855
- abortController.signal
4856
- );
4857
- if (abortController.signal.aborted) return;
4858
- completedCount++;
4859
- progressBar.updateProgress(completedCount, totalChunks);
4860
- } catch (error) {
4861
- if (error.name === "AbortError" || abortController.signal.aborted) {
4862
- return;
4863
- }
4864
- hasFatalError = true;
4865
- fatalError = `Chunk ${chunkIndex + 1}/${totalChunks} upload failed: ${error.message}`;
4866
- abortController.abort();
4867
- throw new Error(fatalError);
4868
- }
4869
- };
4870
- });
4871
- try {
4872
- const results = await Promise.allSettled(uploadTasks.map((task) => task()));
4873
- const failedResults = results.filter(
4874
- (result) => result.status === "rejected"
4875
- );
4876
- if (failedResults.length > 0) {
4877
- const firstFailure = failedResults[0];
4878
- throw new Error(
4879
- firstFailure.reason.message || "Error occurred during upload"
4880
- );
4844
+ .success-icon {
4845
+ font-size: 5rem;
4846
+ margin-bottom: 1.5rem;
4847
+ animation: bounceIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
4848
+ filter: drop-shadow(0 0 20px rgba(0, 200, 255, 0.5));
4881
4849
  }
4882
- if (hasFatalError) {
4883
- throw new Error(fatalError || "Unknown error occurred during upload");
4850
+ @keyframes bounceIn {
4851
+ 0% { transform: scale(0); opacity: 0; }
4852
+ 50% { transform: scale(1.2); }
4853
+ 100% { transform: scale(1); opacity: 1; }
4884
4854
  }
4885
- } catch (error) {
4886
- throw fatalError ? new Error(fatalError) : error;
4887
- }
4888
- }
4889
- async function completeChunkUpload(sessionId, deviceId, importAsCar = false) {
4890
- try {
4891
- const requestBody = { session_id: sessionId, uid: deviceId };
4892
- if (importAsCar) {
4893
- requestBody.import_as_car = true;
4894
- }
4895
- const response = await axios_default.post(
4896
- `${IPFS_API_URL}/chunk/complete`,
4897
- requestBody,
4898
- {
4899
- timeout: TIMEOUT,
4900
- headers: { "Content-Type": "application/json" }
4901
- }
4902
- );
4903
- const { code, msg, data } = response.data;
4904
- if (code === 200 && data) {
4905
- return data.trace_id;
4906
- }
4907
- throw new Error(`Complete upload failed: ${msg} (code: ${code})`);
4908
- } catch (error) {
4909
- if (axios_default.isAxiosError(error)) {
4910
- throw new Error(`Network error: ${error.message}`);
4911
- }
4912
- throw error;
4913
- }
4914
- }
4915
- async function getChunkStatus(sessionId, deviceId) {
4916
- try {
4917
- const response = await axios_default.get(
4918
- `${IPFS_API_URL}/up_status`,
4919
- {
4920
- params: { trace_id: sessionId, uid: deviceId },
4921
- timeout: TIMEOUT,
4922
- headers: { "Content-Type": "application/json" }
4923
- }
4924
- );
4925
- const { code, msg, data } = response.data;
4926
- if (code === 200) {
4927
- return data;
4928
- }
4929
- throw new Error(`Server returned error: ${msg} (code: ${code})`);
4930
- } catch (error) {
4931
- if (axios_default.isAxiosError(error)) {
4932
- throw new Error(`Network error: ${error.message}`);
4933
- }
4934
- throw error;
4935
- }
4936
- }
4937
- async function monitorChunkProgress(traceId, deviceId, progressBar) {
4938
- let consecutiveErrors = 0;
4939
- const startTime = Date.now();
4940
- if (progressBar) {
4941
- progressBar.startSimulatingProgress();
4942
- }
4943
- try {
4944
- while (Date.now() - startTime < MAX_POLL_TIME) {
4945
- try {
4946
- const status = await getChunkStatus(traceId, deviceId);
4947
- consecutiveErrors = 0;
4948
- if (status.is_ready && status.upload_rst.Hash) {
4949
- if (progressBar) {
4950
- progressBar.stopSimulatingProgress();
4951
- }
4952
- return {
4953
- hash: status.upload_rst.Hash,
4954
- shortUrl: status.upload_rst.ShortUrl
4955
- };
4956
- }
4957
- } catch (error) {
4958
- consecutiveErrors++;
4959
- if (consecutiveErrors > 10) {
4960
- throw new Error(`Polling failed: ${error.message}`);
4961
- }
4962
- }
4963
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
4964
- }
4965
- const maxPollTimeMinutes = Math.floor(MAX_POLL_TIME / (60 * 1e3));
4966
- throw new Error(`Polling timeout after ${maxPollTimeMinutes} minutes`);
4967
- } finally {
4968
- if (progressBar) {
4969
- progressBar.stopSimulatingProgress();
4970
- }
4971
- }
4972
- }
4973
- async function uploadDirectoryInChunks(directoryPath, deviceId, importAsCar = false) {
4974
- const sizeCheck = checkDirectorySizeLimit(directoryPath);
4975
- if (sizeCheck.exceeds) {
4976
- throw new Error(
4977
- `Directory ${directoryPath} exceeds size limit ${formatSize(
4978
- sizeCheck.limit
4979
- )} (size: ${formatSize(sizeCheck.size)})`
4980
- );
4981
- }
4982
- const progressBar = new StepProgressBar(import_path5.default.basename(directoryPath), true);
4983
- try {
4984
- progressBar.startStep(0, "Preparing compression");
4985
- const compressedPath = await compressDirectory(directoryPath);
4986
- progressBar.completeStep();
4987
- progressBar.startStep(1, "Initializing session");
4988
- const sessionInfo = await initChunkSession(compressedPath, deviceId, true);
4989
- progressBar.completeStep();
4990
- progressBar.startStep(2, "Chunk upload");
4991
- await uploadFileChunks(
4992
- compressedPath,
4993
- sessionInfo.session_id,
4994
- sessionInfo.total_chunks,
4995
- sessionInfo.chunk_size,
4996
- deviceId,
4997
- progressBar
4998
- );
4999
- progressBar.completeStep();
5000
- progressBar.startStep(3, "Completing upload");
5001
- const traceId = await completeChunkUpload(sessionInfo.session_id, deviceId, importAsCar);
5002
- progressBar.completeStep();
5003
- progressBar.startStep(4, "Waiting for processing");
5004
- const result = await monitorChunkProgress(traceId, deviceId, progressBar);
5005
- progressBar.completeStep();
5006
- try {
5007
- import_fs_extra4.default.unlinkSync(compressedPath);
5008
- } catch (error) {
5009
- }
5010
- const uploadData = {
5011
- path: directoryPath,
5012
- filename: import_path5.default.basename(directoryPath),
5013
- contentHash: (result == null ? void 0 : result.hash) || "unknown",
5014
- size: sizeCheck.size,
5015
- fileCount: 0,
5016
- isDirectory: true,
5017
- shortUrl: (result == null ? void 0 : result.shortUrl) || null
5018
- };
5019
- saveUploadHistory(uploadData);
5020
- if (!(result == null ? void 0 : result.hash)) {
5021
- throw new Error("Server did not return valid hash value");
5022
- }
5023
- progressBar.complete();
5024
- return result;
5025
- } catch (error) {
5026
- progressBar.fail(error.message);
5027
- throw error;
5028
- }
5029
- }
5030
- async function uploadFileInChunks(filePath, deviceId, importAsCar = false) {
5031
- const sizeCheck = checkFileSizeLimit(filePath);
5032
- if (sizeCheck.exceeds) {
5033
- throw new Error(
5034
- `File ${filePath} exceeds size limit ${formatSize(
5035
- sizeCheck.limit
5036
- )} (size: ${formatSize(sizeCheck.size)})`
5037
- );
5038
- }
5039
- const fileName = import_path5.default.basename(filePath);
5040
- const progressBar = new StepProgressBar(fileName, false);
5041
- try {
5042
- progressBar.startStep(0, "Initializing session");
5043
- const sessionInfo = await initChunkSession(filePath, deviceId, false);
5044
- progressBar.completeStep();
5045
- progressBar.startStep(1, "Chunk upload");
5046
- await uploadFileChunks(
5047
- filePath,
5048
- sessionInfo.session_id,
5049
- sessionInfo.total_chunks,
5050
- sessionInfo.chunk_size,
5051
- deviceId,
5052
- progressBar
5053
- );
5054
- progressBar.completeStep();
5055
- progressBar.startStep(2, "Completing upload");
5056
- const traceId = await completeChunkUpload(sessionInfo.session_id, deviceId, importAsCar);
5057
- progressBar.completeStep();
5058
- progressBar.startStep(3, "Waiting for processing");
5059
- const result = await monitorChunkProgress(traceId, deviceId, progressBar);
5060
- progressBar.completeStep();
5061
- const uploadData = {
5062
- path: filePath,
5063
- filename: fileName,
5064
- contentHash: (result == null ? void 0 : result.hash) || "unknown",
5065
- previewHash: null,
5066
- size: sizeCheck.size,
5067
- fileCount: 1,
5068
- isDirectory: false,
5069
- shortUrl: (result == null ? void 0 : result.shortUrl) || null
5070
- };
5071
- saveUploadHistory(uploadData);
5072
- if (!(result == null ? void 0 : result.hash)) {
5073
- throw new Error("Server did not return valid hash value");
5074
- }
5075
- progressBar.complete();
5076
- return result;
5077
- } catch (error) {
5078
- progressBar.fail(error.message);
5079
- throw error;
5080
- }
5081
- }
5082
- async function uploadToIpfsSplit_default(filePath, importAsCar = false) {
5083
- const deviceId = getUid();
5084
- if (!deviceId) {
5085
- throw new Error("Device ID not found");
5086
- }
5087
- try {
5088
- const isDirectory = import_fs_extra4.default.statSync(filePath).isDirectory();
5089
- const result = isDirectory ? await uploadDirectoryInChunks(filePath, deviceId, importAsCar) : await uploadFileInChunks(filePath, deviceId, importAsCar);
5090
- if (result == null ? void 0 : result.hash) {
5091
- return {
5092
- contentHash: result.hash,
5093
- previewHash: null,
5094
- shortUrl: result.shortUrl
5095
- };
5096
- }
5097
- return null;
5098
- } catch (error) {
5099
- return null;
5100
- }
5101
- }
5102
-
5103
- // bin/upload.ts
5104
- var import_fs2 = __toESM(require("fs"));
5105
- var import_crypto_js = __toESM(require("crypto-js"));
5106
-
5107
- // bin/utils/pinmeApi.ts
5108
- var import_chalk4 = __toESM(require("chalk"));
5109
-
5110
- // bin/utils/webLogin.ts
5111
- var import_crypto = __toESM(require("crypto"));
5112
- var import_http3 = __toESM(require("http"));
5113
- var import_url2 = require("url");
5114
- var import_chalk3 = __toESM(require("chalk"));
5115
- var import_child_process = require("child_process");
5116
- var import_fs_extra5 = __toESM(require("fs-extra"));
5117
- var import_os4 = __toESM(require("os"));
5118
- var import_path6 = __toESM(require("path"));
5119
- function openBrowser(url2) {
5120
- const platform = process.platform;
5121
- let command;
5122
- if (platform === "darwin") {
5123
- command = `open "${url2}"`;
5124
- } else if (platform === "win32") {
5125
- command = `start "" "${url2}"`;
5126
- } else {
5127
- command = `xdg-open "${url2}"`;
5128
- }
5129
- (0, import_child_process.exec)(command, (err) => {
5130
- if (err) {
5131
- console.log(import_chalk3.default.yellow(`Unable to open browser automatically. Please visit manually: ${url2}`));
5132
- }
5133
- });
5134
- }
5135
- var CONFIG_DIR2 = import_path6.default.join(import_os4.default.homedir(), ".pinme");
5136
- var AUTH_FILE2 = import_path6.default.join(CONFIG_DIR2, "auth.json");
5137
- var DEFAULT_OPTIONS = {
5138
- apiBaseUrl: "https://pinme.dev/api/v4",
5139
- webBaseUrl: process.env.PINME_WEB_URL || "http://localhost:5173",
5140
- callbackPort: 34567,
5141
- callbackPath: "/cli/callback"
5142
- };
5143
- var WebLoginManager = class {
5144
- config;
5145
- server = null;
5146
- resolvePromise = null;
5147
- rejectPromise = null;
5148
- loginToken = "";
5149
- constructor(options = {}) {
5150
- this.config = { ...DEFAULT_OPTIONS, ...options };
5151
- }
5152
- async login() {
5153
- console.log(import_chalk3.default.blue("Starting login flow...\n"));
5154
- this.loginToken = this.generateLoginToken();
5155
- console.log(import_chalk3.default.blue("Starting local callback server..."));
5156
- await this.startCallbackServer();
5157
- try {
5158
- const loginUrl = this.buildLoginUrl();
5159
- console.log(import_chalk3.default.blue("Opening browser..."));
5160
- console.log(import_chalk3.default.white("If browser does not open automatically, please visit manually:"));
5161
- console.log(import_chalk3.default.cyan(` ${loginUrl}
5162
- `));
5163
- openBrowser(loginUrl);
5164
- console.log(import_chalk3.default.yellow("Please complete login in browser..."));
5165
- console.log(import_chalk3.default.gray("Browser will close automatically after successful login.\n"));
5166
- const authToken = await this.waitForCallback();
5167
- const authConfig = this.parseAuthToken(authToken);
5168
- this.saveAuthConfig(authConfig);
5169
- console.log(import_chalk3.default.green("\nLogin successful!"));
5170
- if (authConfig.email) {
5171
- console.log(import_chalk3.default.green(`Welcome, ${authConfig.email}`));
5172
- }
5173
- console.log(import_chalk3.default.gray(`Address: ${authConfig.address}`));
5174
- return authConfig;
5175
- } catch (error) {
5176
- console.error(import_chalk3.default.red(`
5177
- Login failed: ${error.message}`));
5178
- throw error;
5179
- } finally {
5180
- this.closeServer();
4855
+ h1 {
4856
+ color: #fff;
4857
+ font-size: 2.2rem;
4858
+ font-weight: 700;
4859
+ margin: 0 0 0.75rem 0;
4860
+ background: linear-gradient(90deg, #fff, #00d4ff);
4861
+ -webkit-background-clip: text;
4862
+ -webkit-text-fill-color: transparent;
4863
+ background-clip: text;
5181
4864
  }
5182
- }
5183
- generateLoginToken() {
5184
- return import_crypto.default.randomBytes(32).toString("hex");
5185
- }
5186
- async startCallbackServer() {
5187
- return new Promise((resolve, reject) => {
5188
- this.server = import_http3.default.createServer(async (req, res) => {
5189
- try {
5190
- const url2 = new import_url2.URL(req.url || "", `http://localhost:${this.config.callbackPort}`);
5191
- if (url2.pathname === this.config.callbackPath) {
5192
- const authToken = url2.searchParams.get("token");
5193
- const error = url2.searchParams.get("error");
5194
- const loginToken = url2.searchParams.get("login_token");
5195
- if (error) {
5196
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
5197
- res.end(this.getErrorHtml(error));
5198
- if (this.rejectPromise) {
5199
- this.rejectPromise(new Error(error));
5200
- }
5201
- return;
5202
- }
5203
- if (!authToken) {
5204
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
5205
- res.end(this.getErrorHtml("Auth token not received"));
5206
- if (this.rejectPromise) {
5207
- this.rejectPromise(new Error("Auth token not received"));
5208
- }
5209
- return;
5210
- }
5211
- if (loginToken !== this.loginToken) {
5212
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
5213
- res.end(this.getErrorHtml("Login token invalid or expired"));
5214
- if (this.rejectPromise) {
5215
- this.rejectPromise(new Error("Login token invalid or expired"));
5216
- }
5217
- return;
5218
- }
5219
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
5220
- res.end(this.getSuccessHtml());
5221
- if (this.resolvePromise) {
5222
- this.resolvePromise(authToken);
5223
- }
5224
- } else {
5225
- res.writeHead(404, { "Content-Type": "text/plain" });
5226
- res.end("Not Found");
5227
- }
5228
- } catch (err) {
5229
- console.error("Callback error:", err);
5230
- res.writeHead(500, { "Content-Type": "text/plain" });
5231
- res.end("Internal Server Error");
5232
- }
5233
- });
5234
- this.server.on("error", (err) => {
5235
- reject(err);
5236
- });
5237
- this.server.listen(this.config.callbackPort, "127.0.0.1", () => {
5238
- console.log(import_chalk3.default.gray(`Local server: http://localhost:${this.config.callbackPort}`));
5239
- resolve();
5240
- });
5241
- setTimeout(() => {
5242
- if (this.rejectPromise) {
5243
- this.rejectPromise(new Error("Login timeout, please try again"));
5244
- }
5245
- this.closeServer();
5246
- }, 10 * 60 * 1e3);
5247
- });
5248
- }
5249
- buildLoginUrl() {
5250
- const callbackUrl = `http://localhost:${this.config.callbackPort}${this.config.callbackPath}`;
5251
- const url2 = `${this.config.webBaseUrl}/#/cli-login?login_token=${this.loginToken}&callback_url=${encodeURIComponent(callbackUrl)}`;
5252
- return url2;
5253
- }
5254
- waitForCallback() {
5255
- return new Promise((resolve, reject) => {
5256
- this.resolvePromise = resolve;
5257
- this.rejectPromise = reject;
5258
- });
5259
- }
5260
- parseAuthToken(authToken) {
5261
- const firstDash = authToken.indexOf("-");
5262
- if (firstDash <= 0 || firstDash === authToken.length - 1) {
5263
- throw new Error("Invalid token format");
4865
+ p {
4866
+ color: rgba(255, 255, 255, 0.6);
4867
+ font-size: 1.1rem;
4868
+ margin: 0 0 2rem 0;
4869
+ line-height: 1.6;
5264
4870
  }
5265
- const address = authToken.slice(0, firstDash).trim();
5266
- const token = authToken.slice(firstDash + 1).trim();
5267
- if (!address || !token) {
5268
- throw new Error("Token parsing failed: address or token is empty");
4871
+ .highlight { color: #00d4ff; font-weight: 600; }
4872
+ .sparkle {
4873
+ position: absolute;
4874
+ width: 4px;
4875
+ height: 4px;
4876
+ background: #00d4ff;
4877
+ border-radius: 50%;
4878
+ animation: sparkle 2s ease-in-out infinite;
5269
4879
  }
5270
- return { address, token };
5271
- }
5272
- saveAuthConfig(config) {
5273
- import_fs_extra5.default.ensureDirSync(CONFIG_DIR2);
5274
- import_fs_extra5.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
5275
- import_fs_extra5.default.chmodSync(AUTH_FILE2, 384);
5276
- }
5277
- closeServer() {
5278
- if (this.server) {
5279
- this.server.close();
5280
- this.server = null;
4880
+ .sparkle:nth-child(1) { top: 20%; left: 10%; animation-delay: 0s; }
4881
+ .sparkle:nth-child(2) { top: 30%; right: 15%; animation-delay: 0.5s; }
4882
+ .sparkle:nth-child(3) { bottom: 25%; left: 20%; animation-delay: 1s; }
4883
+ .sparkle:nth-child(4) { bottom: 35%; right: 10%; animation-delay: 1.5s; }
4884
+ @keyframes sparkle {
4885
+ 0%, 100% { opacity: 0; transform: scale(0); }
4886
+ 50% { opacity: 1; transform: scale(1); }
5281
4887
  }
4888
+ </style>
4889
+ </head>
4890
+ <body>
4891
+ <div class="bg"></div>
4892
+ <div class="grid"></div>
4893
+ <div class="container">
4894
+ <div class="sparkle"></div>
4895
+ <div class="sparkle"></div>
4896
+ <div class="sparkle"></div>
4897
+ <div class="sparkle"></div>
4898
+ <div class="success-icon">\u{1F389}</div>
4899
+ <h1>Welcome to PinMe</h1>
4900
+ <p>You are now logged in! <span class="highlight">\u{1F680}</span><br>Return to your terminal to continue.</p>
4901
+ </div>
4902
+ </body>
4903
+ </html>`;
5282
4904
  }
5283
- // HTML templates
5284
- getSuccessHtml() {
4905
+ getErrorHtml(error) {
4906
+ const encodedError = encodeURIComponent(error);
5285
4907
  return `
5286
4908
  <!DOCTYPE html>
5287
4909
  <html>
5288
4910
  <head>
5289
- <title>Login Success - PinMe</title>
4911
+ <title>Login Failed - PinMe</title>
5290
4912
  <style>
5291
4913
  * { margin: 0; padding: 0; box-sizing: border-box; }
5292
4914
  body {
@@ -5305,9 +4927,9 @@ Login failed: ${error.message}`));
5305
4927
  width: 100%;
5306
4928
  height: 100%;
5307
4929
  background:
5308
- radial-gradient(ellipse at 20% 80%, rgba(120, 0, 255, 0.3) 0%, transparent 50%),
5309
- radial-gradient(ellipse at 80% 20%, rgba(0, 200, 255, 0.3) 0%, transparent 50%),
5310
- radial-gradient(ellipse at 50% 50%, rgba(255, 0, 150, 0.15) 0%, transparent 60%);
4930
+ radial-gradient(ellipse at 20% 80%, rgba(255, 50, 50, 0.2) 0%, transparent 50%),
4931
+ radial-gradient(ellipse at 80% 20%, rgba(255, 100, 50, 0.2) 0%, transparent 50%),
4932
+ radial-gradient(ellipse at 50% 50%, rgba(100, 0, 50, 0.15) 0%, transparent 60%);
5311
4933
  animation: bgPulse 6s ease-in-out infinite;
5312
4934
  }
5313
4935
  @keyframes bgPulse {
@@ -5321,8 +4943,8 @@ Login failed: ${error.message}`));
5321
4943
  width: 200%;
5322
4944
  height: 200%;
5323
4945
  background-image:
5324
- linear-gradient(rgba(0, 200, 255, 0.03) 1px, transparent 1px),
5325
- linear-gradient(90deg, rgba(0, 200, 255, 0.03) 1px, transparent 1px);
4946
+ linear-gradient(rgba(255, 80, 80, 0.03) 1px, transparent 1px),
4947
+ linear-gradient(90deg, rgba(255, 80, 80, 0.03) 1px, transparent 1px);
5326
4948
  background-size: 50px 50px;
5327
4949
  transform: perspective(500px) rotateX(60deg) translateY(-50%) translateZ(-200px);
5328
4950
  animation: gridMove 20s linear infinite;
@@ -5334,16 +4956,16 @@ Login failed: ${error.message}`));
5334
4956
  .container {
5335
4957
  position: relative;
5336
4958
  z-index: 10;
5337
- background: linear-gradient(135deg, rgba(20, 20, 40, 0.9) 0%, rgba(10, 10, 30, 0.95) 100%);
4959
+ background: linear-gradient(135deg, rgba(40, 20, 20, 0.9) 0%, rgba(30, 10, 10, 0.95) 100%);
5338
4960
  padding: 3.5rem 4rem;
5339
4961
  border-radius: 32px;
5340
4962
  box-shadow:
5341
- 0 0 60px rgba(0, 200, 255, 0.15),
4963
+ 0 0 60px rgba(255, 50, 50, 0.15),
5342
4964
  0 25px 50px rgba(0, 0, 0, 0.5),
5343
4965
  inset 0 1px 0 rgba(255, 255, 255, 0.1),
5344
- inset 0 -1px 0 rgba(0, 200, 255, 0.1);
4966
+ inset 0 -1px 0 rgba(255, 50, 50, 0.1);
5345
4967
  text-align: center;
5346
- border: 1px solid rgba(0, 200, 255, 0.2);
4968
+ border: 1px solid rgba(255, 50, 50, 0.2);
5347
4969
  max-width: 440px;
5348
4970
  backdrop-filter: blur(30px);
5349
4971
  }
@@ -5355,255 +4977,652 @@ Login failed: ${error.message}`));
5355
4977
  right: -1px;
5356
4978
  bottom: -1px;
5357
4979
  border-radius: 32px;
5358
- background: linear-gradient(135deg, rgba(0, 200, 255, 0.5), rgba(255, 0, 150, 0.5), rgba(120, 0, 255, 0.5));
4980
+ background: linear-gradient(135deg, rgba(255, 50, 50, 0.5), rgba(255, 150, 50, 0.5), rgba(150, 0, 50, 0.5));
5359
4981
  z-index: -1;
5360
4982
  opacity: 0.5;
5361
4983
  animation: borderGlow 3s ease-in-out infinite;
5362
4984
  }
5363
- @keyframes borderGlow {
5364
- 0%, 100% { opacity: 0.3; }
5365
- 50% { opacity: 0.7; }
4985
+ @keyframes borderGlow {
4986
+ 0%, 100% { opacity: 0.3; }
4987
+ 50% { opacity: 0.7; }
4988
+ }
4989
+ .error-icon {
4990
+ font-size: 5rem;
4991
+ margin-bottom: 1.5rem;
4992
+ animation: shake 0.5s ease-in-out;
4993
+ filter: drop-shadow(0 0 20px rgba(255, 50, 50, 0.5));
4994
+ }
4995
+ @keyframes shake {
4996
+ 0%, 100% { transform: translateX(0); }
4997
+ 20% { transform: translateX(-10px) rotate(-5deg); }
4998
+ 40% { transform: translateX(10px) rotate(5deg); }
4999
+ 60% { transform: translateX(-10px) rotate(-5deg); }
5000
+ 80% { transform: translateX(10px) rotate(5deg); }
5001
+ }
5002
+ h1 {
5003
+ color: #fff;
5004
+ font-size: 2.2rem;
5005
+ font-weight: 700;
5006
+ margin: 0 0 0.75rem 0;
5007
+ background: linear-gradient(90deg, #fff, #ff5050);
5008
+ -webkit-background-clip: text;
5009
+ -webkit-text-fill-color: transparent;
5010
+ background-clip: text;
5011
+ }
5012
+ .error {
5013
+ color: #ff6b6b;
5014
+ font-size: 1rem;
5015
+ margin: 0 0 2rem 0;
5016
+ padding: 1.25rem;
5017
+ background: rgba(255, 50, 50, 0.1);
5018
+ border-radius: 16px;
5019
+ border: 1px solid rgba(255, 50, 50, 0.2);
5020
+ font-weight: 500;
5021
+ box-shadow: 0 0 20px rgba(255, 50, 50, 0.1);
5022
+ }
5023
+ </style>
5024
+ </head>
5025
+ <body>
5026
+ <div class="bg"></div>
5027
+ <div class="grid"></div>
5028
+ <div class="container">
5029
+ <div class="error-icon">\u{1F635}</div>
5030
+ <h1>Oops!</h1>
5031
+ <div class="error">${error}</div>
5032
+ </div>
5033
+ </body>
5034
+ </html>`;
5035
+ }
5036
+ };
5037
+ var webLoginManager = new WebLoginManager();
5038
+ function setAuthToken(combined) {
5039
+ const firstDash = combined.indexOf("-");
5040
+ if (firstDash <= 0 || firstDash === combined.length - 1) {
5041
+ throw new Error('Invalid token format. Expected "<address>-<jwt>".');
5042
+ }
5043
+ const address = combined.slice(0, firstDash).trim();
5044
+ const token = combined.slice(firstDash + 1).trim();
5045
+ if (!address || !token) {
5046
+ throw new Error("Invalid token content. Address or token is empty.");
5047
+ }
5048
+ const config = { address, token };
5049
+ import_fs_extra4.default.ensureDirSync(CONFIG_DIR2);
5050
+ import_fs_extra4.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
5051
+ return config;
5052
+ }
5053
+ function getAuthConfig2() {
5054
+ try {
5055
+ if (!import_fs_extra4.default.existsSync(AUTH_FILE2)) return null;
5056
+ const data = import_fs_extra4.default.readJsonSync(AUTH_FILE2);
5057
+ if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
5058
+ return data;
5059
+ } catch {
5060
+ return null;
5061
+ }
5062
+ }
5063
+ function clearAuthToken() {
5064
+ try {
5065
+ if (import_fs_extra4.default.existsSync(AUTH_FILE2)) {
5066
+ import_fs_extra4.default.removeSync(AUTH_FILE2);
5067
+ }
5068
+ } catch (error) {
5069
+ console.error(`Failed to clear auth token: ${error}`);
5070
+ }
5071
+ }
5072
+ function getAuthHeaders() {
5073
+ const conf = getAuthConfig2();
5074
+ if (!conf) {
5075
+ throw new Error("Auth not set. Run: pinme login");
5076
+ }
5077
+ return {
5078
+ "token-address": conf.address,
5079
+ "authentication-tokens": conf.token
5080
+ };
5081
+ }
5082
+
5083
+ // bin/utils/uploadToIpfsSplit.ts
5084
+ var IPFS_API_URL = "https://pinme.dev/api/v3";
5085
+ var MAX_RETRIES = parseInt(process.env.MAX_RETRIES || "2");
5086
+ var RETRY_DELAY = parseInt(process.env.RETRY_DELAY_MS || "1000");
5087
+ var TIMEOUT = parseInt(process.env.TIMEOUT_MS || "600000");
5088
+ var MAX_POLL_TIME = parseInt("5") * 60 * 1e3;
5089
+ var POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL_SECONDS || "2") * 1e3;
5090
+ var PROGRESS_UPDATE_INTERVAL = 200;
5091
+ var EXPECTED_UPLOAD_TIME = 6e4;
5092
+ var MAX_PROGRESS = 0.9;
5093
+ var StepProgressBar = class {
5094
+ spinner;
5095
+ fileName;
5096
+ startTime;
5097
+ currentStep = 0;
5098
+ stepStartTime = 0;
5099
+ progressInterval = null;
5100
+ isSimulatingProgress = false;
5101
+ simulationStartTime = 0;
5102
+ constructor(fileName, isDirectory = false) {
5103
+ this.fileName = fileName;
5104
+ this.spinner = (0, import_ora.default)(`Preparing to upload ${fileName}...`).start();
5105
+ this.startTime = Date.now();
5106
+ this.stepStartTime = Date.now();
5107
+ this.startProgress();
5108
+ }
5109
+ startStep(stepIndex, stepName) {
5110
+ this.currentStep = stepIndex;
5111
+ this.stepStartTime = Date.now();
5112
+ }
5113
+ updateProgress(progress, total) {
5114
+ }
5115
+ completeStep() {
5116
+ }
5117
+ // Start simulating progress to continue display after 90%
5118
+ startSimulatingProgress() {
5119
+ this.isSimulatingProgress = true;
5120
+ this.simulationStartTime = Date.now();
5121
+ }
5122
+ // Stop simulating progress
5123
+ stopSimulatingProgress() {
5124
+ this.isSimulatingProgress = false;
5125
+ }
5126
+ failStep(error) {
5127
+ this.stopProgress();
5128
+ this.spinner.fail(`Upload failed: ${error}`);
5129
+ }
5130
+ complete() {
5131
+ this.stopProgress();
5132
+ const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
5133
+ const progressBar = this.createProgressBar(1);
5134
+ this.spinner.succeed(
5135
+ `Upload completed ${progressBar} 100% (${totalTime}s)`
5136
+ );
5137
+ }
5138
+ fail(error) {
5139
+ this.stopProgress();
5140
+ const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
5141
+ this.spinner.fail(`Upload failed: ${error} (${totalTime}s)`);
5142
+ }
5143
+ startProgress() {
5144
+ this.progressInterval = setInterval(() => {
5145
+ const elapsed = Date.now() - this.startTime;
5146
+ let progress;
5147
+ if (this.isSimulatingProgress) {
5148
+ const simulationElapsed = Date.now() - this.simulationStartTime;
5149
+ const simulationProgress = Math.min(simulationElapsed / 6e4, 1);
5150
+ progress = 0.9 + simulationProgress * 0.09;
5151
+ } else {
5152
+ progress = this.calculateProgress(elapsed);
5153
+ }
5154
+ const duration = this.formatDuration(Math.floor(elapsed / 1e3));
5155
+ const progressBar = this.createProgressBar(progress);
5156
+ this.spinner.text = `Uploading ${this.fileName}... ${progressBar} ${Math.round(progress * 100)}% (${duration})`;
5157
+ }, PROGRESS_UPDATE_INTERVAL);
5158
+ }
5159
+ stopProgress() {
5160
+ if (this.progressInterval) {
5161
+ clearInterval(this.progressInterval);
5162
+ this.progressInterval = null;
5163
+ }
5164
+ }
5165
+ calculateProgress(elapsed) {
5166
+ return Math.min(
5167
+ elapsed / EXPECTED_UPLOAD_TIME * MAX_PROGRESS,
5168
+ MAX_PROGRESS
5169
+ );
5170
+ }
5171
+ createProgressBar(progress, width = 20) {
5172
+ const percentage = Math.min(progress, 1);
5173
+ const filledWidth = Math.round(width * percentage);
5174
+ const emptyWidth = width - filledWidth;
5175
+ return `[${"\u2588".repeat(filledWidth)}${"\u2591".repeat(emptyWidth)}]`;
5176
+ }
5177
+ formatDuration(seconds) {
5178
+ if (seconds < 60) {
5179
+ return `${seconds}s`;
5180
+ } else if (seconds < 3600) {
5181
+ const minutes = Math.floor(seconds / 60);
5182
+ const remainingSeconds = seconds % 60;
5183
+ return `${minutes}m ${remainingSeconds}s`;
5184
+ } else {
5185
+ const hours = Math.floor(seconds / 3600);
5186
+ const minutes = Math.floor(seconds % 3600 / 60);
5187
+ const remainingSeconds = seconds % 60;
5188
+ return `${hours}h ${minutes}m ${remainingSeconds}s`;
5189
+ }
5190
+ }
5191
+ };
5192
+ async function calculateMD5(filePath) {
5193
+ return new Promise((resolve, reject) => {
5194
+ const hash = crypto2.createHash("md5");
5195
+ const stream4 = import_fs_extra5.default.createReadStream(filePath);
5196
+ stream4.on("data", hash.update.bind(hash));
5197
+ stream4.on("end", () => resolve(hash.digest("hex")));
5198
+ stream4.on("error", reject);
5199
+ });
5200
+ }
5201
+ async function compressDirectory(sourcePath) {
5202
+ return new Promise((resolve, reject) => {
5203
+ const tempDir = require("os").tmpdir();
5204
+ if (!import_fs_extra5.default.existsSync(tempDir)) {
5205
+ import_fs_extra5.default.mkdirSync(tempDir, { recursive: true });
5206
+ }
5207
+ const outputPath = import_path6.default.join(
5208
+ tempDir,
5209
+ `pinme_${import_path6.default.basename(sourcePath)}_${Date.now()}.zip`
5210
+ );
5211
+ const output = import_fs_extra5.default.createWriteStream(outputPath);
5212
+ const zlib2 = require("zlib");
5213
+ const gzip = zlib2.createGzip({ level: 9 });
5214
+ output.on("close", () => resolve(outputPath));
5215
+ gzip.on("error", reject);
5216
+ gzip.pipe(output);
5217
+ const stats = import_fs_extra5.default.statSync(sourcePath);
5218
+ if (stats.isDirectory()) {
5219
+ const archive = require("archiver");
5220
+ const archiveStream = archive("zip", { zlib: { level: 9 } });
5221
+ archiveStream.on("error", reject);
5222
+ archiveStream.pipe(output);
5223
+ archiveStream.directory(sourcePath, false);
5224
+ archiveStream.finalize();
5225
+ } else {
5226
+ const fileStream = import_fs_extra5.default.createReadStream(sourcePath);
5227
+ fileStream.pipe(gzip);
5366
5228
  }
5367
- .success-icon {
5368
- font-size: 5rem;
5369
- margin-bottom: 1.5rem;
5370
- animation: bounceIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
5371
- filter: drop-shadow(0 0 20px rgba(0, 200, 255, 0.5));
5229
+ });
5230
+ }
5231
+ async function initChunkSession(filePath, deviceId, isDirectory = false) {
5232
+ const stats = import_fs_extra5.default.statSync(filePath);
5233
+ const fileName = import_path6.default.basename(filePath);
5234
+ const fileSize = stats.size;
5235
+ const md5 = await calculateMD5(filePath);
5236
+ try {
5237
+ const response = await axios_default.post(
5238
+ `${IPFS_API_URL}/chunk/init`,
5239
+ {
5240
+ file_name: fileName,
5241
+ file_size: fileSize,
5242
+ md5,
5243
+ is_directory: isDirectory,
5244
+ uid: deviceId
5245
+ },
5246
+ {
5247
+ timeout: TIMEOUT,
5248
+ headers: { "Content-Type": "application/json" }
5249
+ }
5250
+ );
5251
+ const { code, msg, data } = response.data;
5252
+ if (code === 200 && data) {
5253
+ return data;
5372
5254
  }
5373
- @keyframes bounceIn {
5374
- 0% { transform: scale(0); opacity: 0; }
5375
- 50% { transform: scale(1.2); }
5376
- 100% { transform: scale(1); opacity: 1; }
5255
+ throw new Error(`Session initialization failed: ${msg} (code: ${code})`);
5256
+ } catch (error) {
5257
+ if (axios_default.isAxiosError(error)) {
5258
+ throw new Error(`Network error: ${error.message}`);
5377
5259
  }
5378
- h1 {
5379
- color: #fff;
5380
- font-size: 2.2rem;
5381
- font-weight: 700;
5382
- margin: 0 0 0.75rem 0;
5383
- background: linear-gradient(90deg, #fff, #00d4ff);
5384
- -webkit-background-clip: text;
5385
- -webkit-text-fill-color: transparent;
5386
- background-clip: text;
5260
+ throw error;
5261
+ }
5262
+ }
5263
+ async function uploadChunkWithAbort(sessionId, chunkIndex, chunkData, deviceId, signal, retryCount = 0) {
5264
+ try {
5265
+ if (signal.aborted) {
5266
+ throw new Error("Request cancelled");
5387
5267
  }
5388
- p {
5389
- color: rgba(255, 255, 255, 0.6);
5390
- font-size: 1.1rem;
5391
- margin: 0 0 2rem 0;
5392
- line-height: 1.6;
5268
+ const form = new import_form_data2.default();
5269
+ form.append("session_id", sessionId);
5270
+ form.append("chunk_index", chunkIndex.toString());
5271
+ form.append("uid", deviceId);
5272
+ form.append("chunk", chunkData, {
5273
+ filename: `chunk_${chunkIndex}`,
5274
+ contentType: "application/octet-stream"
5275
+ });
5276
+ const response = await axios_default.post(
5277
+ `${IPFS_API_URL}/chunk/upload`,
5278
+ form,
5279
+ {
5280
+ headers: { ...form.getHeaders() },
5281
+ timeout: TIMEOUT,
5282
+ signal
5283
+ }
5284
+ );
5285
+ const { code, msg, data } = response.data;
5286
+ if (code === 200 && data) {
5287
+ return data;
5393
5288
  }
5394
- .highlight { color: #00d4ff; font-weight: 600; }
5395
- .sparkle {
5396
- position: absolute;
5397
- width: 4px;
5398
- height: 4px;
5399
- background: #00d4ff;
5400
- border-radius: 50%;
5401
- animation: sparkle 2s ease-in-out infinite;
5289
+ throw new Error(`Chunk upload failed: ${msg} (code: ${code})`);
5290
+ } catch (error) {
5291
+ if (error.name === "CanceledError" || signal.aborted) {
5292
+ throw new Error("Request cancelled");
5402
5293
  }
5403
- .sparkle:nth-child(1) { top: 20%; left: 10%; animation-delay: 0s; }
5404
- .sparkle:nth-child(2) { top: 30%; right: 15%; animation-delay: 0.5s; }
5405
- .sparkle:nth-child(3) { bottom: 25%; left: 20%; animation-delay: 1s; }
5406
- .sparkle:nth-child(4) { bottom: 35%; right: 10%; animation-delay: 1.5s; }
5407
- @keyframes sparkle {
5408
- 0%, 100% { opacity: 0; transform: scale(0); }
5409
- 50% { opacity: 1; transform: scale(1); }
5294
+ if (retryCount < MAX_RETRIES) {
5295
+ await delayWithAbortCheck(RETRY_DELAY, signal);
5296
+ return uploadChunkWithAbort(
5297
+ sessionId,
5298
+ chunkIndex,
5299
+ chunkData,
5300
+ deviceId,
5301
+ signal,
5302
+ retryCount + 1
5303
+ );
5410
5304
  }
5411
- </style>
5412
- </head>
5413
- <body>
5414
- <div class="bg"></div>
5415
- <div class="grid"></div>
5416
- <div class="container">
5417
- <div class="sparkle"></div>
5418
- <div class="sparkle"></div>
5419
- <div class="sparkle"></div>
5420
- <div class="sparkle"></div>
5421
- <div class="success-icon">\u{1F389}</div>
5422
- <h1>Welcome to PinMe</h1>
5423
- <p>You are now logged in! <span class="highlight">\u{1F680}</span><br>Return to your terminal to continue.</p>
5424
- </div>
5425
- </body>
5426
- </html>`;
5305
+ throw new Error(
5306
+ `Chunk ${chunkIndex + 1} upload failed after ${MAX_RETRIES} retries: ${error.message}`
5307
+ );
5427
5308
  }
5428
- getErrorHtml(error) {
5429
- const encodedError = encodeURIComponent(error);
5430
- return `
5431
- <!DOCTYPE html>
5432
- <html>
5433
- <head>
5434
- <title>Login Failed - PinMe</title>
5435
- <style>
5436
- * { margin: 0; padding: 0; box-sizing: border-box; }
5437
- body {
5438
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
5439
- display: flex;
5440
- justify-content: center;
5441
- align-items: center;
5442
- min-height: 100vh;
5443
- background: #000;
5444
- overflow: hidden;
5309
+ }
5310
+ async function delayWithAbortCheck(delay, signal) {
5311
+ return new Promise((resolve, reject) => {
5312
+ const timeoutId = setTimeout(() => {
5313
+ if (signal.aborted) {
5314
+ reject(new Error("Request cancelled"));
5315
+ } else {
5316
+ resolve();
5317
+ }
5318
+ }, delay);
5319
+ if (signal.aborted) {
5320
+ clearTimeout(timeoutId);
5321
+ reject(new Error("Request cancelled"));
5322
+ return;
5445
5323
  }
5446
- .bg {
5447
- position: fixed;
5448
- top: 0;
5449
- left: 0;
5450
- width: 100%;
5451
- height: 100%;
5452
- background:
5453
- radial-gradient(ellipse at 20% 80%, rgba(255, 50, 50, 0.2) 0%, transparent 50%),
5454
- radial-gradient(ellipse at 80% 20%, rgba(255, 100, 50, 0.2) 0%, transparent 50%),
5455
- radial-gradient(ellipse at 50% 50%, rgba(100, 0, 50, 0.15) 0%, transparent 60%);
5456
- animation: bgPulse 6s ease-in-out infinite;
5324
+ const checkInterval = setInterval(() => {
5325
+ if (signal.aborted) {
5326
+ clearTimeout(timeoutId);
5327
+ clearInterval(checkInterval);
5328
+ reject(new Error("Request cancelled"));
5329
+ }
5330
+ }, 50);
5331
+ });
5332
+ }
5333
+ async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, deviceId, progressBar) {
5334
+ const fileData = import_fs_extra5.default.readFileSync(filePath);
5335
+ const abortController = new AbortController();
5336
+ let completedCount = 0;
5337
+ let hasFatalError = false;
5338
+ let fatalError = null;
5339
+ const uploadTasks = Array.from({ length: totalChunks }, (_, chunkIndex) => {
5340
+ const start = chunkIndex * chunkSize;
5341
+ const end = Math.min(start + chunkSize, fileData.length);
5342
+ const chunkData = fileData.slice(start, end);
5343
+ return async () => {
5344
+ if (abortController.signal.aborted) return;
5345
+ try {
5346
+ await uploadChunkWithAbort(
5347
+ sessionId,
5348
+ chunkIndex,
5349
+ chunkData,
5350
+ deviceId,
5351
+ abortController.signal
5352
+ );
5353
+ if (abortController.signal.aborted) return;
5354
+ completedCount++;
5355
+ progressBar.updateProgress(completedCount, totalChunks);
5356
+ } catch (error) {
5357
+ if (error.name === "AbortError" || abortController.signal.aborted) {
5358
+ return;
5359
+ }
5360
+ hasFatalError = true;
5361
+ fatalError = `Chunk ${chunkIndex + 1}/${totalChunks} upload failed: ${error.message}`;
5362
+ abortController.abort();
5363
+ throw new Error(fatalError);
5364
+ }
5365
+ };
5366
+ });
5367
+ try {
5368
+ const results = await Promise.allSettled(uploadTasks.map((task) => task()));
5369
+ const failedResults = results.filter(
5370
+ (result) => result.status === "rejected"
5371
+ );
5372
+ if (failedResults.length > 0) {
5373
+ const firstFailure = failedResults[0];
5374
+ throw new Error(
5375
+ firstFailure.reason.message || "Error occurred during upload"
5376
+ );
5457
5377
  }
5458
- @keyframes bgPulse {
5459
- 0%, 100% { opacity: 1; transform: scale(1); }
5460
- 50% { opacity: 0.8; transform: scale(1.05); }
5378
+ if (hasFatalError) {
5379
+ throw new Error(fatalError || "Unknown error occurred during upload");
5461
5380
  }
5462
- .grid {
5463
- position: fixed;
5464
- top: 0;
5465
- left: 0;
5466
- width: 200%;
5467
- height: 200%;
5468
- background-image:
5469
- linear-gradient(rgba(255, 80, 80, 0.03) 1px, transparent 1px),
5470
- linear-gradient(90deg, rgba(255, 80, 80, 0.03) 1px, transparent 1px);
5471
- background-size: 50px 50px;
5472
- transform: perspective(500px) rotateX(60deg) translateY(-50%) translateZ(-200px);
5473
- animation: gridMove 20s linear infinite;
5381
+ } catch (error) {
5382
+ throw fatalError ? new Error(fatalError) : error;
5383
+ }
5384
+ }
5385
+ async function completeChunkUpload(sessionId, deviceId, importAsCar = false) {
5386
+ var _a;
5387
+ try {
5388
+ const requestBody = { session_id: sessionId, uid: deviceId };
5389
+ const projectName = (_a = process.env.PINME_PROJECT_NAME) == null ? void 0 : _a.trim();
5390
+ let authHeaders = {};
5391
+ if (importAsCar) {
5392
+ requestBody.import_as_car = true;
5474
5393
  }
5475
- @keyframes gridMove {
5476
- 0% { transform: perspective(500px) rotateX(60deg) translateY(0) translateZ(-200px); }
5477
- 100% { transform: perspective(500px) rotateX(60deg) translateY(50px) translateZ(-200px); }
5394
+ if (projectName) {
5395
+ requestBody.project_name = projectName;
5396
+ authHeaders = getAuthHeaders();
5478
5397
  }
5479
- .container {
5480
- position: relative;
5481
- z-index: 10;
5482
- background: linear-gradient(135deg, rgba(40, 20, 20, 0.9) 0%, rgba(30, 10, 10, 0.95) 100%);
5483
- padding: 3.5rem 4rem;
5484
- border-radius: 32px;
5485
- box-shadow:
5486
- 0 0 60px rgba(255, 50, 50, 0.15),
5487
- 0 25px 50px rgba(0, 0, 0, 0.5),
5488
- inset 0 1px 0 rgba(255, 255, 255, 0.1),
5489
- inset 0 -1px 0 rgba(255, 50, 50, 0.1);
5490
- text-align: center;
5491
- border: 1px solid rgba(255, 50, 50, 0.2);
5492
- max-width: 440px;
5493
- backdrop-filter: blur(30px);
5398
+ const response = await axios_default.post(
5399
+ `${IPFS_API_URL}/chunk/complete`,
5400
+ requestBody,
5401
+ {
5402
+ timeout: TIMEOUT,
5403
+ headers: {
5404
+ "Content-Type": "application/json",
5405
+ ...authHeaders
5406
+ }
5407
+ }
5408
+ );
5409
+ const { code, msg, data } = response.data;
5410
+ if (code === 200 && data) {
5411
+ return data.trace_id;
5494
5412
  }
5495
- .container::before {
5496
- content: '';
5497
- position: absolute;
5498
- top: -1px;
5499
- left: -1px;
5500
- right: -1px;
5501
- bottom: -1px;
5502
- border-radius: 32px;
5503
- background: linear-gradient(135deg, rgba(255, 50, 50, 0.5), rgba(255, 150, 50, 0.5), rgba(150, 0, 50, 0.5));
5504
- z-index: -1;
5505
- opacity: 0.5;
5506
- animation: borderGlow 3s ease-in-out infinite;
5413
+ throw new Error(`Complete upload failed: ${msg} (code: ${code})`);
5414
+ } catch (error) {
5415
+ if (axios_default.isAxiosError(error)) {
5416
+ throw new Error(`Network error: ${error.message}`);
5507
5417
  }
5508
- @keyframes borderGlow {
5509
- 0%, 100% { opacity: 0.3; }
5510
- 50% { opacity: 0.7; }
5418
+ throw error;
5419
+ }
5420
+ }
5421
+ async function getChunkStatus(sessionId, deviceId) {
5422
+ var _a;
5423
+ try {
5424
+ const projectName = (_a = process.env.PINME_PROJECT_NAME) == null ? void 0 : _a.trim();
5425
+ const queryParams = new URLSearchParams({
5426
+ trace_id: sessionId,
5427
+ uid: deviceId
5428
+ });
5429
+ if (projectName) {
5430
+ queryParams.append("project_name", projectName);
5511
5431
  }
5512
- .error-icon {
5513
- font-size: 5rem;
5514
- margin-bottom: 1.5rem;
5515
- animation: shake 0.5s ease-in-out;
5516
- filter: drop-shadow(0 0 20px rgba(255, 50, 50, 0.5));
5432
+ const response = await axios_default.get(
5433
+ `${IPFS_API_URL}/up_status?${queryParams.toString()}`,
5434
+ {
5435
+ timeout: TIMEOUT,
5436
+ headers: { "Content-Type": "application/json" }
5437
+ }
5438
+ );
5439
+ const { code, msg, data } = response.data;
5440
+ if (code === 200) {
5441
+ return data;
5517
5442
  }
5518
- @keyframes shake {
5519
- 0%, 100% { transform: translateX(0); }
5520
- 20% { transform: translateX(-10px) rotate(-5deg); }
5521
- 40% { transform: translateX(10px) rotate(5deg); }
5522
- 60% { transform: translateX(-10px) rotate(-5deg); }
5523
- 80% { transform: translateX(10px) rotate(5deg); }
5443
+ throw new Error(`Server returned error: ${msg} (code: ${code})`);
5444
+ } catch (error) {
5445
+ if (axios_default.isAxiosError(error)) {
5446
+ throw new Error(`Network error: ${error.message}`);
5524
5447
  }
5525
- h1 {
5526
- color: #fff;
5527
- font-size: 2.2rem;
5528
- font-weight: 700;
5529
- margin: 0 0 0.75rem 0;
5530
- background: linear-gradient(90deg, #fff, #ff5050);
5531
- -webkit-background-clip: text;
5532
- -webkit-text-fill-color: transparent;
5533
- background-clip: text;
5448
+ throw error;
5449
+ }
5450
+ }
5451
+ async function monitorChunkProgress(traceId, deviceId, progressBar) {
5452
+ let consecutiveErrors = 0;
5453
+ const startTime = Date.now();
5454
+ if (progressBar) {
5455
+ progressBar.startSimulatingProgress();
5456
+ }
5457
+ try {
5458
+ while (Date.now() - startTime < MAX_POLL_TIME) {
5459
+ try {
5460
+ const status = await getChunkStatus(traceId, deviceId);
5461
+ consecutiveErrors = 0;
5462
+ if (status.is_ready && status.upload_rst.Hash) {
5463
+ if (progressBar) {
5464
+ progressBar.stopSimulatingProgress();
5465
+ }
5466
+ const shortUrl = status.upload_rst.ShortUrl;
5467
+ const domain = status.domain;
5468
+ const fullShortUrl = shortUrl && domain ? `${shortUrl}.${domain}` : shortUrl;
5469
+ return {
5470
+ hash: status.upload_rst.Hash,
5471
+ shortUrl: fullShortUrl
5472
+ };
5473
+ }
5474
+ } catch (error) {
5475
+ consecutiveErrors++;
5476
+ if (consecutiveErrors > 10) {
5477
+ throw new Error(`Polling failed: ${error.message}`);
5478
+ }
5479
+ }
5480
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
5534
5481
  }
5535
- .error {
5536
- color: #ff6b6b;
5537
- font-size: 1rem;
5538
- margin: 0 0 2rem 0;
5539
- padding: 1.25rem;
5540
- background: rgba(255, 50, 50, 0.1);
5541
- border-radius: 16px;
5542
- border: 1px solid rgba(255, 50, 50, 0.2);
5543
- font-weight: 500;
5544
- box-shadow: 0 0 20px rgba(255, 50, 50, 0.1);
5482
+ const maxPollTimeMinutes = Math.floor(MAX_POLL_TIME / (60 * 1e3));
5483
+ throw new Error(`Polling timeout after ${maxPollTimeMinutes} minutes`);
5484
+ } finally {
5485
+ if (progressBar) {
5486
+ progressBar.stopSimulatingProgress();
5545
5487
  }
5546
- </style>
5547
- </head>
5548
- <body>
5549
- <div class="bg"></div>
5550
- <div class="grid"></div>
5551
- <div class="container">
5552
- <div class="error-icon">\u{1F635}</div>
5553
- <h1>Oops!</h1>
5554
- <div class="error">${error}</div>
5555
- </div>
5556
- </body>
5557
- </html>`;
5558
5488
  }
5559
- };
5560
- var webLoginManager = new WebLoginManager();
5561
- function setAuthToken(combined) {
5562
- const firstDash = combined.indexOf("-");
5563
- if (firstDash <= 0 || firstDash === combined.length - 1) {
5564
- throw new Error('Invalid token format. Expected "<address>-<jwt>".');
5489
+ }
5490
+ async function uploadDirectoryInChunks(directoryPath, deviceId, importAsCar = false) {
5491
+ const sizeCheck = checkDirectorySizeLimit(directoryPath);
5492
+ if (sizeCheck.exceeds) {
5493
+ throw new Error(
5494
+ `Directory ${directoryPath} exceeds size limit ${formatSize(
5495
+ sizeCheck.limit
5496
+ )} (size: ${formatSize(sizeCheck.size)})`
5497
+ );
5565
5498
  }
5566
- const address = combined.slice(0, firstDash).trim();
5567
- const token = combined.slice(firstDash + 1).trim();
5568
- if (!address || !token) {
5569
- throw new Error("Invalid token content. Address or token is empty.");
5499
+ const progressBar = new StepProgressBar(import_path6.default.basename(directoryPath), true);
5500
+ try {
5501
+ progressBar.startStep(0, "Preparing compression");
5502
+ const compressedPath = await compressDirectory(directoryPath);
5503
+ progressBar.completeStep();
5504
+ progressBar.startStep(1, "Initializing session");
5505
+ const sessionInfo = await initChunkSession(compressedPath, deviceId, true);
5506
+ progressBar.completeStep();
5507
+ progressBar.startStep(2, "Chunk upload");
5508
+ await uploadFileChunks(
5509
+ compressedPath,
5510
+ sessionInfo.session_id,
5511
+ sessionInfo.total_chunks,
5512
+ sessionInfo.chunk_size,
5513
+ deviceId,
5514
+ progressBar
5515
+ );
5516
+ progressBar.completeStep();
5517
+ progressBar.startStep(3, "Completing upload");
5518
+ const traceId = await completeChunkUpload(sessionInfo.session_id, deviceId, importAsCar);
5519
+ progressBar.completeStep();
5520
+ progressBar.startStep(4, "Waiting for processing");
5521
+ const result = await monitorChunkProgress(traceId, deviceId, progressBar);
5522
+ progressBar.completeStep();
5523
+ try {
5524
+ import_fs_extra5.default.unlinkSync(compressedPath);
5525
+ } catch (error) {
5526
+ }
5527
+ const uploadData = {
5528
+ path: directoryPath,
5529
+ filename: import_path6.default.basename(directoryPath),
5530
+ contentHash: (result == null ? void 0 : result.hash) || "unknown",
5531
+ size: sizeCheck.size,
5532
+ fileCount: 0,
5533
+ isDirectory: true,
5534
+ shortUrl: (result == null ? void 0 : result.shortUrl) || null
5535
+ };
5536
+ saveUploadHistory(uploadData);
5537
+ if (!(result == null ? void 0 : result.hash)) {
5538
+ throw new Error("Server did not return valid hash value");
5539
+ }
5540
+ progressBar.complete();
5541
+ return result;
5542
+ } catch (error) {
5543
+ progressBar.fail(error.message);
5544
+ throw error;
5545
+ }
5546
+ }
5547
+ async function uploadFileInChunks(filePath, deviceId, importAsCar = false) {
5548
+ const sizeCheck = checkFileSizeLimit(filePath);
5549
+ if (sizeCheck.exceeds) {
5550
+ throw new Error(
5551
+ `File ${filePath} exceeds size limit ${formatSize(
5552
+ sizeCheck.limit
5553
+ )} (size: ${formatSize(sizeCheck.size)})`
5554
+ );
5555
+ }
5556
+ const fileName = import_path6.default.basename(filePath);
5557
+ const progressBar = new StepProgressBar(fileName, false);
5558
+ try {
5559
+ progressBar.startStep(0, "Initializing session");
5560
+ const sessionInfo = await initChunkSession(filePath, deviceId, false);
5561
+ progressBar.completeStep();
5562
+ progressBar.startStep(1, "Chunk upload");
5563
+ await uploadFileChunks(
5564
+ filePath,
5565
+ sessionInfo.session_id,
5566
+ sessionInfo.total_chunks,
5567
+ sessionInfo.chunk_size,
5568
+ deviceId,
5569
+ progressBar
5570
+ );
5571
+ progressBar.completeStep();
5572
+ progressBar.startStep(2, "Completing upload");
5573
+ const traceId = await completeChunkUpload(sessionInfo.session_id, deviceId, importAsCar);
5574
+ progressBar.completeStep();
5575
+ progressBar.startStep(3, "Waiting for processing");
5576
+ const result = await monitorChunkProgress(traceId, deviceId, progressBar);
5577
+ progressBar.completeStep();
5578
+ const uploadData = {
5579
+ path: filePath,
5580
+ filename: fileName,
5581
+ contentHash: (result == null ? void 0 : result.hash) || "unknown",
5582
+ previewHash: null,
5583
+ size: sizeCheck.size,
5584
+ fileCount: 1,
5585
+ isDirectory: false,
5586
+ shortUrl: (result == null ? void 0 : result.shortUrl) || null
5587
+ };
5588
+ saveUploadHistory(uploadData);
5589
+ if (!(result == null ? void 0 : result.hash)) {
5590
+ throw new Error("Server did not return valid hash value");
5591
+ }
5592
+ progressBar.complete();
5593
+ return result;
5594
+ } catch (error) {
5595
+ progressBar.fail(error.message);
5596
+ throw error;
5570
5597
  }
5571
- const config = { address, token };
5572
- import_fs_extra5.default.ensureDirSync(CONFIG_DIR2);
5573
- import_fs_extra5.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
5574
- return config;
5575
5598
  }
5576
- function getAuthConfig2() {
5577
- try {
5578
- if (!import_fs_extra5.default.existsSync(AUTH_FILE2)) return null;
5579
- const data = import_fs_extra5.default.readJsonSync(AUTH_FILE2);
5580
- if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
5581
- return data;
5582
- } catch {
5583
- return null;
5599
+ async function uploadToIpfsSplit_default(filePath, importAsCar = false) {
5600
+ const deviceId = getUid();
5601
+ if (!deviceId) {
5602
+ throw new Error("Device ID not found");
5584
5603
  }
5585
- }
5586
- function clearAuthToken() {
5587
5604
  try {
5588
- if (import_fs_extra5.default.existsSync(AUTH_FILE2)) {
5589
- import_fs_extra5.default.removeSync(AUTH_FILE2);
5605
+ const isDirectory = import_fs_extra5.default.statSync(filePath).isDirectory();
5606
+ const result = isDirectory ? await uploadDirectoryInChunks(filePath, deviceId, importAsCar) : await uploadFileInChunks(filePath, deviceId, importAsCar);
5607
+ if (result == null ? void 0 : result.hash) {
5608
+ return {
5609
+ contentHash: result.hash,
5610
+ previewHash: null,
5611
+ shortUrl: result.shortUrl
5612
+ };
5590
5613
  }
5614
+ throw new Error("Upload failed: no hash returned");
5591
5615
  } catch (error) {
5592
- console.error(`Failed to clear auth token: ${error}`);
5593
- }
5594
- }
5595
- function getAuthHeaders() {
5596
- const conf = getAuthConfig2();
5597
- if (!conf) {
5598
- throw new Error("Auth not set. Run: pinme login");
5616
+ throw error;
5599
5617
  }
5600
- return {
5601
- "token-address": conf.address,
5602
- "authentication-tokens": conf.token
5603
- };
5604
5618
  }
5605
5619
 
5620
+ // bin/upload.ts
5621
+ var import_fs2 = __toESM(require("fs"));
5622
+ var import_crypto_js = __toESM(require("crypto-js"));
5623
+
5606
5624
  // bin/utils/pinmeApi.ts
5625
+ var import_chalk4 = __toESM(require("chalk"));
5607
5626
  var DEFAULT_BASE = "https://pinme.dev/api/v4";
5608
5627
  var TOKEN_EXPIRED_CODES = [
5609
5628
  401,
@@ -5785,7 +5804,7 @@ async function isVip(tokenAddress, authToken) {
5785
5804
  throw e;
5786
5805
  }
5787
5806
  }
5788
- var CAR_API_BASE = process.env.CAR_API_BASE || "https://pinme.dev/api/v4";
5807
+ var CAR_API_BASE = process.env.CAR_API_BASE || "https://pinme.dev/api/v3";
5789
5808
  function createCarClient() {
5790
5809
  let headers = {};
5791
5810
  try {
@@ -5916,6 +5935,31 @@ function checkPathSync(inputPath) {
5916
5935
  return null;
5917
5936
  }
5918
5937
  }
5938
+ function formatEnsUrl(shortUrl) {
5939
+ if (!shortUrl) return "";
5940
+ const normalized = shortUrl.trim();
5941
+ if (!normalized) return "";
5942
+ if (/^https?:\/\//.test(normalized)) return normalized;
5943
+ if (normalized.includes(".")) return `https://${normalized}`;
5944
+ return `https://${normalized}.pinit.eth.limo`;
5945
+ }
5946
+ function printUploadUrls(contentHash, shortUrl) {
5947
+ var _a;
5948
+ const uid = getUid();
5949
+ const encryptedCID = encryptHash(contentHash, secretKey, uid);
5950
+ const previewUrl = `${URL3}${encryptedCID}`;
5951
+ const projectName = (_a = process.env.PINME_PROJECT_NAME) == null ? void 0 : _a.trim();
5952
+ if (projectName) {
5953
+ const ensUrl = formatEnsUrl(shortUrl);
5954
+ console.log(import_chalk5.default.cyan(`URL:`));
5955
+ console.log(import_chalk5.default.cyan(ensUrl || previewUrl));
5956
+ console.log(import_chalk5.default.cyan(`Management page:`));
5957
+ console.log(import_chalk5.default.cyan(previewUrl));
5958
+ return;
5959
+ }
5960
+ console.log(import_chalk5.default.cyan(`URL:`));
5961
+ console.log(import_chalk5.default.cyan(previewUrl));
5962
+ }
5919
5963
  function getDomainFromArgs() {
5920
5964
  const args = process.argv.slice(2);
5921
5965
  const dIdx = args.findIndex((a) => a === "--domain" || a === "-d");
@@ -6042,39 +6086,39 @@ var upload_default = async (options) => {
6042
6086
  }
6043
6087
  }
6044
6088
  console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
6089
+ let result;
6045
6090
  try {
6046
- const result = await uploadToIpfsSplit_default(absolutePath);
6047
- if (result) {
6048
- const uid = getUid();
6049
- const encryptedCID = encryptHash(result.contentHash, secretKey, uid);
6050
- console.log(
6051
- import_chalk5.default.cyan(
6052
- import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
6053
- )
6054
- );
6055
- console.log(import_chalk5.default.cyan(`URL:`));
6056
- console.log(import_chalk5.default.cyan(`${URL3}${encryptedCID}`));
6057
- if (domainArg) {
6058
- console.log(
6059
- import_chalk5.default.blue(
6060
- `Binding domain: ${displayDomain} with CID: ${result.contentHash}`
6061
- )
6062
- );
6063
- try {
6064
- await bindDomain(domainArg, result.contentHash, isDns, authConfig);
6065
- } catch (e) {
6066
- if (e.message === "Token expired") {
6067
- process.exit(1);
6068
- }
6069
- throw e;
6070
- }
6071
- }
6072
- console.log(import_chalk5.default.green("\n\u{1F389} upload successful, program exit"));
6073
- }
6091
+ result = await uploadToIpfsSplit_default(absolutePath);
6074
6092
  } catch (error) {
6075
- console.error(import_chalk5.default.red(`Error: ${error.message}`));
6093
+ console.error(import_chalk5.default.red(`Upload error: ${error.message}`));
6076
6094
  process.exit(1);
6077
6095
  }
6096
+ if (!result) {
6097
+ console.error(import_chalk5.default.red("Upload failed: no result returned"));
6098
+ process.exit(1);
6099
+ }
6100
+ console.log(
6101
+ import_chalk5.default.cyan(
6102
+ import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
6103
+ )
6104
+ );
6105
+ printUploadUrls(result.contentHash, result.shortUrl);
6106
+ if (domainArg) {
6107
+ console.log(
6108
+ import_chalk5.default.blue(
6109
+ `Binding domain: ${displayDomain} with CID: ${result.contentHash}`
6110
+ )
6111
+ );
6112
+ try {
6113
+ await bindDomain(domainArg, result.contentHash, isDns, authConfig);
6114
+ } catch (e) {
6115
+ if (e.message === "Token expired") {
6116
+ process.exit(1);
6117
+ }
6118
+ throw e;
6119
+ }
6120
+ }
6121
+ console.log(import_chalk5.default.green("\n\u{1F389} upload successful, program exit"));
6078
6122
  process.exit(0);
6079
6123
  }
6080
6124
  const answer = await import_inquirer.default.prompt([
@@ -6133,39 +6177,39 @@ var upload_default = async (options) => {
6133
6177
  }
6134
6178
  }
6135
6179
  console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
6180
+ let result;
6136
6181
  try {
6137
- const result = await uploadToIpfsSplit_default(absolutePath);
6138
- if (result) {
6139
- const uid = getUid();
6140
- const encryptedCID = encryptHash(result.contentHash, secretKey, uid);
6141
- console.log(
6142
- import_chalk5.default.cyan(
6143
- import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
6144
- )
6145
- );
6146
- console.log(import_chalk5.default.cyan(`URL:`));
6147
- console.log(import_chalk5.default.cyan(`${URL3}${encryptedCID}`));
6148
- if (domainArg) {
6149
- console.log(
6150
- import_chalk5.default.blue(
6151
- `Binding domain: ${displayDomain} with CID: ${result.contentHash}`
6152
- )
6153
- );
6154
- try {
6155
- await bindDomain(domainArg, result.contentHash, isDns, authConfig);
6156
- } catch (e) {
6157
- if (e.message === "Token expired") {
6158
- process.exit(1);
6159
- }
6160
- throw e;
6161
- }
6162
- }
6163
- console.log(import_chalk5.default.green("\n\u{1F389} upload successful, program exit"));
6164
- }
6182
+ result = await uploadToIpfsSplit_default(absolutePath);
6165
6183
  } catch (error) {
6166
- console.error(import_chalk5.default.red(`Error: ${error.message}`));
6184
+ console.error(import_chalk5.default.red(`Upload error: ${error.message}`));
6185
+ process.exit(1);
6186
+ }
6187
+ if (!result) {
6188
+ console.error(import_chalk5.default.red("Upload failed: no result returned"));
6167
6189
  process.exit(1);
6168
6190
  }
6191
+ console.log(
6192
+ import_chalk5.default.cyan(
6193
+ import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
6194
+ )
6195
+ );
6196
+ printUploadUrls(result.contentHash, result.shortUrl);
6197
+ if (domainArg) {
6198
+ console.log(
6199
+ import_chalk5.default.blue(
6200
+ `Binding domain: ${displayDomain} with CID: ${result.contentHash}`
6201
+ )
6202
+ );
6203
+ try {
6204
+ await bindDomain(domainArg, result.contentHash, isDns, authConfig);
6205
+ } catch (e) {
6206
+ if (e.message === "Token expired") {
6207
+ process.exit(1);
6208
+ }
6209
+ throw e;
6210
+ }
6211
+ }
6212
+ console.log(import_chalk5.default.green("\n\u{1F389} upload successful, program exit"));
6169
6213
  process.exit(0);
6170
6214
  }
6171
6215
  } catch (error) {
@@ -6987,7 +7031,6 @@ async function bindCmd() {
6987
7031
  return;
6988
7032
  }
6989
7033
  const isDns = dns || isDnsDomain2(domain);
6990
- console.log(isDns, "isDns");
6991
7034
  const displayDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
6992
7035
  if (isDns) {
6993
7036
  const validation = validateDnsDomain2(domain);
@@ -7105,25 +7148,174 @@ Login failed: ${(e == null ? void 0 : e.message) || e}`));
7105
7148
  }
7106
7149
 
7107
7150
  // bin/create.ts
7108
- var import_chalk16 = __toESM(require("chalk"));
7151
+ var import_chalk17 = __toESM(require("chalk"));
7109
7152
  var import_fs_extra6 = __toESM(require("fs-extra"));
7110
7153
  var import_path11 = __toESM(require("path"));
7111
7154
  var import_inquirer8 = __toESM(require("inquirer"));
7112
7155
  var import_child_process2 = require("child_process");
7156
+
7157
+ // bin/utils/cliError.ts
7158
+ var import_chalk16 = __toESM(require("chalk"));
7159
+ var CliError = class extends Error {
7160
+ stage;
7161
+ details;
7162
+ suggestions;
7163
+ cause;
7164
+ constructor(options) {
7165
+ super(options.summary);
7166
+ this.name = "CliError";
7167
+ this.stage = options.stage;
7168
+ this.details = options.details || [];
7169
+ this.suggestions = options.suggestions || [];
7170
+ this.cause = options.cause;
7171
+ }
7172
+ };
7173
+ function stringifyValue(value) {
7174
+ if (value === void 0 || value === null) {
7175
+ return "";
7176
+ }
7177
+ if (typeof value === "string") {
7178
+ return value;
7179
+ }
7180
+ try {
7181
+ return JSON.stringify(value);
7182
+ } catch (error) {
7183
+ return String(value);
7184
+ }
7185
+ }
7186
+ function getApiMessage(data) {
7187
+ var _a, _b, _c;
7188
+ return ((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.error) || ((_c = (_b = data == null ? void 0 : data.errors) == null ? void 0 : _b[0]) == null ? void 0 : _c.message) || (data == null ? void 0 : data.message) || (data == null ? void 0 : data.msg) || (data == null ? void 0 : data.error);
7189
+ }
7190
+ function getBusinessCode(data) {
7191
+ if ((data == null ? void 0 : data.code) === void 0 || (data == null ? void 0 : data.code) === null) {
7192
+ return void 0;
7193
+ }
7194
+ return String(data.code);
7195
+ }
7196
+ function getBusinessMessage(data) {
7197
+ if (!(data == null ? void 0 : data.msg)) {
7198
+ return void 0;
7199
+ }
7200
+ return String(data.msg);
7201
+ }
7202
+ function dedupeSuggestions(suggestions) {
7203
+ return Array.from(new Set(suggestions.filter(Boolean)));
7204
+ }
7205
+ function createConfigError(summary, suggestions = []) {
7206
+ return new CliError({
7207
+ summary,
7208
+ stage: "configuration",
7209
+ suggestions
7210
+ });
7211
+ }
7212
+ function createCommandError(stage, command, error, suggestions = []) {
7213
+ const exitCode = (error == null ? void 0 : error.status) ?? (error == null ? void 0 : error.code);
7214
+ const signal = error == null ? void 0 : error.signal;
7215
+ const detailLines = [`Command: ${command}`];
7216
+ if (exitCode !== void 0) {
7217
+ detailLines.push(`Exit code: ${exitCode}`);
7218
+ }
7219
+ if (signal) {
7220
+ detailLines.push(`Signal: ${signal}`);
7221
+ }
7222
+ if (error == null ? void 0 : error.message) {
7223
+ detailLines.push(`Reason: ${error.message}`);
7224
+ }
7225
+ return new CliError({
7226
+ summary: `${stage} failed.`,
7227
+ stage,
7228
+ details: detailLines,
7229
+ suggestions,
7230
+ cause: error
7231
+ });
7232
+ }
7233
+ function createApiError(stage, error, context = [], suggestions = []) {
7234
+ var _a, _b;
7235
+ const status = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status;
7236
+ const responseData = (_b = error == null ? void 0 : error.response) == null ? void 0 : _b.data;
7237
+ const errorCode = error == null ? void 0 : error.code;
7238
+ const apiMessage = getApiMessage(responseData);
7239
+ const businessCode = getBusinessCode(responseData);
7240
+ const businessMessage = getBusinessMessage(responseData);
7241
+ const summary = apiMessage || (error == null ? void 0 : error.message) || `${stage} failed.`;
7242
+ const detailLines = [...context];
7243
+ if (status) {
7244
+ detailLines.push(`HTTP status: ${status}`);
7245
+ }
7246
+ if (businessCode) {
7247
+ detailLines.push(`Business code: ${businessCode}`);
7248
+ }
7249
+ if (businessMessage && businessMessage !== apiMessage) {
7250
+ detailLines.push(`Business message: ${businessMessage}`);
7251
+ }
7252
+ if (apiMessage && apiMessage !== summary) {
7253
+ detailLines.push(`Error message: ${apiMessage}`);
7254
+ }
7255
+ if (errorCode && errorCode !== "ERR_BAD_REQUEST" && !responseData) {
7256
+ detailLines.push(`Error code: ${errorCode}`);
7257
+ }
7258
+ if (!responseData && (error == null ? void 0 : error.message) && error.message !== apiMessage) {
7259
+ detailLines.push(`Reason: ${error.message}`);
7260
+ }
7261
+ return new CliError({
7262
+ summary,
7263
+ stage,
7264
+ details: detailLines,
7265
+ suggestions: dedupeSuggestions(suggestions),
7266
+ cause: error
7267
+ });
7268
+ }
7269
+ function normalizeCliError(error, fallbackSummary, suggestions = []) {
7270
+ if (error instanceof CliError) {
7271
+ return error;
7272
+ }
7273
+ if (error instanceof Error) {
7274
+ return new CliError({
7275
+ summary: error.message || fallbackSummary,
7276
+ suggestions: dedupeSuggestions(suggestions),
7277
+ cause: error
7278
+ });
7279
+ }
7280
+ return new CliError({
7281
+ summary: fallbackSummary,
7282
+ details: [`Raw error: ${stringifyValue(error)}`],
7283
+ suggestions: dedupeSuggestions(suggestions),
7284
+ cause: error
7285
+ });
7286
+ }
7287
+ function printCliError(error, fallbackSummary) {
7288
+ const cliError = normalizeCliError(error, fallbackSummary);
7289
+ console.error(import_chalk16.default.red(`
7290
+ Error: ${cliError.message}`));
7291
+ if (cliError.stage) {
7292
+ console.error(import_chalk16.default.gray(`Stage: ${cliError.stage}`));
7293
+ }
7294
+ for (const detail of cliError.details) {
7295
+ console.error(import_chalk16.default.gray(detail));
7296
+ }
7297
+ if (cliError.suggestions.length > 0) {
7298
+ console.error(import_chalk16.default.yellow("\nNext steps:"));
7299
+ for (const suggestion of cliError.suggestions) {
7300
+ console.error(import_chalk16.default.yellow(`- ${suggestion}`));
7301
+ }
7302
+ }
7303
+ }
7304
+
7305
+ // bin/create.ts
7113
7306
  var PROJECT_DIR = process.cwd();
7114
7307
  var API_BASE = "https://pinme.dev/api/v4";
7115
7308
  var TEMPLATE_REPO = "glitternetwork/pinme-worker-template";
7116
7309
  var TEMPLATE_ZIP_URL = `https://github.com/${TEMPLATE_REPO}/archive/refs/heads/main.zip`;
7117
7310
  async function createCmd(options) {
7118
- var _a, _b, _c, _d, _e, _f;
7119
7311
  try {
7120
7312
  const headers = getAuthHeaders();
7121
7313
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
7122
- console.log(import_chalk16.default.yellow("\n\u26A0\uFE0F You are not logged in."));
7123
- console.log(import_chalk16.default.gray("Please run: pinme login"));
7124
- process.exit(1);
7314
+ throw createConfigError("No valid local login session was found.", [
7315
+ "Run `pinme login` and retry."
7316
+ ]);
7125
7317
  }
7126
- console.log(import_chalk16.default.blue("Creating new project from template...\n"));
7318
+ console.log(import_chalk17.default.blue("Creating new project from template...\n"));
7127
7319
  let projectName = options.name;
7128
7320
  if (!projectName) {
7129
7321
  const answers = await import_inquirer8.default.prompt([
@@ -7144,7 +7336,7 @@ async function createCmd(options) {
7144
7336
  }
7145
7337
  const targetDir = import_path11.default.join(PROJECT_DIR, projectName);
7146
7338
  if (import_fs_extra6.default.existsSync(targetDir) && !options.force) {
7147
- console.log(import_chalk16.default.yellow(`
7339
+ console.log(import_chalk17.default.yellow(`
7148
7340
  Directory "${projectName}" already exists.`));
7149
7341
  const answers = await import_inquirer8.default.prompt([
7150
7342
  {
@@ -7155,16 +7347,16 @@ Directory "${projectName}" already exists.`));
7155
7347
  }
7156
7348
  ]);
7157
7349
  if (!answers.overwrite) {
7158
- console.log(import_chalk16.default.gray("Cancelled."));
7350
+ console.log(import_chalk17.default.gray("Cancelled."));
7159
7351
  process.exit(0);
7160
7352
  }
7161
7353
  import_fs_extra6.default.removeSync(targetDir);
7162
7354
  }
7163
- console.log(import_chalk16.default.blue("\n1. Creating worker and database..."));
7355
+ console.log(import_chalk17.default.blue("\n1. Creating worker and database..."));
7164
7356
  const apiUrl = `${API_BASE}/create_worker`;
7165
- console.log(import_chalk16.default.gray(`API URL: ${apiUrl}`));
7357
+ console.log(import_chalk17.default.gray(`API URL: ${apiUrl}`));
7166
7358
  const normalizedProjectName = projectName.toLowerCase();
7167
- console.log(import_chalk16.default.gray(`Project name: ${normalizedProjectName}`));
7359
+ console.log(import_chalk17.default.gray(`Project name: ${normalizedProjectName}`));
7168
7360
  let workerData;
7169
7361
  try {
7170
7362
  const response = await axios_default.post(apiUrl, {
@@ -7177,24 +7369,28 @@ Directory "${projectName}" already exists.`));
7177
7369
  });
7178
7370
  const data = response.data;
7179
7371
  if (data.code !== 200) {
7180
- const errorMsg = ((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.error) || (data == null ? void 0 : data.msg) || "Failed to create worker";
7181
- throw new Error(errorMsg);
7372
+ throw createApiError("project creation", { response: { status: response.status, data } }, [
7373
+ `Project name: ${normalizedProjectName}`,
7374
+ `Endpoint: ${apiUrl}`
7375
+ ]);
7182
7376
  }
7183
7377
  workerData = data.data;
7184
- console.log(import_chalk16.default.gray(` API Response: ${JSON.stringify(workerData)}`));
7185
- console.log(import_chalk16.default.green(` API Domain: ${workerData.api_domain}`));
7186
- console.log(import_chalk16.default.green(` Project Name: ${workerData.project_name}`));
7187
- console.log(import_chalk16.default.green(` D1 UUID: ${workerData.uuid}`));
7378
+ console.log(import_chalk17.default.gray(` API Response: ${JSON.stringify(workerData)}`));
7379
+ console.log(import_chalk17.default.green(` API Domain: ${workerData.api_domain}`));
7380
+ console.log(import_chalk17.default.green(` Project Name: ${workerData.project_name}`));
7381
+ console.log(import_chalk17.default.green(` D1 UUID: ${workerData.uuid}`));
7188
7382
  } catch (error) {
7189
- const errorMsg = ((_d = (_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.data) == null ? void 0 : _d.error) || ((_f = (_e = error.response) == null ? void 0 : _e.data) == null ? void 0 : _f.msg) || error.message || "Failed to create worker";
7190
- throw new Error(errorMsg);
7383
+ throw createApiError("project creation", error, [
7384
+ `Project name: ${normalizedProjectName}`,
7385
+ `Endpoint: ${apiUrl}`
7386
+ ]);
7191
7387
  }
7192
- console.log(import_chalk16.default.blue("\n2. Downloading template from repository..."));
7388
+ console.log(import_chalk17.default.blue("\n2. Downloading template from repository..."));
7193
7389
  const zipPath = import_path11.default.join(PROJECT_DIR, "template.zip");
7194
7390
  let downloadSuccess = false;
7195
7391
  for (let attempt = 1; attempt <= 3 && !downloadSuccess; attempt++) {
7196
7392
  try {
7197
- console.log(import_chalk16.default.gray(` Download attempt ${attempt}/3...`));
7393
+ console.log(import_chalk17.default.gray(` Download attempt ${attempt}/3...`));
7198
7394
  (0, import_child_process2.execSync)(`curl -L --retry 3 --retry-delay 2 -o "${zipPath}" "${TEMPLATE_ZIP_URL}"`, {
7199
7395
  stdio: "inherit"
7200
7396
  });
@@ -7203,7 +7399,7 @@ Directory "${projectName}" already exists.`));
7203
7399
  }
7204
7400
  downloadSuccess = true;
7205
7401
  } catch (downloadError) {
7206
- console.log(import_chalk16.default.yellow(` Attempt ${attempt} failed: ${downloadError.message}`));
7402
+ console.log(import_chalk17.default.yellow(` Attempt ${attempt} failed: ${downloadError.message}`));
7207
7403
  if (import_fs_extra6.default.existsSync(zipPath)) {
7208
7404
  import_fs_extra6.default.removeSync(zipPath);
7209
7405
  }
@@ -7222,11 +7418,13 @@ Directory "${projectName}" already exists.`));
7222
7418
  import_fs_extra6.default.removeSync(subDir);
7223
7419
  }
7224
7420
  import_fs_extra6.default.removeSync(zipPath);
7225
- console.log(import_chalk16.default.green(` Template downloaded to: ${targetDir}`));
7421
+ console.log(import_chalk17.default.green(` Template downloaded to: ${targetDir}`));
7226
7422
  } catch (error) {
7227
- throw new Error(`Failed to extract template: ${error.message}`);
7423
+ throw createCommandError("template extraction", `unzip -o "${zipPath}" -d "${PROJECT_DIR}"`, error, [
7424
+ "Check whether `unzip` is available and the downloaded template archive is valid."
7425
+ ]);
7228
7426
  }
7229
- console.log(import_chalk16.default.blue("\n3. Updating configuration..."));
7427
+ console.log(import_chalk17.default.blue("\n3. Updating configuration..."));
7230
7428
  const configPath = import_path11.default.join(targetDir, "pinme.toml");
7231
7429
  const config = import_fs_extra6.default.readFileSync(configPath, "utf-8");
7232
7430
  let updatedConfig = config.replace(
@@ -7234,9 +7432,9 @@ Directory "${projectName}" already exists.`));
7234
7432
  `project_name = "${workerData.project_name}"`
7235
7433
  );
7236
7434
  import_fs_extra6.default.writeFileSync(configPath, updatedConfig);
7237
- console.log(import_chalk16.default.green(` Updated pinme.toml`));
7238
- console.log(import_chalk16.default.gray(` metadata: ${workerData.metadata}`));
7239
- console.log(import_chalk16.default.gray(` VITE_API_URL: ${workerData.api_domain}`));
7435
+ console.log(import_chalk17.default.green(` Updated pinme.toml`));
7436
+ console.log(import_chalk17.default.gray(` metadata: ${workerData.metadata}`));
7437
+ console.log(import_chalk17.default.gray(` VITE_API_URL: ${workerData.api_domain}`));
7240
7438
  const backendDir = import_path11.default.join(targetDir, "backend");
7241
7439
  if (import_fs_extra6.default.existsSync(backendDir) && workerData.metadata) {
7242
7440
  const metadataContent = typeof workerData.metadata === "string" ? workerData.metadata : JSON.stringify(workerData.metadata, null, 2);
@@ -7244,7 +7442,7 @@ Directory "${projectName}" already exists.`));
7244
7442
  import_path11.default.join(backendDir, "metadata.json"),
7245
7443
  metadataContent
7246
7444
  );
7247
- console.log(import_chalk16.default.green(` Saved metadata.json`));
7445
+ console.log(import_chalk17.default.green(` Saved metadata.json`));
7248
7446
  }
7249
7447
  const wranglerPath = import_path11.default.join(backendDir, "wrangler.toml");
7250
7448
  if (import_fs_extra6.default.existsSync(wranglerPath) && workerData.api_key) {
@@ -7254,7 +7452,7 @@ Directory "${projectName}" already exists.`));
7254
7452
  `name = "${workerData.project_name}"`
7255
7453
  );
7256
7454
  import_fs_extra6.default.writeFileSync(wranglerPath, wranglerContent);
7257
- console.log(import_chalk16.default.green(` Updated backend/wrangler.toml API_KEY`));
7455
+ console.log(import_chalk17.default.green(` Updated backend/wrangler.toml API_KEY`));
7258
7456
  }
7259
7457
  const envExamplePath = import_path11.default.join(targetDir, "frontend", ".env.example");
7260
7458
  const envPath = import_path11.default.join(targetDir, "frontend", ".env");
@@ -7266,68 +7464,67 @@ Directory "${projectName}" already exists.`));
7266
7464
  `VITE_API_URL=${workerData.api_domain}`
7267
7465
  );
7268
7466
  import_fs_extra6.default.writeFileSync(envPath, envContent);
7269
- console.log(import_chalk16.default.green(` Created frontend/.env file`));
7467
+ console.log(import_chalk17.default.green(` Created frontend/.env file`));
7270
7468
  }
7271
- console.log(import_chalk16.default.blue("\n4. Building frontend..."));
7469
+ console.log(import_chalk17.default.blue("\n4. Building frontend..."));
7272
7470
  try {
7273
7471
  (0, import_child_process2.execSync)("npm install", {
7274
7472
  cwd: targetDir,
7275
7473
  stdio: "inherit"
7276
7474
  });
7277
- console.log(import_chalk16.default.green(" Root dependencies installed"));
7475
+ console.log(import_chalk17.default.green(" Project dependencies installed"));
7278
7476
  } catch (error) {
7279
- console.log(import_chalk16.default.yellow(" Warning: Root dependencies install failed, continuing..."));
7477
+ throw createCommandError("project dependency install", "npm install", error, [
7478
+ "Check network connectivity and npm registry availability.",
7479
+ "Inspect the generated workspace `package.json` files for dependency conflicts."
7480
+ ]);
7280
7481
  }
7281
7482
  const frontendDir = import_path11.default.join(targetDir, "frontend");
7282
7483
  if (import_fs_extra6.default.existsSync(frontendDir)) {
7283
7484
  try {
7284
- (0, import_child_process2.execSync)("npm install", {
7285
- cwd: frontendDir,
7286
- stdio: "inherit"
7287
- });
7288
- console.log(import_chalk16.default.green(" Frontend dependencies installed"));
7289
- } catch (error) {
7290
- console.log(import_chalk16.default.yellow(" Warning: Frontend dependencies install failed, continuing..."));
7291
- }
7292
- try {
7293
- (0, import_child_process2.execSync)("npm run build", {
7294
- cwd: frontendDir,
7485
+ (0, import_child_process2.execSync)("npm run build:frontend", {
7486
+ cwd: targetDir,
7295
7487
  stdio: "inherit"
7296
7488
  });
7297
- console.log(import_chalk16.default.green(" Frontend built"));
7489
+ console.log(import_chalk17.default.green(" Frontend built"));
7298
7490
  } catch (error) {
7299
- throw new Error(`Frontend build failed: ${error.message}`);
7491
+ throw createCommandError("frontend build", "npm run build:frontend", error, [
7492
+ "Fix the frontend build error shown above, then rerun `pinme create`."
7493
+ ]);
7300
7494
  }
7301
- console.log(import_chalk16.default.blue(" Uploading to IPFS..."));
7495
+ console.log(import_chalk17.default.blue(" Uploading to IPFS..."));
7302
7496
  try {
7303
7497
  (0, import_child_process2.execSync)("pinme upload ./dist", {
7304
7498
  cwd: frontendDir,
7305
- stdio: "inherit"
7499
+ stdio: "inherit",
7500
+ env: {
7501
+ ...process.env,
7502
+ PINME_PROJECT_NAME: workerData.project_name
7503
+ }
7306
7504
  });
7307
- console.log(import_chalk16.default.green(" Frontend uploaded to IPFS"));
7505
+ console.log(import_chalk17.default.green(" Frontend uploaded to IPFS"));
7308
7506
  } catch (error) {
7309
- console.log(import_chalk16.default.yellow(" Warning: IPFS upload failed, you can upload manually later"));
7507
+ console.log(import_chalk17.default.yellow(" Warning: IPFS upload failed, you can upload manually later"));
7310
7508
  }
7311
7509
  }
7312
- console.log(import_chalk16.default.green("\n\u2705 Project created successfully!"));
7313
- console.log(import_chalk16.default.gray(`
7510
+ console.log(import_chalk17.default.green("\nProject created successfully."));
7511
+ console.log(import_chalk17.default.gray(`
7314
7512
  Project Details:`));
7315
- console.log(import_chalk16.default.gray(` API Domain: ${workerData.api_domain}`));
7316
- console.log(import_chalk16.default.gray(` Project Name: ${workerData.project_name}`));
7317
- console.log(import_chalk16.default.gray(`
7513
+ console.log(import_chalk17.default.gray(` API Domain: ${workerData.api_domain}`));
7514
+ console.log(import_chalk17.default.gray(` Project Name: ${workerData.project_name}`));
7515
+ console.log(import_chalk17.default.gray(`
7318
7516
  Next steps:`));
7319
- console.log(import_chalk16.default.gray(` cd ${projectName}`));
7320
- console.log(import_chalk16.default.gray(` pinme save # \u9996\u6B21\u90E8\u7F72\u540E\u7AEF + \u524D\u7AEF`));
7517
+ console.log(import_chalk17.default.gray(` cd ${projectName}`));
7518
+ console.log(import_chalk17.default.gray(` pinme save`));
7321
7519
  process.exit(0);
7322
7520
  } catch (error) {
7323
- console.error(import_chalk16.default.red(`
7324
- Error: ${error.message || error}`));
7521
+ printCliError(error, "Project creation failed.");
7325
7522
  process.exit(1);
7326
7523
  }
7327
7524
  }
7328
7525
 
7329
7526
  // bin/save.ts
7330
- var import_chalk17 = __toESM(require("chalk"));
7527
+ var import_chalk18 = __toESM(require("chalk"));
7331
7528
  var import_fs_extra7 = __toESM(require("fs-extra"));
7332
7529
  var import_path12 = __toESM(require("path"));
7333
7530
  var import_child_process3 = require("child_process");
@@ -7336,7 +7533,10 @@ var API_BASE2 = "https://pinme.dev/api/v4";
7336
7533
  function loadConfig() {
7337
7534
  const configPath = import_path12.default.join(PROJECT_DIR2, "pinme.toml");
7338
7535
  if (!import_fs_extra7.default.existsSync(configPath)) {
7339
- throw new Error("pinme.toml not found");
7536
+ throw createConfigError("`pinme.toml` not found in the current directory.", [
7537
+ "Run this command from the Pinme project root.",
7538
+ "If the project has not been initialized yet, create or restore `pinme.toml` first."
7539
+ ]);
7340
7540
  }
7341
7541
  const configContent = import_fs_extra7.default.readFileSync(configPath, "utf-8");
7342
7542
  const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
@@ -7347,67 +7547,52 @@ function loadConfig() {
7347
7547
  function getMetadata() {
7348
7548
  const metadataPath = import_path12.default.join(PROJECT_DIR2, "backend", "metadata.json");
7349
7549
  if (!import_fs_extra7.default.existsSync(metadataPath)) {
7350
- console.log(import_chalk17.default.yellow(" Warning: metadata.json not found, using empty metadata"));
7550
+ console.log(import_chalk18.default.yellow(" Warning: metadata.json not found, using empty metadata"));
7351
7551
  return {};
7352
7552
  }
7353
7553
  return import_fs_extra7.default.readJsonSync(metadataPath);
7354
7554
  }
7355
7555
  function buildWorker() {
7356
- console.log(import_chalk17.default.blue("Building worker..."));
7556
+ console.log(import_chalk18.default.blue("Building worker..."));
7357
7557
  try {
7358
7558
  (0, import_child_process3.execSync)("npm run build:worker", {
7359
7559
  cwd: PROJECT_DIR2,
7360
7560
  stdio: "inherit"
7361
7561
  });
7362
- console.log(import_chalk17.default.green("Worker built"));
7562
+ console.log(import_chalk18.default.green("Worker built"));
7363
7563
  } catch (error) {
7364
- throw new Error(`Worker build failed: ${error.message}`);
7564
+ throw createCommandError("worker build", "npm run build:worker", error, [
7565
+ "Fix the build error shown above, then rerun `pinme save`."
7566
+ ]);
7365
7567
  }
7366
7568
  }
7367
7569
  function installDependencies() {
7368
- console.log(import_chalk17.default.blue("Installing dependencies..."));
7570
+ console.log(import_chalk18.default.blue("Installing dependencies..."));
7369
7571
  try {
7370
7572
  (0, import_child_process3.execSync)("npm install", {
7371
7573
  cwd: PROJECT_DIR2,
7372
7574
  stdio: "inherit"
7373
7575
  });
7374
- console.log(import_chalk17.default.green("Root dependencies installed"));
7576
+ console.log(import_chalk18.default.green("Project dependencies installed"));
7375
7577
  } catch (error) {
7376
- throw new Error(`Root dependencies install failed: ${error.message}`);
7377
- }
7378
- const backendDir = import_path12.default.join(PROJECT_DIR2, "backend");
7379
- if (import_fs_extra7.default.existsSync(import_path12.default.join(backendDir, "package.json"))) {
7380
- try {
7381
- (0, import_child_process3.execSync)("npm install", {
7382
- cwd: backendDir,
7383
- stdio: "inherit"
7384
- });
7385
- console.log(import_chalk17.default.green("Backend dependencies installed"));
7386
- } catch (error) {
7387
- throw new Error(`Backend dependencies install failed: ${error.message}`);
7388
- }
7389
- }
7390
- const frontendDir = import_path12.default.join(PROJECT_DIR2, "frontend");
7391
- if (import_fs_extra7.default.existsSync(import_path12.default.join(frontendDir, "package.json"))) {
7392
- try {
7393
- (0, import_child_process3.execSync)("npm install", {
7394
- cwd: frontendDir,
7395
- stdio: "inherit"
7396
- });
7397
- console.log(import_chalk17.default.green("Frontend dependencies installed"));
7398
- } catch (error) {
7399
- throw new Error(`Frontend dependencies install failed: ${error.message}`);
7400
- }
7578
+ throw createCommandError("project dependency install", "npm install", error, [
7579
+ "Check network connectivity and npm registry availability.",
7580
+ "If `package-lock.json` is stale or conflicted, resolve that before retrying."
7581
+ ]);
7401
7582
  }
7402
7583
  }
7403
7584
  function getBuiltWorker() {
7404
7585
  const distWorkerDir = import_path12.default.join(PROJECT_DIR2, "dist-worker");
7405
7586
  if (!import_fs_extra7.default.existsSync(distWorkerDir)) {
7406
- throw new Error('Dist worker not found. Run "npm run build:worker" first.');
7587
+ throw createConfigError("Built worker output not found: `dist-worker/`.", [
7588
+ "Make sure `npm run build:worker` completed successfully."
7589
+ ]);
7407
7590
  }
7408
7591
  const workerJsPath = import_path12.default.join(distWorkerDir, "worker.js");
7409
7592
  if (!import_fs_extra7.default.existsSync(workerJsPath)) {
7410
- throw new Error("worker.js not found in dist-worker");
7593
+ throw createConfigError("Built worker entry file not found: `dist-worker/worker.js`.", [
7594
+ "Check the worker build output and bundler config."
7595
+ ]);
7411
7596
  }
7412
7597
  const modulePaths = [];
7413
7598
  const files = import_fs_extra7.default.readdirSync(distWorkerDir);
@@ -7427,16 +7612,16 @@ function getSqlFiles() {
7427
7612
  return files.map((f) => import_path12.default.join(sqlDir, f));
7428
7613
  }
7429
7614
  async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName) {
7430
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
7431
- console.log(import_chalk17.default.blue("Saving worker to platform..."));
7432
- console.log(import_chalk17.default.gray(`Project: ${projectName}`));
7433
- console.log(import_chalk17.default.gray(`workerJsPath: ${workerJsPath}`));
7434
- console.log(import_chalk17.default.gray(`modulePaths: ${modulePaths}`));
7435
- console.log(import_chalk17.default.gray(`sqlFiles: ${sqlFiles}`));
7436
- console.log(import_chalk17.default.gray(`metadata: ${metadata}`));
7615
+ var _a, _b;
7616
+ console.log(import_chalk18.default.blue("Saving worker to platform..."));
7617
+ console.log(import_chalk18.default.gray(`Project: ${projectName}`));
7618
+ console.log(import_chalk18.default.gray(`workerJsPath: ${workerJsPath}`));
7619
+ console.log(import_chalk18.default.gray(`modulePaths: ${modulePaths}`));
7620
+ console.log(import_chalk18.default.gray(`sqlFiles: ${sqlFiles}`));
7621
+ console.log(import_chalk18.default.gray(`metadata: ${metadata}`));
7437
7622
  const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
7438
7623
  const headers = getAuthHeaders();
7439
- console.log(import_chalk17.default.gray(`API URL: ${apiUrl}`));
7624
+ console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
7440
7625
  try {
7441
7626
  const FormData4 = (await import("formdata-node")).FormData;
7442
7627
  const Blob2 = (await import("formdata-node")).Blob;
@@ -7461,61 +7646,76 @@ async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, project
7461
7646
  formData.append("sql_file", new Blob2([content], {
7462
7647
  type: "application/sql"
7463
7648
  }), filename);
7464
- console.log(import_chalk17.default.gray(` Including SQL: ${filename}`));
7649
+ console.log(import_chalk18.default.gray(` Including SQL: ${filename}`));
7465
7650
  }
7466
7651
  const response = await axios_default.put(apiUrl, formData, {
7467
7652
  headers: { ...headers },
7468
7653
  timeout: 12e4
7469
7654
  });
7470
- console.log(import_chalk17.default.gray(` Response: ${JSON.stringify(response.data)}`));
7655
+ console.log(import_chalk18.default.gray(` Response: ${JSON.stringify(response.data)}`));
7471
7656
  if (response.data) {
7472
- console.log(import_chalk17.default.green("Worker saved"));
7657
+ console.log(import_chalk18.default.green("Worker saved"));
7473
7658
  if ((_b = (_a = response.data) == null ? void 0 : _a.data) == null ? void 0 : _b.sql_results) {
7474
7659
  for (const result of response.data.data.sql_results) {
7475
- console.log(import_chalk17.default.gray(` SQL ${result.filename}: ${result.status}`));
7660
+ console.log(import_chalk18.default.gray(` SQL ${result.filename}: ${result.status}`));
7476
7661
  }
7477
7662
  }
7478
7663
  } else {
7479
- throw new Error(((_e = (_d = (_c = response.data) == null ? void 0 : _c.errors) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) || "Failed to save worker");
7664
+ throw createApiError("worker save", { response: { data: response.data } }, [
7665
+ `Project: ${projectName}`,
7666
+ `Endpoint: ${apiUrl}`
7667
+ ], [
7668
+ "Verify the project exists and your account has permission to update it."
7669
+ ]);
7480
7670
  }
7481
7671
  } catch (error) {
7482
- console.log(import_chalk17.default.red(` Response status: ${(_f = error.response) == null ? void 0 : _f.status}`));
7483
- console.log(import_chalk17.default.red(` Response data: ${JSON.stringify((_g = error.response) == null ? void 0 : _g.data)}`));
7484
- const errorMsg = ((_k = (_j = (_i = (_h = error.response) == null ? void 0 : _h.data) == null ? void 0 : _i.errors) == null ? void 0 : _j[0]) == null ? void 0 : _k.message) || ((_m = (_l = error.response) == null ? void 0 : _l.data) == null ? void 0 : _m.error) || error.message || "Failed to save worker";
7485
- throw new Error(errorMsg);
7672
+ throw createApiError("worker save", error, [
7673
+ `Project: ${projectName}`,
7674
+ `Endpoint: ${apiUrl}`
7675
+ ], [
7676
+ "Check whether backend metadata, SQL files, or worker bundle contains invalid content."
7677
+ ]);
7486
7678
  }
7487
7679
  }
7488
7680
  function buildFrontend() {
7489
- console.log(import_chalk17.default.blue("Building frontend..."));
7681
+ console.log(import_chalk18.default.blue("Building frontend..."));
7490
7682
  try {
7491
7683
  (0, import_child_process3.execSync)("npm run build:frontend", {
7492
7684
  cwd: PROJECT_DIR2,
7493
7685
  stdio: "inherit"
7494
7686
  });
7495
- console.log(import_chalk17.default.green("Frontend built"));
7687
+ console.log(import_chalk18.default.green("Frontend built"));
7496
7688
  } catch (error) {
7497
- throw new Error(`Frontend build failed: ${error.message}`);
7689
+ throw createCommandError("frontend build", "npm run build:frontend", error, [
7690
+ "Fix the frontend build error shown above, then rerun `pinme save`."
7691
+ ]);
7498
7692
  }
7499
7693
  }
7500
- function deployFrontend() {
7501
- console.log(import_chalk17.default.blue("Deploying frontend to IPFS..."));
7694
+ function deployFrontend(projectName) {
7695
+ console.log(import_chalk18.default.blue("Deploying frontend to IPFS..."));
7502
7696
  try {
7503
7697
  (0, import_child_process3.execSync)("pinme upload ./frontend/dist", {
7504
7698
  cwd: PROJECT_DIR2,
7505
- stdio: "inherit"
7699
+ stdio: "inherit",
7700
+ env: {
7701
+ ...process.env,
7702
+ PINME_PROJECT_NAME: projectName
7703
+ }
7506
7704
  });
7507
- console.log(import_chalk17.default.green("Frontend deployed to IPFS"));
7705
+ console.log(import_chalk18.default.green("Frontend deployed to IPFS"));
7508
7706
  } catch (error) {
7509
- throw new Error(`Frontend deploy failed: ${error.message}`);
7707
+ throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
7708
+ "Make sure `frontend/dist` exists and `pinme upload` works in this environment."
7709
+ ]);
7510
7710
  }
7511
7711
  }
7512
7712
  async function saveCmd(options) {
7513
7713
  try {
7514
7714
  const headers = getAuthHeaders();
7515
7715
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
7516
- console.log(import_chalk17.default.yellow("\n\u26A0\uFE0F You are not logged in."));
7517
- console.log(import_chalk17.default.gray("Please run: pinme login"));
7518
- process.exit(1);
7716
+ throw createConfigError("No valid local login session was found.", [
7717
+ "Run `pinme login` and retry."
7718
+ ]);
7519
7719
  }
7520
7720
  const projectDir = options.projectName || options.name ? import_path12.default.join(PROJECT_DIR2, options.projectName || options.name) : PROJECT_DIR2;
7521
7721
  const tokenFileSrc = import_path12.default.join(PROJECT_DIR2, ".token.json");
@@ -7523,40 +7723,41 @@ async function saveCmd(options) {
7523
7723
  if (import_fs_extra7.default.existsSync(tokenFileSrc) && !import_fs_extra7.default.existsSync(tokenFileDst)) {
7524
7724
  import_fs_extra7.default.copySync(tokenFileSrc, tokenFileDst);
7525
7725
  }
7526
- console.log(import_chalk17.default.blue("\u{1F680} Deploying to platform...\n"));
7527
- console.log(import_chalk17.default.gray(`Project dir: ${PROJECT_DIR2}`));
7726
+ console.log(import_chalk18.default.blue("Deploying to platform...\n"));
7727
+ console.log(import_chalk18.default.gray(`Project dir: ${PROJECT_DIR2}`));
7528
7728
  const config = loadConfig();
7529
7729
  const projectName = config.project_name;
7530
7730
  if (!projectName) {
7531
- throw new Error("project_name not found in pinme.toml");
7731
+ throw createConfigError("`project_name` is missing in `pinme.toml`.", [
7732
+ 'Set `project_name = "your-project-name"` in `pinme.toml`.'
7733
+ ]);
7532
7734
  }
7533
- console.log(import_chalk17.default.gray(`Project: ${projectName}`));
7735
+ console.log(import_chalk18.default.gray(`Project: ${projectName}`));
7534
7736
  const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
7535
- console.log(import_chalk17.default.gray(`API URL: ${apiUrl}`));
7536
- console.log(import_chalk17.default.blue("\n--- Backend ---"));
7737
+ console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
7738
+ console.log(import_chalk18.default.blue("\n--- Backend ---"));
7537
7739
  installDependencies();
7538
7740
  buildWorker();
7539
7741
  const metadata = getMetadata();
7540
7742
  const { workerJsPath, modulePaths } = getBuiltWorker();
7541
- console.log(import_chalk17.default.gray(`Worker JS: ${workerJsPath}`));
7542
- console.log(import_chalk17.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
7743
+ console.log(import_chalk18.default.gray(`Worker JS: ${workerJsPath}`));
7744
+ console.log(import_chalk18.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
7543
7745
  const sqlFiles = getSqlFiles();
7544
- console.log(import_chalk17.default.gray(`SQL files: ${JSON.stringify(sqlFiles)}`));
7746
+ console.log(import_chalk18.default.gray(`SQL files: ${JSON.stringify(sqlFiles)}`));
7545
7747
  await saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName);
7546
- console.log(import_chalk17.default.blue("\n--- Frontend ---"));
7748
+ console.log(import_chalk18.default.blue("\n--- Frontend ---"));
7547
7749
  buildFrontend();
7548
- deployFrontend();
7549
- console.log(import_chalk17.default.green("\n\u2705 Deployment complete!"));
7750
+ deployFrontend(projectName);
7751
+ console.log(import_chalk18.default.green("\nDeployment complete."));
7550
7752
  process.exit(0);
7551
7753
  } catch (error) {
7552
- console.error(import_chalk17.default.red(`
7553
- \u274C Error: ${error.message}`));
7754
+ printCliError(error, "Save failed.");
7554
7755
  process.exit(1);
7555
7756
  }
7556
7757
  }
7557
7758
 
7558
7759
  // bin/updateDb.ts
7559
- var import_chalk18 = __toESM(require("chalk"));
7760
+ var import_chalk19 = __toESM(require("chalk"));
7560
7761
  var import_fs_extra8 = __toESM(require("fs-extra"));
7561
7762
  var import_path13 = __toESM(require("path"));
7562
7763
  var PROJECT_DIR3 = process.cwd();
@@ -7564,7 +7765,9 @@ var API_BASE3 = "https://pinme.dev/api/v4";
7564
7765
  function loadConfig2() {
7565
7766
  const configPath = import_path13.default.join(PROJECT_DIR3, "pinme.toml");
7566
7767
  if (!import_fs_extra8.default.existsSync(configPath)) {
7567
- throw new Error("pinme.toml not found");
7768
+ throw createConfigError("`pinme.toml` not found in the current directory.", [
7769
+ "Run this command from the Pinme project root."
7770
+ ]);
7568
7771
  }
7569
7772
  const configContent = import_fs_extra8.default.readFileSync(configPath, "utf-8");
7570
7773
  const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
@@ -7575,22 +7778,25 @@ function loadConfig2() {
7575
7778
  function getSqlFiles2() {
7576
7779
  const sqlDir = import_path13.default.join(PROJECT_DIR3, "db");
7577
7780
  if (!import_fs_extra8.default.existsSync(sqlDir)) {
7578
- throw new Error("SQL directory not found: db");
7781
+ throw createConfigError("SQL directory not found: `db/`.", [
7782
+ "Create a `db/` directory and add at least one `.sql` migration file."
7783
+ ]);
7579
7784
  }
7580
7785
  const files = import_fs_extra8.default.readdirSync(sqlDir).filter((f) => f.endsWith(".sql")).sort();
7581
7786
  if (files.length === 0) {
7582
- throw new Error("No SQL files found in db");
7787
+ throw createConfigError("No `.sql` files were found in `db/`.", [
7788
+ "Add one or more migration files before running `pinme update-db`."
7789
+ ]);
7583
7790
  }
7584
7791
  return files.map((f) => import_path13.default.join(sqlDir, f));
7585
7792
  }
7586
7793
  async function updateDb(sqlFiles, projectName) {
7587
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
7588
- console.log(import_chalk18.default.blue("Importing SQL files to database..."));
7589
- console.log(import_chalk18.default.gray(`Project: ${projectName}`));
7590
- console.log(import_chalk18.default.gray(`SQL files: ${sqlFiles.length}`));
7794
+ console.log(import_chalk19.default.blue("Importing SQL files to database..."));
7795
+ console.log(import_chalk19.default.gray(`Project: ${projectName}`));
7796
+ console.log(import_chalk19.default.gray(`SQL files: ${sqlFiles.length}`));
7591
7797
  const apiUrl = `${API_BASE3}/update_db?project_name=${encodeURIComponent(projectName)}`;
7592
7798
  const headers = getAuthHeaders();
7593
- console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
7799
+ console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
7594
7800
  try {
7595
7801
  const FormData4 = (await import("formdata-node")).FormData;
7596
7802
  const Blob2 = (await import("formdata-node")).Blob;
@@ -7601,49 +7807,57 @@ async function updateDb(sqlFiles, projectName) {
7601
7807
  const content = import_fs_extra8.default.readFileSync(sqlFile);
7602
7808
  totalSize += content.length;
7603
7809
  if (totalSize > 10 * 1024 * 1024) {
7604
- throw new Error("Total SQL files size exceeds 10MB limit");
7810
+ throw createConfigError("Total SQL payload exceeds the 10MB platform limit.", [
7811
+ "Split migrations into smaller batches, then rerun `pinme update-db`."
7812
+ ]);
7605
7813
  }
7606
7814
  formData.append("file", new Blob2([content], {
7607
7815
  type: "application/sql"
7608
7816
  }), filename);
7609
- console.log(import_chalk18.default.gray(` Including: ${filename} (${content.length} bytes)`));
7817
+ console.log(import_chalk19.default.gray(` Including: ${filename} (${content.length} bytes)`));
7610
7818
  }
7611
7819
  const response = await axios_default.post(apiUrl, formData, {
7612
7820
  headers: { ...headers },
7613
7821
  timeout: 12e4
7614
7822
  });
7615
- console.log(import_chalk18.default.gray(` Response: ${JSON.stringify(response.data)}`));
7823
+ console.log(import_chalk19.default.gray(` Response: ${JSON.stringify(response.data)}`));
7616
7824
  if (response.data.code === 200) {
7617
- console.log(import_chalk18.default.green("SQL files imported successfully!"));
7825
+ console.log(import_chalk19.default.green("SQL files imported successfully!"));
7618
7826
  const results = response.data.data.results;
7619
7827
  for (const result of results) {
7620
7828
  if (result.status === "complete") {
7621
- console.log(import_chalk18.default.green(` \u2713 ${result.filename}: ${result.num_queries} queries, ${result.duration}ms`));
7829
+ console.log(import_chalk19.default.green(` COMPLETE ${result.filename}: ${result.num_queries} queries, ${result.duration}ms`));
7622
7830
  if (result.changes !== void 0) {
7623
- console.log(import_chalk18.default.gray(` Changes: ${result.changes}, Read: ${result.rows_read}, Written: ${result.rows_written}`));
7831
+ console.log(import_chalk19.default.gray(` Changes: ${result.changes}, Read: ${result.rows_read}, Written: ${result.rows_written}`));
7624
7832
  }
7625
7833
  } else if (result.status === "error") {
7626
- console.log(import_chalk18.default.red(` \u2717 ${result.filename}: ${result.error}`));
7834
+ console.log(import_chalk19.default.red(` ERROR ${result.filename}: ${result.error}`));
7627
7835
  }
7628
7836
  }
7629
7837
  } else {
7630
- const errorMsg = response.data.msg || response.data.error || "Failed to import SQL files";
7631
- throw new Error(errorMsg);
7838
+ throw createApiError("database update", { response: { data: response.data } }, [
7839
+ `Project: ${projectName}`,
7840
+ `Endpoint: ${apiUrl}`
7841
+ ], [
7842
+ "Inspect the SQL result list above to identify the failing migration file."
7843
+ ]);
7632
7844
  }
7633
7845
  } catch (error) {
7634
- console.log(import_chalk18.default.red(` Response status: ${(_a = error.response) == null ? void 0 : _a.status}`));
7635
- console.log(import_chalk18.default.red(` Response data: ${JSON.stringify((_b = error.response) == null ? void 0 : _b.data)}`));
7636
- const errorMsg = ((_f = (_e = (_d = (_c = error.response) == null ? void 0 : _c.data) == null ? void 0 : _d.errors) == null ? void 0 : _e[0]) == null ? void 0 : _f.message) || ((_h = (_g = error.response) == null ? void 0 : _g.data) == null ? void 0 : _h.error) || ((_j = (_i = error.response) == null ? void 0 : _i.data) == null ? void 0 : _j.msg) || error.message || "Failed to import SQL files";
7637
- throw new Error(errorMsg);
7846
+ throw createApiError("database update", error, [
7847
+ `Project: ${projectName}`,
7848
+ `Endpoint: ${apiUrl}`
7849
+ ], [
7850
+ "Validate the SQL syntax and check whether any migration is re-applying an existing schema change."
7851
+ ]);
7638
7852
  }
7639
7853
  }
7640
7854
  async function updateDbCmd(options) {
7641
7855
  try {
7642
7856
  const headers = getAuthHeaders();
7643
7857
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
7644
- console.log(import_chalk18.default.yellow("\n\u26A0\uFE0F You are not logged in."));
7645
- console.log(import_chalk18.default.gray("Please run: pinme login"));
7646
- process.exit(1);
7858
+ throw createConfigError("No valid local login session was found.", [
7859
+ "Run `pinme login` and retry."
7860
+ ]);
7647
7861
  }
7648
7862
  const projectDir = (options == null ? void 0 : options.projectName) || (options == null ? void 0 : options.name) ? import_path13.default.join(PROJECT_DIR3, options.projectName || options.name) : PROJECT_DIR3;
7649
7863
  const tokenFileSrc = import_path13.default.join(PROJECT_DIR3, ".token.json");
@@ -7651,28 +7865,29 @@ async function updateDbCmd(options) {
7651
7865
  if (import_fs_extra8.default.existsSync(tokenFileSrc) && !import_fs_extra8.default.existsSync(tokenFileDst)) {
7652
7866
  import_fs_extra8.default.copySync(tokenFileSrc, tokenFileDst);
7653
7867
  }
7654
- console.log(import_chalk18.default.blue("\u{1F680} Importing SQL to database...\n"));
7655
- console.log(import_chalk18.default.gray(`Project dir: ${PROJECT_DIR3}`));
7868
+ console.log(import_chalk19.default.blue("Importing SQL to database...\n"));
7869
+ console.log(import_chalk19.default.gray(`Project dir: ${PROJECT_DIR3}`));
7656
7870
  const config = loadConfig2();
7657
7871
  const projectName = config.project_name;
7658
7872
  if (!projectName) {
7659
- throw new Error("project_name not found in pinme.toml");
7873
+ throw createConfigError("`project_name` is missing in `pinme.toml`.", [
7874
+ 'Set `project_name = "your-project-name"` in `pinme.toml`.'
7875
+ ]);
7660
7876
  }
7661
- console.log(import_chalk18.default.gray(`Project: ${projectName}`));
7877
+ console.log(import_chalk19.default.gray(`Project: ${projectName}`));
7662
7878
  const sqlFiles = getSqlFiles2();
7663
- console.log(import_chalk18.default.gray(`Found ${sqlFiles.length} SQL file(s) in db`));
7879
+ console.log(import_chalk19.default.gray(`Found ${sqlFiles.length} SQL file(s) in db`));
7664
7880
  await updateDb(sqlFiles, projectName);
7665
- console.log(import_chalk18.default.green("\n\u2705 Database update complete!"));
7881
+ console.log(import_chalk19.default.green("\nDatabase update complete."));
7666
7882
  process.exit(0);
7667
7883
  } catch (error) {
7668
- console.error(import_chalk18.default.red(`
7669
- \u274C Error: ${error.message}`));
7884
+ printCliError(error, "Database update failed.");
7670
7885
  process.exit(1);
7671
7886
  }
7672
7887
  }
7673
7888
 
7674
7889
  // bin/updateWorker.ts
7675
- var import_chalk19 = __toESM(require("chalk"));
7890
+ var import_chalk20 = __toESM(require("chalk"));
7676
7891
  var import_fs_extra9 = __toESM(require("fs-extra"));
7677
7892
  var import_path14 = __toESM(require("path"));
7678
7893
  var import_child_process4 = require("child_process");
@@ -7681,7 +7896,9 @@ var API_BASE4 = "https://pinme.dev/api/v4";
7681
7896
  function loadConfig3() {
7682
7897
  const configPath = import_path14.default.join(PROJECT_DIR4, "pinme.toml");
7683
7898
  if (!import_fs_extra9.default.existsSync(configPath)) {
7684
- throw new Error("pinme.toml not found");
7899
+ throw createConfigError("`pinme.toml` not found in the current directory.", [
7900
+ "Run this command from the Pinme project root."
7901
+ ]);
7685
7902
  }
7686
7903
  const configContent = import_fs_extra9.default.readFileSync(configPath, "utf-8");
7687
7904
  const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
@@ -7692,30 +7909,38 @@ function loadConfig3() {
7692
7909
  function getMetadata2() {
7693
7910
  const metadataPath = import_path14.default.join(PROJECT_DIR4, "backend", "metadata.json");
7694
7911
  if (!import_fs_extra9.default.existsSync(metadataPath)) {
7695
- throw new Error("metadata.json not found in backend directory");
7912
+ throw createConfigError("`backend/metadata.json` not found.", [
7913
+ "Create `backend/metadata.json` or restore it from the project template."
7914
+ ]);
7696
7915
  }
7697
7916
  return import_fs_extra9.default.readJsonSync(metadataPath);
7698
7917
  }
7699
7918
  function buildWorker2() {
7700
- console.log(import_chalk19.default.blue("Building worker..."));
7919
+ console.log(import_chalk20.default.blue("Building worker..."));
7701
7920
  try {
7702
7921
  (0, import_child_process4.execSync)("npm run build:worker", {
7703
7922
  cwd: PROJECT_DIR4,
7704
7923
  stdio: "inherit"
7705
7924
  });
7706
- console.log(import_chalk19.default.green("Worker built"));
7925
+ console.log(import_chalk20.default.green("Worker built"));
7707
7926
  } catch (error) {
7708
- throw new Error(`Worker build failed: ${error.message}`);
7927
+ throw createCommandError("worker build", "npm run build:worker", error, [
7928
+ "Fix the build error shown above, then rerun `pinme update-worker`."
7929
+ ]);
7709
7930
  }
7710
7931
  }
7711
7932
  function getBuiltWorker2() {
7712
7933
  const distWorkerDir = import_path14.default.join(PROJECT_DIR4, "dist-worker");
7713
7934
  if (!import_fs_extra9.default.existsSync(distWorkerDir)) {
7714
- throw new Error('Dist worker not found. Run "npm run build:worker" first.');
7935
+ throw createConfigError("Built worker output not found: `dist-worker/`.", [
7936
+ "Make sure `npm run build:worker` completed successfully."
7937
+ ]);
7715
7938
  }
7716
7939
  const workerJsPath = import_path14.default.join(distWorkerDir, "worker.js");
7717
7940
  if (!import_fs_extra9.default.existsSync(workerJsPath)) {
7718
- throw new Error("worker.js not found in dist-worker");
7941
+ throw createConfigError("Built worker entry file not found: `dist-worker/worker.js`.", [
7942
+ "Check the worker build output and bundler config."
7943
+ ]);
7719
7944
  }
7720
7945
  const modulePaths = [];
7721
7946
  const files = import_fs_extra9.default.readdirSync(distWorkerDir);
@@ -7727,15 +7952,14 @@ function getBuiltWorker2() {
7727
7952
  return { workerJsPath, modulePaths };
7728
7953
  }
7729
7954
  async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
7730
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
7731
- console.log(import_chalk19.default.blue("Updating worker on platform..."));
7732
- console.log(import_chalk19.default.gray(`Project: ${projectName}`));
7733
- console.log(import_chalk19.default.gray(`workerJsPath: ${workerJsPath}`));
7734
- console.log(import_chalk19.default.gray(`modulePaths: ${modulePaths}`));
7735
- console.log(import_chalk19.default.gray(`metadata: ${metadata}`));
7955
+ console.log(import_chalk20.default.blue("Updating worker on platform..."));
7956
+ console.log(import_chalk20.default.gray(`Project: ${projectName}`));
7957
+ console.log(import_chalk20.default.gray(`workerJsPath: ${workerJsPath}`));
7958
+ console.log(import_chalk20.default.gray(`modulePaths: ${modulePaths}`));
7959
+ console.log(import_chalk20.default.gray(`metadata: ${metadata}`));
7736
7960
  const apiUrl = `${API_BASE4}/update_worker?project_name=${encodeURIComponent(projectName)}`;
7737
7961
  const headers = getAuthHeaders();
7738
- console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
7962
+ console.log(import_chalk20.default.gray(`API URL: ${apiUrl}`));
7739
7963
  try {
7740
7964
  const FormData4 = (await import("formdata-node")).FormData;
7741
7965
  const Blob2 = (await import("formdata-node")).Blob;
@@ -7758,51 +7982,58 @@ async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
7758
7982
  headers: { ...headers },
7759
7983
  timeout: 12e4
7760
7984
  });
7761
- console.log(import_chalk19.default.gray(` Response: ${JSON.stringify(response.data)}`));
7985
+ console.log(import_chalk20.default.gray(` Response: ${JSON.stringify(response.data)}`));
7762
7986
  if (response.data) {
7763
- console.log(import_chalk19.default.green("Worker updated"));
7987
+ console.log(import_chalk20.default.green("Worker updated"));
7764
7988
  const data = response.data.data;
7765
7989
  if (data.worker_id) {
7766
- console.log(import_chalk19.default.gray(` Worker ID: ${data.worker_id}`));
7990
+ console.log(import_chalk20.default.gray(` Worker ID: ${data.worker_id}`));
7767
7991
  }
7768
7992
  if (data.deployment_id) {
7769
- console.log(import_chalk19.default.gray(` Deployment ID: ${data.deployment_id}`));
7993
+ console.log(import_chalk20.default.gray(` Deployment ID: ${data.deployment_id}`));
7770
7994
  }
7771
7995
  if (data.entry_point) {
7772
- console.log(import_chalk19.default.gray(` Entry Point: ${data.entry_point}`));
7996
+ console.log(import_chalk20.default.gray(` Entry Point: ${data.entry_point}`));
7773
7997
  }
7774
7998
  if (data.created_on) {
7775
- console.log(import_chalk19.default.gray(` Created: ${data.created_on}`));
7999
+ console.log(import_chalk20.default.gray(` Created: ${data.created_on}`));
7776
8000
  }
7777
8001
  if (data.modified_on) {
7778
- console.log(import_chalk19.default.gray(` Modified: ${data.modified_on}`));
8002
+ console.log(import_chalk20.default.gray(` Modified: ${data.modified_on}`));
7779
8003
  }
7780
8004
  if (data.startup_time_ms !== void 0) {
7781
- console.log(import_chalk19.default.gray(` Startup Time: ${data.startup_time_ms}ms`));
8005
+ console.log(import_chalk20.default.gray(` Startup Time: ${data.startup_time_ms}ms`));
7782
8006
  }
7783
8007
  if (data.has_modules !== void 0) {
7784
- console.log(import_chalk19.default.gray(` Has Modules: ${data.has_modules}`));
8008
+ console.log(import_chalk20.default.gray(` Has Modules: ${data.has_modules}`));
7785
8009
  }
7786
8010
  if (data.domain) {
7787
- console.log(import_chalk19.default.gray(` Domain: ${data.domain}`));
8011
+ console.log(import_chalk20.default.gray(` Domain: ${data.domain}`));
7788
8012
  }
7789
8013
  } else {
7790
- throw new Error(((_c = (_b = (_a = response.data) == null ? void 0 : _a.errors) == null ? void 0 : _b[0]) == null ? void 0 : _c.message) || "Failed to update worker");
8014
+ throw createApiError("worker update", { response: { data: response.data } }, [
8015
+ `Project: ${projectName}`,
8016
+ `Endpoint: ${apiUrl}`
8017
+ ], [
8018
+ "Verify the project exists and your account has permission to update it."
8019
+ ]);
7791
8020
  }
7792
8021
  } catch (error) {
7793
- console.log(import_chalk19.default.red(` Response status: ${(_d = error.response) == null ? void 0 : _d.status}`));
7794
- console.log(import_chalk19.default.red(` Response data: ${JSON.stringify((_e = error.response) == null ? void 0 : _e.data)}`));
7795
- const errorMsg = ((_i = (_h = (_g = (_f = error.response) == null ? void 0 : _f.data) == null ? void 0 : _g.errors) == null ? void 0 : _h[0]) == null ? void 0 : _i.message) || ((_k = (_j = error.response) == null ? void 0 : _j.data) == null ? void 0 : _k.error) || error.message || "Failed to update worker";
7796
- throw new Error(errorMsg);
8022
+ throw createApiError("worker update", error, [
8023
+ `Project: ${projectName}`,
8024
+ `Endpoint: ${apiUrl}`
8025
+ ], [
8026
+ "Check whether `backend/metadata.json` and the built worker bundle are valid."
8027
+ ]);
7797
8028
  }
7798
8029
  }
7799
8030
  async function updateWorkerCmd(options) {
7800
8031
  try {
7801
8032
  const headers = getAuthHeaders();
7802
8033
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
7803
- console.log(import_chalk19.default.yellow("\n\u26A0\uFE0F You are not logged in."));
7804
- console.log(import_chalk19.default.gray("Please run: pinme login"));
7805
- process.exit(1);
8034
+ throw createConfigError("No valid local login session was found.", [
8035
+ "Run `pinme login` and retry."
8036
+ ]);
7806
8037
  }
7807
8038
  const projectDir = (options == null ? void 0 : options.projectName) || (options == null ? void 0 : options.name) ? import_path14.default.join(PROJECT_DIR4, options.projectName || options.name) : PROJECT_DIR4;
7808
8039
  const tokenFileSrc = import_path14.default.join(PROJECT_DIR4, ".token.json");
@@ -7810,33 +8041,34 @@ async function updateWorkerCmd(options) {
7810
8041
  if (import_fs_extra9.default.existsSync(tokenFileSrc) && !import_fs_extra9.default.existsSync(tokenFileDst)) {
7811
8042
  import_fs_extra9.default.copySync(tokenFileSrc, tokenFileDst);
7812
8043
  }
7813
- console.log(import_chalk19.default.blue("\u{1F680} Updating worker...\n"));
7814
- console.log(import_chalk19.default.gray(`Project dir: ${PROJECT_DIR4}`));
8044
+ console.log(import_chalk20.default.blue("Updating worker...\n"));
8045
+ console.log(import_chalk20.default.gray(`Project dir: ${PROJECT_DIR4}`));
7815
8046
  const config = loadConfig3();
7816
8047
  const projectName = config.project_name;
7817
8048
  if (!projectName) {
7818
- throw new Error("project_name not found in pinme.toml");
8049
+ throw createConfigError("`project_name` is missing in `pinme.toml`.", [
8050
+ 'Set `project_name = "your-project-name"` in `pinme.toml`.'
8051
+ ]);
7819
8052
  }
7820
- console.log(import_chalk19.default.gray(`Project: ${projectName}`));
7821
- console.log(import_chalk19.default.blue("\n--- Worker Update ---"));
8053
+ console.log(import_chalk20.default.gray(`Project: ${projectName}`));
8054
+ console.log(import_chalk20.default.blue("\n--- Worker Update ---"));
7822
8055
  buildWorker2();
7823
8056
  const metadata = getMetadata2();
7824
8057
  const { workerJsPath, modulePaths } = getBuiltWorker2();
7825
- console.log(import_chalk19.default.gray(`Worker JS: ${workerJsPath}`));
7826
- console.log(import_chalk19.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
7827
- console.log(import_chalk19.default.gray(`SQL files: ignored (not processed for update_worker)`));
8058
+ console.log(import_chalk20.default.gray(`Worker JS: ${workerJsPath}`));
8059
+ console.log(import_chalk20.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
8060
+ console.log(import_chalk20.default.gray(`SQL files: ignored (not processed for update_worker)`));
7828
8061
  await updateWorker(workerJsPath, modulePaths, metadata, projectName);
7829
- console.log(import_chalk19.default.green("\n\u2705 Worker update complete!"));
8062
+ console.log(import_chalk20.default.green("\nWorker update complete."));
7830
8063
  process.exit(0);
7831
8064
  } catch (error) {
7832
- console.error(import_chalk19.default.red(`
7833
- \u274C Error: ${error.message}`));
8065
+ printCliError(error, "Worker update failed.");
7834
8066
  process.exit(1);
7835
8067
  }
7836
8068
  }
7837
8069
 
7838
8070
  // bin/updateWeb.ts
7839
- var import_chalk20 = __toESM(require("chalk"));
8071
+ var import_chalk21 = __toESM(require("chalk"));
7840
8072
  var import_fs_extra10 = __toESM(require("fs-extra"));
7841
8073
  var import_path15 = __toESM(require("path"));
7842
8074
  var import_child_process5 = require("child_process");
@@ -7844,7 +8076,9 @@ var PROJECT_DIR5 = process.cwd();
7844
8076
  function loadConfig4() {
7845
8077
  const configPath = import_path15.default.join(PROJECT_DIR5, "pinme.toml");
7846
8078
  if (!import_fs_extra10.default.existsSync(configPath)) {
7847
- throw new Error("pinme.toml not found");
8079
+ throw createConfigError("`pinme.toml` not found in the current directory.", [
8080
+ "Run this command from the Pinme project root."
8081
+ ]);
7848
8082
  }
7849
8083
  const configContent = import_fs_extra10.default.readFileSync(configPath, "utf-8");
7850
8084
  const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
@@ -7853,36 +8087,44 @@ function loadConfig4() {
7853
8087
  };
7854
8088
  }
7855
8089
  function buildFrontend2() {
7856
- console.log(import_chalk20.default.blue("Building frontend..."));
8090
+ console.log(import_chalk21.default.blue("Building frontend..."));
7857
8091
  try {
7858
8092
  (0, import_child_process5.execSync)("npm run build:frontend", {
7859
8093
  cwd: PROJECT_DIR5,
7860
8094
  stdio: "inherit"
7861
8095
  });
7862
- console.log(import_chalk20.default.green("Frontend built"));
8096
+ console.log(import_chalk21.default.green("Frontend built"));
7863
8097
  } catch (error) {
7864
- throw new Error(`Frontend build failed: ${error.message}`);
8098
+ throw createCommandError("frontend build", "npm run build:frontend", error, [
8099
+ "Fix the frontend build error shown above, then rerun `pinme update-web`."
8100
+ ]);
7865
8101
  }
7866
8102
  }
7867
- function deployFrontend2() {
7868
- console.log(import_chalk20.default.blue("Deploying frontend to IPFS..."));
8103
+ function deployFrontend2(projectName) {
8104
+ console.log(import_chalk21.default.blue("Deploying frontend to IPFS..."));
7869
8105
  try {
7870
8106
  (0, import_child_process5.execSync)("pinme upload ./frontend/dist", {
7871
8107
  cwd: PROJECT_DIR5,
7872
- stdio: "inherit"
8108
+ stdio: "inherit",
8109
+ env: {
8110
+ ...process.env,
8111
+ PINME_PROJECT_NAME: projectName
8112
+ }
7873
8113
  });
7874
- console.log(import_chalk20.default.green("Frontend deployed to IPFS"));
8114
+ console.log(import_chalk21.default.green("Frontend deployed to IPFS"));
7875
8115
  } catch (error) {
7876
- throw new Error(`Frontend deploy failed: ${error.message}`);
8116
+ throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
8117
+ "Make sure `frontend/dist` exists and `pinme upload` can run successfully."
8118
+ ]);
7877
8119
  }
7878
8120
  }
7879
8121
  async function updateWebCmd(options) {
7880
8122
  try {
7881
8123
  const headers = getAuthHeaders();
7882
8124
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
7883
- console.log(import_chalk20.default.yellow("\n\u26A0\uFE0F You are not logged in."));
7884
- console.log(import_chalk20.default.gray("Please run: pinme login"));
7885
- process.exit(1);
8125
+ throw createConfigError("No valid local login session was found.", [
8126
+ "Run `pinme login` and retry."
8127
+ ]);
7886
8128
  }
7887
8129
  const projectDir = (options == null ? void 0 : options.projectName) || (options == null ? void 0 : options.name) ? import_path15.default.join(PROJECT_DIR5, options.projectName || options.name) : PROJECT_DIR5;
7888
8130
  const tokenFileSrc = import_path15.default.join(PROJECT_DIR5, ".token.json");
@@ -7890,28 +8132,29 @@ async function updateWebCmd(options) {
7890
8132
  if (import_fs_extra10.default.existsSync(tokenFileSrc) && !import_fs_extra10.default.existsSync(tokenFileDst)) {
7891
8133
  import_fs_extra10.default.copySync(tokenFileSrc, tokenFileDst);
7892
8134
  }
7893
- console.log(import_chalk20.default.blue("\u{1F680} Updating web (frontend)...\n"));
7894
- console.log(import_chalk20.default.gray(`Project dir: ${PROJECT_DIR5}`));
8135
+ console.log(import_chalk21.default.blue("Updating web (frontend)...\n"));
8136
+ console.log(import_chalk21.default.gray(`Project dir: ${PROJECT_DIR5}`));
7895
8137
  const config = loadConfig4();
7896
8138
  const projectName = config.project_name;
7897
8139
  if (!projectName) {
7898
- throw new Error("project_name not found in pinme.toml");
8140
+ throw createConfigError("`project_name` is missing in `pinme.toml`.", [
8141
+ 'Set `project_name = "your-project-name"` in `pinme.toml`.'
8142
+ ]);
7899
8143
  }
7900
- console.log(import_chalk20.default.gray(`Project: ${projectName}`));
7901
- console.log(import_chalk20.default.blue("\n--- Frontend Update ---"));
8144
+ console.log(import_chalk21.default.gray(`Project: ${projectName}`));
8145
+ console.log(import_chalk21.default.blue("\n--- Frontend Update ---"));
7902
8146
  buildFrontend2();
7903
- deployFrontend2();
7904
- console.log(import_chalk20.default.green("\n\u2705 Web update complete!"));
8147
+ deployFrontend2(projectName);
8148
+ console.log(import_chalk21.default.green("\nWeb update complete."));
7905
8149
  process.exit(0);
7906
8150
  } catch (error) {
7907
- console.error(import_chalk20.default.red(`
7908
- \u274C Error: ${error.message}`));
8151
+ printCliError(error, "Web update failed.");
7909
8152
  process.exit(1);
7910
8153
  }
7911
8154
  }
7912
8155
 
7913
8156
  // bin/delete.ts
7914
- var import_chalk21 = __toESM(require("chalk"));
8157
+ var import_chalk22 = __toESM(require("chalk"));
7915
8158
  var import_inquirer9 = __toESM(require("inquirer"));
7916
8159
  var import_fs_extra11 = __toESM(require("fs-extra"));
7917
8160
  var import_path16 = __toESM(require("path"));
@@ -7930,23 +8173,23 @@ async function deleteCmd(options) {
7930
8173
  try {
7931
8174
  const headers = getAuthHeaders();
7932
8175
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
7933
- console.log(import_chalk21.default.yellow("\n\u26A0\uFE0F You are not logged in."));
7934
- console.log(import_chalk21.default.gray("Please run: pinme login"));
8176
+ console.log(import_chalk22.default.yellow("\n\u26A0\uFE0F You are not logged in."));
8177
+ console.log(import_chalk22.default.gray("Please run: pinme login"));
7935
8178
  process.exit(1);
7936
8179
  }
7937
- console.log(import_chalk21.default.blue("Deleting project...\n"));
8180
+ console.log(import_chalk22.default.blue("Deleting project...\n"));
7938
8181
  let projectName = options.name || getProjectName();
7939
8182
  if (!projectName) {
7940
- console.log(import_chalk21.default.red("\n\u274C Error: Cannot find project name."));
7941
- console.log(import_chalk21.default.yellow(" Please make sure you are in the project directory."));
7942
- console.log(import_chalk21.default.gray(" The project directory should contain a pinme.toml file."));
7943
- console.log(import_chalk21.default.gray("\n Or specify the project name:"));
7944
- console.log(import_chalk21.default.gray(" cd /path/to/your-project"));
7945
- console.log(import_chalk21.default.gray(" pinme delete"));
8183
+ console.log(import_chalk22.default.red("\n\u274C Error: Cannot find project name."));
8184
+ console.log(import_chalk22.default.yellow(" Please make sure you are in the project directory."));
8185
+ console.log(import_chalk22.default.gray(" The project directory should contain a pinme.toml file."));
8186
+ console.log(import_chalk22.default.gray("\n Or specify the project name:"));
8187
+ console.log(import_chalk22.default.gray(" cd /path/to/your-project"));
8188
+ console.log(import_chalk22.default.gray(" pinme delete"));
7946
8189
  process.exit(1);
7947
8190
  }
7948
- console.log(import_chalk21.default.gray(`Project: ${projectName}`));
7949
- console.log(import_chalk21.default.gray(`Directory: ${process.cwd()}`));
8191
+ console.log(import_chalk22.default.gray(`Project: ${projectName}`));
8192
+ console.log(import_chalk22.default.gray(`Directory: ${process.cwd()}`));
7950
8193
  if (!options.force) {
7951
8194
  const answers = await import_inquirer9.default.prompt([
7952
8195
  {
@@ -7957,14 +8200,14 @@ async function deleteCmd(options) {
7957
8200
  }
7958
8201
  ]);
7959
8202
  if (!answers.confirm) {
7960
- console.log(import_chalk21.default.gray("Cancelled."));
8203
+ console.log(import_chalk22.default.gray("Cancelled."));
7961
8204
  process.exit(0);
7962
8205
  }
7963
8206
  }
7964
- console.log(import_chalk21.default.blue("Deleting project on platform..."));
8207
+ console.log(import_chalk22.default.blue("Deleting project on platform..."));
7965
8208
  const apiUrl = `${API_BASE5}/delete_project`;
7966
- console.log(import_chalk21.default.gray(`API URL: ${apiUrl}`));
7967
- console.log(import_chalk21.default.gray(`Project name: ${projectName}`));
8209
+ console.log(import_chalk22.default.gray(`API URL: ${apiUrl}`));
8210
+ console.log(import_chalk22.default.gray(`Project name: ${projectName}`));
7968
8211
  const response = await axios_default.post(apiUrl, {
7969
8212
  project_name: projectName
7970
8213
  }, {
@@ -7974,35 +8217,32 @@ async function deleteCmd(options) {
7974
8217
  }
7975
8218
  }).catch((error) => {
7976
8219
  var _a2, _b2;
7977
- console.log(import_chalk21.default.red(` Response status: ${(_a2 = error.response) == null ? void 0 : _a2.status}`));
7978
- console.log(import_chalk21.default.red(` Response data: ${JSON.stringify((_b2 = error.response) == null ? void 0 : _b2.data)}`));
8220
+ if (error.response) {
8221
+ console.log(import_chalk22.default.red(` Response status: ${(_a2 = error.response) == null ? void 0 : _a2.status}`));
8222
+ console.log(import_chalk22.default.red(` Response data: ${JSON.stringify((_b2 = error.response) == null ? void 0 : _b2.data)}`));
8223
+ } else {
8224
+ console.log(import_chalk22.default.red("No Response"));
8225
+ }
7979
8226
  throw error;
7980
8227
  });
7981
8228
  const data = response.data;
7982
8229
  if (data.code === 200) {
7983
- console.log(import_chalk21.default.green("\n\u2705 Project deleted successfully!"));
7984
- console.log(import_chalk21.default.gray(`
8230
+ console.log(import_chalk22.default.green("\n\u2705 Project deleted successfully!"));
8231
+ console.log(import_chalk22.default.gray(`
7985
8232
  Project: ${data.data.project_name}`));
7986
- console.log(import_chalk21.default.gray(` Domain deleted: ${data.data.domain_deleted ? "\u2705" : "\u274C"}`));
7987
- console.log(import_chalk21.default.gray(` Worker deleted: ${data.data.worker_deleted ? "\u2705" : "\u274C"}`));
7988
- console.log(import_chalk21.default.gray(` Database deleted: ${data.data.database_deleted ? "\u2705" : "\u274C"}`));
7989
- const projectDir = process.cwd();
7990
- if (import_fs_extra11.default.existsSync(projectDir)) {
7991
- console.log(import_chalk21.default.blue("\nDeleting local project directory..."));
7992
- const parentDir = import_path16.default.dirname(projectDir);
7993
- process.chdir(parentDir);
7994
- await import_fs_extra11.default.remove(projectDir);
7995
- console.log(import_chalk21.default.green(`\u2705 Local directory deleted: ${projectDir}`));
7996
- }
8233
+ console.log(import_chalk22.default.gray(` Domain deleted: ${data.data.domain_deleted ? "\u2705" : "\u274C"}`));
8234
+ console.log(import_chalk22.default.gray(` Worker deleted: ${data.data.worker_deleted ? "\u2705" : "\u274C"}`));
8235
+ console.log(import_chalk22.default.gray(` Database deleted: ${data.data.database_deleted ? "\u2705" : "\u274C"}`));
8236
+ console.log(import_chalk22.default.gray("\nLocal files are kept unchanged."));
7997
8237
  } else {
7998
8238
  const errorMsg = (data == null ? void 0 : data.msg) || "Failed to delete project";
7999
8239
  throw new Error(errorMsg);
8000
8240
  }
8001
8241
  process.exit(0);
8002
8242
  } catch (error) {
8003
- console.log(import_chalk21.default.red(error));
8243
+ console.log(import_chalk22.default.red(error));
8004
8244
  const errorMsg = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) || error.message || "Failed to delete project";
8005
- console.error(import_chalk21.default.red(`
8245
+ console.error(import_chalk22.default.red(`
8006
8246
  \u274C Error: ${errorMsg}`));
8007
8247
  process.exit(1);
8008
8248
  }
@@ -8013,9 +8253,9 @@ import_dotenv.default.config();
8013
8253
  checkNodeVersion();
8014
8254
  function showBanner() {
8015
8255
  console.log(
8016
- import_chalk22.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
8256
+ import_chalk23.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
8017
8257
  );
8018
- console.log(import_chalk22.default.cyan("A command-line tool for uploading files to IPFS\n"));
8258
+ console.log(import_chalk23.default.cyan("A command-line tool for uploading files to IPFS\n"));
8019
8259
  }
8020
8260
  var program = new import_commander.Command();
8021
8261
  program.name("pinme").version(version).option("-v, --version", "output the current version");