pinme 2.0.2-beta.2 → 2.0.2-beta.3

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