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