pinme 2.0.2-beta.2 → 2.0.2-beta.4

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 (3) hide show
  1. package/README.md +27 -22
  2. package/dist/index.js +1405 -1322
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1033,7 +1033,7 @@ var require_debug = __commonJS({
1033
1033
  var require_follow_redirects = __commonJS({
1034
1034
  "node_modules/.pnpm/follow-redirects@1.15.2/node_modules/follow-redirects/index.js"(exports2, module2) {
1035
1035
  var url2 = require("url");
1036
- var URL5 = url2.URL;
1036
+ var URL3 = url2.URL;
1037
1037
  var http3 = require("http");
1038
1038
  var https2 = require("https");
1039
1039
  var Writable = require("stream").Writable;
@@ -1367,7 +1367,7 @@ var require_follow_redirects = __commonJS({
1367
1367
  if (isString2(input)) {
1368
1368
  var parsed;
1369
1369
  try {
1370
- parsed = urlToOptions(new URL5(input));
1370
+ parsed = urlToOptions(new URL3(input));
1371
1371
  } catch (err) {
1372
1372
  parsed = url2.parse(input);
1373
1373
  }
@@ -1375,7 +1375,7 @@ var require_follow_redirects = __commonJS({
1375
1375
  throw new InvalidUrlError({ input });
1376
1376
  }
1377
1377
  input = parsed;
1378
- } else if (URL5 && input instanceof URL5) {
1378
+ } else if (URL3 && input instanceof URL3) {
1379
1379
  input = urlToOptions(input);
1380
1380
  } else {
1381
1381
  callback = options;
@@ -1519,17 +1519,21 @@ function checkNodeVersion() {
1519
1519
 
1520
1520
  // bin/index.ts
1521
1521
  var import_commander = require("commander");
1522
- var import_chalk24 = __toESM(require("chalk"));
1522
+ var import_chalk25 = __toESM(require("chalk"));
1523
1523
  var import_figlet5 = __toESM(require("figlet"));
1524
1524
 
1525
1525
  // package.json
1526
- var version = "2.0.2-beta.2";
1526
+ var version = "2.0.2-beta.4";
1527
1527
 
1528
1528
  // bin/upload.ts
1529
1529
  var import_path7 = __toESM(require("path"));
1530
1530
  var import_chalk5 = __toESM(require("chalk"));
1531
1531
  var import_inquirer = __toESM(require("inquirer"));
1532
1532
  var import_figlet = __toESM(require("figlet"));
1533
+ var import_fs2 = __toESM(require("fs"));
1534
+
1535
+ // bin/utils/pinmeApi.ts
1536
+ var import_chalk3 = __toESM(require("chalk"));
1533
1537
 
1534
1538
  // node_modules/.pnpm/axios@1.3.2/node_modules/axios/lib/helpers/bind.js
1535
1539
  function bind(fn, thisArg) {
@@ -4398,201 +4402,58 @@ var {
4398
4402
  mergeConfig: mergeConfig2
4399
4403
  } = axios_default;
4400
4404
 
4401
- // bin/utils/uploadToIpfsSplit.ts
4402
- var import_fs_extra5 = __toESM(require("fs-extra"));
4403
- var import_path6 = __toESM(require("path"));
4404
- var import_form_data2 = __toESM(require("form-data"));
4405
- var import_ora = __toESM(require("ora"));
4406
- var crypto2 = __toESM(require("crypto"));
4407
-
4408
- // bin/utils/uploadLimits.ts
4409
- var import_fs = __toESM(require("fs"));
4410
- var import_path = __toESM(require("path"));
4411
- var FILE_SIZE_LIMIT = parseInt("500", 10) * 1024 * 1024;
4412
- var DIRECTORY_SIZE_LIMIT = parseInt("500", 10) * 1024 * 1024;
4413
- function checkFileSizeLimit(filePath) {
4414
- const stats = import_fs.default.statSync(filePath);
4415
- return {
4416
- size: stats.size,
4417
- limit: FILE_SIZE_LIMIT,
4418
- exceeds: stats.size > FILE_SIZE_LIMIT
4419
- };
4420
- }
4421
- function checkDirectorySizeLimit(directoryPath) {
4422
- const totalSize = calculateDirectorySize(directoryPath);
4423
- return {
4424
- size: totalSize,
4425
- limit: DIRECTORY_SIZE_LIMIT,
4426
- exceeds: totalSize > DIRECTORY_SIZE_LIMIT
4427
- };
4428
- }
4429
- function calculateDirectorySize(directoryPath) {
4430
- let totalSize = 0;
4431
- const files = import_fs.default.readdirSync(directoryPath);
4432
- for (const file of files) {
4433
- const filePath = import_path.default.join(directoryPath, file);
4434
- const stats = import_fs.default.statSync(filePath);
4435
- if (stats.isFile()) {
4436
- totalSize += stats.size;
4437
- } else if (stats.isDirectory()) {
4438
- totalSize += calculateDirectorySize(filePath);
4439
- }
4440
- }
4441
- return totalSize;
4442
- }
4443
- function formatSize(bytes) {
4444
- if (bytes < 1024) return bytes + " bytes";
4445
- else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + " KB";
4446
- else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + " MB";
4447
- else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB";
4448
- }
4449
-
4450
- // bin/utils/history.ts
4405
+ // bin/utils/webLogin.ts
4406
+ var import_crypto = __toESM(require("crypto"));
4407
+ var import_http3 = __toESM(require("http"));
4408
+ var import_url2 = require("url");
4409
+ var import_chalk2 = __toESM(require("chalk"));
4410
+ var import_child_process = require("child_process");
4451
4411
  var import_fs_extra = __toESM(require("fs-extra"));
4452
- var import_path2 = __toESM(require("path"));
4453
4412
  var import_os = __toESM(require("os"));
4454
- var import_dayjs = __toESM(require("dayjs"));
4455
- var import_chalk2 = __toESM(require("chalk"));
4456
- var HISTORY_DIR = import_path2.default.join(import_os.default.homedir(), ".pinme");
4457
- var HISTORY_FILE = import_path2.default.join(HISTORY_DIR, "upload-history.json");
4458
- var ensureHistoryDir = () => {
4459
- if (!import_fs_extra.default.existsSync(HISTORY_DIR)) {
4460
- import_fs_extra.default.mkdirSync(HISTORY_DIR, { recursive: true });
4461
- }
4462
- if (!import_fs_extra.default.existsSync(HISTORY_FILE)) {
4463
- import_fs_extra.default.writeJsonSync(HISTORY_FILE, { uploads: [] });
4464
- }
4465
- };
4466
- var saveUploadHistory = (uploadData) => {
4467
- try {
4468
- ensureHistoryDir();
4469
- const history = import_fs_extra.default.readJsonSync(HISTORY_FILE);
4470
- const newRecord = {
4471
- timestamp: Date.now(),
4472
- date: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss"),
4473
- path: uploadData.path,
4474
- filename: uploadData.filename || import_path2.default.basename(uploadData.path),
4475
- contentHash: uploadData.contentHash,
4476
- previewHash: uploadData.previewHash,
4477
- size: uploadData.size,
4478
- fileCount: uploadData.fileCount || 1,
4479
- type: uploadData.isDirectory ? "directory" : "file",
4480
- shortUrl: (uploadData == null ? void 0 : uploadData.shortUrl) || null
4481
- };
4482
- history.uploads.unshift(newRecord);
4483
- import_fs_extra.default.writeJsonSync(HISTORY_FILE, history, { spaces: 2 });
4484
- return true;
4485
- } catch (error) {
4486
- console.error(import_chalk2.default.red(`Error saving upload history: ${error.message}`));
4487
- return false;
4488
- }
4489
- };
4490
- var getUploadHistory = (limit = 10) => {
4491
- try {
4492
- ensureHistoryDir();
4493
- const history = import_fs_extra.default.readJsonSync(HISTORY_FILE);
4494
- return history.uploads.slice(0, limit);
4495
- } catch (error) {
4496
- console.error(import_chalk2.default.red(`Error reading upload history: ${error.message}`));
4497
- return [];
4498
- }
4499
- };
4500
- var displayUploadHistory = (limit = 10) => {
4501
- const history = getUploadHistory(limit);
4502
- if (history.length === 0) {
4503
- console.log(import_chalk2.default.yellow("No upload history found."));
4504
- return;
4505
- }
4506
- console.log(import_chalk2.default.cyan("Upload History:"));
4507
- console.log(import_chalk2.default.cyan("-".repeat(80)));
4508
- const recentHistory = history.slice(-limit);
4509
- recentHistory.forEach((item, index) => {
4510
- console.log(import_chalk2.default.green(`${index + 1}. ${item.filename}`));
4511
- console.log(import_chalk2.default.white(` Path: ${item.path}`));
4512
- console.log(import_chalk2.default.white(` IPFS CID: ${item.contentHash}`));
4513
- if (item.shortUrl) {
4514
- console.log(import_chalk2.default.white(` ENS URL: https://${item.shortUrl}.pinit.eth.limo`));
4515
- }
4516
- console.log(import_chalk2.default.white(` Size: ${formatSize(item.size)}`));
4517
- console.log(import_chalk2.default.white(` Files: ${item.fileCount}`));
4518
- console.log(import_chalk2.default.white(` Type: ${item.type === "directory" ? "Directory" : "File"}`));
4519
- if (item.timestamp) {
4520
- console.log(import_chalk2.default.white(` Date: ${new Date(item.timestamp).toLocaleString()}`));
4521
- }
4522
- console.log(import_chalk2.default.cyan("-".repeat(80)));
4523
- });
4524
- const totalSize = history.reduce((sum, record) => sum + record.size, 0);
4525
- const totalFiles = history.reduce((sum, record) => sum + record.fileCount, 0);
4526
- console.log(import_chalk2.default.bold(`Total Uploads: ${history.length}`));
4527
- console.log(import_chalk2.default.bold(`Total Files: ${totalFiles}`));
4528
- console.log(import_chalk2.default.bold(`Total Size: ${formatSize(totalSize)}`));
4529
- };
4530
- var clearUploadHistory = () => {
4531
- try {
4532
- ensureHistoryDir();
4533
- import_fs_extra.default.writeJsonSync(HISTORY_FILE, { uploads: [] });
4534
- console.log(import_chalk2.default.green("Upload history cleared successfully."));
4535
- return true;
4536
- } catch (error) {
4537
- console.error(import_chalk2.default.red(`Error clearing upload history: ${error.message}`));
4538
- return false;
4539
- }
4540
- };
4541
-
4542
- // bin/utils/getDeviceId.ts
4543
- var import_fs_extra3 = __toESM(require("fs-extra"));
4544
- var import_path4 = __toESM(require("path"));
4545
- var import_os3 = __toESM(require("os"));
4546
- var import_uuid = require("uuid");
4547
-
4548
- // bin/utils/auth.ts
4549
- var import_fs_extra2 = __toESM(require("fs-extra"));
4550
- var import_os2 = __toESM(require("os"));
4551
- var import_path3 = __toESM(require("path"));
4552
- var CONFIG_DIR = import_path3.default.join(import_os2.default.homedir(), ".pinme");
4553
- var AUTH_FILE = import_path3.default.join(CONFIG_DIR, "auth.json");
4554
- function getAuthConfig() {
4555
- try {
4556
- if (!import_fs_extra2.default.existsSync(AUTH_FILE)) return null;
4557
- const data = import_fs_extra2.default.readJsonSync(AUTH_FILE);
4558
- if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
4559
- return data;
4560
- } catch {
4561
- return null;
4562
- }
4563
- }
4413
+ var import_path = __toESM(require("path"));
4564
4414
 
4565
- // bin/utils/getDeviceId.ts
4566
- function getDeviceId() {
4567
- const configDir = import_path4.default.join(import_os3.default.homedir(), ".pinme");
4568
- const configFile = import_path4.default.join(configDir, "device-id");
4569
- if (!import_fs_extra3.default.existsSync(configDir)) {
4570
- import_fs_extra3.default.mkdirSync(configDir, { recursive: true });
4571
- }
4572
- if (import_fs_extra3.default.existsSync(configFile)) {
4573
- return import_fs_extra3.default.readFileSync(configFile, "utf8").trim();
4574
- }
4575
- const deviceId = (0, import_uuid.v4)();
4576
- import_fs_extra3.default.writeFileSync(configFile, deviceId);
4577
- return deviceId;
4578
- }
4579
- function getUid() {
4580
- const auth = getAuthConfig();
4581
- if (auth == null ? void 0 : auth.address) {
4582
- return auth.address;
4415
+ // bin/utils/config.ts
4416
+ function trimTrailingSlash(value) {
4417
+ return value.replace(/\/+$/, "");
4418
+ }
4419
+ function readNumberEnv(name, fallback) {
4420
+ const rawValue = process.env[name];
4421
+ if (!rawValue) {
4422
+ return fallback;
4423
+ }
4424
+ const parsed = Number.parseInt(rawValue, 10);
4425
+ return Number.isFinite(parsed) ? parsed : fallback;
4426
+ }
4427
+ var DEFAULT_PINME_WEB_URL = "http://localhost:5173";
4428
+ var _a;
4429
+ var APP_CONFIG = {
4430
+ pinmeApiBase: trimTrailingSlash("https://pinme.benny1996.win/api/v4"),
4431
+ ipfsApiUrl: trimTrailingSlash("https://pinme.benny1996.win/api/v3"),
4432
+ carApiBase: trimTrailingSlash(
4433
+ process.env.CAR_API_BASE || "https://pinme.benny1996.win/api/v3"
4434
+ ),
4435
+ pinmeWebUrl: trimTrailingSlash(
4436
+ process.env.PINME_WEB_URL || DEFAULT_PINME_WEB_URL
4437
+ ),
4438
+ pinmeCheckDomainPath: process.env.PINME_CHECK_DOMAIN_PATH || "/check_domain",
4439
+ ipfsPreviewUrl: "https://pinme.eth.limo/#/preview/",
4440
+ secretKey: "pinme-secret-key",
4441
+ pinmeProjectName: (_a = process.env.PINME_PROJECT_NAME) == null ? void 0 : _a.trim(),
4442
+ upload: {
4443
+ maxRetries: readNumberEnv("MAX_RETRIES", 2),
4444
+ retryDelayMs: readNumberEnv("RETRY_DELAY_MS", 1e3),
4445
+ timeoutMs: readNumberEnv("TIMEOUT_MS", 6e5),
4446
+ maxPollTimeMs: readNumberEnv("MAX_POLL_TIME_MINUTES", 5) * 60 * 1e3,
4447
+ pollIntervalMs: readNumberEnv("POLL_INTERVAL_SECONDS", 2) * 1e3,
4448
+ pollTimeoutMs: readNumberEnv("POLL_TIMEOUT_SECONDS", 10) * 1e3
4583
4449
  }
4584
- return getDeviceId();
4450
+ };
4451
+ function getPinmeApiUrl(pathname) {
4452
+ const normalizedPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
4453
+ return `${APP_CONFIG.pinmeApiBase}${normalizedPath}`;
4585
4454
  }
4586
4455
 
4587
4456
  // 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
4457
  function openBrowser(url2) {
4597
4458
  const platform = process.platform;
4598
4459
  let command;
@@ -4605,15 +4466,15 @@ function openBrowser(url2) {
4605
4466
  }
4606
4467
  (0, import_child_process.exec)(command, (err) => {
4607
4468
  if (err) {
4608
- console.log(import_chalk3.default.yellow(`Unable to open browser automatically. Please visit manually: ${url2}`));
4469
+ console.log(import_chalk2.default.yellow(`Unable to open browser automatically. Please visit manually: ${url2}`));
4609
4470
  }
4610
4471
  });
4611
4472
  }
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");
4473
+ var CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".pinme");
4474
+ var AUTH_FILE = import_path.default.join(CONFIG_DIR, "auth.json");
4614
4475
  var DEFAULT_OPTIONS = {
4615
- apiBaseUrl: "https://pinme.benny1996.win/api/v4",
4616
- webBaseUrl: process.env.PINME_WEB_URL || "http://localhost:5173",
4476
+ apiBaseUrl: APP_CONFIG.pinmeApiBase,
4477
+ webBaseUrl: APP_CONFIG.pinmeWebUrl,
4617
4478
  callbackPort: 34567,
4618
4479
  callbackPath: "/cli/callback"
4619
4480
  };
@@ -4627,30 +4488,30 @@ var WebLoginManager = class {
4627
4488
  this.config = { ...DEFAULT_OPTIONS, ...options };
4628
4489
  }
4629
4490
  async login() {
4630
- console.log(import_chalk3.default.blue("Starting login flow...\n"));
4491
+ console.log(import_chalk2.default.blue("Starting login flow...\n"));
4631
4492
  this.loginToken = this.generateLoginToken();
4632
- console.log(import_chalk3.default.blue("Starting local callback server..."));
4493
+ console.log(import_chalk2.default.blue("Starting local callback server..."));
4633
4494
  await this.startCallbackServer();
4634
4495
  try {
4635
4496
  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}
4497
+ console.log(import_chalk2.default.blue("Opening browser..."));
4498
+ console.log(import_chalk2.default.white("If browser does not open automatically, please visit manually:"));
4499
+ console.log(import_chalk2.default.cyan(` ${loginUrl}
4639
4500
  `));
4640
4501
  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"));
4502
+ console.log(import_chalk2.default.yellow("Please complete login in browser..."));
4503
+ console.log(import_chalk2.default.gray("Browser will close automatically after successful login.\n"));
4643
4504
  const authToken = await this.waitForCallback();
4644
4505
  const authConfig = this.parseAuthToken(authToken);
4645
4506
  this.saveAuthConfig(authConfig);
4646
- console.log(import_chalk3.default.green("\nLogin successful!"));
4507
+ console.log(import_chalk2.default.green("\nLogin successful!"));
4647
4508
  if (authConfig.email) {
4648
- console.log(import_chalk3.default.green(`Welcome, ${authConfig.email}`));
4509
+ console.log(import_chalk2.default.green(`Welcome, ${authConfig.email}`));
4649
4510
  }
4650
- console.log(import_chalk3.default.gray(`Address: ${authConfig.address}`));
4511
+ console.log(import_chalk2.default.gray(`Address: ${authConfig.address}`));
4651
4512
  return authConfig;
4652
4513
  } catch (error) {
4653
- console.error(import_chalk3.default.red(`
4514
+ console.error(import_chalk2.default.red(`
4654
4515
  Login failed: ${error.message}`));
4655
4516
  throw error;
4656
4517
  } finally {
@@ -4712,7 +4573,7 @@ Login failed: ${error.message}`));
4712
4573
  reject(err);
4713
4574
  });
4714
4575
  this.server.listen(this.config.callbackPort, "127.0.0.1", () => {
4715
- console.log(import_chalk3.default.gray(`Local server: http://localhost:${this.config.callbackPort}`));
4576
+ console.log(import_chalk2.default.gray(`Local server: http://localhost:${this.config.callbackPort}`));
4716
4577
  resolve();
4717
4578
  });
4718
4579
  setTimeout(() => {
@@ -4747,9 +4608,9 @@ Login failed: ${error.message}`));
4747
4608
  return { address, token };
4748
4609
  }
4749
4610
  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);
4611
+ import_fs_extra.default.ensureDirSync(CONFIG_DIR);
4612
+ import_fs_extra.default.writeJsonSync(AUTH_FILE, config, { spaces: 2 });
4613
+ import_fs_extra.default.chmodSync(AUTH_FILE, 384);
4753
4614
  }
4754
4615
  closeServer() {
4755
4616
  if (this.server) {
@@ -5046,14 +4907,14 @@ function setAuthToken(combined) {
5046
4907
  throw new Error("Invalid token content. Address or token is empty.");
5047
4908
  }
5048
4909
  const config = { address, token };
5049
- import_fs_extra4.default.ensureDirSync(CONFIG_DIR2);
5050
- import_fs_extra4.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
4910
+ import_fs_extra.default.ensureDirSync(CONFIG_DIR);
4911
+ import_fs_extra.default.writeJsonSync(AUTH_FILE, config, { spaces: 2 });
5051
4912
  return config;
5052
4913
  }
5053
- function getAuthConfig2() {
4914
+ function getAuthConfig() {
5054
4915
  try {
5055
- if (!import_fs_extra4.default.existsSync(AUTH_FILE2)) return null;
5056
- const data = import_fs_extra4.default.readJsonSync(AUTH_FILE2);
4916
+ if (!import_fs_extra.default.existsSync(AUTH_FILE)) return null;
4917
+ const data = import_fs_extra.default.readJsonSync(AUTH_FILE);
5057
4918
  if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
5058
4919
  return data;
5059
4920
  } catch {
@@ -5062,15 +4923,15 @@ function getAuthConfig2() {
5062
4923
  }
5063
4924
  function clearAuthToken() {
5064
4925
  try {
5065
- if (import_fs_extra4.default.existsSync(AUTH_FILE2)) {
5066
- import_fs_extra4.default.removeSync(AUTH_FILE2);
4926
+ if (import_fs_extra.default.existsSync(AUTH_FILE)) {
4927
+ import_fs_extra.default.removeSync(AUTH_FILE);
5067
4928
  }
5068
4929
  } catch (error) {
5069
4930
  console.error(`Failed to clear auth token: ${error}`);
5070
4931
  }
5071
4932
  }
5072
4933
  function getAuthHeaders() {
5073
- const conf = getAuthConfig2();
4934
+ const conf = getAuthConfig();
5074
4935
  if (!conf) {
5075
4936
  throw new Error("Auth not set. Run: pinme login");
5076
4937
  }
@@ -5080,849 +4941,1112 @@ function getAuthHeaders() {
5080
4941
  };
5081
4942
  }
5082
4943
 
5083
- // bin/utils/uploadToIpfsSplit.ts
5084
- var IPFS_API_URL = "https://pinme.benny1996.win/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();
4944
+ // bin/utils/apiClient.ts
4945
+ function safeGetAuthHeaders() {
4946
+ try {
4947
+ return getAuthHeaders();
4948
+ } catch (error) {
4949
+ return {};
5121
4950
  }
5122
- // Stop simulating progress
5123
- stopSimulatingProgress() {
5124
- this.isSimulatingProgress = false;
4951
+ }
4952
+ function createApiClient(options = {}) {
4953
+ const {
4954
+ baseURL = APP_CONFIG.pinmeApiBase,
4955
+ includeAuth = true,
4956
+ timeout = 2e4,
4957
+ headers = {}
4958
+ } = options;
4959
+ const client = axios_default.create({
4960
+ baseURL,
4961
+ timeout,
4962
+ headers: {
4963
+ ...includeAuth ? safeGetAuthHeaders() : {},
4964
+ Accept: "*/*",
4965
+ "Content-Type": "application/json",
4966
+ "User-Agent": "Pinme-CLI",
4967
+ Connection: "keep-alive",
4968
+ ...headers
4969
+ }
4970
+ });
4971
+ client.interceptors.response.use(
4972
+ (response) => response,
4973
+ (error) => Promise.reject(error)
4974
+ );
4975
+ return client;
4976
+ }
4977
+ function createPinmeApiClient(options = {}) {
4978
+ return createApiClient({
4979
+ ...options,
4980
+ baseURL: APP_CONFIG.pinmeApiBase
4981
+ });
4982
+ }
4983
+ function createCarApiClient(options = {}) {
4984
+ return createApiClient({
4985
+ ...options,
4986
+ baseURL: APP_CONFIG.carApiBase
4987
+ });
4988
+ }
4989
+
4990
+ // bin/utils/pinmeApi.ts
4991
+ var TOKEN_EXPIRED_CODES = [
4992
+ 401,
4993
+ 403,
4994
+ 10001,
4995
+ 10002,
4996
+ 20001,
4997
+ "TOKEN_EXPIRED",
4998
+ "AUTH_FAILED"
4999
+ ];
5000
+ var TOKEN_EXPIRED_MESSAGES = [
5001
+ "token expired",
5002
+ "invalid token",
5003
+ "authentication failed",
5004
+ "auth failed",
5005
+ "unauthorized",
5006
+ "\u767B\u5F55",
5007
+ "\u8FC7\u671F",
5008
+ "token",
5009
+ "\u9274\u6743"
5010
+ ];
5011
+ function isTokenExpired(error) {
5012
+ var _a2, _b, _c, _d, _e, _f, _g;
5013
+ const status = (_a2 = error.response) == null ? void 0 : _a2.status;
5014
+ const message = ((_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.msg) || ((_e = (_d = error.response) == null ? void 0 : _d.data) == null ? void 0 : _e.message) || error.message || "";
5015
+ const code = (_g = (_f = error.response) == null ? void 0 : _f.data) == null ? void 0 : _g.code;
5016
+ if (status && TOKEN_EXPIRED_CODES.includes(status)) {
5017
+ return true;
5125
5018
  }
5126
- failStep(error) {
5127
- this.stopProgress();
5128
- this.spinner.fail(`Upload failed: ${error}`);
5019
+ if (code && TOKEN_EXPIRED_CODES.includes(code)) {
5020
+ return true;
5129
5021
  }
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)`
5022
+ const lowerMessage = message.toLowerCase();
5023
+ return TOKEN_EXPIRED_MESSAGES.some(
5024
+ (m) => lowerMessage.includes(m.toLowerCase())
5025
+ );
5026
+ }
5027
+ function showTokenExpiredHint() {
5028
+ console.log(import_chalk3.default.red("\n\u26A0\uFE0F Token has expired or is invalid."));
5029
+ console.log(import_chalk3.default.yellow("Please re-run: pinme set-appkey <AppKey>\n"));
5030
+ }
5031
+ async function bindAnonymousDevice(anonymousUid) {
5032
+ try {
5033
+ const client = createPinmeApiClient();
5034
+ const { data } = await client.post("/bind_anonymous", {
5035
+ anonymous_uid: anonymousUid
5036
+ });
5037
+ return (data == null ? void 0 : data.code) === 200;
5038
+ } catch (e) {
5039
+ if (isTokenExpired(e)) {
5040
+ showTokenExpiredHint();
5041
+ return false;
5042
+ }
5043
+ console.log(
5044
+ import_chalk3.default.yellow(`Failed to trigger anonymous binding: ${(e == null ? void 0 : e.message) || e}`)
5136
5045
  );
5046
+ return false;
5137
5047
  }
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);
5048
+ }
5049
+ async function checkDomainAvailable(domainName) {
5050
+ var _a2;
5051
+ const client = createPinmeApiClient();
5052
+ const configured = APP_CONFIG.pinmeCheckDomainPath;
5053
+ const fallbacks = [configured, "/check_domain_available"];
5054
+ for (const p of fallbacks) {
5055
+ try {
5056
+ const { data } = await client.post(p, { domain_name: domainName });
5057
+ if (typeof (data == null ? void 0 : data.is_valid) === "boolean") {
5058
+ return { is_valid: data.is_valid, error: data == null ? void 0 : data.error };
5059
+ }
5060
+ if ((data == null ? void 0 : data.data) && typeof data.data.is_valid === "boolean") {
5061
+ return { is_valid: data.data.is_valid, error: (_a2 = data.data) == null ? void 0 : _a2.error };
5062
+ }
5063
+ } catch (e) {
5064
+ if (isTokenExpired(e)) {
5065
+ showTokenExpiredHint();
5066
+ throw new Error("Token expired");
5153
5067
  }
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
5068
  }
5164
5069
  }
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`;
5070
+ return { is_valid: true };
5071
+ }
5072
+ async function bindPinmeDomain(domainName, hash) {
5073
+ try {
5074
+ const client = createPinmeApiClient();
5075
+ const { data } = await client.post("/bind_pinme_domain", {
5076
+ domain_name: domainName,
5077
+ hash
5078
+ });
5079
+ return (data == null ? void 0 : data.code) === 200;
5080
+ } catch (e) {
5081
+ if (isTokenExpired(e)) {
5082
+ showTokenExpiredHint();
5083
+ throw new Error("Token expired");
5189
5084
  }
5085
+ throw e;
5190
5086
  }
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
5087
  }
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 });
5088
+ async function getMyDomains() {
5089
+ var _a2;
5090
+ try {
5091
+ const client = createPinmeApiClient();
5092
+ const { data } = await client.get("/my_domains");
5093
+ if ((data == null ? void 0 : data.code) === 200) {
5094
+ if (Array.isArray(data == null ? void 0 : data.data)) {
5095
+ return data.data;
5096
+ }
5097
+ if (((_a2 = data == null ? void 0 : data.data) == null ? void 0 : _a2.list) && Array.isArray(data.data.list)) {
5098
+ return data.data.list;
5099
+ }
5206
5100
  }
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);
5101
+ if ((data == null ? void 0 : data.code) === 401 || (data == null ? void 0 : data.code) === 403) {
5102
+ showTokenExpiredHint();
5103
+ throw new Error("Token expired");
5228
5104
  }
5229
- });
5105
+ return [];
5106
+ } catch (e) {
5107
+ if (isTokenExpired(e)) {
5108
+ showTokenExpiredHint();
5109
+ throw new Error("Token expired");
5110
+ }
5111
+ throw e;
5112
+ }
5230
5113
  }
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);
5114
+ async function bindDnsDomainV4(domainName, hash, tokenAddress, authToken) {
5236
5115
  try {
5237
- const response = await axios_default.post(
5238
- `${IPFS_API_URL}/chunk/init`,
5116
+ const client = createPinmeApiClient();
5117
+ const { data } = await client.post(
5118
+ "/bind_dns",
5239
5119
  {
5240
- file_name: fileName,
5241
- file_size: fileSize,
5242
- md5,
5243
- is_directory: isDirectory,
5244
- uid: deviceId
5120
+ domain_name: domainName,
5121
+ hash
5245
5122
  },
5246
5123
  {
5247
- timeout: TIMEOUT,
5248
- headers: { "Content-Type": "application/json" }
5124
+ headers: {
5125
+ "x-auth-token": authToken,
5126
+ "x-token-address": tokenAddress
5127
+ }
5249
5128
  }
5250
5129
  );
5251
- const { code, msg, data } = response.data;
5252
- if (code === 200 && data) {
5253
- return data;
5254
- }
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}`);
5130
+ return data;
5131
+ } catch (e) {
5132
+ if (isTokenExpired(e)) {
5133
+ showTokenExpiredHint();
5134
+ throw new Error("Token expired");
5259
5135
  }
5260
- throw error;
5136
+ throw e;
5261
5137
  }
5262
5138
  }
5263
- async function uploadChunkWithAbort(sessionId, chunkIndex, chunkData, deviceId, signal, retryCount = 0) {
5139
+ async function getWalletBalance(tokenAddress, authToken) {
5264
5140
  try {
5265
- if (signal.aborted) {
5266
- throw new Error("Request cancelled");
5267
- }
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,
5141
+ const client = createPinmeApiClient();
5142
+ const { data } = await client.get(
5143
+ "/pay/wallet/balance",
5279
5144
  {
5280
- headers: { ...form.getHeaders() },
5281
- timeout: TIMEOUT,
5282
- signal
5145
+ headers: {
5146
+ "authentication-tokens": authToken,
5147
+ "token-address": tokenAddress
5148
+ }
5283
5149
  }
5284
5150
  );
5285
- const { code, msg, data } = response.data;
5286
- if (code === 200 && data) {
5287
- return data;
5288
- }
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");
5293
- }
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
- );
5151
+ return data;
5152
+ } catch (e) {
5153
+ if (isTokenExpired(e)) {
5154
+ showTokenExpiredHint();
5155
+ throw new Error("Token expired");
5304
5156
  }
5305
- throw new Error(
5306
- `Chunk ${chunkIndex + 1} upload failed after ${MAX_RETRIES} retries: ${error.message}`
5307
- );
5157
+ throw e;
5308
5158
  }
5309
5159
  }
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();
5160
+ async function requestCarExport(cid, uid) {
5161
+ var _a2, _b;
5162
+ try {
5163
+ const client = createCarApiClient();
5164
+ const { data } = await client.post("/car/export", null, {
5165
+ params: {
5166
+ cid,
5167
+ uid
5317
5168
  }
5318
- }, delay);
5319
- if (signal.aborted) {
5320
- clearTimeout(timeoutId);
5321
- reject(new Error("Request cancelled"));
5322
- return;
5169
+ });
5170
+ if ((data == null ? void 0 : data.code) === 200 && (data == null ? void 0 : data.data)) {
5171
+ return data.data;
5323
5172
  }
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
- );
5173
+ throw new Error((data == null ? void 0 : data.msg) || "Failed to request CAR export");
5174
+ } catch (e) {
5175
+ if (isTokenExpired(e)) {
5176
+ showTokenExpiredHint();
5177
+ throw new Error("Token expired");
5377
5178
  }
5378
- if (hasFatalError) {
5379
- throw new Error(fatalError || "Unknown error occurred during upload");
5179
+ if ((_b = (_a2 = e.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.msg) {
5180
+ throw new Error(e.response.data.msg);
5380
5181
  }
5381
- } catch (error) {
5382
- throw fatalError ? new Error(fatalError) : error;
5182
+ throw new Error(`Failed to request CAR export: ${(e == null ? void 0 : e.message) || e}`);
5383
5183
  }
5384
5184
  }
5385
- async function completeChunkUpload(sessionId, deviceId, importAsCar = false) {
5386
- var _a;
5185
+ async function checkCarExportStatus(taskId) {
5186
+ var _a2, _b;
5387
5187
  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;
5393
- }
5394
- if (projectName) {
5395
- requestBody.project_name = projectName;
5396
- authHeaders = getAuthHeaders();
5397
- }
5398
- const response = await axios_default.post(
5399
- `${IPFS_API_URL}/chunk/complete`,
5400
- requestBody,
5188
+ const client = createCarApiClient();
5189
+ const { data } = await client.get(
5190
+ "/car/export/status",
5401
5191
  {
5402
- timeout: TIMEOUT,
5403
- headers: {
5404
- "Content-Type": "application/json",
5405
- ...authHeaders
5192
+ params: {
5193
+ task_id: taskId
5406
5194
  }
5407
5195
  }
5408
5196
  );
5409
- const { code, msg, data } = response.data;
5410
- if (code === 200 && data) {
5411
- return data.trace_id;
5197
+ if ((data == null ? void 0 : data.code) === 200 && (data == null ? void 0 : data.data)) {
5198
+ return data.data;
5412
5199
  }
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}`);
5200
+ throw new Error((data == null ? void 0 : data.msg) || "Failed to check export status");
5201
+ } catch (e) {
5202
+ if (isTokenExpired(e)) {
5203
+ showTokenExpiredHint();
5204
+ throw new Error("Token expired");
5417
5205
  }
5418
- throw error;
5206
+ if ((_b = (_a2 = e.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.msg) {
5207
+ throw new Error(e.response.data.msg);
5208
+ }
5209
+ throw new Error(`Failed to check export status: ${(e == null ? void 0 : e.message) || e}`);
5419
5210
  }
5420
5211
  }
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);
5212
+
5213
+ // bin/utils/domainValidator.ts
5214
+ function normalizeDomain(domain) {
5215
+ return domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
5216
+ }
5217
+ function isDnsDomain(domain) {
5218
+ return normalizeDomain(domain).includes(".");
5219
+ }
5220
+ function validateDnsDomain(domain) {
5221
+ const cleanDomain = normalizeDomain(domain);
5222
+ const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9][a-zA-Z0-9-]*)*\.[a-zA-Z]{2,}$/;
5223
+ const parts = cleanDomain.split(".");
5224
+ if (parts.length < 2) {
5225
+ return {
5226
+ valid: false,
5227
+ message: "Invalid domain format. Please enter a complete domain (e.g., example.com)"
5228
+ };
5229
+ }
5230
+ for (const part of parts) {
5231
+ if (part.length === 0) {
5232
+ return {
5233
+ valid: false,
5234
+ message: "Invalid domain format. Consecutive dots are not allowed"
5235
+ };
5431
5236
  }
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;
5237
+ if (part.length > 63) {
5238
+ return {
5239
+ valid: false,
5240
+ message: "Invalid domain format. Each label must be 63 characters or less"
5241
+ };
5442
5242
  }
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}`);
5243
+ if (!/^[a-zA-Z0-9-]+$/.test(part)) {
5244
+ return {
5245
+ valid: false,
5246
+ message: "Invalid domain format. Domains can only contain letters, numbers, and hyphens"
5247
+ };
5248
+ }
5249
+ if (/^-|-$/.test(part)) {
5250
+ return {
5251
+ valid: false,
5252
+ message: "Invalid domain format. Labels cannot start or end with hyphens"
5253
+ };
5447
5254
  }
5448
- throw error;
5449
5255
  }
5450
- }
5451
- async function monitorChunkProgress(traceId, deviceId, progressBar) {
5452
- let consecutiveErrors = 0;
5453
- const startTime = Date.now();
5454
- if (progressBar) {
5455
- progressBar.startSimulatingProgress();
5256
+ if (!domainRegex.test(cleanDomain)) {
5257
+ return { valid: false, message: "Invalid domain format" };
5456
5258
  }
5259
+ return { valid: true };
5260
+ }
5261
+
5262
+ // bin/services/uploadService.ts
5263
+ var import_crypto_js = __toESM(require("crypto-js"));
5264
+
5265
+ // bin/utils/getDeviceId.ts
5266
+ var import_fs_extra3 = __toESM(require("fs-extra"));
5267
+ var import_path3 = __toESM(require("path"));
5268
+ var import_os3 = __toESM(require("os"));
5269
+ var import_uuid = require("uuid");
5270
+
5271
+ // bin/utils/auth.ts
5272
+ var import_fs_extra2 = __toESM(require("fs-extra"));
5273
+ var import_os2 = __toESM(require("os"));
5274
+ var import_path2 = __toESM(require("path"));
5275
+ var CONFIG_DIR2 = import_path2.default.join(import_os2.default.homedir(), ".pinme");
5276
+ var AUTH_FILE2 = import_path2.default.join(CONFIG_DIR2, "auth.json");
5277
+ function getAuthConfig2() {
5457
5278
  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));
5481
- }
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();
5487
- }
5279
+ if (!import_fs_extra2.default.existsSync(AUTH_FILE2)) return null;
5280
+ const data = import_fs_extra2.default.readJsonSync(AUTH_FILE2);
5281
+ if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
5282
+ return data;
5283
+ } catch {
5284
+ return null;
5488
5285
  }
5489
5286
  }
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
- );
5287
+
5288
+ // bin/utils/getDeviceId.ts
5289
+ function getDeviceId() {
5290
+ const configDir = import_path3.default.join(import_os3.default.homedir(), ".pinme");
5291
+ const configFile = import_path3.default.join(configDir, "device-id");
5292
+ if (!import_fs_extra3.default.existsSync(configDir)) {
5293
+ import_fs_extra3.default.mkdirSync(configDir, { recursive: true });
5498
5294
  }
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");
5295
+ if (import_fs_extra3.default.existsSync(configFile)) {
5296
+ return import_fs_extra3.default.readFileSync(configFile, "utf8").trim();
5297
+ }
5298
+ const deviceId = (0, import_uuid.v4)();
5299
+ import_fs_extra3.default.writeFileSync(configFile, deviceId);
5300
+ return deviceId;
5301
+ }
5302
+ function getUid() {
5303
+ const auth = getAuthConfig2();
5304
+ if (auth == null ? void 0 : auth.address) {
5305
+ return auth.address;
5306
+ }
5307
+ return getDeviceId();
5308
+ }
5309
+
5310
+ // bin/utils/uploadToIpfsSplit.ts
5311
+ var import_fs_extra5 = __toESM(require("fs-extra"));
5312
+ var import_path6 = __toESM(require("path"));
5313
+ var import_form_data2 = __toESM(require("form-data"));
5314
+ var import_ora = __toESM(require("ora"));
5315
+ var crypto2 = __toESM(require("crypto"));
5316
+
5317
+ // bin/utils/uploadLimits.ts
5318
+ var import_fs = __toESM(require("fs"));
5319
+ var import_path4 = __toESM(require("path"));
5320
+ var FILE_SIZE_LIMIT = parseInt("500", 10) * 1024 * 1024;
5321
+ var DIRECTORY_SIZE_LIMIT = parseInt("500", 10) * 1024 * 1024;
5322
+ function checkFileSizeLimit(filePath) {
5323
+ const stats = import_fs.default.statSync(filePath);
5324
+ return {
5325
+ size: stats.size,
5326
+ limit: FILE_SIZE_LIMIT,
5327
+ exceeds: stats.size > FILE_SIZE_LIMIT
5328
+ };
5329
+ }
5330
+ function checkDirectorySizeLimit(directoryPath) {
5331
+ const totalSize = calculateDirectorySize(directoryPath);
5332
+ return {
5333
+ size: totalSize,
5334
+ limit: DIRECTORY_SIZE_LIMIT,
5335
+ exceeds: totalSize > DIRECTORY_SIZE_LIMIT
5336
+ };
5337
+ }
5338
+ function calculateDirectorySize(directoryPath) {
5339
+ let totalSize = 0;
5340
+ const files = import_fs.default.readdirSync(directoryPath);
5341
+ for (const file of files) {
5342
+ const filePath = import_path4.default.join(directoryPath, file);
5343
+ const stats = import_fs.default.statSync(filePath);
5344
+ if (stats.isFile()) {
5345
+ totalSize += stats.size;
5346
+ } else if (stats.isDirectory()) {
5347
+ totalSize += calculateDirectorySize(filePath);
5539
5348
  }
5540
- progressBar.complete();
5541
- return result;
5542
- } catch (error) {
5543
- progressBar.fail(error.message);
5544
- throw error;
5545
5349
  }
5350
+ return totalSize;
5546
5351
  }
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
- );
5352
+ function formatSize(bytes) {
5353
+ if (bytes < 1024) return bytes + " bytes";
5354
+ else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + " KB";
5355
+ else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + " MB";
5356
+ else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB";
5357
+ }
5358
+
5359
+ // bin/utils/history.ts
5360
+ var import_fs_extra4 = __toESM(require("fs-extra"));
5361
+ var import_path5 = __toESM(require("path"));
5362
+ var import_os4 = __toESM(require("os"));
5363
+ var import_dayjs = __toESM(require("dayjs"));
5364
+ var import_chalk4 = __toESM(require("chalk"));
5365
+ var HISTORY_DIR = import_path5.default.join(import_os4.default.homedir(), ".pinme");
5366
+ var HISTORY_FILE = import_path5.default.join(HISTORY_DIR, "upload-history.json");
5367
+ var ensureHistoryDir = () => {
5368
+ if (!import_fs_extra4.default.existsSync(HISTORY_DIR)) {
5369
+ import_fs_extra4.default.mkdirSync(HISTORY_DIR, { recursive: true });
5555
5370
  }
5556
- const fileName = import_path6.default.basename(filePath);
5557
- const progressBar = new StepProgressBar(fileName, false);
5371
+ if (!import_fs_extra4.default.existsSync(HISTORY_FILE)) {
5372
+ import_fs_extra4.default.writeJsonSync(HISTORY_FILE, { uploads: [] });
5373
+ }
5374
+ };
5375
+ var saveUploadHistory = (uploadData) => {
5558
5376
  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
5377
+ ensureHistoryDir();
5378
+ const history = import_fs_extra4.default.readJsonSync(HISTORY_FILE);
5379
+ const newRecord = {
5380
+ timestamp: Date.now(),
5381
+ date: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss"),
5382
+ path: uploadData.path,
5383
+ filename: uploadData.filename || import_path5.default.basename(uploadData.path),
5384
+ contentHash: uploadData.contentHash,
5385
+ previewHash: uploadData.previewHash,
5386
+ size: uploadData.size,
5387
+ fileCount: uploadData.fileCount || 1,
5388
+ type: uploadData.isDirectory ? "directory" : "file",
5389
+ shortUrl: (uploadData == null ? void 0 : uploadData.shortUrl) || null
5587
5390
  };
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;
5391
+ history.uploads.unshift(newRecord);
5392
+ import_fs_extra4.default.writeJsonSync(HISTORY_FILE, history, { spaces: 2 });
5393
+ return true;
5594
5394
  } catch (error) {
5595
- progressBar.fail(error.message);
5596
- throw error;
5597
- }
5598
- }
5599
- async function uploadToIpfsSplit_default(filePath, importAsCar = false) {
5600
- const deviceId = getUid();
5601
- if (!deviceId) {
5602
- throw new Error("Device ID not found");
5395
+ console.error(import_chalk4.default.red(`Error saving upload history: ${error.message}`));
5396
+ return false;
5603
5397
  }
5398
+ };
5399
+ var getUploadHistory = (limit = 10) => {
5604
5400
  try {
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
- };
5401
+ ensureHistoryDir();
5402
+ const history = import_fs_extra4.default.readJsonSync(HISTORY_FILE);
5403
+ return history.uploads.slice(0, limit);
5404
+ } catch (error) {
5405
+ console.error(import_chalk4.default.red(`Error reading upload history: ${error.message}`));
5406
+ return [];
5407
+ }
5408
+ };
5409
+ var displayUploadHistory = (limit = 10) => {
5410
+ const history = getUploadHistory(limit);
5411
+ if (history.length === 0) {
5412
+ console.log(import_chalk4.default.yellow("No upload history found."));
5413
+ return;
5414
+ }
5415
+ console.log(import_chalk4.default.cyan("Upload History:"));
5416
+ console.log(import_chalk4.default.cyan("-".repeat(80)));
5417
+ const recentHistory = history.slice(-limit);
5418
+ recentHistory.forEach((item, index) => {
5419
+ console.log(import_chalk4.default.green(`${index + 1}. ${item.filename}`));
5420
+ console.log(import_chalk4.default.white(` Path: ${item.path}`));
5421
+ console.log(import_chalk4.default.white(` IPFS CID: ${item.contentHash}`));
5422
+ if (item.shortUrl) {
5423
+ console.log(import_chalk4.default.white(` ENS URL: https://${item.shortUrl}.pinit.eth.limo`));
5613
5424
  }
5614
- throw new Error("Upload failed: no hash returned");
5425
+ console.log(import_chalk4.default.white(` Size: ${formatSize(item.size)}`));
5426
+ console.log(import_chalk4.default.white(` Files: ${item.fileCount}`));
5427
+ console.log(import_chalk4.default.white(` Type: ${item.type === "directory" ? "Directory" : "File"}`));
5428
+ if (item.timestamp) {
5429
+ console.log(import_chalk4.default.white(` Date: ${new Date(item.timestamp).toLocaleString()}`));
5430
+ }
5431
+ console.log(import_chalk4.default.cyan("-".repeat(80)));
5432
+ });
5433
+ const totalSize = history.reduce((sum, record) => sum + record.size, 0);
5434
+ const totalFiles = history.reduce((sum, record) => sum + record.fileCount, 0);
5435
+ console.log(import_chalk4.default.bold(`Total Uploads: ${history.length}`));
5436
+ console.log(import_chalk4.default.bold(`Total Files: ${totalFiles}`));
5437
+ console.log(import_chalk4.default.bold(`Total Size: ${formatSize(totalSize)}`));
5438
+ };
5439
+ var clearUploadHistory = () => {
5440
+ try {
5441
+ ensureHistoryDir();
5442
+ import_fs_extra4.default.writeJsonSync(HISTORY_FILE, { uploads: [] });
5443
+ console.log(import_chalk4.default.green("Upload history cleared successfully."));
5444
+ return true;
5615
5445
  } catch (error) {
5616
- throw error;
5446
+ console.error(import_chalk4.default.red(`Error clearing upload history: ${error.message}`));
5447
+ return false;
5617
5448
  }
5618
- }
5619
-
5620
- // bin/upload.ts
5621
- var import_fs2 = __toESM(require("fs"));
5622
- var import_crypto_js = __toESM(require("crypto-js"));
5449
+ };
5623
5450
 
5624
- // bin/utils/pinmeApi.ts
5625
- var import_chalk4 = __toESM(require("chalk"));
5626
- var DEFAULT_BASE = "https://pinme.benny1996.win/api/v4";
5627
- var TOKEN_EXPIRED_CODES = [
5628
- 401,
5629
- 403,
5630
- 10001,
5631
- 10002,
5632
- 20001,
5633
- "TOKEN_EXPIRED",
5634
- "AUTH_FAILED"
5635
- ];
5636
- var TOKEN_EXPIRED_MESSAGES = [
5637
- "token expired",
5638
- "invalid token",
5639
- "authentication failed",
5640
- "auth failed",
5641
- "unauthorized",
5642
- "\u767B\u5F55",
5643
- "\u8FC7\u671F",
5644
- "token",
5645
- "\u9274\u6743"
5646
- ];
5647
- function isTokenExpired(error) {
5648
- var _a, _b, _c, _d, _e, _f, _g;
5649
- const status = (_a = error.response) == null ? void 0 : _a.status;
5650
- const message = ((_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.msg) || ((_e = (_d = error.response) == null ? void 0 : _d.data) == null ? void 0 : _e.message) || error.message || "";
5651
- const code = (_g = (_f = error.response) == null ? void 0 : _f.data) == null ? void 0 : _g.code;
5652
- if (status && TOKEN_EXPIRED_CODES.includes(status)) {
5653
- return true;
5451
+ // bin/utils/uploadToIpfsSplit.ts
5452
+ var IPFS_API_URL = APP_CONFIG.ipfsApiUrl;
5453
+ var MAX_RETRIES = APP_CONFIG.upload.maxRetries;
5454
+ var RETRY_DELAY = APP_CONFIG.upload.retryDelayMs;
5455
+ var TIMEOUT = APP_CONFIG.upload.timeoutMs;
5456
+ var MAX_POLL_TIME = APP_CONFIG.upload.maxPollTimeMs;
5457
+ var POLL_INTERVAL = APP_CONFIG.upload.pollIntervalMs;
5458
+ var PROGRESS_UPDATE_INTERVAL = 200;
5459
+ var EXPECTED_UPLOAD_TIME = 6e4;
5460
+ var MAX_PROGRESS = 0.9;
5461
+ var StepProgressBar = class {
5462
+ spinner;
5463
+ fileName;
5464
+ startTime;
5465
+ currentStep = 0;
5466
+ stepStartTime = 0;
5467
+ progressInterval = null;
5468
+ isSimulatingProgress = false;
5469
+ simulationStartTime = 0;
5470
+ constructor(fileName, isDirectory = false) {
5471
+ this.fileName = fileName;
5472
+ this.spinner = (0, import_ora.default)(`Preparing to upload ${fileName}...`).start();
5473
+ this.startTime = Date.now();
5474
+ this.stepStartTime = Date.now();
5475
+ this.startProgress();
5654
5476
  }
5655
- if (code && TOKEN_EXPIRED_CODES.includes(code)) {
5656
- return true;
5477
+ startStep(stepIndex, stepName) {
5478
+ this.currentStep = stepIndex;
5479
+ this.stepStartTime = Date.now();
5657
5480
  }
5658
- const lowerMessage = message.toLowerCase();
5659
- return TOKEN_EXPIRED_MESSAGES.some(
5660
- (m) => lowerMessage.includes(m.toLowerCase())
5661
- );
5662
- }
5663
- function showTokenExpiredHint() {
5664
- console.log(import_chalk4.default.red("\n\u26A0\uFE0F Token has expired or is invalid."));
5665
- console.log(import_chalk4.default.yellow("Please re-run: pinme set-appkey <AppKey>\n"));
5666
- }
5667
- function createClient() {
5668
- const headers = getAuthHeaders();
5669
- return axios_default.create({
5670
- baseURL: DEFAULT_BASE,
5671
- timeout: 2e4,
5672
- headers: {
5673
- ...headers,
5674
- Accept: "*/*",
5675
- "Content-Type": "application/json",
5676
- "User-Agent": "Pinme-CLI",
5677
- Connection: "keep-alive"
5481
+ updateProgress(progress, total) {
5482
+ }
5483
+ completeStep() {
5484
+ }
5485
+ // Start simulating progress to continue display after 90%
5486
+ startSimulatingProgress() {
5487
+ this.isSimulatingProgress = true;
5488
+ this.simulationStartTime = Date.now();
5489
+ }
5490
+ // Stop simulating progress
5491
+ stopSimulatingProgress() {
5492
+ this.isSimulatingProgress = false;
5493
+ }
5494
+ failStep(error) {
5495
+ this.stopProgress();
5496
+ this.spinner.fail(`Upload failed: ${error}`);
5497
+ }
5498
+ complete() {
5499
+ this.stopProgress();
5500
+ const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
5501
+ const progressBar = this.createProgressBar(1);
5502
+ this.spinner.succeed(
5503
+ `Upload completed ${progressBar} 100% (${totalTime}s)`
5504
+ );
5505
+ }
5506
+ fail(error) {
5507
+ this.stopProgress();
5508
+ const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
5509
+ this.spinner.fail(`Upload failed: ${error} (${totalTime}s)`);
5510
+ }
5511
+ startProgress() {
5512
+ this.progressInterval = setInterval(() => {
5513
+ const elapsed = Date.now() - this.startTime;
5514
+ let progress;
5515
+ if (this.isSimulatingProgress) {
5516
+ const simulationElapsed = Date.now() - this.simulationStartTime;
5517
+ const simulationProgress = Math.min(simulationElapsed / 6e4, 1);
5518
+ progress = 0.9 + simulationProgress * 0.09;
5519
+ } else {
5520
+ progress = this.calculateProgress(elapsed);
5521
+ }
5522
+ const duration = this.formatDuration(Math.floor(elapsed / 1e3));
5523
+ const progressBar = this.createProgressBar(progress);
5524
+ this.spinner.text = `Uploading ${this.fileName}... ${progressBar} ${Math.round(progress * 100)}% (${duration})`;
5525
+ }, PROGRESS_UPDATE_INTERVAL);
5526
+ }
5527
+ stopProgress() {
5528
+ if (this.progressInterval) {
5529
+ clearInterval(this.progressInterval);
5530
+ this.progressInterval = null;
5678
5531
  }
5532
+ }
5533
+ calculateProgress(elapsed) {
5534
+ return Math.min(
5535
+ elapsed / EXPECTED_UPLOAD_TIME * MAX_PROGRESS,
5536
+ MAX_PROGRESS
5537
+ );
5538
+ }
5539
+ createProgressBar(progress, width = 20) {
5540
+ const percentage = Math.min(progress, 1);
5541
+ const filledWidth = Math.round(width * percentage);
5542
+ const emptyWidth = width - filledWidth;
5543
+ return `[${"\u2588".repeat(filledWidth)}${"\u2591".repeat(emptyWidth)}]`;
5544
+ }
5545
+ formatDuration(seconds) {
5546
+ if (seconds < 60) {
5547
+ return `${seconds}s`;
5548
+ } else if (seconds < 3600) {
5549
+ const minutes = Math.floor(seconds / 60);
5550
+ const remainingSeconds = seconds % 60;
5551
+ return `${minutes}m ${remainingSeconds}s`;
5552
+ } else {
5553
+ const hours = Math.floor(seconds / 3600);
5554
+ const minutes = Math.floor(seconds % 3600 / 60);
5555
+ const remainingSeconds = seconds % 60;
5556
+ return `${hours}h ${minutes}m ${remainingSeconds}s`;
5557
+ }
5558
+ }
5559
+ };
5560
+ async function calculateMD5(filePath) {
5561
+ return new Promise((resolve, reject) => {
5562
+ const hash = crypto2.createHash("md5");
5563
+ const stream4 = import_fs_extra5.default.createReadStream(filePath);
5564
+ stream4.on("data", hash.update.bind(hash));
5565
+ stream4.on("end", () => resolve(hash.digest("hex")));
5566
+ stream4.on("error", reject);
5679
5567
  });
5680
5568
  }
5681
- async function bindAnonymousDevice(anonymousUid) {
5682
- try {
5683
- const client = createClient();
5684
- const { data } = await client.post("/bind_anonymous", {
5685
- anonymous_uid: anonymousUid
5686
- });
5687
- return (data == null ? void 0 : data.code) === 200;
5688
- } catch (e) {
5689
- if (isTokenExpired(e)) {
5690
- showTokenExpiredHint();
5691
- return false;
5569
+ async function compressDirectory(sourcePath) {
5570
+ return new Promise((resolve, reject) => {
5571
+ const tempDir = require("os").tmpdir();
5572
+ if (!import_fs_extra5.default.existsSync(tempDir)) {
5573
+ import_fs_extra5.default.mkdirSync(tempDir, { recursive: true });
5692
5574
  }
5693
- console.log(
5694
- import_chalk4.default.yellow(`Failed to trigger anonymous binding: ${(e == null ? void 0 : e.message) || e}`)
5575
+ const outputPath = import_path6.default.join(
5576
+ tempDir,
5577
+ `pinme_${import_path6.default.basename(sourcePath)}_${Date.now()}.zip`
5695
5578
  );
5696
- return false;
5697
- }
5579
+ const output = import_fs_extra5.default.createWriteStream(outputPath);
5580
+ const zlib2 = require("zlib");
5581
+ const gzip = zlib2.createGzip({ level: 9 });
5582
+ output.on("close", () => resolve(outputPath));
5583
+ gzip.on("error", reject);
5584
+ gzip.pipe(output);
5585
+ const stats = import_fs_extra5.default.statSync(sourcePath);
5586
+ if (stats.isDirectory()) {
5587
+ const archive = require("archiver");
5588
+ const archiveStream = archive("zip", { zlib: { level: 9 } });
5589
+ archiveStream.on("error", reject);
5590
+ archiveStream.pipe(output);
5591
+ archiveStream.directory(sourcePath, false);
5592
+ archiveStream.finalize();
5593
+ } else {
5594
+ const fileStream = import_fs_extra5.default.createReadStream(sourcePath);
5595
+ fileStream.pipe(gzip);
5596
+ }
5597
+ });
5698
5598
  }
5699
- async function checkDomainAvailable(domainName) {
5700
- var _a;
5701
- const client = createClient();
5702
- const configured = process.env.PINME_CHECK_DOMAIN_PATH || "/check_domain";
5703
- const fallbacks = [configured, "/check_domain_available"];
5704
- for (const p of fallbacks) {
5705
- try {
5706
- const { data } = await client.post(p, { domain_name: domainName });
5707
- if (typeof (data == null ? void 0 : data.is_valid) === "boolean") {
5708
- return { is_valid: data.is_valid, error: data == null ? void 0 : data.error };
5709
- }
5710
- if ((data == null ? void 0 : data.data) && typeof data.data.is_valid === "boolean") {
5711
- return { is_valid: data.data.is_valid, error: (_a = data.data) == null ? void 0 : _a.error };
5712
- }
5713
- } catch (e) {
5714
- if (isTokenExpired(e)) {
5715
- showTokenExpiredHint();
5716
- throw new Error("Token expired");
5599
+ async function initChunkSession(filePath, deviceId, isDirectory = false) {
5600
+ const stats = import_fs_extra5.default.statSync(filePath);
5601
+ const fileName = import_path6.default.basename(filePath);
5602
+ const fileSize = stats.size;
5603
+ const md5 = await calculateMD5(filePath);
5604
+ try {
5605
+ const response = await axios_default.post(
5606
+ `${IPFS_API_URL}/chunk/init`,
5607
+ {
5608
+ file_name: fileName,
5609
+ file_size: fileSize,
5610
+ md5,
5611
+ is_directory: isDirectory,
5612
+ uid: deviceId
5613
+ },
5614
+ {
5615
+ timeout: TIMEOUT,
5616
+ headers: { "Content-Type": "application/json" }
5717
5617
  }
5618
+ );
5619
+ const { code, msg, data } = response.data;
5620
+ if (code === 200 && data) {
5621
+ return data;
5718
5622
  }
5623
+ throw new Error(`Session initialization failed: ${msg} (code: ${code})`);
5624
+ } catch (error) {
5625
+ if (axios_default.isAxiosError(error)) {
5626
+ throw new Error(`Network error: ${error.message}`);
5627
+ }
5628
+ throw error;
5719
5629
  }
5720
- return { is_valid: true };
5721
5630
  }
5722
- async function bindPinmeDomain(domainName, hash) {
5631
+ async function uploadChunkWithAbort(sessionId, chunkIndex, chunkData, deviceId, signal, retryCount = 0) {
5723
5632
  try {
5724
- const client = createClient();
5725
- const { data } = await client.post("/bind_pinme_domain", {
5726
- domain_name: domainName,
5727
- hash
5633
+ if (signal.aborted) {
5634
+ throw new Error("Request cancelled");
5635
+ }
5636
+ const form = new import_form_data2.default();
5637
+ form.append("session_id", sessionId);
5638
+ form.append("chunk_index", chunkIndex.toString());
5639
+ form.append("uid", deviceId);
5640
+ form.append("chunk", chunkData, {
5641
+ filename: `chunk_${chunkIndex}`,
5642
+ contentType: "application/octet-stream"
5728
5643
  });
5729
- return (data == null ? void 0 : data.code) === 200;
5730
- } catch (e) {
5731
- if (isTokenExpired(e)) {
5732
- showTokenExpiredHint();
5733
- throw new Error("Token expired");
5644
+ const response = await axios_default.post(
5645
+ `${IPFS_API_URL}/chunk/upload`,
5646
+ form,
5647
+ {
5648
+ headers: { ...form.getHeaders() },
5649
+ timeout: TIMEOUT,
5650
+ signal
5651
+ }
5652
+ );
5653
+ const { code, msg, data } = response.data;
5654
+ if (code === 200 && data) {
5655
+ return data;
5656
+ }
5657
+ throw new Error(`Chunk upload failed: ${msg} (code: ${code})`);
5658
+ } catch (error) {
5659
+ if (error.name === "CanceledError" || signal.aborted) {
5660
+ throw new Error("Request cancelled");
5661
+ }
5662
+ if (retryCount < MAX_RETRIES) {
5663
+ await delayWithAbortCheck(RETRY_DELAY, signal);
5664
+ return uploadChunkWithAbort(
5665
+ sessionId,
5666
+ chunkIndex,
5667
+ chunkData,
5668
+ deviceId,
5669
+ signal,
5670
+ retryCount + 1
5671
+ );
5734
5672
  }
5735
- throw e;
5673
+ throw new Error(
5674
+ `Chunk ${chunkIndex + 1} upload failed after ${MAX_RETRIES} retries: ${error.message}`
5675
+ );
5736
5676
  }
5737
5677
  }
5738
- async function getMyDomains() {
5739
- var _a;
5740
- try {
5741
- const client = createClient();
5742
- const { data } = await client.get("/my_domains");
5743
- if ((data == null ? void 0 : data.code) === 200) {
5744
- if (Array.isArray(data == null ? void 0 : data.data)) {
5745
- return data.data;
5746
- }
5747
- if (((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.list) && Array.isArray(data.data.list)) {
5748
- return data.data.list;
5678
+ async function delayWithAbortCheck(delay, signal) {
5679
+ return new Promise((resolve, reject) => {
5680
+ const timeoutId = setTimeout(() => {
5681
+ if (signal.aborted) {
5682
+ reject(new Error("Request cancelled"));
5683
+ } else {
5684
+ resolve();
5749
5685
  }
5686
+ }, delay);
5687
+ if (signal.aborted) {
5688
+ clearTimeout(timeoutId);
5689
+ reject(new Error("Request cancelled"));
5690
+ return;
5750
5691
  }
5751
- if ((data == null ? void 0 : data.code) === 401 || (data == null ? void 0 : data.code) === 403) {
5752
- showTokenExpiredHint();
5753
- throw new Error("Token expired");
5692
+ const checkInterval = setInterval(() => {
5693
+ if (signal.aborted) {
5694
+ clearTimeout(timeoutId);
5695
+ clearInterval(checkInterval);
5696
+ reject(new Error("Request cancelled"));
5697
+ }
5698
+ }, 50);
5699
+ });
5700
+ }
5701
+ async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, deviceId, progressBar) {
5702
+ const fileData = import_fs_extra5.default.readFileSync(filePath);
5703
+ const abortController = new AbortController();
5704
+ let completedCount = 0;
5705
+ let hasFatalError = false;
5706
+ let fatalError = null;
5707
+ const uploadTasks = Array.from({ length: totalChunks }, (_, chunkIndex) => {
5708
+ const start = chunkIndex * chunkSize;
5709
+ const end = Math.min(start + chunkSize, fileData.length);
5710
+ const chunkData = fileData.slice(start, end);
5711
+ return async () => {
5712
+ if (abortController.signal.aborted) return;
5713
+ try {
5714
+ await uploadChunkWithAbort(
5715
+ sessionId,
5716
+ chunkIndex,
5717
+ chunkData,
5718
+ deviceId,
5719
+ abortController.signal
5720
+ );
5721
+ if (abortController.signal.aborted) return;
5722
+ completedCount++;
5723
+ progressBar.updateProgress(completedCount, totalChunks);
5724
+ } catch (error) {
5725
+ if (error.name === "AbortError" || abortController.signal.aborted) {
5726
+ return;
5727
+ }
5728
+ hasFatalError = true;
5729
+ fatalError = `Chunk ${chunkIndex + 1}/${totalChunks} upload failed: ${error.message}`;
5730
+ abortController.abort();
5731
+ throw new Error(fatalError);
5732
+ }
5733
+ };
5734
+ });
5735
+ try {
5736
+ const results = await Promise.allSettled(uploadTasks.map((task) => task()));
5737
+ const failedResults = results.filter(
5738
+ (result) => result.status === "rejected"
5739
+ );
5740
+ if (failedResults.length > 0) {
5741
+ const firstFailure = failedResults[0];
5742
+ throw new Error(
5743
+ firstFailure.reason.message || "Error occurred during upload"
5744
+ );
5754
5745
  }
5755
- return [];
5756
- } catch (e) {
5757
- if (isTokenExpired(e)) {
5758
- showTokenExpiredHint();
5759
- throw new Error("Token expired");
5746
+ if (hasFatalError) {
5747
+ throw new Error(fatalError || "Unknown error occurred during upload");
5760
5748
  }
5761
- throw e;
5749
+ } catch (error) {
5750
+ throw fatalError ? new Error(fatalError) : error;
5762
5751
  }
5763
5752
  }
5764
- async function bindDnsDomainV4(domainName, hash, tokenAddress, authToken) {
5753
+ async function completeChunkUpload(sessionId, deviceId, options = {}) {
5754
+ var _a2;
5765
5755
  try {
5766
- const client = createClient();
5767
- const { data } = await client.post(
5768
- "/bind_dns",
5769
- {
5770
- domain_name: domainName,
5771
- hash
5772
- },
5756
+ const requestBody = { session_id: sessionId, uid: deviceId };
5757
+ const projectName = (_a2 = options.projectName) == null ? void 0 : _a2.trim();
5758
+ let authHeaders = {};
5759
+ if (options.importAsCar) {
5760
+ requestBody.import_as_car = true;
5761
+ }
5762
+ if (projectName) {
5763
+ requestBody.project_name = projectName;
5764
+ authHeaders = getAuthHeaders();
5765
+ }
5766
+ const response = await axios_default.post(
5767
+ `${IPFS_API_URL}/chunk/complete`,
5768
+ requestBody,
5773
5769
  {
5770
+ timeout: TIMEOUT,
5774
5771
  headers: {
5775
- "x-auth-token": authToken,
5776
- "x-token-address": tokenAddress
5772
+ "Content-Type": "application/json",
5773
+ ...authHeaders
5777
5774
  }
5778
5775
  }
5779
5776
  );
5780
- return data;
5781
- } catch (e) {
5782
- if (isTokenExpired(e)) {
5783
- showTokenExpiredHint();
5784
- throw new Error("Token expired");
5777
+ const { code, msg, data } = response.data;
5778
+ if (code === 200 && data) {
5779
+ return data.trace_id;
5785
5780
  }
5786
- throw e;
5781
+ throw new Error(`Complete upload failed: ${msg} (code: ${code})`);
5782
+ } catch (error) {
5783
+ if (axios_default.isAxiosError(error)) {
5784
+ throw new Error(`Network error: ${error.message}`);
5785
+ }
5786
+ throw error;
5787
5787
  }
5788
5788
  }
5789
- async function isVip(tokenAddress, authToken) {
5789
+ async function getChunkStatus(sessionId, deviceId, options = {}) {
5790
+ var _a2;
5790
5791
  try {
5791
- const client = createClient();
5792
- const { data } = await client.get("/is_vip", {
5793
- headers: {
5794
- "x-auth-token": authToken,
5795
- "x-token-address": tokenAddress
5796
- }
5792
+ const projectName = (_a2 = options.projectName) == null ? void 0 : _a2.trim();
5793
+ const queryParams = new URLSearchParams({
5794
+ trace_id: sessionId,
5795
+ uid: deviceId
5797
5796
  });
5798
- return data;
5799
- } catch (e) {
5800
- if (isTokenExpired(e)) {
5801
- showTokenExpiredHint();
5802
- throw new Error("Token expired");
5797
+ if (projectName) {
5798
+ queryParams.append("project_name", projectName);
5803
5799
  }
5804
- throw e;
5800
+ const response = await axios_default.get(
5801
+ `${IPFS_API_URL}/up_status?${queryParams.toString()}`,
5802
+ {
5803
+ timeout: TIMEOUT,
5804
+ headers: { "Content-Type": "application/json" }
5805
+ }
5806
+ );
5807
+ const { code, msg, data } = response.data;
5808
+ if (code === 200) {
5809
+ return data;
5810
+ }
5811
+ throw new Error(`Server returned error: ${msg} (code: ${code})`);
5812
+ } catch (error) {
5813
+ if (axios_default.isAxiosError(error)) {
5814
+ throw new Error(`Network error: ${error.message}`);
5815
+ }
5816
+ throw error;
5805
5817
  }
5806
5818
  }
5807
- var CAR_API_BASE = process.env.CAR_API_BASE || "https://pinme.benny1996.win/api/v3";
5808
- function createCarClient() {
5809
- let headers = {};
5810
- try {
5811
- headers = getAuthHeaders();
5812
- } catch (e) {
5819
+ async function monitorChunkProgress(traceId, deviceId, options = {}, progressBar) {
5820
+ let consecutiveErrors = 0;
5821
+ const startTime = Date.now();
5822
+ if (progressBar) {
5823
+ progressBar.startSimulatingProgress();
5813
5824
  }
5814
- return axios_default.create({
5815
- baseURL: CAR_API_BASE,
5816
- timeout: 2e4,
5817
- headers: {
5818
- ...headers,
5819
- Accept: "*/*",
5820
- "Content-Type": "application/json",
5821
- "User-Agent": "Pinme-CLI",
5822
- Connection: "keep-alive"
5823
- }
5824
- });
5825
- }
5826
- async function requestCarExport(cid, uid) {
5827
- var _a, _b;
5828
5825
  try {
5829
- const client = createCarClient();
5830
- const { data } = await client.post("/car/export", null, {
5831
- params: {
5832
- cid,
5833
- uid
5826
+ while (Date.now() - startTime < MAX_POLL_TIME) {
5827
+ try {
5828
+ const status = await getChunkStatus(traceId, deviceId, options);
5829
+ consecutiveErrors = 0;
5830
+ if (status.is_ready && status.upload_rst.Hash) {
5831
+ if (progressBar) {
5832
+ progressBar.stopSimulatingProgress();
5833
+ }
5834
+ const shortUrl = status.upload_rst.ShortUrl;
5835
+ const domain = status.domain;
5836
+ const fullShortUrl = shortUrl && domain ? `${shortUrl}.${domain}` : shortUrl;
5837
+ return {
5838
+ hash: status.upload_rst.Hash,
5839
+ shortUrl: fullShortUrl
5840
+ };
5841
+ }
5842
+ } catch (error) {
5843
+ consecutiveErrors++;
5844
+ if (consecutiveErrors > 10) {
5845
+ throw new Error(`Polling failed: ${error.message}`);
5846
+ }
5834
5847
  }
5835
- });
5836
- if ((data == null ? void 0 : data.code) === 200 && (data == null ? void 0 : data.data)) {
5837
- return data.data;
5848
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
5838
5849
  }
5839
- throw new Error((data == null ? void 0 : data.msg) || "Failed to request CAR export");
5840
- } catch (e) {
5841
- if (isTokenExpired(e)) {
5842
- showTokenExpiredHint();
5843
- throw new Error("Token expired");
5850
+ const maxPollTimeMinutes = Math.floor(MAX_POLL_TIME / (60 * 1e3));
5851
+ throw new Error(`Polling timeout after ${maxPollTimeMinutes} minutes`);
5852
+ } finally {
5853
+ if (progressBar) {
5854
+ progressBar.stopSimulatingProgress();
5844
5855
  }
5845
- if ((_b = (_a = e.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) {
5846
- throw new Error(e.response.data.msg);
5856
+ }
5857
+ }
5858
+ async function uploadDirectoryInChunks(directoryPath, deviceId, options = {}) {
5859
+ const sizeCheck = checkDirectorySizeLimit(directoryPath);
5860
+ if (sizeCheck.exceeds) {
5861
+ throw new Error(
5862
+ `Directory ${directoryPath} exceeds size limit ${formatSize(
5863
+ sizeCheck.limit
5864
+ )} (size: ${formatSize(sizeCheck.size)})`
5865
+ );
5866
+ }
5867
+ const progressBar = new StepProgressBar(import_path6.default.basename(directoryPath), true);
5868
+ try {
5869
+ progressBar.startStep(0, "Preparing compression");
5870
+ const compressedPath = await compressDirectory(directoryPath);
5871
+ progressBar.completeStep();
5872
+ progressBar.startStep(1, "Initializing session");
5873
+ const sessionInfo = await initChunkSession(compressedPath, deviceId, true);
5874
+ progressBar.completeStep();
5875
+ progressBar.startStep(2, "Chunk upload");
5876
+ await uploadFileChunks(
5877
+ compressedPath,
5878
+ sessionInfo.session_id,
5879
+ sessionInfo.total_chunks,
5880
+ sessionInfo.chunk_size,
5881
+ deviceId,
5882
+ progressBar
5883
+ );
5884
+ progressBar.completeStep();
5885
+ progressBar.startStep(3, "Completing upload");
5886
+ const traceId = await completeChunkUpload(
5887
+ sessionInfo.session_id,
5888
+ deviceId,
5889
+ options
5890
+ );
5891
+ progressBar.completeStep();
5892
+ progressBar.startStep(4, "Waiting for processing");
5893
+ const result = await monitorChunkProgress(traceId, deviceId, options, progressBar);
5894
+ progressBar.completeStep();
5895
+ try {
5896
+ import_fs_extra5.default.unlinkSync(compressedPath);
5897
+ } catch (error) {
5898
+ }
5899
+ const uploadData = {
5900
+ path: directoryPath,
5901
+ filename: import_path6.default.basename(directoryPath),
5902
+ contentHash: (result == null ? void 0 : result.hash) || "unknown",
5903
+ size: sizeCheck.size,
5904
+ fileCount: 0,
5905
+ isDirectory: true,
5906
+ shortUrl: (result == null ? void 0 : result.shortUrl) || null
5907
+ };
5908
+ saveUploadHistory(uploadData);
5909
+ if (!(result == null ? void 0 : result.hash)) {
5910
+ throw new Error("Server did not return valid hash value");
5847
5911
  }
5848
- throw new Error(`Failed to request CAR export: ${(e == null ? void 0 : e.message) || e}`);
5912
+ progressBar.complete();
5913
+ return result;
5914
+ } catch (error) {
5915
+ progressBar.fail(error.message);
5916
+ throw error;
5849
5917
  }
5850
5918
  }
5851
- async function checkCarExportStatus(taskId) {
5852
- var _a, _b;
5919
+ async function uploadFileInChunks(filePath, deviceId, options = {}) {
5920
+ const sizeCheck = checkFileSizeLimit(filePath);
5921
+ if (sizeCheck.exceeds) {
5922
+ throw new Error(
5923
+ `File ${filePath} exceeds size limit ${formatSize(
5924
+ sizeCheck.limit
5925
+ )} (size: ${formatSize(sizeCheck.size)})`
5926
+ );
5927
+ }
5928
+ const fileName = import_path6.default.basename(filePath);
5929
+ const progressBar = new StepProgressBar(fileName, false);
5853
5930
  try {
5854
- const client = createCarClient();
5855
- const { data } = await client.get(
5856
- "/car/export/status",
5857
- {
5858
- params: {
5859
- task_id: taskId
5860
- }
5861
- }
5931
+ progressBar.startStep(0, "Initializing session");
5932
+ const sessionInfo = await initChunkSession(filePath, deviceId, false);
5933
+ progressBar.completeStep();
5934
+ progressBar.startStep(1, "Chunk upload");
5935
+ await uploadFileChunks(
5936
+ filePath,
5937
+ sessionInfo.session_id,
5938
+ sessionInfo.total_chunks,
5939
+ sessionInfo.chunk_size,
5940
+ deviceId,
5941
+ progressBar
5862
5942
  );
5863
- if ((data == null ? void 0 : data.code) === 200 && (data == null ? void 0 : data.data)) {
5864
- return data.data;
5865
- }
5866
- throw new Error((data == null ? void 0 : data.msg) || "Failed to check export status");
5867
- } catch (e) {
5868
- if (isTokenExpired(e)) {
5869
- showTokenExpiredHint();
5870
- throw new Error("Token expired");
5943
+ progressBar.completeStep();
5944
+ progressBar.startStep(2, "Completing upload");
5945
+ const traceId = await completeChunkUpload(
5946
+ sessionInfo.session_id,
5947
+ deviceId,
5948
+ options
5949
+ );
5950
+ progressBar.completeStep();
5951
+ progressBar.startStep(3, "Waiting for processing");
5952
+ const result = await monitorChunkProgress(traceId, deviceId, options, progressBar);
5953
+ progressBar.completeStep();
5954
+ const uploadData = {
5955
+ path: filePath,
5956
+ filename: fileName,
5957
+ contentHash: (result == null ? void 0 : result.hash) || "unknown",
5958
+ previewHash: null,
5959
+ size: sizeCheck.size,
5960
+ fileCount: 1,
5961
+ isDirectory: false,
5962
+ shortUrl: (result == null ? void 0 : result.shortUrl) || null
5963
+ };
5964
+ saveUploadHistory(uploadData);
5965
+ if (!(result == null ? void 0 : result.hash)) {
5966
+ throw new Error("Server did not return valid hash value");
5871
5967
  }
5872
- if ((_b = (_a = e.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) {
5873
- throw new Error(e.response.data.msg);
5968
+ progressBar.complete();
5969
+ return result;
5970
+ } catch (error) {
5971
+ progressBar.fail(error.message);
5972
+ throw error;
5973
+ }
5974
+ }
5975
+ async function uploadToIpfsSplit_default(filePath, options = {}) {
5976
+ const deviceId = getUid();
5977
+ if (!deviceId) {
5978
+ throw new Error("Device ID not found");
5979
+ }
5980
+ try {
5981
+ const isDirectory = import_fs_extra5.default.statSync(filePath).isDirectory();
5982
+ const result = isDirectory ? await uploadDirectoryInChunks(filePath, deviceId, options) : await uploadFileInChunks(filePath, deviceId, options);
5983
+ if (result == null ? void 0 : result.hash) {
5984
+ return {
5985
+ contentHash: result.hash,
5986
+ previewHash: null,
5987
+ shortUrl: result.shortUrl
5988
+ };
5874
5989
  }
5875
- throw new Error(`Failed to check export status: ${(e == null ? void 0 : e.message) || e}`);
5990
+ throw new Error("Upload failed: no hash returned");
5991
+ } catch (error) {
5992
+ throw error;
5876
5993
  }
5877
5994
  }
5878
5995
 
5879
- // bin/upload.ts
5880
- var URL3 = "https://pinme.eth.limo/#/preview/";
5881
- var secretKey = "pinme-secret-key";
5882
- checkNodeVersion();
5883
- function isDnsDomain(domain) {
5884
- return domain.includes(".");
5996
+ // bin/services/uploadService.ts
5997
+ function encryptHash(contentHash, key, uid) {
5998
+ if (!key) {
5999
+ return contentHash;
6000
+ }
6001
+ const combined = uid ? `${contentHash}-${uid}` : contentHash;
6002
+ const encrypted = import_crypto_js.default.RC4.encrypt(combined, key).toString();
6003
+ return encrypted.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
5885
6004
  }
5886
- function validateDnsDomain(domain) {
5887
- const cleanDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
5888
- const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9][a-zA-Z0-9-]*)*\.[a-zA-Z]{2,}$/;
5889
- const parts = cleanDomain.split(".");
5890
- if (parts.length < 2) {
5891
- return { valid: false, message: "Invalid domain format. Please enter a complete domain (e.g., example.com)" };
6005
+ function formatShortUrl(shortUrl) {
6006
+ if (!shortUrl) {
6007
+ return void 0;
5892
6008
  }
5893
- for (const part of parts) {
5894
- if (part.length === 0) {
5895
- return { valid: false, message: "Invalid domain format. Consecutive dots are not allowed" };
5896
- }
5897
- if (part.length > 63) {
5898
- return { valid: false, message: "Invalid domain format. Each label must be 63 characters or less" };
5899
- }
5900
- if (!/^[a-zA-Z0-9-]+$/.test(part)) {
5901
- return { valid: false, message: "Invalid domain format. Domains can only contain letters, numbers, and hyphens" };
5902
- }
5903
- if (/^-|-$/.test(part)) {
5904
- return { valid: false, message: "Invalid domain format. Labels cannot start or end with hyphens" };
5905
- }
6009
+ const normalized = shortUrl.trim();
6010
+ if (!normalized) {
6011
+ return void 0;
5906
6012
  }
5907
- if (!domainRegex.test(cleanDomain)) {
5908
- return { valid: false, message: "Invalid domain format" };
6013
+ if (/^https?:\/\//.test(normalized)) {
6014
+ return normalized;
5909
6015
  }
5910
- return { valid: true };
6016
+ if (normalized.includes(".")) {
6017
+ return `https://${normalized}`;
6018
+ }
6019
+ return `https://${normalized}.pinit.eth.limo`;
5911
6020
  }
5912
- function encryptHash(contentHash, key, uid) {
5913
- try {
5914
- if (!key) {
5915
- throw new Error("Secret key not found");
5916
- }
5917
- const combined = uid ? `${contentHash}-${uid}` : contentHash;
5918
- const encrypted = import_crypto_js.default.RC4.encrypt(combined, key).toString();
5919
- const urlSafe = encrypted.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
5920
- return urlSafe;
5921
- } catch (error) {
5922
- console.error(`Encryption error: ${error.message}`);
5923
- return contentHash;
6021
+ function resolveUploadUrls(contentHash, shortUrl) {
6022
+ const uid = getUid();
6023
+ const encryptedCID = encryptHash(contentHash, APP_CONFIG.secretKey, uid);
6024
+ const managementUrl = `${APP_CONFIG.ipfsPreviewUrl}${encryptedCID}`;
6025
+ const publicUrl = formatShortUrl(shortUrl) || managementUrl;
6026
+ return {
6027
+ publicUrl,
6028
+ managementUrl
6029
+ };
6030
+ }
6031
+ async function uploadPath(targetPath, options = {}) {
6032
+ const result = await uploadToIpfsSplit_default(targetPath, {
6033
+ importAsCar: options.importAsCar,
6034
+ projectName: options.projectName
6035
+ });
6036
+ if (!(result == null ? void 0 : result.contentHash)) {
6037
+ throw new Error("Upload failed: no content hash returned");
5924
6038
  }
6039
+ const urls = resolveUploadUrls(result.contentHash, result.shortUrl);
6040
+ return {
6041
+ contentHash: result.contentHash,
6042
+ shortUrl: result.shortUrl,
6043
+ publicUrl: urls.publicUrl,
6044
+ managementUrl: urls.managementUrl
6045
+ };
5925
6046
  }
6047
+
6048
+ // bin/upload.ts
6049
+ checkNodeVersion();
5926
6050
  function checkPathSync(inputPath) {
5927
6051
  try {
5928
6052
  const absolutePath = import_path7.default.resolve(inputPath);
@@ -5935,30 +6059,18 @@ function checkPathSync(inputPath) {
5935
6059
  return null;
5936
6060
  }
5937
6061
  }
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
6062
  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();
6063
+ const projectName = APP_CONFIG.pinmeProjectName;
6064
+ const { publicUrl, managementUrl } = resolveUploadUrls(contentHash, shortUrl);
5952
6065
  if (projectName) {
5953
- const ensUrl = formatEnsUrl(shortUrl);
5954
6066
  console.log(import_chalk5.default.cyan(`URL:`));
5955
- console.log(import_chalk5.default.cyan(ensUrl || previewUrl));
6067
+ console.log(import_chalk5.default.cyan(publicUrl));
5956
6068
  console.log(import_chalk5.default.cyan(`Management page:`));
5957
- console.log(import_chalk5.default.cyan(previewUrl));
6069
+ console.log(import_chalk5.default.cyan(managementUrl));
5958
6070
  return;
5959
6071
  }
5960
6072
  console.log(import_chalk5.default.cyan(`URL:`));
5961
- console.log(import_chalk5.default.cyan(previewUrl));
6073
+ console.log(import_chalk5.default.cyan(publicUrl));
5962
6074
  }
5963
6075
  function getDomainFromArgs() {
5964
6076
  const args = process.argv.slice(2);
@@ -5972,26 +6084,27 @@ function getDnsFromArgs() {
5972
6084
  const args = process.argv.slice(2);
5973
6085
  return args.includes("--dns") || args.includes("-D");
5974
6086
  }
5975
- async function checkVipStatus(authConfig) {
5976
- var _a;
5977
- console.log(import_chalk5.default.blue("Checking VIP status..."));
6087
+ async function checkWalletBalanceStatus(authConfig) {
6088
+ var _a2;
6089
+ console.log(import_chalk5.default.blue("Checking wallet balance..."));
5978
6090
  try {
5979
- const vipResult = await isVip(authConfig.address, authConfig.token);
5980
- if (!((_a = vipResult.data) == null ? void 0 : _a.is_vip)) {
6091
+ const balanceResult = await getWalletBalance(authConfig.address, authConfig.token);
6092
+ const balance = Number(((_a2 = balanceResult.data) == null ? void 0 : _a2.wallet_balance_usd) ?? 0);
6093
+ if (!Number.isFinite(balance) || balance <= 0) {
5981
6094
  return false;
5982
6095
  }
5983
- console.log(import_chalk5.default.green("VIP verified."));
6096
+ console.log(import_chalk5.default.green(`Wallet balance available: $${balance.toFixed(2)}`));
5984
6097
  return true;
5985
6098
  } catch (e) {
5986
6099
  if (e.message === "Token expired") {
5987
6100
  throw e;
5988
6101
  }
5989
- console.log(import_chalk5.default.yellow("Failed to check VIP status, continuing..."));
6102
+ console.log(import_chalk5.default.yellow("Failed to check wallet balance, continuing..."));
5990
6103
  return true;
5991
6104
  }
5992
6105
  }
5993
6106
  async function bindDomain(domain, contentHash, isDns, authConfig) {
5994
- const displayDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
6107
+ const displayDomain = normalizeDomain(domain);
5995
6108
  if (isDns) {
5996
6109
  console.log(import_chalk5.default.blue("Binding DNS domain..."));
5997
6110
  const dnsResult = await bindDnsDomainV4(displayDomain, contentHash, authConfig.address, authConfig.token);
@@ -6030,7 +6143,7 @@ var upload_default = async (options) => {
6030
6143
  const needsAuth = !!domainArg || dnsArg;
6031
6144
  let authConfig = null;
6032
6145
  if (needsAuth) {
6033
- authConfig = getAuthConfig2();
6146
+ authConfig = getAuthConfig();
6034
6147
  if (!authConfig) {
6035
6148
  console.log(import_chalk5.default.red("Please login first. Run: pinme set-appkey <AppKey>"));
6036
6149
  return;
@@ -6054,9 +6167,9 @@ var upload_default = async (options) => {
6054
6167
  }
6055
6168
  if (domainArg) {
6056
6169
  try {
6057
- const isVipUser = await checkVipStatus(authConfig);
6058
- if (!isVipUser) {
6059
- console.log(import_chalk5.default.red("Domain binding requires VIP. Please upgrade to VIP first."));
6170
+ const hasWalletBalance = await checkWalletBalanceStatus(authConfig);
6171
+ if (!hasWalletBalance) {
6172
+ console.log(import_chalk5.default.red("Insufficient wallet balance. Please recharge your wallet first."));
6060
6173
  return;
6061
6174
  }
6062
6175
  } catch (e) {
@@ -6088,7 +6201,9 @@ var upload_default = async (options) => {
6088
6201
  console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
6089
6202
  let result;
6090
6203
  try {
6091
- result = await uploadToIpfsSplit_default(absolutePath);
6204
+ result = await uploadPath(absolutePath, {
6205
+ projectName: APP_CONFIG.pinmeProjectName
6206
+ });
6092
6207
  } catch (error) {
6093
6208
  console.error(import_chalk5.default.red(`Upload error: ${error.message}`));
6094
6209
  process.exit(1);
@@ -6145,9 +6260,9 @@ var upload_default = async (options) => {
6145
6260
  }
6146
6261
  if (domainArg) {
6147
6262
  try {
6148
- const isVipUser = await checkVipStatus(authConfig);
6149
- if (!isVipUser) {
6150
- console.log(import_chalk5.default.red("Domain binding requires VIP. Please upgrade to VIP first."));
6263
+ const hasWalletBalance = await checkWalletBalanceStatus(authConfig);
6264
+ if (!hasWalletBalance) {
6265
+ console.log(import_chalk5.default.red("Insufficient wallet balance. Please recharge your wallet first."));
6151
6266
  return;
6152
6267
  }
6153
6268
  } catch (e) {
@@ -6179,7 +6294,9 @@ var upload_default = async (options) => {
6179
6294
  console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
6180
6295
  let result;
6181
6296
  try {
6182
- result = await uploadToIpfsSplit_default(absolutePath);
6297
+ result = await uploadPath(absolutePath, {
6298
+ projectName: APP_CONFIG.pinmeProjectName
6299
+ });
6183
6300
  } catch (error) {
6184
6301
  console.error(import_chalk5.default.red(`Upload error: ${error.message}`));
6185
6302
  process.exit(1);
@@ -6225,8 +6342,6 @@ var import_inquirer2 = __toESM(require("inquirer"));
6225
6342
  var import_figlet2 = __toESM(require("figlet"));
6226
6343
  var import_fs3 = __toESM(require("fs"));
6227
6344
  var import_crypto_js2 = __toESM(require("crypto-js"));
6228
- var URL4 = "https://pinme.eth.limo/#/preview/";
6229
- var secretKey2 = "pinme-secret-key";
6230
6345
  checkNodeVersion();
6231
6346
  function encryptHash2(contentHash, key, uid) {
6232
6347
  try {
@@ -6263,7 +6378,7 @@ function getDomainFromArgs2() {
6263
6378
  return null;
6264
6379
  }
6265
6380
  function getUid2() {
6266
- const auth = getAuthConfig2();
6381
+ const auth = getAuthConfig();
6267
6382
  if (auth == null ? void 0 : auth.address) {
6268
6383
  return auth.address;
6269
6384
  }
@@ -6298,17 +6413,17 @@ var importCar_default = async (options) => {
6298
6413
  }
6299
6414
  console.log(import_chalk6.default.blue(`importing ${absolutePath} to ipfs as CAR...`));
6300
6415
  try {
6301
- const result = await uploadToIpfsSplit_default(absolutePath, true);
6416
+ const result = await uploadPath(absolutePath, { importAsCar: true });
6302
6417
  if (result) {
6303
6418
  const uid = getUid2();
6304
- const encryptedCID = encryptHash2(result.contentHash, secretKey2, uid);
6419
+ const encryptedCID = encryptHash2(result.contentHash, APP_CONFIG.secretKey, uid);
6305
6420
  console.log(
6306
6421
  import_chalk6.default.cyan(
6307
6422
  import_figlet2.default.textSync("Successful", { horizontalLayout: "full" })
6308
6423
  )
6309
6424
  );
6310
6425
  console.log(import_chalk6.default.cyan(`URL:`));
6311
- console.log(import_chalk6.default.cyan(`${URL4}${encryptedCID}`));
6426
+ console.log(import_chalk6.default.cyan(`${APP_CONFIG.ipfsPreviewUrl}${encryptedCID}`));
6312
6427
  if (domainArg) {
6313
6428
  console.log(import_chalk6.default.blue(`Binding domain: ${domainArg} with CID: ${result.contentHash}`));
6314
6429
  const ok = await bindPinmeDomain(domainArg, result.contentHash);
@@ -6349,17 +6464,17 @@ var importCar_default = async (options) => {
6349
6464
  }
6350
6465
  console.log(import_chalk6.default.blue(`importing ${absolutePath} to ipfs as CAR...`));
6351
6466
  try {
6352
- const result = await uploadToIpfsSplit_default(absolutePath, true);
6467
+ const result = await uploadPath(absolutePath, { importAsCar: true });
6353
6468
  if (result) {
6354
6469
  const uid = getUid2();
6355
- const encryptedCID = encryptHash2(result.contentHash, secretKey2, uid);
6470
+ const encryptedCID = encryptHash2(result.contentHash, APP_CONFIG.secretKey, uid);
6356
6471
  console.log(
6357
6472
  import_chalk6.default.cyan(
6358
6473
  import_figlet2.default.textSync("Successful", { horizontalLayout: "full" })
6359
6474
  )
6360
6475
  );
6361
6476
  console.log(import_chalk6.default.cyan(`URL:`));
6362
- console.log(import_chalk6.default.cyan(`${URL4}${encryptedCID}`));
6477
+ console.log(import_chalk6.default.cyan(`${APP_CONFIG.ipfsPreviewUrl}${encryptedCID}`));
6363
6478
  if (domainArg) {
6364
6479
  console.log(import_chalk6.default.blue(`Binding domain: ${domainArg} with CID: ${result.contentHash}`));
6365
6480
  const ok = await bindPinmeDomain(domainArg, result.contentHash);
@@ -6597,7 +6712,7 @@ var import_figlet4 = __toESM(require("figlet"));
6597
6712
 
6598
6713
  // bin/utils/removeFromIpfs.ts
6599
6714
  var import_chalk8 = __toESM(require("chalk"));
6600
- var ipfsApiUrl = "https://pinme.benny1996.win/api/v3";
6715
+ var ipfsApiUrl = APP_CONFIG.ipfsApiUrl;
6601
6716
  async function removeFromIpfs(value, type = "hash") {
6602
6717
  try {
6603
6718
  const uid = getUid();
@@ -6851,7 +6966,7 @@ var import_chalk11 = __toESM(require("chalk"));
6851
6966
  var import_inquirer6 = __toESM(require("inquirer"));
6852
6967
  async function logoutCmd() {
6853
6968
  try {
6854
- const auth = getAuthConfig2();
6969
+ const auth = getAuthConfig();
6855
6970
  if (!auth) {
6856
6971
  console.log(import_chalk11.default.yellow("No active session found. You are already logged out."));
6857
6972
  return;
@@ -6880,7 +6995,7 @@ async function logoutCmd() {
6880
6995
  var import_chalk12 = __toESM(require("chalk"));
6881
6996
  function showAppKeyCmd() {
6882
6997
  try {
6883
- const auth = getAuthConfig2();
6998
+ const auth = getAuthConfig();
6884
6999
  if (!auth) {
6885
7000
  console.log(import_chalk12.default.yellow("No AppKey found. Please set your AppKey first."));
6886
7001
  console.log(import_chalk12.default.gray("Run: pinme set-appkey <AppKey>"));
@@ -6936,39 +7051,33 @@ async function myDomainsCmd() {
6936
7051
  }
6937
7052
  }
6938
7053
 
6939
- // bin/bind.ts
6940
- var import_path10 = __toESM(require("path"));
7054
+ // bin/wallet-balance.ts
6941
7055
  var import_chalk14 = __toESM(require("chalk"));
6942
- var import_inquirer7 = __toESM(require("inquirer"));
6943
- function isDnsDomain2(domain) {
6944
- return domain.includes(".");
6945
- }
6946
- function validateDnsDomain2(domain) {
6947
- const cleanDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
6948
- const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9][a-zA-Z0-9-]*)*\.[a-zA-Z]{2,}$/;
6949
- const parts = cleanDomain.split(".");
6950
- if (parts.length < 2) {
6951
- return { valid: false, message: "Invalid domain format. Please enter a complete domain (e.g., example.com)" };
6952
- }
6953
- for (const part of parts) {
6954
- if (part.length === 0) {
6955
- return { valid: false, message: "Invalid domain format. Consecutive dots are not allowed" };
6956
- }
6957
- if (part.length > 63) {
6958
- return { valid: false, message: "Invalid domain format. Each label must be 63 characters or less" };
6959
- }
6960
- if (!/^[a-zA-Z0-9-]+$/.test(part)) {
6961
- return { valid: false, message: "Invalid domain format. Domains can only contain letters, numbers, and hyphens" };
7056
+ async function walletBalanceCmd() {
7057
+ var _a2;
7058
+ try {
7059
+ const auth = getAuthConfig();
7060
+ if (!auth) {
7061
+ console.log(import_chalk14.default.yellow("Please login first. Run: pinme set-appkey <AppKey>"));
7062
+ return;
6962
7063
  }
6963
- if (/^-|-$/.test(part)) {
6964
- return { valid: false, message: "Invalid domain format. Labels cannot start or end with hyphens" };
7064
+ const result = await getWalletBalance(auth.address, auth.token);
7065
+ const balance = Number(((_a2 = result.data) == null ? void 0 : _a2.wallet_balance_usd) ?? 0);
7066
+ if (!Number.isFinite(balance)) {
7067
+ console.log(import_chalk14.default.red("Failed to parse wallet balance."));
7068
+ return;
6965
7069
  }
7070
+ console.log(import_chalk14.default.cyan("Wallet balance:"));
7071
+ console.log(import_chalk14.default.green(` USD: $${balance.toFixed(2)}`));
7072
+ } catch (e) {
7073
+ console.log(import_chalk14.default.red(`Failed to fetch wallet balance: ${(e == null ? void 0 : e.message) || e}`));
6966
7074
  }
6967
- if (!domainRegex.test(cleanDomain)) {
6968
- return { valid: false, message: "Invalid domain format" };
6969
- }
6970
- return { valid: true };
6971
7075
  }
7076
+
7077
+ // bin/bind.ts
7078
+ var import_path10 = __toESM(require("path"));
7079
+ var import_chalk15 = __toESM(require("chalk"));
7080
+ var import_inquirer7 = __toESM(require("inquirer"));
6972
7081
  function parseArgs() {
6973
7082
  const args = process.argv.slice(2);
6974
7083
  const res = {};
@@ -6987,31 +7096,32 @@ function parseArgs() {
6987
7096
  }
6988
7097
  return res;
6989
7098
  }
6990
- async function checkVipStatus2(authConfig) {
6991
- var _a;
6992
- console.log(import_chalk14.default.blue("Checking VIP status..."));
7099
+ async function checkWalletBalanceStatus2(authConfig) {
7100
+ var _a2;
7101
+ console.log(import_chalk15.default.blue("Checking wallet balance..."));
6993
7102
  try {
6994
- const vipResult = await isVip(authConfig.address, authConfig.token);
6995
- if (!((_a = vipResult.data) == null ? void 0 : _a.is_vip)) {
7103
+ const balanceResult = await getWalletBalance(authConfig.address, authConfig.token);
7104
+ const balance = Number(((_a2 = balanceResult.data) == null ? void 0 : _a2.wallet_balance_usd) ?? 0);
7105
+ if (!Number.isFinite(balance) || balance <= 0) {
6996
7106
  return false;
6997
7107
  }
6998
- console.log(import_chalk14.default.green("VIP verified."));
7108
+ console.log(import_chalk15.default.green(`Wallet balance available: $${balance.toFixed(2)}`));
6999
7109
  return true;
7000
7110
  } catch (e) {
7001
7111
  if (e.message === "Token expired") {
7002
7112
  throw e;
7003
7113
  }
7004
- console.log(import_chalk14.default.yellow("Failed to check VIP status, continuing..."));
7114
+ console.log(import_chalk15.default.yellow("Failed to check wallet balance, continuing..."));
7005
7115
  return true;
7006
7116
  }
7007
7117
  }
7008
7118
  async function bindCmd() {
7009
- var _a;
7119
+ var _a2;
7010
7120
  try {
7011
7121
  let { domain, targetPath, dns } = parseArgs();
7012
- const authConfig = getAuthConfig2();
7122
+ const authConfig = getAuthConfig();
7013
7123
  if (!authConfig) {
7014
- console.log(import_chalk14.default.red("Please login first. Run: pinme set-appkey <AppKey>"));
7124
+ console.log(import_chalk15.default.red("Please login first. Run: pinme set-appkey <AppKey>"));
7015
7125
  return;
7016
7126
  }
7017
7127
  if (!targetPath) {
@@ -7024,25 +7134,25 @@ async function bindCmd() {
7024
7134
  const ans = await import_inquirer7.default.prompt([
7025
7135
  { type: "input", name: "domain", message: "Enter the domain to bind (e.g., my-site or example.com): " }
7026
7136
  ]);
7027
- domain = (_a = ans.domain) == null ? void 0 : _a.trim();
7137
+ domain = (_a2 = ans.domain) == null ? void 0 : _a2.trim();
7028
7138
  }
7029
7139
  if (!targetPath || !domain) {
7030
- console.log(import_chalk14.default.red("Missing parameters. Path and domain are required."));
7140
+ console.log(import_chalk15.default.red("Missing parameters. Path and domain are required."));
7031
7141
  return;
7032
7142
  }
7033
- const isDns = dns || isDnsDomain2(domain);
7034
- const displayDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
7143
+ const isDns = dns || isDnsDomain(domain);
7144
+ const displayDomain = normalizeDomain(domain);
7035
7145
  if (isDns) {
7036
- const validation = validateDnsDomain2(domain);
7146
+ const validation = validateDnsDomain(domain);
7037
7147
  if (!validation.valid) {
7038
- console.log(import_chalk14.default.red(validation.message));
7148
+ console.log(import_chalk15.default.red(validation.message));
7039
7149
  return;
7040
7150
  }
7041
7151
  }
7042
7152
  try {
7043
- const isVipUser = await checkVipStatus2(authConfig);
7044
- if (!isVipUser) {
7045
- console.log(import_chalk14.default.red("Domain binding requires VIP. Please upgrade to VIP first."));
7153
+ const hasWalletBalance = await checkWalletBalanceStatus2(authConfig);
7154
+ if (!hasWalletBalance) {
7155
+ console.log(import_chalk15.default.red("Insufficient wallet balance. Please recharge your wallet first."));
7046
7156
  return;
7047
7157
  }
7048
7158
  } catch (e) {
@@ -7054,10 +7164,10 @@ async function bindCmd() {
7054
7164
  try {
7055
7165
  const check = await checkDomainAvailable(displayDomain);
7056
7166
  if (!check.is_valid) {
7057
- console.log(import_chalk14.default.red(`Domain not available: ${check.error || "unknown reason"}`));
7167
+ console.log(import_chalk15.default.red(`Domain not available: ${check.error || "unknown reason"}`));
7058
7168
  return;
7059
7169
  }
7060
- console.log(import_chalk14.default.green(`Domain available: ${displayDomain}`));
7170
+ console.log(import_chalk15.default.green(`Domain available: ${displayDomain}`));
7061
7171
  } catch (e) {
7062
7172
  if (e.message === "Token expired") {
7063
7173
  return;
@@ -7065,33 +7175,33 @@ async function bindCmd() {
7065
7175
  throw e;
7066
7176
  }
7067
7177
  const absolutePath = import_path10.default.resolve(targetPath);
7068
- console.log(import_chalk14.default.blue(`Uploading: ${absolutePath}`));
7069
- const up = await uploadToIpfsSplit_default(absolutePath);
7178
+ console.log(import_chalk15.default.blue(`Uploading: ${absolutePath}`));
7179
+ const up = await uploadPath(absolutePath);
7070
7180
  if (!(up == null ? void 0 : up.contentHash)) {
7071
- console.log(import_chalk14.default.red("Upload failed, binding aborted."));
7181
+ console.log(import_chalk15.default.red("Upload failed, binding aborted."));
7072
7182
  return;
7073
7183
  }
7074
- console.log(import_chalk14.default.green(`Upload success, CID: ${up.contentHash}`));
7184
+ console.log(import_chalk15.default.green(`Upload success, CID: ${up.contentHash}`));
7075
7185
  try {
7076
7186
  if (isDns) {
7077
- console.log(import_chalk14.default.blue("Binding DNS domain..."));
7187
+ console.log(import_chalk15.default.blue("Binding DNS domain..."));
7078
7188
  const dnsResult = await bindDnsDomainV4(displayDomain, up.contentHash, authConfig.address, authConfig.token);
7079
7189
  if (dnsResult.code !== 200) {
7080
- console.log(import_chalk14.default.red(`DNS binding failed: ${dnsResult.msg}`));
7190
+ console.log(import_chalk15.default.red(`DNS binding failed: ${dnsResult.msg}`));
7081
7191
  return;
7082
7192
  }
7083
- console.log(import_chalk14.default.green(`DNS bind success: ${displayDomain}`));
7084
- console.log(import_chalk14.default.white(`Visit: https://${displayDomain}`));
7085
- console.log(import_chalk14.default.cyan("\n\u{1F4DA} DNS Setup Guide: https://pinme.eth.limo/#/docs?id=custom-domain"));
7193
+ console.log(import_chalk15.default.green(`DNS bind success: ${displayDomain}`));
7194
+ console.log(import_chalk15.default.white(`Visit: https://${displayDomain}`));
7195
+ console.log(import_chalk15.default.cyan("\n\u{1F4DA} DNS Setup Guide: https://pinme.eth.limo/#/docs?id=custom-domain"));
7086
7196
  } else {
7087
- console.log(import_chalk14.default.blue("Binding Pinme subdomain..."));
7197
+ console.log(import_chalk15.default.blue("Binding Pinme subdomain..."));
7088
7198
  const ok = await bindPinmeDomain(displayDomain, up.contentHash);
7089
7199
  if (!ok) {
7090
- console.log(import_chalk14.default.red("Binding failed. Please try again later."));
7200
+ console.log(import_chalk15.default.red("Binding failed. Please try again later."));
7091
7201
  return;
7092
7202
  }
7093
- console.log(import_chalk14.default.green(`Bind success: ${displayDomain}`));
7094
- console.log(import_chalk14.default.white(`Visit: https://${displayDomain}.pinit.eth.limo`));
7203
+ console.log(import_chalk15.default.green(`Bind success: ${displayDomain}`));
7204
+ console.log(import_chalk15.default.white(`Visit: https://${displayDomain}.pinit.eth.limo`));
7095
7205
  }
7096
7206
  } catch (e) {
7097
7207
  if (e.message === "Token expired") {
@@ -7100,12 +7210,12 @@ async function bindCmd() {
7100
7210
  throw e;
7101
7211
  }
7102
7212
  } catch (e) {
7103
- console.log(import_chalk14.default.red(`Execution failed: ${(e == null ? void 0 : e.message) || e}`));
7213
+ console.log(import_chalk15.default.red(`Execution failed: ${(e == null ? void 0 : e.message) || e}`));
7104
7214
  }
7105
7215
  }
7106
7216
 
7107
7217
  // bin/login.ts
7108
- var import_chalk15 = __toESM(require("chalk"));
7218
+ var import_chalk16 = __toESM(require("chalk"));
7109
7219
  var ENV_URLS = {
7110
7220
  dev: "http://localhost:5173",
7111
7221
  test: "http://test-pinme.pinit.eth.limo",
@@ -7117,30 +7227,30 @@ async function loginCmd(options = {}) {
7117
7227
  const env = (options.env || "prod").toLowerCase();
7118
7228
  if (ENV_URLS[env]) {
7119
7229
  webBaseUrl = ENV_URLS[env];
7120
- console.log(import_chalk15.default.blue(`Using ${env} environment: ${webBaseUrl}`));
7230
+ console.log(import_chalk16.default.blue(`Using ${env} environment: ${webBaseUrl}`));
7121
7231
  } else {
7122
- console.log(import_chalk15.default.yellow(`Unknown environment: ${options.env}. Using default prod.`));
7232
+ console.log(import_chalk16.default.yellow(`Unknown environment: ${options.env}. Using default prod.`));
7123
7233
  webBaseUrl = ENV_URLS.prod;
7124
- console.log(import_chalk15.default.blue(`Using prod environment: ${webBaseUrl}`));
7234
+ console.log(import_chalk16.default.blue(`Using prod environment: ${webBaseUrl}`));
7125
7235
  }
7126
7236
  const manager = new WebLoginManager({ webBaseUrl });
7127
7237
  await manager.login();
7128
- console.log(import_chalk15.default.blue("\nMerging history..."));
7238
+ console.log(import_chalk16.default.blue("\nMerging history..."));
7129
7239
  const deviceId = getDeviceId();
7130
7240
  const ok = await bindAnonymousDevice(deviceId);
7131
7241
  if (ok) {
7132
- console.log(import_chalk15.default.green("History merged to your account"));
7242
+ console.log(import_chalk16.default.green("History merged to your account"));
7133
7243
  }
7134
7244
  process.exit(0);
7135
7245
  } catch (e) {
7136
- console.log(import_chalk15.default.red(`
7246
+ console.log(import_chalk16.default.red(`
7137
7247
  Login failed: ${(e == null ? void 0 : e.message) || e}`));
7138
7248
  process.exit(1);
7139
7249
  }
7140
7250
  }
7141
7251
 
7142
7252
  // bin/create.ts
7143
- var import_chalk18 = __toESM(require("chalk"));
7253
+ var import_chalk19 = __toESM(require("chalk"));
7144
7254
  var import_fs_extra7 = __toESM(require("fs-extra"));
7145
7255
  var import_path12 = __toESM(require("path"));
7146
7256
  var import_inquirer8 = __toESM(require("inquirer"));
@@ -7150,7 +7260,7 @@ var import_child_process3 = require("child_process");
7150
7260
  var import_fs_extra6 = __toESM(require("fs-extra"));
7151
7261
  var import_os5 = __toESM(require("os"));
7152
7262
  var import_path11 = __toESM(require("path"));
7153
- var import_chalk16 = __toESM(require("chalk"));
7263
+ var import_chalk17 = __toESM(require("chalk"));
7154
7264
  var import_child_process2 = require("child_process");
7155
7265
  function makeTempCacheDir() {
7156
7266
  return import_fs_extra6.default.mkdtempSync(import_path11.default.join(import_os5.default.tmpdir(), "pinme-npm-cache-"));
@@ -7173,7 +7283,7 @@ function installProjectDependencies(cwd) {
7173
7283
  const cacheDir = makeTempCacheDir();
7174
7284
  try {
7175
7285
  if (attempt > 1) {
7176
- console.log(import_chalk16.default.yellow(" Retrying dependency install with a fresh npm cache..."));
7286
+ console.log(import_chalk17.default.yellow(" Retrying dependency install with a fresh npm cache..."));
7177
7287
  }
7178
7288
  runInstall(cwd, cacheDir);
7179
7289
  return;
@@ -7187,7 +7297,7 @@ function installProjectDependencies(cwd) {
7187
7297
  }
7188
7298
 
7189
7299
  // bin/utils/cliError.ts
7190
- var import_chalk17 = __toESM(require("chalk"));
7300
+ var import_chalk18 = __toESM(require("chalk"));
7191
7301
  var CliError = class extends Error {
7192
7302
  stage;
7193
7303
  details;
@@ -7216,8 +7326,8 @@ function stringifyValue(value) {
7216
7326
  }
7217
7327
  }
7218
7328
  function getApiMessage(data) {
7219
- var _a, _b, _c;
7220
- 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);
7329
+ var _a2, _b, _c;
7330
+ return ((_a2 = data == null ? void 0 : data.data) == null ? void 0 : _a2.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);
7221
7331
  }
7222
7332
  function getBusinessCode(data) {
7223
7333
  if ((data == null ? void 0 : data.code) === void 0 || (data == null ? void 0 : data.code) === null) {
@@ -7263,8 +7373,8 @@ function createCommandError(stage, command, error, suggestions = []) {
7263
7373
  });
7264
7374
  }
7265
7375
  function createApiError(stage, error, context = [], suggestions = []) {
7266
- var _a, _b;
7267
- const status = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status;
7376
+ var _a2, _b;
7377
+ const status = (_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status;
7268
7378
  const responseData = (_b = error == null ? void 0 : error.response) == null ? void 0 : _b.data;
7269
7379
  const errorCode = error == null ? void 0 : error.code;
7270
7380
  const apiMessage = getApiMessage(responseData);
@@ -7318,25 +7428,24 @@ function normalizeCliError(error, fallbackSummary, suggestions = []) {
7318
7428
  }
7319
7429
  function printCliError(error, fallbackSummary) {
7320
7430
  const cliError = normalizeCliError(error, fallbackSummary);
7321
- console.error(import_chalk17.default.red(`
7431
+ console.error(import_chalk18.default.red(`
7322
7432
  Error: ${cliError.message}`));
7323
7433
  if (cliError.stage) {
7324
- console.error(import_chalk17.default.gray(`Stage: ${cliError.stage}`));
7434
+ console.error(import_chalk18.default.gray(`Stage: ${cliError.stage}`));
7325
7435
  }
7326
7436
  for (const detail of cliError.details) {
7327
- console.error(import_chalk17.default.gray(detail));
7437
+ console.error(import_chalk18.default.gray(detail));
7328
7438
  }
7329
7439
  if (cliError.suggestions.length > 0) {
7330
- console.error(import_chalk17.default.yellow("\nNext steps:"));
7440
+ console.error(import_chalk18.default.yellow("\nNext steps:"));
7331
7441
  for (const suggestion of cliError.suggestions) {
7332
- console.error(import_chalk17.default.yellow(`- ${suggestion}`));
7442
+ console.error(import_chalk18.default.yellow(`- ${suggestion}`));
7333
7443
  }
7334
7444
  }
7335
7445
  }
7336
7446
 
7337
7447
  // bin/create.ts
7338
7448
  var PROJECT_DIR = process.cwd();
7339
- var API_BASE = "https://pinme.benny1996.win/api/v4";
7340
7449
  var TEMPLATE_BRANCH = "feat/auth";
7341
7450
  var TEMPLATE_REPO = "glitternetwork/pinme-worker-template";
7342
7451
  var TEMPLATE_REPO_NAME = TEMPLATE_REPO.split("/").pop() || "pinme-worker-template";
@@ -7374,8 +7483,24 @@ function resolveExtractedTemplateDir(extractDir) {
7374
7483
  }
7375
7484
  return import_path12.default.join(extractDir, templateDir.name);
7376
7485
  }
7486
+ function updateFrontendUrlInConfig(configPath, frontendUrl) {
7487
+ let config = import_fs_extra7.default.readFileSync(configPath, "utf-8");
7488
+ if (config.includes("frontend_url")) {
7489
+ config = config.replace(
7490
+ /frontend_url\s*=\s*"[^"]*"/,
7491
+ `frontend_url = "${frontendUrl}"`
7492
+ );
7493
+ } else {
7494
+ config = config.replace(
7495
+ /(project_name\s*=\s*"[^"]*"\n)/,
7496
+ `$1frontend_url = "${frontendUrl}"
7497
+ `
7498
+ );
7499
+ }
7500
+ import_fs_extra7.default.writeFileSync(configPath, config);
7501
+ }
7377
7502
  async function createCmd(options) {
7378
- var _a, _b;
7503
+ var _a2, _b;
7379
7504
  try {
7380
7505
  const headers = getAuthHeaders();
7381
7506
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
@@ -7383,7 +7508,7 @@ async function createCmd(options) {
7383
7508
  "Run `pinme login` and retry."
7384
7509
  ]);
7385
7510
  }
7386
- console.log(import_chalk18.default.blue("Creating new project from template...\n"));
7511
+ console.log(import_chalk19.default.blue("Creating new project from template...\n"));
7387
7512
  let projectName = options.name;
7388
7513
  if (!projectName) {
7389
7514
  const answers = await import_inquirer8.default.prompt([
@@ -7404,7 +7529,7 @@ async function createCmd(options) {
7404
7529
  }
7405
7530
  const targetDir = import_path12.default.join(PROJECT_DIR, projectName);
7406
7531
  if (import_fs_extra7.default.existsSync(targetDir) && !options.force) {
7407
- console.log(import_chalk18.default.yellow(`
7532
+ console.log(import_chalk19.default.yellow(`
7408
7533
  Directory "${projectName}" already exists.`));
7409
7534
  const answers = await import_inquirer8.default.prompt([
7410
7535
  {
@@ -7415,16 +7540,16 @@ Directory "${projectName}" already exists.`));
7415
7540
  }
7416
7541
  ]);
7417
7542
  if (!answers.overwrite) {
7418
- console.log(import_chalk18.default.gray("Cancelled."));
7543
+ console.log(import_chalk19.default.gray("Cancelled."));
7419
7544
  process.exit(0);
7420
7545
  }
7421
7546
  import_fs_extra7.default.removeSync(targetDir);
7422
7547
  }
7423
- console.log(import_chalk18.default.blue("\n1. Creating worker and database..."));
7424
- const apiUrl = `${API_BASE}/create_worker`;
7425
- console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
7548
+ console.log(import_chalk19.default.blue("\n1. Creating worker and database..."));
7549
+ const apiUrl = getPinmeApiUrl("/create_worker");
7550
+ console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
7426
7551
  const normalizedProjectName = projectName.toLowerCase();
7427
- console.log(import_chalk18.default.gray(`Project name: ${normalizedProjectName}`));
7552
+ console.log(import_chalk19.default.gray(`Project name: ${normalizedProjectName}`));
7428
7553
  let workerData;
7429
7554
  try {
7430
7555
  const response = await axios_default.post(apiUrl, {
@@ -7443,24 +7568,24 @@ Directory "${projectName}" already exists.`));
7443
7568
  ]);
7444
7569
  }
7445
7570
  workerData = data.data;
7446
- console.log(import_chalk18.default.gray(` API Response: ${JSON.stringify(workerData)}`));
7447
- console.log(import_chalk18.default.green(` API Domain: ${workerData.api_domain}`));
7448
- console.log(import_chalk18.default.green(` Project Name: ${workerData.project_name}`));
7571
+ console.log(import_chalk19.default.gray(` API Response: ${JSON.stringify(workerData)}`));
7572
+ console.log(import_chalk19.default.green(` API Domain: ${workerData.api_domain}`));
7573
+ console.log(import_chalk19.default.green(` Project Name: ${workerData.project_name}`));
7449
7574
  } catch (error) {
7450
7575
  throw createApiError("project creation", error, [
7451
7576
  `Project name: ${normalizedProjectName}`,
7452
7577
  `Endpoint: ${apiUrl}`
7453
7578
  ]);
7454
7579
  }
7455
- console.log(import_chalk18.default.blue("\n2. Downloading template from repository..."));
7580
+ console.log(import_chalk19.default.blue("\n2. Downloading template from repository..."));
7456
7581
  const zipPath = import_path12.default.join(PROJECT_DIR, "template.zip");
7457
7582
  const extractDir = import_path12.default.join(PROJECT_DIR, `.pinme-template-${Date.now()}`);
7458
7583
  const templateZipUrl = getTemplateZipUrl(TEMPLATE_BRANCH);
7459
7584
  let downloadSuccess = false;
7460
- console.log(import_chalk18.default.gray(` Template branch: ${TEMPLATE_BRANCH}`));
7585
+ console.log(import_chalk19.default.gray(` Template branch: ${TEMPLATE_BRANCH}`));
7461
7586
  for (let attempt = 1; attempt <= 3 && !downloadSuccess; attempt++) {
7462
7587
  try {
7463
- console.log(import_chalk18.default.gray(` Download attempt ${attempt}/3...`));
7588
+ console.log(import_chalk19.default.gray(` Download attempt ${attempt}/3...`));
7464
7589
  (0, import_child_process3.execSync)(`curl -L --retry 3 --retry-delay 2 -o "${zipPath}" "${templateZipUrl}"`, {
7465
7590
  stdio: "inherit"
7466
7591
  });
@@ -7469,7 +7594,7 @@ Directory "${projectName}" already exists.`));
7469
7594
  }
7470
7595
  downloadSuccess = true;
7471
7596
  } catch (downloadError) {
7472
- console.log(import_chalk18.default.yellow(` Attempt ${attempt} failed: ${downloadError.message}`));
7597
+ console.log(import_chalk19.default.yellow(` Attempt ${attempt} failed: ${downloadError.message}`));
7473
7598
  if (import_fs_extra7.default.existsSync(zipPath)) {
7474
7599
  import_fs_extra7.default.removeSync(zipPath);
7475
7600
  }
@@ -7490,11 +7615,11 @@ Directory "${projectName}" already exists.`));
7490
7615
  const nodeModulesPath = import_path12.default.join(targetDir, "node_modules");
7491
7616
  const packageLockPath = import_path12.default.join(targetDir, "package-lock.json");
7492
7617
  if (import_fs_extra7.default.existsSync(nodeModulesPath)) {
7493
- console.log(import_chalk18.default.gray(" Removing existing node_modules..."));
7618
+ console.log(import_chalk19.default.gray(" Removing existing node_modules..."));
7494
7619
  import_fs_extra7.default.removeSync(nodeModulesPath);
7495
7620
  }
7496
7621
  if (import_fs_extra7.default.existsSync(packageLockPath)) {
7497
- console.log(import_chalk18.default.gray(" Removing existing package-lock.json..."));
7622
+ console.log(import_chalk19.default.gray(" Removing existing package-lock.json..."));
7498
7623
  import_fs_extra7.default.removeSync(packageLockPath);
7499
7624
  }
7500
7625
  const frontendNodeModules = import_path12.default.join(targetDir, "frontend", "node_modules");
@@ -7505,13 +7630,13 @@ Directory "${projectName}" already exists.`));
7505
7630
  if (import_fs_extra7.default.existsSync(backendNodeModules)) import_fs_extra7.default.removeSync(backendNodeModules);
7506
7631
  if (import_fs_extra7.default.existsSync(frontendPackageLock)) import_fs_extra7.default.removeSync(frontendPackageLock);
7507
7632
  if (import_fs_extra7.default.existsSync(backendPackageLock)) import_fs_extra7.default.removeSync(backendPackageLock);
7508
- console.log(import_chalk18.default.green(` Template downloaded to: ${targetDir}`));
7633
+ console.log(import_chalk19.default.green(` Template downloaded to: ${targetDir}`));
7509
7634
  } catch (error) {
7510
7635
  throw createCommandError("template extraction", `unzip -o "${zipPath}" -d "${PROJECT_DIR}"`, error, [
7511
7636
  "Check whether `unzip` is available and the downloaded template archive is valid."
7512
7637
  ]);
7513
7638
  }
7514
- console.log(import_chalk18.default.blue("\n3. Updating configuration..."));
7639
+ console.log(import_chalk19.default.blue("\n3. Updating configuration..."));
7515
7640
  const configPath = import_path12.default.join(targetDir, "pinme.toml");
7516
7641
  const config = import_fs_extra7.default.readFileSync(configPath, "utf-8");
7517
7642
  let updatedConfig = config.replace(
@@ -7519,8 +7644,8 @@ Directory "${projectName}" already exists.`));
7519
7644
  `project_name = "${workerData.project_name}"`
7520
7645
  );
7521
7646
  import_fs_extra7.default.writeFileSync(configPath, updatedConfig);
7522
- console.log(import_chalk18.default.green(` Updated pinme.toml`));
7523
- console.log(import_chalk18.default.gray(` metadata: ${workerData.metadata}`));
7647
+ console.log(import_chalk19.default.green(` Updated pinme.toml`));
7648
+ console.log(import_chalk19.default.gray(` metadata: ${workerData.metadata}`));
7524
7649
  const backendDir = import_path12.default.join(targetDir, "backend");
7525
7650
  if (import_fs_extra7.default.existsSync(backendDir) && workerData.metadata) {
7526
7651
  const metadataContent = typeof workerData.metadata === "string" ? workerData.metadata : JSON.stringify(workerData.metadata, null, 2);
@@ -7528,7 +7653,7 @@ Directory "${projectName}" already exists.`));
7528
7653
  import_path12.default.join(backendDir, "metadata.json"),
7529
7654
  metadataContent
7530
7655
  );
7531
- console.log(import_chalk18.default.green(` Saved metadata.json`));
7656
+ console.log(import_chalk19.default.green(` Saved metadata.json`));
7532
7657
  }
7533
7658
  const wranglerPath = import_path12.default.join(backendDir, "wrangler.toml");
7534
7659
  if (import_fs_extra7.default.existsSync(wranglerPath) && workerData.api_key) {
@@ -7538,7 +7663,7 @@ Directory "${projectName}" already exists.`));
7538
7663
  `name = "${workerData.project_name}"`
7539
7664
  );
7540
7665
  import_fs_extra7.default.writeFileSync(wranglerPath, wranglerContent);
7541
- console.log(import_chalk18.default.green(` Updated backend/wrangler.toml API_KEY`));
7666
+ console.log(import_chalk19.default.green(` Updated backend/wrangler.toml API_KEY`));
7542
7667
  }
7543
7668
  const frontendConfigPath = import_path12.default.join(targetDir, "frontend", "src", "utils", "config.ts");
7544
7669
  if (workerData.public_client_config) {
@@ -7548,7 +7673,7 @@ Directory "${projectName}" already exists.`));
7548
7673
  frontendConfigPath,
7549
7674
  injectPublicClientConfigIntoFile(frontendConfigContent, workerData.public_client_config)
7550
7675
  );
7551
- console.log(import_chalk18.default.green(` Updated frontend/src/utils/config.ts public_client_config`));
7676
+ console.log(import_chalk19.default.green(` Updated frontend/src/utils/config.ts public_client_config`));
7552
7677
  }
7553
7678
  const envExamplePath = import_path12.default.join(targetDir, "frontend", ".env.example");
7554
7679
  const envPath = import_path12.default.join(targetDir, "frontend", ".env");
@@ -7560,8 +7685,8 @@ Directory "${projectName}" already exists.`));
7560
7685
  `VITE_API_URL=${workerData.api_domain}`
7561
7686
  );
7562
7687
  import_fs_extra7.default.writeFileSync(envPath, envContent);
7563
- console.log(import_chalk18.default.green(` Created frontend/.env file`));
7564
- console.log(import_chalk18.default.gray(` VITE_API_URL: ${workerData.api_domain}`));
7688
+ console.log(import_chalk19.default.green(` Created frontend/.env file`));
7689
+ console.log(import_chalk19.default.gray(` VITE_API_URL: ${workerData.api_domain}`));
7565
7690
  }
7566
7691
  let pinmeConfig = import_fs_extra7.default.readFileSync(configPath, "utf-8");
7567
7692
  if (pinmeConfig.includes("api_url")) {
@@ -7581,11 +7706,11 @@ Directory "${projectName}" already exists.`));
7581
7706
  pinmeConfig = newLines.join("\n");
7582
7707
  }
7583
7708
  import_fs_extra7.default.writeFileSync(configPath, pinmeConfig);
7584
- console.log(import_chalk18.default.green(` Updated pinme.toml with api_url`));
7585
- console.log(import_chalk18.default.blue("\n4. Installing dependencies..."));
7709
+ console.log(import_chalk19.default.green(` Updated pinme.toml with api_url`));
7710
+ console.log(import_chalk19.default.blue("\n4. Installing dependencies..."));
7586
7711
  try {
7587
7712
  installProjectDependencies(targetDir);
7588
- console.log(import_chalk18.default.green(" Project dependencies installed"));
7713
+ console.log(import_chalk19.default.green(" Project dependencies installed"));
7589
7714
  } catch (error) {
7590
7715
  const errorMsg = error.message || "";
7591
7716
  if (errorMsg.includes("EACCES") || errorMsg.includes("EPERM") || errorMsg.includes("permission denied")) {
@@ -7624,13 +7749,13 @@ Directory "${projectName}" already exists.`));
7624
7749
  " sudo chown -R $(whoami) " + targetDir + "/node_modules"
7625
7750
  ]);
7626
7751
  }
7627
- console.log(import_chalk18.default.blue("\n5. Building backend worker..."));
7752
+ console.log(import_chalk19.default.blue("\n5. Building backend worker..."));
7628
7753
  try {
7629
7754
  (0, import_child_process3.execSync)("npm run build:worker", {
7630
7755
  cwd: targetDir,
7631
7756
  stdio: "inherit"
7632
7757
  });
7633
- console.log(import_chalk18.default.green(" Worker built"));
7758
+ console.log(import_chalk19.default.green(" Worker built"));
7634
7759
  } catch (error) {
7635
7760
  throw createCommandError("worker build", "npm run build:worker", error, [
7636
7761
  "Fix the build error shown above, then rerun `pinme create`."
@@ -7656,12 +7781,12 @@ Directory "${projectName}" already exists.`));
7656
7781
  const sqlFileNames = import_fs_extra7.default.readdirSync(sqlDir).filter((f) => f.endsWith(".sql")).sort();
7657
7782
  for (const filename of sqlFileNames) {
7658
7783
  sqlFiles.push(import_path12.default.join(sqlDir, filename));
7659
- console.log(import_chalk18.default.gray(` Including SQL: ${filename}`));
7784
+ console.log(import_chalk19.default.gray(` Including SQL: ${filename}`));
7660
7785
  }
7661
7786
  }
7662
- console.log(import_chalk18.default.blue("\n6. Deploying backend worker..."));
7663
- const saveApiUrl = `${API_BASE}/save_worker?project_name=${encodeURIComponent(workerData.project_name)}`;
7664
- console.log(import_chalk18.default.gray(` API URL: ${saveApiUrl}`));
7787
+ console.log(import_chalk19.default.blue("\n6. Deploying backend worker..."));
7788
+ const saveApiUrl = `${getPinmeApiUrl("/save_worker")}?project_name=${encodeURIComponent(workerData.project_name)}`;
7789
+ console.log(import_chalk19.default.gray(` API URL: ${saveApiUrl}`));
7665
7790
  try {
7666
7791
  const FormData4 = (await import("formdata-node")).FormData;
7667
7792
  const Blob2 = (await import("formdata-node")).Blob;
@@ -7693,10 +7818,10 @@ Directory "${projectName}" already exists.`));
7693
7818
  timeout: 12e4
7694
7819
  });
7695
7820
  if (response.data) {
7696
- console.log(import_chalk18.default.green(" Worker deployed"));
7697
- if ((_b = (_a = response.data) == null ? void 0 : _a.data) == null ? void 0 : _b.sql_results) {
7821
+ console.log(import_chalk19.default.green(" Worker deployed"));
7822
+ if ((_b = (_a2 = response.data) == null ? void 0 : _a2.data) == null ? void 0 : _b.sql_results) {
7698
7823
  for (const result of response.data.data.sql_results) {
7699
- console.log(import_chalk18.default.gray(` SQL ${result.filename}: ${result.status}`));
7824
+ console.log(import_chalk19.default.gray(` SQL ${result.filename}: ${result.status}`));
7700
7825
  }
7701
7826
  }
7702
7827
  } else {
@@ -7715,7 +7840,7 @@ Directory "${projectName}" already exists.`));
7715
7840
  "Check whether backend metadata, SQL files, or worker bundle contains invalid content."
7716
7841
  ]);
7717
7842
  }
7718
- console.log(import_chalk18.default.blue("\n7. Building frontend..."));
7843
+ console.log(import_chalk19.default.blue("\n7. Building frontend..."));
7719
7844
  const frontendDir = import_path12.default.join(targetDir, "frontend");
7720
7845
  if (import_fs_extra7.default.existsSync(frontendDir)) {
7721
7846
  try {
@@ -7723,60 +7848,36 @@ Directory "${projectName}" already exists.`));
7723
7848
  cwd: targetDir,
7724
7849
  stdio: "inherit"
7725
7850
  });
7726
- console.log(import_chalk18.default.green(" Frontend built"));
7851
+ console.log(import_chalk19.default.green(" Frontend built"));
7727
7852
  } catch (error) {
7728
7853
  throw createCommandError("frontend build", "npm run build:frontend", error, [
7729
7854
  "Fix the frontend build error shown above, then rerun `pinme create`."
7730
7855
  ]);
7731
7856
  }
7732
- console.log(import_chalk18.default.blue(" Uploading to IPFS..."));
7733
- let frontendUrl = "";
7857
+ console.log(import_chalk19.default.blue(" Uploading to IPFS..."));
7734
7858
  try {
7735
- const uploadOutput = (0, import_child_process3.execSync)("pinme upload ./dist", {
7736
- cwd: frontendDir,
7737
- encoding: "utf-8",
7738
- env: {
7739
- ...process.env,
7740
- PINME_PROJECT_NAME: workerData.project_name
7741
- }
7859
+ const uploadResult = await uploadPath(import_path12.default.join(frontendDir, "dist"), {
7860
+ projectName: workerData.project_name
7742
7861
  });
7743
- console.log(uploadOutput);
7744
- const urlMatch = uploadOutput.match(/https:\/\/[\w-]+\.pinme\.dev/);
7745
- if (urlMatch) {
7746
- frontendUrl = urlMatch[0];
7747
- console.log(import_chalk18.default.green(` Frontend uploaded to IPFS: ${frontendUrl}`));
7748
- const configPath2 = import_path12.default.join(targetDir, "pinme.toml");
7749
- let config2 = import_fs_extra7.default.readFileSync(configPath2, "utf-8");
7750
- if (config2.includes("frontend_url")) {
7751
- config2 = config2.replace(
7752
- /frontend_url\s*=\s*"[^"]*"/,
7753
- `frontend_url = "${frontendUrl}"`
7754
- );
7755
- } else {
7756
- config2 = config2.replace(
7757
- /(project_name\s*=\s*"[^"]*"\n)/,
7758
- `$1frontend_url = "${frontendUrl}"
7759
- `
7760
- );
7761
- }
7762
- import_fs_extra7.default.writeFileSync(configPath2, config2);
7763
- console.log(import_chalk18.default.green(" Updated pinme.toml with frontend URL"));
7764
- } else {
7765
- console.log(import_chalk18.default.green(" Frontend uploaded to IPFS"));
7766
- }
7862
+ console.log(import_chalk19.default.green(` Frontend uploaded to IPFS: ${uploadResult.publicUrl}`));
7863
+ updateFrontendUrlInConfig(
7864
+ import_path12.default.join(targetDir, "pinme.toml"),
7865
+ uploadResult.publicUrl
7866
+ );
7867
+ console.log(import_chalk19.default.green(" Updated pinme.toml with frontend URL"));
7767
7868
  } catch (error) {
7768
- console.log(import_chalk18.default.yellow(" Warning: IPFS upload failed, you can upload manually later"));
7869
+ console.log(import_chalk19.default.yellow(" Warning: IPFS upload failed, you can upload manually later"));
7769
7870
  }
7770
7871
  }
7771
- console.log(import_chalk18.default.green("\nProject created successfully."));
7772
- console.log(import_chalk18.default.gray(`
7872
+ console.log(import_chalk19.default.green("\nProject created successfully."));
7873
+ console.log(import_chalk19.default.gray(`
7773
7874
  Project Details:`));
7774
- console.log(import_chalk18.default.gray(` API Domain: ${workerData.api_domain}`));
7775
- console.log(import_chalk18.default.gray(` Project Name: ${workerData.project_name}`));
7776
- console.log(import_chalk18.default.gray(`
7875
+ console.log(import_chalk19.default.gray(` API Domain: ${workerData.api_domain}`));
7876
+ console.log(import_chalk19.default.gray(` Project Name: ${workerData.project_name}`));
7877
+ console.log(import_chalk19.default.gray(`
7777
7878
  Next steps:`));
7778
- console.log(import_chalk18.default.gray(` cd ${projectName}`));
7779
- console.log(import_chalk18.default.gray(` pinme save`));
7879
+ console.log(import_chalk19.default.gray(` cd ${projectName}`));
7880
+ console.log(import_chalk19.default.gray(` pinme save`));
7780
7881
  process.exit(0);
7781
7882
  } catch (error) {
7782
7883
  printCliError(error, "Project creation failed.");
@@ -7785,12 +7886,11 @@ Next steps:`));
7785
7886
  }
7786
7887
 
7787
7888
  // bin/save.ts
7788
- var import_chalk19 = __toESM(require("chalk"));
7889
+ var import_chalk20 = __toESM(require("chalk"));
7789
7890
  var import_fs_extra8 = __toESM(require("fs-extra"));
7790
7891
  var import_path13 = __toESM(require("path"));
7791
7892
  var import_child_process4 = require("child_process");
7792
7893
  var PROJECT_DIR2 = process.cwd();
7793
- var API_BASE2 = "https://pinme.benny1996.win/api/v4";
7794
7894
  function loadConfig() {
7795
7895
  const configPath = import_path13.default.join(PROJECT_DIR2, "pinme.toml");
7796
7896
  if (!import_fs_extra8.default.existsSync(configPath)) {
@@ -7808,19 +7908,19 @@ function loadConfig() {
7808
7908
  function getMetadata() {
7809
7909
  const metadataPath = import_path13.default.join(PROJECT_DIR2, "backend", "metadata.json");
7810
7910
  if (!import_fs_extra8.default.existsSync(metadataPath)) {
7811
- console.log(import_chalk19.default.yellow(" Warning: metadata.json not found, using empty metadata"));
7911
+ console.log(import_chalk20.default.yellow(" Warning: metadata.json not found, using empty metadata"));
7812
7912
  return {};
7813
7913
  }
7814
7914
  return import_fs_extra8.default.readJsonSync(metadataPath);
7815
7915
  }
7816
7916
  function buildWorker() {
7817
- console.log(import_chalk19.default.blue("Building worker..."));
7917
+ console.log(import_chalk20.default.blue("Building worker..."));
7818
7918
  try {
7819
7919
  (0, import_child_process4.execSync)("npm run build:worker", {
7820
7920
  cwd: PROJECT_DIR2,
7821
7921
  stdio: "inherit"
7822
7922
  });
7823
- console.log(import_chalk19.default.green("Worker built"));
7923
+ console.log(import_chalk20.default.green("Worker built"));
7824
7924
  } catch (error) {
7825
7925
  throw createCommandError("worker build", "npm run build:worker", error, [
7826
7926
  "Fix the build error shown above, then rerun `pinme save`."
@@ -7828,10 +7928,10 @@ function buildWorker() {
7828
7928
  }
7829
7929
  }
7830
7930
  function installDependencies() {
7831
- console.log(import_chalk19.default.blue("Installing dependencies..."));
7931
+ console.log(import_chalk20.default.blue("Installing dependencies..."));
7832
7932
  try {
7833
7933
  installProjectDependencies(PROJECT_DIR2);
7834
- console.log(import_chalk19.default.green("Project dependencies installed"));
7934
+ console.log(import_chalk20.default.green("Project dependencies installed"));
7835
7935
  } catch (error) {
7836
7936
  const errorMsg = error.message || "";
7837
7937
  if (errorMsg.includes("EACCES") || errorMsg.includes("EPERM") || errorMsg.includes("permission denied")) {
@@ -7902,16 +8002,16 @@ function getSqlFiles() {
7902
8002
  return files.map((f) => import_path13.default.join(sqlDir, f));
7903
8003
  }
7904
8004
  async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName) {
7905
- var _a, _b;
7906
- console.log(import_chalk19.default.blue("Saving worker to platform..."));
7907
- console.log(import_chalk19.default.gray(`Project: ${projectName}`));
7908
- console.log(import_chalk19.default.gray(`workerJsPath: ${workerJsPath}`));
7909
- console.log(import_chalk19.default.gray(`modulePaths: ${modulePaths}`));
7910
- console.log(import_chalk19.default.gray(`sqlFiles: ${sqlFiles}`));
7911
- console.log(import_chalk19.default.gray(`metadata: ${metadata}`));
7912
- const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
8005
+ var _a2, _b;
8006
+ console.log(import_chalk20.default.blue("Saving worker to platform..."));
8007
+ console.log(import_chalk20.default.gray(`Project: ${projectName}`));
8008
+ console.log(import_chalk20.default.gray(`workerJsPath: ${workerJsPath}`));
8009
+ console.log(import_chalk20.default.gray(`modulePaths: ${modulePaths}`));
8010
+ console.log(import_chalk20.default.gray(`sqlFiles: ${sqlFiles}`));
8011
+ console.log(import_chalk20.default.gray(`metadata: ${metadata}`));
8012
+ const apiUrl = `${getPinmeApiUrl("/save_worker")}?project_name=${encodeURIComponent(projectName)}`;
7913
8013
  const headers = getAuthHeaders();
7914
- console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
8014
+ console.log(import_chalk20.default.gray(`API URL: ${apiUrl}`));
7915
8015
  try {
7916
8016
  const FormData4 = (await import("formdata-node")).FormData;
7917
8017
  const Blob2 = (await import("formdata-node")).Blob;
@@ -7936,18 +8036,18 @@ async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, project
7936
8036
  formData.append("sql_file", new Blob2([content], {
7937
8037
  type: "application/sql"
7938
8038
  }), filename);
7939
- console.log(import_chalk19.default.gray(` Including SQL: ${filename}`));
8039
+ console.log(import_chalk20.default.gray(` Including SQL: ${filename}`));
7940
8040
  }
7941
8041
  const response = await axios_default.put(apiUrl, formData, {
7942
8042
  headers: { ...headers },
7943
8043
  timeout: 12e4
7944
8044
  });
7945
- console.log(import_chalk19.default.gray(` Response: ${JSON.stringify(response.data)}`));
8045
+ console.log(import_chalk20.default.gray(` Response: ${JSON.stringify(response.data)}`));
7946
8046
  if (response.data) {
7947
- console.log(import_chalk19.default.green("Worker saved"));
7948
- if ((_b = (_a = response.data) == null ? void 0 : _a.data) == null ? void 0 : _b.sql_results) {
8047
+ console.log(import_chalk20.default.green("Worker saved"));
8048
+ if ((_b = (_a2 = response.data) == null ? void 0 : _a2.data) == null ? void 0 : _b.sql_results) {
7949
8049
  for (const result of response.data.data.sql_results) {
7950
- console.log(import_chalk19.default.gray(` SQL ${result.filename}: ${result.status}`));
8050
+ console.log(import_chalk20.default.gray(` SQL ${result.filename}: ${result.status}`));
7951
8051
  }
7952
8052
  }
7953
8053
  } else {
@@ -7968,57 +8068,47 @@ async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, project
7968
8068
  }
7969
8069
  }
7970
8070
  function buildFrontend() {
7971
- console.log(import_chalk19.default.blue("Building frontend..."));
8071
+ console.log(import_chalk20.default.blue("Building frontend..."));
7972
8072
  try {
7973
8073
  (0, import_child_process4.execSync)("npm run build:frontend", {
7974
8074
  cwd: PROJECT_DIR2,
7975
8075
  stdio: "inherit"
7976
8076
  });
7977
- console.log(import_chalk19.default.green("Frontend built"));
8077
+ console.log(import_chalk20.default.green("Frontend built"));
7978
8078
  } catch (error) {
7979
8079
  throw createCommandError("frontend build", "npm run build:frontend", error, [
7980
8080
  "Fix the frontend build error shown above, then rerun `pinme save`."
7981
8081
  ]);
7982
8082
  }
7983
8083
  }
7984
- function deployFrontend(projectName) {
7985
- console.log(import_chalk19.default.blue("Deploying frontend to IPFS..."));
8084
+ function updateFrontendUrlInConfig2(configPath, frontendUrl) {
8085
+ let config = import_fs_extra8.default.readFileSync(configPath, "utf-8");
8086
+ if (config.includes("frontend_url")) {
8087
+ config = config.replace(
8088
+ /frontend_url\s*=\s*"[^"]*"/,
8089
+ `frontend_url = "${frontendUrl}"`
8090
+ );
8091
+ } else {
8092
+ config = config.replace(
8093
+ /(project_name\s*=\s*"[^"]*"\n)/,
8094
+ `$1frontend_url = "${frontendUrl}"
8095
+ `
8096
+ );
8097
+ }
8098
+ import_fs_extra8.default.writeFileSync(configPath, config);
8099
+ }
8100
+ async function deployFrontend(projectName) {
8101
+ console.log(import_chalk20.default.blue("Deploying frontend to IPFS..."));
7986
8102
  try {
7987
- const uploadOutput = (0, import_child_process4.execSync)("pinme upload ./frontend/dist", {
7988
- cwd: PROJECT_DIR2,
7989
- encoding: "utf-8",
7990
- env: {
7991
- ...process.env,
7992
- PINME_PROJECT_NAME: projectName
7993
- }
8103
+ const uploadResult = await uploadPath(import_path13.default.join(PROJECT_DIR2, "frontend", "dist"), {
8104
+ projectName
7994
8105
  });
7995
- console.log(uploadOutput);
7996
- const urlMatch = uploadOutput.match(/https:\/\/[\w-]+\.pinme\.dev/);
7997
- if (urlMatch) {
7998
- const frontendUrl = urlMatch[0];
7999
- console.log(import_chalk19.default.green(`Frontend deployed to IPFS: ${frontendUrl}`));
8000
- const configPath = import_path13.default.join(PROJECT_DIR2, "pinme.toml");
8001
- let config = import_fs_extra8.default.readFileSync(configPath, "utf-8");
8002
- if (config.includes("frontend_url")) {
8003
- config = config.replace(
8004
- /frontend_url\s*=\s*"[^"]*"/,
8005
- `frontend_url = "${frontendUrl}"`
8006
- );
8007
- } else {
8008
- config = config.replace(
8009
- /(project_name\s*=\s*"[^"]*"\n)/,
8010
- `$1frontend_url = "${frontendUrl}"
8011
- `
8012
- );
8013
- }
8014
- import_fs_extra8.default.writeFileSync(configPath, config);
8015
- console.log(import_chalk19.default.green("Updated pinme.toml with frontend URL"));
8016
- } else {
8017
- console.log(import_chalk19.default.green("Frontend deployed to IPFS"));
8018
- }
8106
+ console.log(import_chalk20.default.green(`Frontend deployed to IPFS: ${uploadResult.publicUrl}`));
8107
+ updateFrontendUrlInConfig2(import_path13.default.join(PROJECT_DIR2, "pinme.toml"), uploadResult.publicUrl);
8108
+ console.log(import_chalk20.default.green("Updated pinme.toml with frontend URL"));
8019
8109
  } catch (error) {
8020
- throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
8021
- "Make sure `frontend/dist` exists and `pinme upload` works in this environment."
8110
+ throw createCommandError("frontend deploy", "upload frontend/dist", error, [
8111
+ "Make sure `frontend/dist` exists and the upload API is reachable."
8022
8112
  ]);
8023
8113
  }
8024
8114
  }
@@ -8036,8 +8126,8 @@ async function saveCmd(options) {
8036
8126
  if (import_fs_extra8.default.existsSync(tokenFileSrc) && !import_fs_extra8.default.existsSync(tokenFileDst)) {
8037
8127
  import_fs_extra8.default.copySync(tokenFileSrc, tokenFileDst);
8038
8128
  }
8039
- console.log(import_chalk19.default.blue("Deploying to platform...\n"));
8040
- console.log(import_chalk19.default.gray(`Project dir: ${PROJECT_DIR2}`));
8129
+ console.log(import_chalk20.default.blue("Deploying to platform...\n"));
8130
+ console.log(import_chalk20.default.gray(`Project dir: ${PROJECT_DIR2}`));
8041
8131
  const config = loadConfig();
8042
8132
  const projectName = config.project_name;
8043
8133
  if (!projectName) {
@@ -8045,23 +8135,23 @@ async function saveCmd(options) {
8045
8135
  'Set `project_name = "your-project-name"` in `pinme.toml`.'
8046
8136
  ]);
8047
8137
  }
8048
- console.log(import_chalk19.default.gray(`Project: ${projectName}`));
8049
- const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
8050
- console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
8051
- console.log(import_chalk19.default.blue("\n--- Backend ---"));
8138
+ console.log(import_chalk20.default.gray(`Project: ${projectName}`));
8139
+ const apiUrl = `${getPinmeApiUrl("/save_worker")}?project_name=${encodeURIComponent(projectName)}`;
8140
+ console.log(import_chalk20.default.gray(`API URL: ${apiUrl}`));
8141
+ console.log(import_chalk20.default.blue("\n--- Backend ---"));
8052
8142
  installDependencies();
8053
8143
  buildWorker();
8054
8144
  const metadata = getMetadata();
8055
8145
  const { workerJsPath, modulePaths } = getBuiltWorker();
8056
- console.log(import_chalk19.default.gray(`Worker JS: ${workerJsPath}`));
8057
- console.log(import_chalk19.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
8146
+ console.log(import_chalk20.default.gray(`Worker JS: ${workerJsPath}`));
8147
+ console.log(import_chalk20.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
8058
8148
  const sqlFiles = getSqlFiles();
8059
- console.log(import_chalk19.default.gray(`SQL files: ${JSON.stringify(sqlFiles)}`));
8149
+ console.log(import_chalk20.default.gray(`SQL files: ${JSON.stringify(sqlFiles)}`));
8060
8150
  await saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName);
8061
- console.log(import_chalk19.default.blue("\n--- Frontend ---"));
8151
+ console.log(import_chalk20.default.blue("\n--- Frontend ---"));
8062
8152
  buildFrontend();
8063
- deployFrontend(projectName);
8064
- console.log(import_chalk19.default.green("\nDeployment complete."));
8153
+ await deployFrontend(projectName);
8154
+ console.log(import_chalk20.default.green("\nDeployment complete."));
8065
8155
  process.exit(0);
8066
8156
  } catch (error) {
8067
8157
  printCliError(error, "Save failed.");
@@ -8070,11 +8160,10 @@ async function saveCmd(options) {
8070
8160
  }
8071
8161
 
8072
8162
  // bin/updateDb.ts
8073
- var import_chalk20 = __toESM(require("chalk"));
8163
+ var import_chalk21 = __toESM(require("chalk"));
8074
8164
  var import_fs_extra9 = __toESM(require("fs-extra"));
8075
8165
  var import_path14 = __toESM(require("path"));
8076
8166
  var PROJECT_DIR3 = process.cwd();
8077
- var API_BASE3 = "https://pinme.benny1996.win/api/v4";
8078
8167
  function loadConfig2() {
8079
8168
  const configPath = import_path14.default.join(PROJECT_DIR3, "pinme.toml");
8080
8169
  if (!import_fs_extra9.default.existsSync(configPath)) {
@@ -8104,12 +8193,12 @@ function getSqlFiles2() {
8104
8193
  return files.map((f) => import_path14.default.join(sqlDir, f));
8105
8194
  }
8106
8195
  async function updateDb(sqlFiles, projectName) {
8107
- console.log(import_chalk20.default.blue("Importing SQL files to database..."));
8108
- console.log(import_chalk20.default.gray(`Project: ${projectName}`));
8109
- console.log(import_chalk20.default.gray(`SQL files: ${sqlFiles.length}`));
8110
- const apiUrl = `${API_BASE3}/update_db?project_name=${encodeURIComponent(projectName)}`;
8196
+ console.log(import_chalk21.default.blue("Importing SQL files to database..."));
8197
+ console.log(import_chalk21.default.gray(`Project: ${projectName}`));
8198
+ console.log(import_chalk21.default.gray(`SQL files: ${sqlFiles.length}`));
8199
+ const apiUrl = `${getPinmeApiUrl("/update_db")}?project_name=${encodeURIComponent(projectName)}`;
8111
8200
  const headers = getAuthHeaders();
8112
- console.log(import_chalk20.default.gray(`API URL: ${apiUrl}`));
8201
+ console.log(import_chalk21.default.gray(`API URL: ${apiUrl}`));
8113
8202
  try {
8114
8203
  const FormData4 = (await import("formdata-node")).FormData;
8115
8204
  const Blob2 = (await import("formdata-node")).Blob;
@@ -8127,24 +8216,24 @@ async function updateDb(sqlFiles, projectName) {
8127
8216
  formData.append("file", new Blob2([content], {
8128
8217
  type: "application/sql"
8129
8218
  }), filename);
8130
- console.log(import_chalk20.default.gray(` Including: ${filename} (${content.length} bytes)`));
8219
+ console.log(import_chalk21.default.gray(` Including: ${filename} (${content.length} bytes)`));
8131
8220
  }
8132
8221
  const response = await axios_default.post(apiUrl, formData, {
8133
8222
  headers: { ...headers },
8134
8223
  timeout: 12e4
8135
8224
  });
8136
- console.log(import_chalk20.default.gray(` Response: ${JSON.stringify(response.data)}`));
8225
+ console.log(import_chalk21.default.gray(` Response: ${JSON.stringify(response.data)}`));
8137
8226
  if (response.data.code === 200) {
8138
- console.log(import_chalk20.default.green("SQL files imported successfully!"));
8227
+ console.log(import_chalk21.default.green("SQL files imported successfully!"));
8139
8228
  const results = response.data.data.results;
8140
8229
  for (const result of results) {
8141
8230
  if (result.status === "complete") {
8142
- console.log(import_chalk20.default.green(` COMPLETE ${result.filename}: ${result.num_queries} queries, ${result.duration}ms`));
8231
+ console.log(import_chalk21.default.green(` COMPLETE ${result.filename}: ${result.num_queries} queries, ${result.duration}ms`));
8143
8232
  if (result.changes !== void 0) {
8144
- console.log(import_chalk20.default.gray(` Changes: ${result.changes}, Read: ${result.rows_read}, Written: ${result.rows_written}`));
8233
+ console.log(import_chalk21.default.gray(` Changes: ${result.changes}, Read: ${result.rows_read}, Written: ${result.rows_written}`));
8145
8234
  }
8146
8235
  } else if (result.status === "error") {
8147
- console.log(import_chalk20.default.red(` ERROR ${result.filename}: ${result.error}`));
8236
+ console.log(import_chalk21.default.red(` ERROR ${result.filename}: ${result.error}`));
8148
8237
  }
8149
8238
  }
8150
8239
  } else {
@@ -8178,8 +8267,8 @@ async function updateDbCmd(options) {
8178
8267
  if (import_fs_extra9.default.existsSync(tokenFileSrc) && !import_fs_extra9.default.existsSync(tokenFileDst)) {
8179
8268
  import_fs_extra9.default.copySync(tokenFileSrc, tokenFileDst);
8180
8269
  }
8181
- console.log(import_chalk20.default.blue("Importing SQL to database...\n"));
8182
- console.log(import_chalk20.default.gray(`Project dir: ${PROJECT_DIR3}`));
8270
+ console.log(import_chalk21.default.blue("Importing SQL to database...\n"));
8271
+ console.log(import_chalk21.default.gray(`Project dir: ${PROJECT_DIR3}`));
8183
8272
  const config = loadConfig2();
8184
8273
  const projectName = config.project_name;
8185
8274
  if (!projectName) {
@@ -8187,11 +8276,11 @@ async function updateDbCmd(options) {
8187
8276
  'Set `project_name = "your-project-name"` in `pinme.toml`.'
8188
8277
  ]);
8189
8278
  }
8190
- console.log(import_chalk20.default.gray(`Project: ${projectName}`));
8279
+ console.log(import_chalk21.default.gray(`Project: ${projectName}`));
8191
8280
  const sqlFiles = getSqlFiles2();
8192
- console.log(import_chalk20.default.gray(`Found ${sqlFiles.length} SQL file(s) in db`));
8281
+ console.log(import_chalk21.default.gray(`Found ${sqlFiles.length} SQL file(s) in db`));
8193
8282
  await updateDb(sqlFiles, projectName);
8194
- console.log(import_chalk20.default.green("\nDatabase update complete."));
8283
+ console.log(import_chalk21.default.green("\nDatabase update complete."));
8195
8284
  process.exit(0);
8196
8285
  } catch (error) {
8197
8286
  printCliError(error, "Database update failed.");
@@ -8200,12 +8289,11 @@ async function updateDbCmd(options) {
8200
8289
  }
8201
8290
 
8202
8291
  // bin/updateWorker.ts
8203
- var import_chalk21 = __toESM(require("chalk"));
8292
+ var import_chalk22 = __toESM(require("chalk"));
8204
8293
  var import_fs_extra10 = __toESM(require("fs-extra"));
8205
8294
  var import_path15 = __toESM(require("path"));
8206
8295
  var import_child_process5 = require("child_process");
8207
8296
  var PROJECT_DIR4 = process.cwd();
8208
- var API_BASE4 = "https://pinme.benny1996.win/api/v4";
8209
8297
  function loadConfig3() {
8210
8298
  const configPath = import_path15.default.join(PROJECT_DIR4, "pinme.toml");
8211
8299
  if (!import_fs_extra10.default.existsSync(configPath)) {
@@ -8229,13 +8317,13 @@ function getMetadata2() {
8229
8317
  return import_fs_extra10.default.readJsonSync(metadataPath);
8230
8318
  }
8231
8319
  function buildWorker2() {
8232
- console.log(import_chalk21.default.blue("Building worker..."));
8320
+ console.log(import_chalk22.default.blue("Building worker..."));
8233
8321
  try {
8234
8322
  (0, import_child_process5.execSync)("npm run build:worker", {
8235
8323
  cwd: PROJECT_DIR4,
8236
8324
  stdio: "inherit"
8237
8325
  });
8238
- console.log(import_chalk21.default.green("Worker built"));
8326
+ console.log(import_chalk22.default.green("Worker built"));
8239
8327
  } catch (error) {
8240
8328
  throw createCommandError("worker build", "npm run build:worker", error, [
8241
8329
  "Fix the build error shown above, then rerun `pinme update-worker`."
@@ -8265,14 +8353,14 @@ function getBuiltWorker2() {
8265
8353
  return { workerJsPath, modulePaths };
8266
8354
  }
8267
8355
  async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
8268
- console.log(import_chalk21.default.blue("Updating worker on platform..."));
8269
- console.log(import_chalk21.default.gray(`Project: ${projectName}`));
8270
- console.log(import_chalk21.default.gray(`workerJsPath: ${workerJsPath}`));
8271
- console.log(import_chalk21.default.gray(`modulePaths: ${modulePaths}`));
8272
- console.log(import_chalk21.default.gray(`metadata: ${metadata}`));
8273
- const apiUrl = `${API_BASE4}/update_worker?project_name=${encodeURIComponent(projectName)}`;
8356
+ console.log(import_chalk22.default.blue("Updating worker on platform..."));
8357
+ console.log(import_chalk22.default.gray(`Project: ${projectName}`));
8358
+ console.log(import_chalk22.default.gray(`workerJsPath: ${workerJsPath}`));
8359
+ console.log(import_chalk22.default.gray(`modulePaths: ${modulePaths}`));
8360
+ console.log(import_chalk22.default.gray(`metadata: ${metadata}`));
8361
+ const apiUrl = `${getPinmeApiUrl("/update_worker")}?project_name=${encodeURIComponent(projectName)}`;
8274
8362
  const headers = getAuthHeaders();
8275
- console.log(import_chalk21.default.gray(`API URL: ${apiUrl}`));
8363
+ console.log(import_chalk22.default.gray(`API URL: ${apiUrl}`));
8276
8364
  try {
8277
8365
  const FormData4 = (await import("formdata-node")).FormData;
8278
8366
  const Blob2 = (await import("formdata-node")).Blob;
@@ -8295,33 +8383,33 @@ async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
8295
8383
  headers: { ...headers },
8296
8384
  timeout: 12e4
8297
8385
  });
8298
- console.log(import_chalk21.default.gray(` Response: ${JSON.stringify(response.data)}`));
8386
+ console.log(import_chalk22.default.gray(` Response: ${JSON.stringify(response.data)}`));
8299
8387
  if (response.data) {
8300
- console.log(import_chalk21.default.green("Worker updated"));
8388
+ console.log(import_chalk22.default.green("Worker updated"));
8301
8389
  const data = response.data.data;
8302
8390
  if (data.worker_id) {
8303
- console.log(import_chalk21.default.gray(` Worker ID: ${data.worker_id}`));
8391
+ console.log(import_chalk22.default.gray(` Worker ID: ${data.worker_id}`));
8304
8392
  }
8305
8393
  if (data.deployment_id) {
8306
- console.log(import_chalk21.default.gray(` Deployment ID: ${data.deployment_id}`));
8394
+ console.log(import_chalk22.default.gray(` Deployment ID: ${data.deployment_id}`));
8307
8395
  }
8308
8396
  if (data.entry_point) {
8309
- console.log(import_chalk21.default.gray(` Entry Point: ${data.entry_point}`));
8397
+ console.log(import_chalk22.default.gray(` Entry Point: ${data.entry_point}`));
8310
8398
  }
8311
8399
  if (data.created_on) {
8312
- console.log(import_chalk21.default.gray(` Created: ${data.created_on}`));
8400
+ console.log(import_chalk22.default.gray(` Created: ${data.created_on}`));
8313
8401
  }
8314
8402
  if (data.modified_on) {
8315
- console.log(import_chalk21.default.gray(` Modified: ${data.modified_on}`));
8403
+ console.log(import_chalk22.default.gray(` Modified: ${data.modified_on}`));
8316
8404
  }
8317
8405
  if (data.startup_time_ms !== void 0) {
8318
- console.log(import_chalk21.default.gray(` Startup Time: ${data.startup_time_ms}ms`));
8406
+ console.log(import_chalk22.default.gray(` Startup Time: ${data.startup_time_ms}ms`));
8319
8407
  }
8320
8408
  if (data.has_modules !== void 0) {
8321
- console.log(import_chalk21.default.gray(` Has Modules: ${data.has_modules}`));
8409
+ console.log(import_chalk22.default.gray(` Has Modules: ${data.has_modules}`));
8322
8410
  }
8323
8411
  if (data.domain) {
8324
- console.log(import_chalk21.default.gray(` Domain: ${data.domain}`));
8412
+ console.log(import_chalk22.default.gray(` Domain: ${data.domain}`));
8325
8413
  }
8326
8414
  } else {
8327
8415
  throw createApiError("worker update", { response: { data: response.data } }, [
@@ -8354,8 +8442,8 @@ async function updateWorkerCmd(options) {
8354
8442
  if (import_fs_extra10.default.existsSync(tokenFileSrc) && !import_fs_extra10.default.existsSync(tokenFileDst)) {
8355
8443
  import_fs_extra10.default.copySync(tokenFileSrc, tokenFileDst);
8356
8444
  }
8357
- console.log(import_chalk21.default.blue("Updating worker...\n"));
8358
- console.log(import_chalk21.default.gray(`Project dir: ${PROJECT_DIR4}`));
8445
+ console.log(import_chalk22.default.blue("Updating worker...\n"));
8446
+ console.log(import_chalk22.default.gray(`Project dir: ${PROJECT_DIR4}`));
8359
8447
  const config = loadConfig3();
8360
8448
  const projectName = config.project_name;
8361
8449
  if (!projectName) {
@@ -8363,16 +8451,16 @@ async function updateWorkerCmd(options) {
8363
8451
  'Set `project_name = "your-project-name"` in `pinme.toml`.'
8364
8452
  ]);
8365
8453
  }
8366
- console.log(import_chalk21.default.gray(`Project: ${projectName}`));
8367
- console.log(import_chalk21.default.blue("\n--- Worker Update ---"));
8454
+ console.log(import_chalk22.default.gray(`Project: ${projectName}`));
8455
+ console.log(import_chalk22.default.blue("\n--- Worker Update ---"));
8368
8456
  buildWorker2();
8369
8457
  const metadata = getMetadata2();
8370
8458
  const { workerJsPath, modulePaths } = getBuiltWorker2();
8371
- console.log(import_chalk21.default.gray(`Worker JS: ${workerJsPath}`));
8372
- console.log(import_chalk21.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
8373
- console.log(import_chalk21.default.gray(`SQL files: ignored (not processed for update_worker)`));
8459
+ console.log(import_chalk22.default.gray(`Worker JS: ${workerJsPath}`));
8460
+ console.log(import_chalk22.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
8461
+ console.log(import_chalk22.default.gray(`SQL files: ignored (not processed for update_worker)`));
8374
8462
  await updateWorker(workerJsPath, modulePaths, metadata, projectName);
8375
- console.log(import_chalk21.default.green("\nWorker update complete."));
8463
+ console.log(import_chalk22.default.green("\nWorker update complete."));
8376
8464
  process.exit(0);
8377
8465
  } catch (error) {
8378
8466
  printCliError(error, "Worker update failed.");
@@ -8381,7 +8469,7 @@ async function updateWorkerCmd(options) {
8381
8469
  }
8382
8470
 
8383
8471
  // bin/updateWeb.ts
8384
- var import_chalk22 = __toESM(require("chalk"));
8472
+ var import_chalk23 = __toESM(require("chalk"));
8385
8473
  var import_fs_extra11 = __toESM(require("fs-extra"));
8386
8474
  var import_path16 = __toESM(require("path"));
8387
8475
  var import_child_process6 = require("child_process");
@@ -8400,34 +8488,29 @@ function loadConfig4() {
8400
8488
  };
8401
8489
  }
8402
8490
  function buildFrontend2() {
8403
- console.log(import_chalk22.default.blue("Building frontend..."));
8491
+ console.log(import_chalk23.default.blue("Building frontend..."));
8404
8492
  try {
8405
8493
  (0, import_child_process6.execSync)("npm run build:frontend", {
8406
8494
  cwd: PROJECT_DIR5,
8407
8495
  stdio: "inherit"
8408
8496
  });
8409
- console.log(import_chalk22.default.green("Frontend built"));
8497
+ console.log(import_chalk23.default.green("Frontend built"));
8410
8498
  } catch (error) {
8411
8499
  throw createCommandError("frontend build", "npm run build:frontend", error, [
8412
8500
  "Fix the frontend build error shown above, then rerun `pinme update-web`."
8413
8501
  ]);
8414
8502
  }
8415
8503
  }
8416
- function deployFrontend2(projectName) {
8417
- console.log(import_chalk22.default.blue("Deploying frontend to IPFS..."));
8504
+ async function deployFrontend2(projectName) {
8505
+ console.log(import_chalk23.default.blue("Deploying frontend to IPFS..."));
8418
8506
  try {
8419
- (0, import_child_process6.execSync)("pinme upload ./frontend/dist", {
8420
- cwd: PROJECT_DIR5,
8421
- stdio: "inherit",
8422
- env: {
8423
- ...process.env,
8424
- PINME_PROJECT_NAME: projectName
8425
- }
8507
+ const uploadResult = await uploadPath(import_path16.default.join(PROJECT_DIR5, "frontend", "dist"), {
8508
+ projectName
8426
8509
  });
8427
- console.log(import_chalk22.default.green("Frontend deployed to IPFS"));
8510
+ console.log(import_chalk23.default.green(`Frontend deployed to IPFS: ${uploadResult.publicUrl}`));
8428
8511
  } catch (error) {
8429
- throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
8430
- "Make sure `frontend/dist` exists and `pinme upload` can run successfully."
8512
+ throw createCommandError("frontend deploy", "upload frontend/dist", error, [
8513
+ "Make sure `frontend/dist` exists and the upload API is reachable."
8431
8514
  ]);
8432
8515
  }
8433
8516
  }
@@ -8445,8 +8528,8 @@ async function updateWebCmd(options) {
8445
8528
  if (import_fs_extra11.default.existsSync(tokenFileSrc) && !import_fs_extra11.default.existsSync(tokenFileDst)) {
8446
8529
  import_fs_extra11.default.copySync(tokenFileSrc, tokenFileDst);
8447
8530
  }
8448
- console.log(import_chalk22.default.blue("Updating web (frontend)...\n"));
8449
- console.log(import_chalk22.default.gray(`Project dir: ${PROJECT_DIR5}`));
8531
+ console.log(import_chalk23.default.blue("Updating web (frontend)...\n"));
8532
+ console.log(import_chalk23.default.gray(`Project dir: ${PROJECT_DIR5}`));
8450
8533
  const config = loadConfig4();
8451
8534
  const projectName = config.project_name;
8452
8535
  if (!projectName) {
@@ -8454,11 +8537,11 @@ async function updateWebCmd(options) {
8454
8537
  'Set `project_name = "your-project-name"` in `pinme.toml`.'
8455
8538
  ]);
8456
8539
  }
8457
- console.log(import_chalk22.default.gray(`Project: ${projectName}`));
8458
- console.log(import_chalk22.default.blue("\n--- Frontend Update ---"));
8540
+ console.log(import_chalk23.default.gray(`Project: ${projectName}`));
8541
+ console.log(import_chalk23.default.blue("\n--- Frontend Update ---"));
8459
8542
  buildFrontend2();
8460
- deployFrontend2(projectName);
8461
- console.log(import_chalk22.default.green("\nWeb update complete."));
8543
+ await deployFrontend2(projectName);
8544
+ console.log(import_chalk23.default.green("\nWeb update complete."));
8462
8545
  process.exit(0);
8463
8546
  } catch (error) {
8464
8547
  printCliError(error, "Web update failed.");
@@ -8467,11 +8550,10 @@ async function updateWebCmd(options) {
8467
8550
  }
8468
8551
 
8469
8552
  // bin/delete.ts
8470
- var import_chalk23 = __toESM(require("chalk"));
8553
+ var import_chalk24 = __toESM(require("chalk"));
8471
8554
  var import_inquirer9 = __toESM(require("inquirer"));
8472
8555
  var import_fs_extra12 = __toESM(require("fs-extra"));
8473
8556
  var import_path17 = __toESM(require("path"));
8474
- var API_BASE5 = "https://pinme.benny1996.win/api/v4";
8475
8557
  function getProjectName() {
8476
8558
  const configPath = import_path17.default.join(process.cwd(), "pinme.toml");
8477
8559
  if (!import_fs_extra12.default.existsSync(configPath)) {
@@ -8482,27 +8564,27 @@ function getProjectName() {
8482
8564
  return (match == null ? void 0 : match[1]) || null;
8483
8565
  }
8484
8566
  async function deleteCmd(options) {
8485
- var _a, _b;
8567
+ var _a2, _b;
8486
8568
  try {
8487
8569
  const headers = getAuthHeaders();
8488
8570
  if (!headers["authentication-tokens"] || !headers["token-address"]) {
8489
- console.log(import_chalk23.default.yellow("\n\u26A0\uFE0F You are not logged in."));
8490
- console.log(import_chalk23.default.gray("Please run: pinme login"));
8571
+ console.log(import_chalk24.default.yellow("\n\u26A0\uFE0F You are not logged in."));
8572
+ console.log(import_chalk24.default.gray("Please run: pinme login"));
8491
8573
  process.exit(1);
8492
8574
  }
8493
- console.log(import_chalk23.default.blue("Deleting project...\n"));
8575
+ console.log(import_chalk24.default.blue("Deleting project...\n"));
8494
8576
  let projectName = options.name || getProjectName();
8495
8577
  if (!projectName) {
8496
- console.log(import_chalk23.default.red("\n\u274C Error: Cannot find project name."));
8497
- console.log(import_chalk23.default.yellow(" Please make sure you are in the project directory."));
8498
- console.log(import_chalk23.default.gray(" The project directory should contain a pinme.toml file."));
8499
- console.log(import_chalk23.default.gray("\n Or specify the project name:"));
8500
- console.log(import_chalk23.default.gray(" cd /path/to/your-project"));
8501
- console.log(import_chalk23.default.gray(" pinme delete"));
8578
+ console.log(import_chalk24.default.red("\n\u274C Error: Cannot find project name."));
8579
+ console.log(import_chalk24.default.yellow(" Please make sure you are in the project directory."));
8580
+ console.log(import_chalk24.default.gray(" The project directory should contain a pinme.toml file."));
8581
+ console.log(import_chalk24.default.gray("\n Or specify the project name:"));
8582
+ console.log(import_chalk24.default.gray(" cd /path/to/your-project"));
8583
+ console.log(import_chalk24.default.gray(" pinme delete"));
8502
8584
  process.exit(1);
8503
8585
  }
8504
- console.log(import_chalk23.default.gray(`Project: ${projectName}`));
8505
- console.log(import_chalk23.default.gray(`Directory: ${process.cwd()}`));
8586
+ console.log(import_chalk24.default.gray(`Project: ${projectName}`));
8587
+ console.log(import_chalk24.default.gray(`Directory: ${process.cwd()}`));
8506
8588
  if (!options.force) {
8507
8589
  const answers = await import_inquirer9.default.prompt([
8508
8590
  {
@@ -8513,14 +8595,14 @@ async function deleteCmd(options) {
8513
8595
  }
8514
8596
  ]);
8515
8597
  if (!answers.confirm) {
8516
- console.log(import_chalk23.default.gray("Cancelled."));
8598
+ console.log(import_chalk24.default.gray("Cancelled."));
8517
8599
  process.exit(0);
8518
8600
  }
8519
8601
  }
8520
- console.log(import_chalk23.default.blue("Deleting project on platform..."));
8521
- const apiUrl = `${API_BASE5}/delete_project`;
8522
- console.log(import_chalk23.default.gray(`API URL: ${apiUrl}`));
8523
- console.log(import_chalk23.default.gray(`Project name: ${projectName}`));
8602
+ console.log(import_chalk24.default.blue("Deleting project on platform..."));
8603
+ const apiUrl = getPinmeApiUrl("/delete_project");
8604
+ console.log(import_chalk24.default.gray(`API URL: ${apiUrl}`));
8605
+ console.log(import_chalk24.default.gray(`Project name: ${projectName}`));
8524
8606
  const response = await axios_default.post(apiUrl, {
8525
8607
  project_name: projectName
8526
8608
  }, {
@@ -8529,33 +8611,33 @@ async function deleteCmd(options) {
8529
8611
  "Content-Type": "application/json"
8530
8612
  }
8531
8613
  }).catch((error) => {
8532
- var _a2, _b2;
8614
+ var _a3, _b2;
8533
8615
  if (error.response) {
8534
- console.log(import_chalk23.default.red(` Response status: ${(_a2 = error.response) == null ? void 0 : _a2.status}`));
8535
- console.log(import_chalk23.default.red(` Response data: ${JSON.stringify((_b2 = error.response) == null ? void 0 : _b2.data)}`));
8616
+ console.log(import_chalk24.default.red(` Response status: ${(_a3 = error.response) == null ? void 0 : _a3.status}`));
8617
+ console.log(import_chalk24.default.red(` Response data: ${JSON.stringify((_b2 = error.response) == null ? void 0 : _b2.data)}`));
8536
8618
  } else {
8537
- console.log(import_chalk23.default.red("No Response"));
8619
+ console.log(import_chalk24.default.red("No Response"));
8538
8620
  }
8539
8621
  throw error;
8540
8622
  });
8541
8623
  const data = response.data;
8542
8624
  if (data.code === 200) {
8543
- console.log(import_chalk23.default.green("\n\u2705 Project deleted successfully!"));
8544
- console.log(import_chalk23.default.gray(`
8625
+ console.log(import_chalk24.default.green("\n\u2705 Project deleted successfully!"));
8626
+ console.log(import_chalk24.default.gray(`
8545
8627
  Project: ${data.data.project_name}`));
8546
- console.log(import_chalk23.default.gray(` Domain deleted: ${data.data.domain_deleted ? "\u2705" : "\u274C"}`));
8547
- console.log(import_chalk23.default.gray(` Worker deleted: ${data.data.worker_deleted ? "\u2705" : "\u274C"}`));
8548
- console.log(import_chalk23.default.gray(` Database deleted: ${data.data.database_deleted ? "\u2705" : "\u274C"}`));
8549
- console.log(import_chalk23.default.gray("\nLocal files are kept unchanged."));
8628
+ console.log(import_chalk24.default.gray(` Domain deleted: ${data.data.domain_deleted ? "\u2705" : "\u274C"}`));
8629
+ console.log(import_chalk24.default.gray(` Worker deleted: ${data.data.worker_deleted ? "\u2705" : "\u274C"}`));
8630
+ console.log(import_chalk24.default.gray(` Database deleted: ${data.data.database_deleted ? "\u2705" : "\u274C"}`));
8631
+ console.log(import_chalk24.default.gray("\nLocal files are kept unchanged."));
8550
8632
  } else {
8551
8633
  const errorMsg = (data == null ? void 0 : data.msg) || "Failed to delete project";
8552
8634
  throw new Error(errorMsg);
8553
8635
  }
8554
8636
  process.exit(0);
8555
8637
  } catch (error) {
8556
- console.log(import_chalk23.default.red(error));
8557
- const errorMsg = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) || error.message || "Failed to delete project";
8558
- console.error(import_chalk23.default.red(`
8638
+ console.log(import_chalk24.default.red(error));
8639
+ const errorMsg = ((_b = (_a2 = error.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.msg) || error.message || "Failed to delete project";
8640
+ console.error(import_chalk24.default.red(`
8559
8641
  \u274C Error: ${errorMsg}`));
8560
8642
  process.exit(1);
8561
8643
  }
@@ -8566,9 +8648,9 @@ import_dotenv.default.config();
8566
8648
  checkNodeVersion();
8567
8649
  function showBanner() {
8568
8650
  console.log(
8569
- import_chalk24.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
8651
+ import_chalk25.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
8570
8652
  );
8571
- console.log(import_chalk24.default.cyan("A command-line tool for uploading files to IPFS\n"));
8653
+ console.log(import_chalk25.default.cyan("A command-line tool for uploading files to IPFS\n"));
8572
8654
  }
8573
8655
  var program = new import_commander.Command();
8574
8656
  program.name("pinme").version(version).option("-v, --version", "output the current version");
@@ -8585,7 +8667,8 @@ program.command("set-appkey").description(
8585
8667
  program.command("logout").description("log out and clear authentication").action(() => logoutCmd());
8586
8668
  program.command("show-appkey").alias("appkey").description("show current AppKey information (masked)").action(() => showAppKeyCmd());
8587
8669
  program.command("my-domains").alias("domain").description("List domains owned by current account").action(() => myDomainsCmd());
8588
- program.command("bind").description("Upload and bind to a domain (requires VIP)").option("-d, --domain <name>", "Domain name to bind").option("--dns", "Force DNS domain mode").action(() => bindCmd());
8670
+ program.command("wallet").alias("wallet-balance").alias("balance").description("Show current wallet balance").action(() => walletBalanceCmd());
8671
+ program.command("bind").description("Upload and bind to a domain (requires wallet balance)").option("-d, --domain <name>", "Domain name to bind").option("--dns", "Force DNS domain mode").action(() => bindCmd());
8589
8672
  program.command("create").description("Create a new project from template").argument("[name]", "Project name").option("-f, --force", "Overwrite if exists").action((name, options) => createCmd({ name, force: options == null ? void 0 : options.force }));
8590
8673
  program.command("save").description("Deploy the project (frontend + backend)").action((options) => saveCmd(options));
8591
8674
  program.command("update-db").description("Execute database migration").action(() => updateDbCmd());