pinme 2.0.0-beta.2 → 2.0.0-beta.21
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 +1544 -962
- package/package.json +32 -32
- package/template/README.md +0 -177
- package/template/backend/package.json +0 -12
- package/template/backend/schema/001_init.sql +0 -35
- package/template/backend/src/worker.ts +0 -108
- package/template/backend/wrangler.toml +0 -11
- package/template/frontend/.env.example +0 -4
- package/template/frontend/index.html +0 -12
- package/template/frontend/package.json +0 -25
- package/template/frontend/pnpm-lock.yaml +0 -1119
- package/template/frontend/src/App.css +0 -389
- package/template/frontend/src/App.tsx +0 -38
- package/template/frontend/src/components/Header.tsx +0 -29
- package/template/frontend/src/main.tsx +0 -21
- package/template/frontend/src/pages/About/index.tsx +0 -39
- package/template/frontend/src/pages/Demo/index.tsx +0 -87
- package/template/frontend/src/pages/Home/index.tsx +0 -94
- package/template/frontend/src/utils/api.ts +0 -6
- package/template/frontend/src/vite-env.d.ts +0 -1
- package/template/frontend/tsconfig.json +0 -22
- package/template/frontend/tsconfig.node.json +0 -11
- package/template/frontend/vite.config.ts +0 -27
- package/template/package.json +0 -16
- package/template/pinme.toml +0 -18
- package/template/pnpm-workspace.yaml +0 -3
package/dist/index.js
CHANGED
|
@@ -96,8 +96,8 @@ var require_package = __commonJS({
|
|
|
96
96
|
// node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/lib/main.js
|
|
97
97
|
var require_main = __commonJS({
|
|
98
98
|
"node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/lib/main.js"(exports2, module2) {
|
|
99
|
-
var
|
|
100
|
-
var
|
|
99
|
+
var fs16 = require("fs");
|
|
100
|
+
var path17 = require("path");
|
|
101
101
|
var os5 = require("os");
|
|
102
102
|
var crypto3 = require("crypto");
|
|
103
103
|
var packageJson = require_package();
|
|
@@ -200,7 +200,7 @@ var require_main = __commonJS({
|
|
|
200
200
|
if (options && options.path && options.path.length > 0) {
|
|
201
201
|
if (Array.isArray(options.path)) {
|
|
202
202
|
for (const filepath of options.path) {
|
|
203
|
-
if (
|
|
203
|
+
if (fs16.existsSync(filepath)) {
|
|
204
204
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
205
205
|
}
|
|
206
206
|
}
|
|
@@ -208,15 +208,15 @@ var require_main = __commonJS({
|
|
|
208
208
|
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
209
209
|
}
|
|
210
210
|
} else {
|
|
211
|
-
possibleVaultPath =
|
|
211
|
+
possibleVaultPath = path17.resolve(process.cwd(), ".env.vault");
|
|
212
212
|
}
|
|
213
|
-
if (
|
|
213
|
+
if (fs16.existsSync(possibleVaultPath)) {
|
|
214
214
|
return possibleVaultPath;
|
|
215
215
|
}
|
|
216
216
|
return null;
|
|
217
217
|
}
|
|
218
218
|
function _resolveHome(envPath) {
|
|
219
|
-
return envPath[0] === "~" ?
|
|
219
|
+
return envPath[0] === "~" ? path17.join(os5.homedir(), envPath.slice(1)) : envPath;
|
|
220
220
|
}
|
|
221
221
|
function _configVault(options) {
|
|
222
222
|
const debug = Boolean(options && options.debug);
|
|
@@ -232,7 +232,7 @@ var require_main = __commonJS({
|
|
|
232
232
|
return { parsed };
|
|
233
233
|
}
|
|
234
234
|
function configDotenv(options) {
|
|
235
|
-
const dotenvPath =
|
|
235
|
+
const dotenvPath = path17.resolve(process.cwd(), ".env");
|
|
236
236
|
let encoding = "utf8";
|
|
237
237
|
const debug = Boolean(options && options.debug);
|
|
238
238
|
if (options && options.encoding) {
|
|
@@ -255,13 +255,13 @@ var require_main = __commonJS({
|
|
|
255
255
|
}
|
|
256
256
|
let lastError;
|
|
257
257
|
const parsedAll = {};
|
|
258
|
-
for (const
|
|
258
|
+
for (const path18 of optionPaths) {
|
|
259
259
|
try {
|
|
260
|
-
const parsed = DotenvModule.parse(
|
|
260
|
+
const parsed = DotenvModule.parse(fs16.readFileSync(path18, { encoding }));
|
|
261
261
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
262
262
|
} catch (e) {
|
|
263
263
|
if (debug) {
|
|
264
|
-
_debug(`Failed to load ${
|
|
264
|
+
_debug(`Failed to load ${path18} ${e.message}`);
|
|
265
265
|
}
|
|
266
266
|
lastError = e;
|
|
267
267
|
}
|
|
@@ -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-beta.
|
|
1526
|
+
var version = "2.0.0-beta.21";
|
|
1527
1527
|
|
|
1528
1528
|
// bin/upload.ts
|
|
1529
1529
|
var import_path7 = __toESM(require("path"));
|
|
@@ -1968,9 +1968,9 @@ function isVisitable(thing) {
|
|
|
1968
1968
|
function removeBrackets(key) {
|
|
1969
1969
|
return utils_default.endsWith(key, "[]") ? key.slice(0, -2) : key;
|
|
1970
1970
|
}
|
|
1971
|
-
function renderKey(
|
|
1972
|
-
if (!
|
|
1973
|
-
return
|
|
1971
|
+
function renderKey(path17, key, dots) {
|
|
1972
|
+
if (!path17) return key;
|
|
1973
|
+
return path17.concat(key).map(function each(token, i) {
|
|
1974
1974
|
token = removeBrackets(token);
|
|
1975
1975
|
return !dots && i ? "[" + token + "]" : token;
|
|
1976
1976
|
}).join(dots ? "." : "");
|
|
@@ -2015,9 +2015,9 @@ function toFormData(obj, formData, options) {
|
|
|
2015
2015
|
}
|
|
2016
2016
|
return value;
|
|
2017
2017
|
}
|
|
2018
|
-
function defaultVisitor(value, key,
|
|
2018
|
+
function defaultVisitor(value, key, path17) {
|
|
2019
2019
|
let arr = value;
|
|
2020
|
-
if (value && !
|
|
2020
|
+
if (value && !path17 && typeof value === "object") {
|
|
2021
2021
|
if (utils_default.endsWith(key, "{}")) {
|
|
2022
2022
|
key = metaTokens ? key : key.slice(0, -2);
|
|
2023
2023
|
value = JSON.stringify(value);
|
|
@@ -2036,7 +2036,7 @@ function toFormData(obj, formData, options) {
|
|
|
2036
2036
|
if (isVisitable(value)) {
|
|
2037
2037
|
return true;
|
|
2038
2038
|
}
|
|
2039
|
-
formData.append(renderKey(
|
|
2039
|
+
formData.append(renderKey(path17, key, dots), convertValue(value));
|
|
2040
2040
|
return false;
|
|
2041
2041
|
}
|
|
2042
2042
|
const stack = [];
|
|
@@ -2045,10 +2045,10 @@ function toFormData(obj, formData, options) {
|
|
|
2045
2045
|
convertValue,
|
|
2046
2046
|
isVisitable
|
|
2047
2047
|
});
|
|
2048
|
-
function build(value,
|
|
2048
|
+
function build(value, path17) {
|
|
2049
2049
|
if (utils_default.isUndefined(value)) return;
|
|
2050
2050
|
if (stack.indexOf(value) !== -1) {
|
|
2051
|
-
throw Error("Circular reference detected in " +
|
|
2051
|
+
throw Error("Circular reference detected in " + path17.join("."));
|
|
2052
2052
|
}
|
|
2053
2053
|
stack.push(value);
|
|
2054
2054
|
utils_default.forEach(value, function each(el, key) {
|
|
@@ -2056,11 +2056,11 @@ function toFormData(obj, formData, options) {
|
|
|
2056
2056
|
formData,
|
|
2057
2057
|
el,
|
|
2058
2058
|
utils_default.isString(key) ? key.trim() : key,
|
|
2059
|
-
|
|
2059
|
+
path17,
|
|
2060
2060
|
exposedHelpers
|
|
2061
2061
|
);
|
|
2062
2062
|
if (result === true) {
|
|
2063
|
-
build(el,
|
|
2063
|
+
build(el, path17 ? path17.concat(key) : [key]);
|
|
2064
2064
|
}
|
|
2065
2065
|
});
|
|
2066
2066
|
stack.pop();
|
|
@@ -2221,7 +2221,7 @@ var node_default = {
|
|
|
2221
2221
|
// node_modules/.pnpm/axios@1.3.2/node_modules/axios/lib/helpers/toURLEncodedForm.js
|
|
2222
2222
|
function toURLEncodedForm(data, options) {
|
|
2223
2223
|
return toFormData_default(data, new node_default.classes.URLSearchParams(), Object.assign({
|
|
2224
|
-
visitor: function(value, key,
|
|
2224
|
+
visitor: function(value, key, path17, helpers) {
|
|
2225
2225
|
if (node_default.isNode && utils_default.isBuffer(value)) {
|
|
2226
2226
|
this.append(key, value.toString("base64"));
|
|
2227
2227
|
return false;
|
|
@@ -2250,10 +2250,10 @@ function arrayToObject(arr) {
|
|
|
2250
2250
|
return obj;
|
|
2251
2251
|
}
|
|
2252
2252
|
function formDataToJSON(formData) {
|
|
2253
|
-
function buildPath(
|
|
2254
|
-
let name =
|
|
2253
|
+
function buildPath(path17, value, target, index) {
|
|
2254
|
+
let name = path17[index++];
|
|
2255
2255
|
const isNumericKey = Number.isFinite(+name);
|
|
2256
|
-
const isLast = index >=
|
|
2256
|
+
const isLast = index >= path17.length;
|
|
2257
2257
|
name = !name && utils_default.isArray(target) ? target.length : name;
|
|
2258
2258
|
if (isLast) {
|
|
2259
2259
|
if (utils_default.hasOwnProp(target, name)) {
|
|
@@ -2266,7 +2266,7 @@ function formDataToJSON(formData) {
|
|
|
2266
2266
|
if (!target[name] || !utils_default.isObject(target[name])) {
|
|
2267
2267
|
target[name] = [];
|
|
2268
2268
|
}
|
|
2269
|
-
const result = buildPath(
|
|
2269
|
+
const result = buildPath(path17, value, target[name], index);
|
|
2270
2270
|
if (result && utils_default.isArray(target[name])) {
|
|
2271
2271
|
target[name] = arrayToObject(target[name]);
|
|
2272
2272
|
}
|
|
@@ -3328,9 +3328,9 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3328
3328
|
auth = urlUsername + ":" + urlPassword;
|
|
3329
3329
|
}
|
|
3330
3330
|
auth && headers.delete("authorization");
|
|
3331
|
-
let
|
|
3331
|
+
let path17;
|
|
3332
3332
|
try {
|
|
3333
|
-
|
|
3333
|
+
path17 = buildURL(
|
|
3334
3334
|
parsed.pathname + parsed.search,
|
|
3335
3335
|
config.params,
|
|
3336
3336
|
config.paramsSerializer
|
|
@@ -3348,7 +3348,7 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config) {
|
|
|
3348
3348
|
false
|
|
3349
3349
|
);
|
|
3350
3350
|
const options = {
|
|
3351
|
-
path:
|
|
3351
|
+
path: path17,
|
|
3352
3352
|
method,
|
|
3353
3353
|
headers: headers.toJSON(),
|
|
3354
3354
|
agents: { http: config.httpAgent, https: config.httpsAgent },
|
|
@@ -3567,14 +3567,14 @@ var cookies_default = node_default.isStandardBrowserEnv ? (
|
|
|
3567
3567
|
// Standard browser envs support document.cookie
|
|
3568
3568
|
/* @__PURE__ */ function standardBrowserEnv() {
|
|
3569
3569
|
return {
|
|
3570
|
-
write: function write(name, value, expires,
|
|
3570
|
+
write: function write(name, value, expires, path17, domain, secure) {
|
|
3571
3571
|
const cookie = [];
|
|
3572
3572
|
cookie.push(name + "=" + encodeURIComponent(value));
|
|
3573
3573
|
if (utils_default.isNumber(expires)) {
|
|
3574
3574
|
cookie.push("expires=" + new Date(expires).toGMTString());
|
|
3575
3575
|
}
|
|
3576
|
-
if (utils_default.isString(
|
|
3577
|
-
cookie.push("path=" +
|
|
3576
|
+
if (utils_default.isString(path17)) {
|
|
3577
|
+
cookie.push("path=" + path17);
|
|
3578
3578
|
}
|
|
3579
3579
|
if (utils_default.isString(domain)) {
|
|
3580
3580
|
cookie.push("domain=" + domain);
|
|
@@ -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,119 +4584,615 @@ 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");
|
|
4667
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");
|
|
4746
|
+
}
|
|
4747
|
+
return { address, token };
|
|
4668
4748
|
}
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
);
|
|
4674
|
-
}
|
|
4675
|
-
createProgressBar(progress, width = 20) {
|
|
4676
|
-
const percentage = Math.min(progress, 1);
|
|
4677
|
-
const filledWidth = Math.round(width * percentage);
|
|
4678
|
-
const emptyWidth = width - filledWidth;
|
|
4679
|
-
return `[${"\u2588".repeat(filledWidth)}${"\u2591".repeat(emptyWidth)}]`;
|
|
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);
|
|
4680
4753
|
}
|
|
4681
|
-
|
|
4682
|
-
if (
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4754
|
+
closeServer() {
|
|
4755
|
+
if (this.server) {
|
|
4756
|
+
this.server.close();
|
|
4757
|
+
this.server = null;
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
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;
|
|
4777
|
+
}
|
|
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;
|
|
4789
|
+
}
|
|
4790
|
+
@keyframes bgPulse {
|
|
4791
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
4792
|
+
50% { opacity: 0.8; transform: scale(1.05); }
|
|
4793
|
+
}
|
|
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;
|
|
4806
|
+
}
|
|
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); }
|
|
4810
|
+
}
|
|
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);
|
|
4826
|
+
}
|
|
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;
|
|
4839
|
+
}
|
|
4840
|
+
@keyframes borderGlow {
|
|
4841
|
+
0%, 100% { opacity: 0.3; }
|
|
4842
|
+
50% { opacity: 0.7; }
|
|
4843
|
+
}
|
|
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));
|
|
4849
|
+
}
|
|
4850
|
+
@keyframes bounceIn {
|
|
4851
|
+
0% { transform: scale(0); opacity: 0; }
|
|
4852
|
+
50% { transform: scale(1.2); }
|
|
4853
|
+
100% { transform: scale(1); opacity: 1; }
|
|
4854
|
+
}
|
|
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;
|
|
4864
|
+
}
|
|
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;
|
|
4870
|
+
}
|
|
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;
|
|
4879
|
+
}
|
|
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); }
|
|
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>`;
|
|
4904
|
+
}
|
|
4905
|
+
getErrorHtml(error) {
|
|
4906
|
+
const encodedError = encodeURIComponent(error);
|
|
4907
|
+
return `
|
|
4908
|
+
<!DOCTYPE html>
|
|
4909
|
+
<html>
|
|
4910
|
+
<head>
|
|
4911
|
+
<title>Login Failed - PinMe</title>
|
|
4912
|
+
<style>
|
|
4913
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
4914
|
+
body {
|
|
4915
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
4916
|
+
display: flex;
|
|
4917
|
+
justify-content: center;
|
|
4918
|
+
align-items: center;
|
|
4919
|
+
min-height: 100vh;
|
|
4920
|
+
background: #000;
|
|
4921
|
+
overflow: hidden;
|
|
4922
|
+
}
|
|
4923
|
+
.bg {
|
|
4924
|
+
position: fixed;
|
|
4925
|
+
top: 0;
|
|
4926
|
+
left: 0;
|
|
4927
|
+
width: 100%;
|
|
4928
|
+
height: 100%;
|
|
4929
|
+
background:
|
|
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%);
|
|
4933
|
+
animation: bgPulse 6s ease-in-out infinite;
|
|
4934
|
+
}
|
|
4935
|
+
@keyframes bgPulse {
|
|
4936
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
4937
|
+
50% { opacity: 0.8; transform: scale(1.05); }
|
|
4938
|
+
}
|
|
4939
|
+
.grid {
|
|
4940
|
+
position: fixed;
|
|
4941
|
+
top: 0;
|
|
4942
|
+
left: 0;
|
|
4943
|
+
width: 200%;
|
|
4944
|
+
height: 200%;
|
|
4945
|
+
background-image:
|
|
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);
|
|
4948
|
+
background-size: 50px 50px;
|
|
4949
|
+
transform: perspective(500px) rotateX(60deg) translateY(-50%) translateZ(-200px);
|
|
4950
|
+
animation: gridMove 20s linear infinite;
|
|
4951
|
+
}
|
|
4952
|
+
@keyframes gridMove {
|
|
4953
|
+
0% { transform: perspective(500px) rotateX(60deg) translateY(0) translateZ(-200px); }
|
|
4954
|
+
100% { transform: perspective(500px) rotateX(60deg) translateY(50px) translateZ(-200px); }
|
|
4955
|
+
}
|
|
4956
|
+
.container {
|
|
4957
|
+
position: relative;
|
|
4958
|
+
z-index: 10;
|
|
4959
|
+
background: linear-gradient(135deg, rgba(40, 20, 20, 0.9) 0%, rgba(30, 10, 10, 0.95) 100%);
|
|
4960
|
+
padding: 3.5rem 4rem;
|
|
4961
|
+
border-radius: 32px;
|
|
4962
|
+
box-shadow:
|
|
4963
|
+
0 0 60px rgba(255, 50, 50, 0.15),
|
|
4964
|
+
0 25px 50px rgba(0, 0, 0, 0.5),
|
|
4965
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.1),
|
|
4966
|
+
inset 0 -1px 0 rgba(255, 50, 50, 0.1);
|
|
4967
|
+
text-align: center;
|
|
4968
|
+
border: 1px solid rgba(255, 50, 50, 0.2);
|
|
4969
|
+
max-width: 440px;
|
|
4970
|
+
backdrop-filter: blur(30px);
|
|
4971
|
+
}
|
|
4972
|
+
.container::before {
|
|
4973
|
+
content: '';
|
|
4974
|
+
position: absolute;
|
|
4975
|
+
top: -1px;
|
|
4976
|
+
left: -1px;
|
|
4977
|
+
right: -1px;
|
|
4978
|
+
bottom: -1px;
|
|
4979
|
+
border-radius: 32px;
|
|
4980
|
+
background: linear-gradient(135deg, rgba(255, 50, 50, 0.5), rgba(255, 150, 50, 0.5), rgba(150, 0, 50, 0.5));
|
|
4981
|
+
z-index: -1;
|
|
4982
|
+
opacity: 0.5;
|
|
4983
|
+
animation: borderGlow 3s ease-in-out infinite;
|
|
4984
|
+
}
|
|
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`;
|
|
4693
5189
|
}
|
|
4694
5190
|
}
|
|
4695
5191
|
};
|
|
4696
5192
|
async function calculateMD5(filePath) {
|
|
4697
5193
|
return new Promise((resolve, reject) => {
|
|
4698
|
-
const hash =
|
|
4699
|
-
const stream4 =
|
|
5194
|
+
const hash = crypto2.createHash("md5");
|
|
5195
|
+
const stream4 = import_fs_extra5.default.createReadStream(filePath);
|
|
4700
5196
|
stream4.on("data", hash.update.bind(hash));
|
|
4701
5197
|
stream4.on("end", () => resolve(hash.digest("hex")));
|
|
4702
5198
|
stream4.on("error", reject);
|
|
@@ -4705,20 +5201,20 @@ async function calculateMD5(filePath) {
|
|
|
4705
5201
|
async function compressDirectory(sourcePath) {
|
|
4706
5202
|
return new Promise((resolve, reject) => {
|
|
4707
5203
|
const tempDir = require("os").tmpdir();
|
|
4708
|
-
if (!
|
|
4709
|
-
|
|
5204
|
+
if (!import_fs_extra5.default.existsSync(tempDir)) {
|
|
5205
|
+
import_fs_extra5.default.mkdirSync(tempDir, { recursive: true });
|
|
4710
5206
|
}
|
|
4711
|
-
const outputPath =
|
|
5207
|
+
const outputPath = import_path6.default.join(
|
|
4712
5208
|
tempDir,
|
|
4713
|
-
`pinme_${
|
|
5209
|
+
`pinme_${import_path6.default.basename(sourcePath)}_${Date.now()}.zip`
|
|
4714
5210
|
);
|
|
4715
|
-
const output =
|
|
5211
|
+
const output = import_fs_extra5.default.createWriteStream(outputPath);
|
|
4716
5212
|
const zlib2 = require("zlib");
|
|
4717
5213
|
const gzip = zlib2.createGzip({ level: 9 });
|
|
4718
5214
|
output.on("close", () => resolve(outputPath));
|
|
4719
5215
|
gzip.on("error", reject);
|
|
4720
5216
|
gzip.pipe(output);
|
|
4721
|
-
const stats =
|
|
5217
|
+
const stats = import_fs_extra5.default.statSync(sourcePath);
|
|
4722
5218
|
if (stats.isDirectory()) {
|
|
4723
5219
|
const archive = require("archiver");
|
|
4724
5220
|
const archiveStream = archive("zip", { zlib: { level: 9 } });
|
|
@@ -4727,14 +5223,14 @@ async function compressDirectory(sourcePath) {
|
|
|
4727
5223
|
archiveStream.directory(sourcePath, false);
|
|
4728
5224
|
archiveStream.finalize();
|
|
4729
5225
|
} else {
|
|
4730
|
-
const fileStream =
|
|
5226
|
+
const fileStream = import_fs_extra5.default.createReadStream(sourcePath);
|
|
4731
5227
|
fileStream.pipe(gzip);
|
|
4732
5228
|
}
|
|
4733
5229
|
});
|
|
4734
5230
|
}
|
|
4735
5231
|
async function initChunkSession(filePath, deviceId, isDirectory = false) {
|
|
4736
|
-
const stats =
|
|
4737
|
-
const fileName =
|
|
5232
|
+
const stats = import_fs_extra5.default.statSync(filePath);
|
|
5233
|
+
const fileName = import_path6.default.basename(filePath);
|
|
4738
5234
|
const fileSize = stats.size;
|
|
4739
5235
|
const md5 = await calculateMD5(filePath);
|
|
4740
5236
|
try {
|
|
@@ -4835,7 +5331,7 @@ async function delayWithAbortCheck(delay, signal) {
|
|
|
4835
5331
|
});
|
|
4836
5332
|
}
|
|
4837
5333
|
async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, deviceId, progressBar) {
|
|
4838
|
-
const fileData =
|
|
5334
|
+
const fileData = import_fs_extra5.default.readFileSync(filePath);
|
|
4839
5335
|
const abortController = new AbortController();
|
|
4840
5336
|
let completedCount = 0;
|
|
4841
5337
|
let hasFatalError = false;
|
|
@@ -4887,17 +5383,27 @@ async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, dev
|
|
|
4887
5383
|
}
|
|
4888
5384
|
}
|
|
4889
5385
|
async function completeChunkUpload(sessionId, deviceId, importAsCar = false) {
|
|
5386
|
+
var _a;
|
|
4890
5387
|
try {
|
|
4891
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 = {};
|
|
4892
5391
|
if (importAsCar) {
|
|
4893
5392
|
requestBody.import_as_car = true;
|
|
4894
5393
|
}
|
|
5394
|
+
if (projectName) {
|
|
5395
|
+
requestBody.project_name = projectName;
|
|
5396
|
+
authHeaders = getAuthHeaders();
|
|
5397
|
+
}
|
|
4895
5398
|
const response = await axios_default.post(
|
|
4896
5399
|
`${IPFS_API_URL}/chunk/complete`,
|
|
4897
5400
|
requestBody,
|
|
4898
5401
|
{
|
|
4899
5402
|
timeout: TIMEOUT,
|
|
4900
|
-
headers: {
|
|
5403
|
+
headers: {
|
|
5404
|
+
"Content-Type": "application/json",
|
|
5405
|
+
...authHeaders
|
|
5406
|
+
}
|
|
4901
5407
|
}
|
|
4902
5408
|
);
|
|
4903
5409
|
const { code, msg, data } = response.data;
|
|
@@ -4909,525 +5415,214 @@ async function completeChunkUpload(sessionId, deviceId, importAsCar = false) {
|
|
|
4909
5415
|
if (axios_default.isAxiosError(error)) {
|
|
4910
5416
|
throw new Error(`Network error: ${error.message}`);
|
|
4911
5417
|
}
|
|
4912
|
-
throw error;
|
|
4913
|
-
}
|
|
4914
|
-
}
|
|
4915
|
-
async function getChunkStatus(sessionId, deviceId) {
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
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: 3e3,
|
|
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();
|
|
5181
|
-
}
|
|
5182
|
-
}
|
|
5183
|
-
generateLoginToken() {
|
|
5184
|
-
return import_crypto.default.randomBytes(32).toString("hex");
|
|
5185
|
-
}
|
|
5186
|
-
async startCallbackServer() {
|
|
5187
|
-
return new Promise((resolve, reject) => {
|
|
5188
|
-
this.server = import_http3.default.createServer(async (req, res) => {
|
|
5189
|
-
try {
|
|
5190
|
-
const url2 = new import_url2.URL(req.url || "", `http://localhost:${this.config.callbackPort}`);
|
|
5191
|
-
if (url2.pathname === this.config.callbackPath) {
|
|
5192
|
-
const authToken = url2.searchParams.get("token");
|
|
5193
|
-
const error = url2.searchParams.get("error");
|
|
5194
|
-
const loginToken = url2.searchParams.get("login_token");
|
|
5195
|
-
if (error) {
|
|
5196
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
5197
|
-
res.end(this.getErrorHtml(error));
|
|
5198
|
-
if (this.rejectPromise) {
|
|
5199
|
-
this.rejectPromise(new Error(error));
|
|
5200
|
-
}
|
|
5201
|
-
return;
|
|
5202
|
-
}
|
|
5203
|
-
if (!authToken) {
|
|
5204
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
5205
|
-
res.end(this.getErrorHtml("Auth token not received"));
|
|
5206
|
-
if (this.rejectPromise) {
|
|
5207
|
-
this.rejectPromise(new Error("Auth token not received"));
|
|
5208
|
-
}
|
|
5209
|
-
return;
|
|
5210
|
-
}
|
|
5211
|
-
if (loginToken !== this.loginToken) {
|
|
5212
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
5213
|
-
res.end(this.getErrorHtml("Login token invalid or expired"));
|
|
5214
|
-
if (this.rejectPromise) {
|
|
5215
|
-
this.rejectPromise(new Error("Login token invalid or expired"));
|
|
5216
|
-
}
|
|
5217
|
-
return;
|
|
5218
|
-
}
|
|
5219
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
5220
|
-
res.end(this.getSuccessHtml());
|
|
5221
|
-
if (this.resolvePromise) {
|
|
5222
|
-
this.resolvePromise(authToken);
|
|
5223
|
-
}
|
|
5224
|
-
} else {
|
|
5225
|
-
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
5226
|
-
res.end("Not Found");
|
|
5227
|
-
}
|
|
5228
|
-
} catch (err) {
|
|
5229
|
-
console.error("Callback error:", err);
|
|
5230
|
-
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
5231
|
-
res.end("Internal Server Error");
|
|
5232
|
-
}
|
|
5233
|
-
});
|
|
5234
|
-
this.server.on("error", (err) => {
|
|
5235
|
-
reject(err);
|
|
5236
|
-
});
|
|
5237
|
-
this.server.listen(this.config.callbackPort, "127.0.0.1", () => {
|
|
5238
|
-
console.log(import_chalk3.default.gray(`Local server: http://localhost:${this.config.callbackPort}`));
|
|
5239
|
-
resolve();
|
|
5240
|
-
});
|
|
5241
|
-
setTimeout(() => {
|
|
5242
|
-
if (this.rejectPromise) {
|
|
5243
|
-
this.rejectPromise(new Error("Login timeout, please try again"));
|
|
5244
|
-
}
|
|
5245
|
-
this.closeServer();
|
|
5246
|
-
}, 10 * 60 * 1e3);
|
|
5247
|
-
});
|
|
5248
|
-
}
|
|
5249
|
-
buildLoginUrl() {
|
|
5250
|
-
const callbackUrl = `http://localhost:${this.config.callbackPort}${this.config.callbackPath}`;
|
|
5251
|
-
const url2 = `${this.config.webBaseUrl}/#/cli-login?login_token=${this.loginToken}&callback_url=${encodeURIComponent(callbackUrl)}`;
|
|
5252
|
-
return url2;
|
|
5253
|
-
}
|
|
5254
|
-
waitForCallback() {
|
|
5255
|
-
return new Promise((resolve, reject) => {
|
|
5256
|
-
this.resolvePromise = resolve;
|
|
5257
|
-
this.rejectPromise = reject;
|
|
5258
|
-
});
|
|
5259
|
-
}
|
|
5260
|
-
parseAuthToken(authToken) {
|
|
5261
|
-
const firstDash = authToken.indexOf("-");
|
|
5262
|
-
if (firstDash <= 0 || firstDash === authToken.length - 1) {
|
|
5263
|
-
throw new Error("Invalid token format");
|
|
5264
|
-
}
|
|
5265
|
-
const address = authToken.slice(0, firstDash).trim();
|
|
5266
|
-
const token = authToken.slice(firstDash + 1).trim();
|
|
5267
|
-
if (!address || !token) {
|
|
5268
|
-
throw new Error("Token parsing failed: address or token is empty");
|
|
5269
|
-
}
|
|
5270
|
-
return { address, token };
|
|
5271
|
-
}
|
|
5272
|
-
saveAuthConfig(config) {
|
|
5273
|
-
import_fs_extra5.default.ensureDirSync(CONFIG_DIR2);
|
|
5274
|
-
import_fs_extra5.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
|
|
5275
|
-
import_fs_extra5.default.chmodSync(AUTH_FILE2, 384);
|
|
5276
|
-
}
|
|
5277
|
-
closeServer() {
|
|
5278
|
-
if (this.server) {
|
|
5279
|
-
this.server.close();
|
|
5280
|
-
this.server = null;
|
|
5281
|
-
}
|
|
5282
|
-
}
|
|
5283
|
-
// HTML templates
|
|
5284
|
-
getSuccessHtml() {
|
|
5285
|
-
return `
|
|
5286
|
-
<!DOCTYPE html>
|
|
5287
|
-
<html>
|
|
5288
|
-
<head>
|
|
5289
|
-
<title>Login Success - PinMe</title>
|
|
5290
|
-
<style>
|
|
5291
|
-
body {
|
|
5292
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
5293
|
-
display: flex;
|
|
5294
|
-
justify-content: center;
|
|
5295
|
-
align-items: center;
|
|
5296
|
-
height: 100vh;
|
|
5297
|
-
margin: 0;
|
|
5298
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
5299
|
-
}
|
|
5300
|
-
.container {
|
|
5301
|
-
background: white;
|
|
5302
|
-
padding: 3rem;
|
|
5303
|
-
border-radius: 12px;
|
|
5304
|
-
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
|
5305
|
-
text-align: center;
|
|
5306
|
-
max-width: 400px;
|
|
5307
|
-
}
|
|
5308
|
-
.success-icon {
|
|
5309
|
-
font-size: 4rem;
|
|
5310
|
-
margin-bottom: 1rem;
|
|
5311
|
-
}
|
|
5312
|
-
h1 {
|
|
5313
|
-
color: #1f2937;
|
|
5314
|
-
margin: 0 0 1rem 0;
|
|
5315
|
-
}
|
|
5316
|
-
p {
|
|
5317
|
-
color: #6b7280;
|
|
5318
|
-
margin: 0 0 2rem 0;
|
|
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);
|
|
5319
5431
|
}
|
|
5320
|
-
.
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
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;
|
|
5329
5442
|
}
|
|
5330
|
-
|
|
5331
|
-
|
|
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}`);
|
|
5332
5447
|
}
|
|
5333
|
-
|
|
5334
|
-
</head>
|
|
5335
|
-
<body>
|
|
5336
|
-
<div class="container">
|
|
5337
|
-
<div class="success-icon">\u2705</div>
|
|
5338
|
-
<h1>Login Successful!</h1>
|
|
5339
|
-
<p>You have successfully logged in to PinMe CLI.</p>
|
|
5340
|
-
<p>You can close this window and return to the command line.</p>
|
|
5341
|
-
<button id="closeBtn" class="close-btn">Close Window</button>
|
|
5342
|
-
<p id="message" style="color: #6b7280; margin-top: 1rem;"></p>
|
|
5343
|
-
</div>
|
|
5344
|
-
<script>
|
|
5345
|
-
// For redirected pages, show message instead of auto-close
|
|
5346
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
5347
|
-
document.getElementById('closeBtn').addEventListener('click', function() {
|
|
5348
|
-
// Try to close, fallback to showing message
|
|
5349
|
-
try {
|
|
5350
|
-
window.close();
|
|
5351
|
-
} catch (e) {
|
|
5352
|
-
document.getElementById('message').textContent = 'You can close this window manually.';
|
|
5353
|
-
}
|
|
5354
|
-
});
|
|
5355
|
-
});
|
|
5356
|
-
</script>
|
|
5357
|
-
</body>
|
|
5358
|
-
</html>`;
|
|
5359
|
-
}
|
|
5360
|
-
getErrorHtml(error) {
|
|
5361
|
-
const encodedError = encodeURIComponent(error);
|
|
5362
|
-
return `
|
|
5363
|
-
<!DOCTYPE html>
|
|
5364
|
-
<html>
|
|
5365
|
-
<head>
|
|
5366
|
-
<title>Login Failed - PinMe</title>
|
|
5367
|
-
<style>
|
|
5368
|
-
body { font-family: sans-serif; padding: 2rem; text-align: center; background: #f3f4f6; }
|
|
5369
|
-
.container { background: white; padding: 2rem; border-radius: 12px; max-width: 400px; margin: 0 auto; }
|
|
5370
|
-
.error { color: #dc2626; font-size: 1.25rem; margin: 1rem 0; }
|
|
5371
|
-
button { padding: 0.5rem 1rem; cursor: pointer; background: #3b82f6; color: white; border: none; border-radius: 6px; }
|
|
5372
|
-
</style>
|
|
5373
|
-
</head>
|
|
5374
|
-
<body>
|
|
5375
|
-
<div class="container">
|
|
5376
|
-
<h2>Login Failed</h2>
|
|
5377
|
-
<div class="error">${error}</div>
|
|
5378
|
-
<button onclick="window.close()">Close</button>
|
|
5379
|
-
</div>
|
|
5380
|
-
</body>
|
|
5381
|
-
</html>`;
|
|
5448
|
+
throw error;
|
|
5382
5449
|
}
|
|
5383
|
-
}
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
const
|
|
5387
|
-
if (
|
|
5388
|
-
|
|
5450
|
+
}
|
|
5451
|
+
async function monitorChunkProgress(traceId, deviceId, progressBar) {
|
|
5452
|
+
let consecutiveErrors = 0;
|
|
5453
|
+
const startTime = Date.now();
|
|
5454
|
+
if (progressBar) {
|
|
5455
|
+
progressBar.startSimulatingProgress();
|
|
5389
5456
|
}
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
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));
|
|
5481
|
+
}
|
|
5482
|
+
const maxPollTimeMinutes = Math.floor(MAX_POLL_TIME / (60 * 1e3));
|
|
5483
|
+
throw new Error(`Polling timeout after ${maxPollTimeMinutes} minutes`);
|
|
5484
|
+
} finally {
|
|
5485
|
+
if (progressBar) {
|
|
5486
|
+
progressBar.stopSimulatingProgress();
|
|
5487
|
+
}
|
|
5394
5488
|
}
|
|
5395
|
-
const config = { address, token };
|
|
5396
|
-
import_fs_extra5.default.ensureDirSync(CONFIG_DIR2);
|
|
5397
|
-
import_fs_extra5.default.writeJsonSync(AUTH_FILE2, config, { spaces: 2 });
|
|
5398
|
-
return config;
|
|
5399
5489
|
}
|
|
5400
|
-
function
|
|
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
|
+
);
|
|
5498
|
+
}
|
|
5499
|
+
const progressBar = new StepProgressBar(import_path6.default.basename(directoryPath), true);
|
|
5401
5500
|
try {
|
|
5402
|
-
|
|
5403
|
-
const
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
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;
|
|
5408
5545
|
}
|
|
5409
5546
|
}
|
|
5410
|
-
function
|
|
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);
|
|
5411
5558
|
try {
|
|
5412
|
-
|
|
5413
|
-
|
|
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");
|
|
5414
5591
|
}
|
|
5592
|
+
progressBar.complete();
|
|
5593
|
+
return result;
|
|
5415
5594
|
} catch (error) {
|
|
5416
|
-
|
|
5595
|
+
progressBar.fail(error.message);
|
|
5596
|
+
throw error;
|
|
5417
5597
|
}
|
|
5418
5598
|
}
|
|
5419
|
-
function
|
|
5420
|
-
const
|
|
5421
|
-
if (!
|
|
5422
|
-
throw new Error("
|
|
5599
|
+
async function uploadToIpfsSplit_default(filePath, importAsCar = false) {
|
|
5600
|
+
const deviceId = getUid();
|
|
5601
|
+
if (!deviceId) {
|
|
5602
|
+
throw new Error("Device ID not found");
|
|
5603
|
+
}
|
|
5604
|
+
try {
|
|
5605
|
+
const isDirectory = import_fs_extra5.default.statSync(filePath).isDirectory();
|
|
5606
|
+
const result = isDirectory ? await uploadDirectoryInChunks(filePath, deviceId, importAsCar) : await uploadFileInChunks(filePath, deviceId, importAsCar);
|
|
5607
|
+
if (result == null ? void 0 : result.hash) {
|
|
5608
|
+
return {
|
|
5609
|
+
contentHash: result.hash,
|
|
5610
|
+
previewHash: null,
|
|
5611
|
+
shortUrl: result.shortUrl
|
|
5612
|
+
};
|
|
5613
|
+
}
|
|
5614
|
+
throw new Error("Upload failed: no hash returned");
|
|
5615
|
+
} catch (error) {
|
|
5616
|
+
throw error;
|
|
5423
5617
|
}
|
|
5424
|
-
return {
|
|
5425
|
-
"token-address": conf.address,
|
|
5426
|
-
"authentication-tokens": conf.token
|
|
5427
|
-
};
|
|
5428
5618
|
}
|
|
5429
5619
|
|
|
5620
|
+
// bin/upload.ts
|
|
5621
|
+
var import_fs2 = __toESM(require("fs"));
|
|
5622
|
+
var import_crypto_js = __toESM(require("crypto-js"));
|
|
5623
|
+
|
|
5430
5624
|
// bin/utils/pinmeApi.ts
|
|
5625
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
5431
5626
|
var DEFAULT_BASE = "https://pinme.dev/api/v4";
|
|
5432
5627
|
var TOKEN_EXPIRED_CODES = [
|
|
5433
5628
|
401,
|
|
@@ -5609,7 +5804,7 @@ async function isVip(tokenAddress, authToken) {
|
|
|
5609
5804
|
throw e;
|
|
5610
5805
|
}
|
|
5611
5806
|
}
|
|
5612
|
-
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";
|
|
5613
5808
|
function createCarClient() {
|
|
5614
5809
|
let headers = {};
|
|
5615
5810
|
try {
|
|
@@ -5740,6 +5935,31 @@ function checkPathSync(inputPath) {
|
|
|
5740
5935
|
return null;
|
|
5741
5936
|
}
|
|
5742
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
|
+
}
|
|
5743
5963
|
function getDomainFromArgs() {
|
|
5744
5964
|
const args = process.argv.slice(2);
|
|
5745
5965
|
const dIdx = args.findIndex((a) => a === "--domain" || a === "-d");
|
|
@@ -5865,40 +6085,40 @@ var upload_default = async (options) => {
|
|
|
5865
6085
|
throw e;
|
|
5866
6086
|
}
|
|
5867
6087
|
}
|
|
5868
|
-
console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
}
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
}
|
|
6088
|
+
console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
|
|
6089
|
+
let result;
|
|
6090
|
+
try {
|
|
6091
|
+
result = await uploadToIpfsSplit_default(absolutePath);
|
|
6092
|
+
} catch (error) {
|
|
6093
|
+
console.error(import_chalk5.default.red(`Upload error: ${error.message}`));
|
|
6094
|
+
process.exit(1);
|
|
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"));
|
|
5902
6122
|
process.exit(0);
|
|
5903
6123
|
}
|
|
5904
6124
|
const answer = await import_inquirer.default.prompt([
|
|
@@ -5957,39 +6177,39 @@ var upload_default = async (options) => {
|
|
|
5957
6177
|
}
|
|
5958
6178
|
}
|
|
5959
6179
|
console.log(import_chalk5.default.blue(`uploading ${absolutePath} to ipfs...`));
|
|
6180
|
+
let result;
|
|
5960
6181
|
try {
|
|
5961
|
-
|
|
5962
|
-
if (result) {
|
|
5963
|
-
const uid = getUid();
|
|
5964
|
-
const encryptedCID = encryptHash(result.contentHash, secretKey, uid);
|
|
5965
|
-
console.log(
|
|
5966
|
-
import_chalk5.default.cyan(
|
|
5967
|
-
import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
|
|
5968
|
-
)
|
|
5969
|
-
);
|
|
5970
|
-
console.log(import_chalk5.default.cyan(`URL:`));
|
|
5971
|
-
console.log(import_chalk5.default.cyan(`${URL3}${encryptedCID}`));
|
|
5972
|
-
if (domainArg) {
|
|
5973
|
-
console.log(
|
|
5974
|
-
import_chalk5.default.blue(
|
|
5975
|
-
`Binding domain: ${displayDomain} with CID: ${result.contentHash}`
|
|
5976
|
-
)
|
|
5977
|
-
);
|
|
5978
|
-
try {
|
|
5979
|
-
await bindDomain(domainArg, result.contentHash, isDns, authConfig);
|
|
5980
|
-
} catch (e) {
|
|
5981
|
-
if (e.message === "Token expired") {
|
|
5982
|
-
process.exit(1);
|
|
5983
|
-
}
|
|
5984
|
-
throw e;
|
|
5985
|
-
}
|
|
5986
|
-
}
|
|
5987
|
-
console.log(import_chalk5.default.green("\n\u{1F389} upload successful, program exit"));
|
|
5988
|
-
}
|
|
6182
|
+
result = await uploadToIpfsSplit_default(absolutePath);
|
|
5989
6183
|
} catch (error) {
|
|
5990
|
-
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"));
|
|
5991
6189
|
process.exit(1);
|
|
5992
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"));
|
|
5993
6213
|
process.exit(0);
|
|
5994
6214
|
}
|
|
5995
6215
|
} catch (error) {
|
|
@@ -6811,7 +7031,6 @@ async function bindCmd() {
|
|
|
6811
7031
|
return;
|
|
6812
7032
|
}
|
|
6813
7033
|
const isDns = dns || isDnsDomain2(domain);
|
|
6814
|
-
console.log(isDns, "isDns");
|
|
6815
7034
|
const displayDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
6816
7035
|
if (isDns) {
|
|
6817
7036
|
const validation = validateDnsDomain2(domain);
|
|
@@ -6894,14 +7113,6 @@ var ENV_URLS = {
|
|
|
6894
7113
|
};
|
|
6895
7114
|
async function loginCmd(options = {}) {
|
|
6896
7115
|
try {
|
|
6897
|
-
const existingAuth = getAuthConfig2();
|
|
6898
|
-
if (existingAuth) {
|
|
6899
|
-
console.log(import_chalk15.default.yellow("Already logged in"));
|
|
6900
|
-
console.log(import_chalk15.default.gray(` Address: ${existingAuth.address}`));
|
|
6901
|
-
console.log(import_chalk15.default.gray(" To re-login, please run: pinme logout\n"));
|
|
6902
|
-
process.exit(0);
|
|
6903
|
-
return;
|
|
6904
|
-
}
|
|
6905
7116
|
let webBaseUrl;
|
|
6906
7117
|
const env = (options.env || "prod").toLowerCase();
|
|
6907
7118
|
if (ENV_URLS[env]) {
|
|
@@ -6929,23 +7140,174 @@ Login failed: ${(e == null ? void 0 : e.message) || e}`));
|
|
|
6929
7140
|
}
|
|
6930
7141
|
|
|
6931
7142
|
// bin/create.ts
|
|
6932
|
-
var
|
|
7143
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
6933
7144
|
var import_fs_extra6 = __toESM(require("fs-extra"));
|
|
6934
7145
|
var import_path11 = __toESM(require("path"));
|
|
6935
7146
|
var import_inquirer8 = __toESM(require("inquirer"));
|
|
6936
|
-
var
|
|
7147
|
+
var import_child_process2 = require("child_process");
|
|
7148
|
+
|
|
7149
|
+
// bin/utils/cliError.ts
|
|
7150
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
7151
|
+
var CliError = class extends Error {
|
|
7152
|
+
stage;
|
|
7153
|
+
details;
|
|
7154
|
+
suggestions;
|
|
7155
|
+
cause;
|
|
7156
|
+
constructor(options) {
|
|
7157
|
+
super(options.summary);
|
|
7158
|
+
this.name = "CliError";
|
|
7159
|
+
this.stage = options.stage;
|
|
7160
|
+
this.details = options.details || [];
|
|
7161
|
+
this.suggestions = options.suggestions || [];
|
|
7162
|
+
this.cause = options.cause;
|
|
7163
|
+
}
|
|
7164
|
+
};
|
|
7165
|
+
function stringifyValue(value) {
|
|
7166
|
+
if (value === void 0 || value === null) {
|
|
7167
|
+
return "";
|
|
7168
|
+
}
|
|
7169
|
+
if (typeof value === "string") {
|
|
7170
|
+
return value;
|
|
7171
|
+
}
|
|
7172
|
+
try {
|
|
7173
|
+
return JSON.stringify(value);
|
|
7174
|
+
} catch (error) {
|
|
7175
|
+
return String(value);
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
function getApiMessage(data) {
|
|
7179
|
+
var _a, _b, _c;
|
|
7180
|
+
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);
|
|
7181
|
+
}
|
|
7182
|
+
function getBusinessCode(data) {
|
|
7183
|
+
if ((data == null ? void 0 : data.code) === void 0 || (data == null ? void 0 : data.code) === null) {
|
|
7184
|
+
return void 0;
|
|
7185
|
+
}
|
|
7186
|
+
return String(data.code);
|
|
7187
|
+
}
|
|
7188
|
+
function getBusinessMessage(data) {
|
|
7189
|
+
if (!(data == null ? void 0 : data.msg)) {
|
|
7190
|
+
return void 0;
|
|
7191
|
+
}
|
|
7192
|
+
return String(data.msg);
|
|
7193
|
+
}
|
|
7194
|
+
function dedupeSuggestions(suggestions) {
|
|
7195
|
+
return Array.from(new Set(suggestions.filter(Boolean)));
|
|
7196
|
+
}
|
|
7197
|
+
function createConfigError(summary, suggestions = []) {
|
|
7198
|
+
return new CliError({
|
|
7199
|
+
summary,
|
|
7200
|
+
stage: "configuration",
|
|
7201
|
+
suggestions
|
|
7202
|
+
});
|
|
7203
|
+
}
|
|
7204
|
+
function createCommandError(stage, command, error, suggestions = []) {
|
|
7205
|
+
const exitCode = (error == null ? void 0 : error.status) ?? (error == null ? void 0 : error.code);
|
|
7206
|
+
const signal = error == null ? void 0 : error.signal;
|
|
7207
|
+
const detailLines = [`Command: ${command}`];
|
|
7208
|
+
if (exitCode !== void 0) {
|
|
7209
|
+
detailLines.push(`Exit code: ${exitCode}`);
|
|
7210
|
+
}
|
|
7211
|
+
if (signal) {
|
|
7212
|
+
detailLines.push(`Signal: ${signal}`);
|
|
7213
|
+
}
|
|
7214
|
+
if (error == null ? void 0 : error.message) {
|
|
7215
|
+
detailLines.push(`Reason: ${error.message}`);
|
|
7216
|
+
}
|
|
7217
|
+
return new CliError({
|
|
7218
|
+
summary: `${stage} failed.`,
|
|
7219
|
+
stage,
|
|
7220
|
+
details: detailLines,
|
|
7221
|
+
suggestions,
|
|
7222
|
+
cause: error
|
|
7223
|
+
});
|
|
7224
|
+
}
|
|
7225
|
+
function createApiError(stage, error, context = [], suggestions = []) {
|
|
7226
|
+
var _a, _b;
|
|
7227
|
+
const status = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status;
|
|
7228
|
+
const responseData = (_b = error == null ? void 0 : error.response) == null ? void 0 : _b.data;
|
|
7229
|
+
const errorCode = error == null ? void 0 : error.code;
|
|
7230
|
+
const apiMessage = getApiMessage(responseData);
|
|
7231
|
+
const businessCode = getBusinessCode(responseData);
|
|
7232
|
+
const businessMessage = getBusinessMessage(responseData);
|
|
7233
|
+
const summary = apiMessage || (error == null ? void 0 : error.message) || `${stage} failed.`;
|
|
7234
|
+
const detailLines = [...context];
|
|
7235
|
+
if (status) {
|
|
7236
|
+
detailLines.push(`HTTP status: ${status}`);
|
|
7237
|
+
}
|
|
7238
|
+
if (businessCode) {
|
|
7239
|
+
detailLines.push(`Business code: ${businessCode}`);
|
|
7240
|
+
}
|
|
7241
|
+
if (businessMessage && businessMessage !== apiMessage) {
|
|
7242
|
+
detailLines.push(`Business message: ${businessMessage}`);
|
|
7243
|
+
}
|
|
7244
|
+
if (apiMessage && apiMessage !== summary) {
|
|
7245
|
+
detailLines.push(`Error message: ${apiMessage}`);
|
|
7246
|
+
}
|
|
7247
|
+
if (errorCode && errorCode !== "ERR_BAD_REQUEST" && !responseData) {
|
|
7248
|
+
detailLines.push(`Error code: ${errorCode}`);
|
|
7249
|
+
}
|
|
7250
|
+
if (!responseData && (error == null ? void 0 : error.message) && error.message !== apiMessage) {
|
|
7251
|
+
detailLines.push(`Reason: ${error.message}`);
|
|
7252
|
+
}
|
|
7253
|
+
return new CliError({
|
|
7254
|
+
summary,
|
|
7255
|
+
stage,
|
|
7256
|
+
details: detailLines,
|
|
7257
|
+
suggestions: dedupeSuggestions(suggestions),
|
|
7258
|
+
cause: error
|
|
7259
|
+
});
|
|
7260
|
+
}
|
|
7261
|
+
function normalizeCliError(error, fallbackSummary, suggestions = []) {
|
|
7262
|
+
if (error instanceof CliError) {
|
|
7263
|
+
return error;
|
|
7264
|
+
}
|
|
7265
|
+
if (error instanceof Error) {
|
|
7266
|
+
return new CliError({
|
|
7267
|
+
summary: error.message || fallbackSummary,
|
|
7268
|
+
suggestions: dedupeSuggestions(suggestions),
|
|
7269
|
+
cause: error
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
return new CliError({
|
|
7273
|
+
summary: fallbackSummary,
|
|
7274
|
+
details: [`Raw error: ${stringifyValue(error)}`],
|
|
7275
|
+
suggestions: dedupeSuggestions(suggestions),
|
|
7276
|
+
cause: error
|
|
7277
|
+
});
|
|
7278
|
+
}
|
|
7279
|
+
function printCliError(error, fallbackSummary) {
|
|
7280
|
+
const cliError = normalizeCliError(error, fallbackSummary);
|
|
7281
|
+
console.error(import_chalk16.default.red(`
|
|
7282
|
+
Error: ${cliError.message}`));
|
|
7283
|
+
if (cliError.stage) {
|
|
7284
|
+
console.error(import_chalk16.default.gray(`Stage: ${cliError.stage}`));
|
|
7285
|
+
}
|
|
7286
|
+
for (const detail of cliError.details) {
|
|
7287
|
+
console.error(import_chalk16.default.gray(detail));
|
|
7288
|
+
}
|
|
7289
|
+
if (cliError.suggestions.length > 0) {
|
|
7290
|
+
console.error(import_chalk16.default.yellow("\nNext steps:"));
|
|
7291
|
+
for (const suggestion of cliError.suggestions) {
|
|
7292
|
+
console.error(import_chalk16.default.yellow(`- ${suggestion}`));
|
|
7293
|
+
}
|
|
7294
|
+
}
|
|
7295
|
+
}
|
|
7296
|
+
|
|
7297
|
+
// bin/create.ts
|
|
6937
7298
|
var PROJECT_DIR = process.cwd();
|
|
6938
|
-
var API_BASE = "https://pinme.
|
|
7299
|
+
var API_BASE = "https://pinme.dev/api/v4";
|
|
7300
|
+
var TEMPLATE_REPO = "glitternetwork/pinme-worker-template";
|
|
7301
|
+
var TEMPLATE_ZIP_URL = `https://github.com/${TEMPLATE_REPO}/archive/refs/heads/main.zip`;
|
|
6939
7302
|
async function createCmd(options) {
|
|
6940
|
-
var _a, _b, _c, _d, _e, _f;
|
|
6941
7303
|
try {
|
|
6942
7304
|
const headers = getAuthHeaders();
|
|
6943
7305
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
7306
|
+
throw createConfigError("No valid local login session was found.", [
|
|
7307
|
+
"Run `pinme login` and retry."
|
|
7308
|
+
]);
|
|
6947
7309
|
}
|
|
6948
|
-
console.log(
|
|
7310
|
+
console.log(import_chalk17.default.blue("Creating new project from template...\n"));
|
|
6949
7311
|
let projectName = options.name;
|
|
6950
7312
|
if (!projectName) {
|
|
6951
7313
|
const answers = await import_inquirer8.default.prompt([
|
|
@@ -6966,7 +7328,7 @@ async function createCmd(options) {
|
|
|
6966
7328
|
}
|
|
6967
7329
|
const targetDir = import_path11.default.join(PROJECT_DIR, projectName);
|
|
6968
7330
|
if (import_fs_extra6.default.existsSync(targetDir) && !options.force) {
|
|
6969
|
-
console.log(
|
|
7331
|
+
console.log(import_chalk17.default.yellow(`
|
|
6970
7332
|
Directory "${projectName}" already exists.`));
|
|
6971
7333
|
const answers = await import_inquirer8.default.prompt([
|
|
6972
7334
|
{
|
|
@@ -6977,16 +7339,16 @@ Directory "${projectName}" already exists.`));
|
|
|
6977
7339
|
}
|
|
6978
7340
|
]);
|
|
6979
7341
|
if (!answers.overwrite) {
|
|
6980
|
-
console.log(
|
|
7342
|
+
console.log(import_chalk17.default.gray("Cancelled."));
|
|
6981
7343
|
process.exit(0);
|
|
6982
7344
|
}
|
|
6983
7345
|
import_fs_extra6.default.removeSync(targetDir);
|
|
6984
7346
|
}
|
|
6985
|
-
console.log(
|
|
7347
|
+
console.log(import_chalk17.default.blue("\n1. Creating worker and database..."));
|
|
6986
7348
|
const apiUrl = `${API_BASE}/create_worker`;
|
|
6987
|
-
console.log(
|
|
7349
|
+
console.log(import_chalk17.default.gray(`API URL: ${apiUrl}`));
|
|
6988
7350
|
const normalizedProjectName = projectName.toLowerCase();
|
|
6989
|
-
console.log(
|
|
7351
|
+
console.log(import_chalk17.default.gray(`Project name: ${normalizedProjectName}`));
|
|
6990
7352
|
let workerData;
|
|
6991
7353
|
try {
|
|
6992
7354
|
const response = await axios_default.post(apiUrl, {
|
|
@@ -6999,40 +7361,72 @@ Directory "${projectName}" already exists.`));
|
|
|
6999
7361
|
});
|
|
7000
7362
|
const data = response.data;
|
|
7001
7363
|
if (data.code !== 200) {
|
|
7002
|
-
|
|
7003
|
-
|
|
7364
|
+
throw createApiError("project creation", { response: { status: response.status, data } }, [
|
|
7365
|
+
`Project name: ${normalizedProjectName}`,
|
|
7366
|
+
`Endpoint: ${apiUrl}`
|
|
7367
|
+
]);
|
|
7004
7368
|
}
|
|
7005
7369
|
workerData = data.data;
|
|
7006
|
-
console.log(
|
|
7007
|
-
console.log(
|
|
7008
|
-
console.log(
|
|
7009
|
-
console.log(
|
|
7370
|
+
console.log(import_chalk17.default.gray(` API Response: ${JSON.stringify(workerData)}`));
|
|
7371
|
+
console.log(import_chalk17.default.green(` API Domain: ${workerData.api_domain}`));
|
|
7372
|
+
console.log(import_chalk17.default.green(` Project Name: ${workerData.project_name}`));
|
|
7373
|
+
console.log(import_chalk17.default.green(` D1 UUID: ${workerData.uuid}`));
|
|
7010
7374
|
} catch (error) {
|
|
7011
|
-
|
|
7012
|
-
|
|
7375
|
+
throw createApiError("project creation", error, [
|
|
7376
|
+
`Project name: ${normalizedProjectName}`,
|
|
7377
|
+
`Endpoint: ${apiUrl}`
|
|
7378
|
+
]);
|
|
7379
|
+
}
|
|
7380
|
+
console.log(import_chalk17.default.blue("\n2. Downloading template from repository..."));
|
|
7381
|
+
const zipPath = import_path11.default.join(PROJECT_DIR, "template.zip");
|
|
7382
|
+
let downloadSuccess = false;
|
|
7383
|
+
for (let attempt = 1; attempt <= 3 && !downloadSuccess; attempt++) {
|
|
7384
|
+
try {
|
|
7385
|
+
console.log(import_chalk17.default.gray(` Download attempt ${attempt}/3...`));
|
|
7386
|
+
(0, import_child_process2.execSync)(`curl -L --retry 3 --retry-delay 2 -o "${zipPath}" "${TEMPLATE_ZIP_URL}"`, {
|
|
7387
|
+
stdio: "inherit"
|
|
7388
|
+
});
|
|
7389
|
+
if (!import_fs_extra6.default.existsSync(zipPath) || import_fs_extra6.default.statSync(zipPath).size < 100) {
|
|
7390
|
+
throw new Error("Downloaded file is too small or empty");
|
|
7391
|
+
}
|
|
7392
|
+
downloadSuccess = true;
|
|
7393
|
+
} catch (downloadError) {
|
|
7394
|
+
console.log(import_chalk17.default.yellow(` Attempt ${attempt} failed: ${downloadError.message}`));
|
|
7395
|
+
if (import_fs_extra6.default.existsSync(zipPath)) {
|
|
7396
|
+
import_fs_extra6.default.removeSync(zipPath);
|
|
7397
|
+
}
|
|
7398
|
+
if (attempt === 3) {
|
|
7399
|
+
throw new Error(`Failed to download template after 3 attempts: ${downloadError.message}`);
|
|
7400
|
+
}
|
|
7401
|
+
}
|
|
7402
|
+
}
|
|
7403
|
+
try {
|
|
7404
|
+
(0, import_child_process2.execSync)(`unzip -o "${zipPath}" -d "${PROJECT_DIR}"`, {
|
|
7405
|
+
stdio: "inherit"
|
|
7406
|
+
});
|
|
7407
|
+
const subDir = import_path11.default.join(PROJECT_DIR, "pinme-worker-template-main");
|
|
7408
|
+
if (import_fs_extra6.default.existsSync(subDir)) {
|
|
7409
|
+
import_fs_extra6.default.copySync(subDir, targetDir);
|
|
7410
|
+
import_fs_extra6.default.removeSync(subDir);
|
|
7411
|
+
}
|
|
7412
|
+
import_fs_extra6.default.removeSync(zipPath);
|
|
7413
|
+
console.log(import_chalk17.default.green(` Template downloaded to: ${targetDir}`));
|
|
7414
|
+
} catch (error) {
|
|
7415
|
+
throw createCommandError("template extraction", `unzip -o "${zipPath}" -d "${PROJECT_DIR}"`, error, [
|
|
7416
|
+
"Check whether `unzip` is available and the downloaded template archive is valid."
|
|
7417
|
+
]);
|
|
7013
7418
|
}
|
|
7014
|
-
console.log(
|
|
7015
|
-
import_fs_extra6.default.copySync(TEMPLATE_DIR, targetDir);
|
|
7016
|
-
console.log(import_chalk16.default.green(` Template copied to: ${targetDir}`));
|
|
7017
|
-
console.log(import_chalk16.default.blue("\n3. Updating configuration..."));
|
|
7419
|
+
console.log(import_chalk17.default.blue("\n3. Updating configuration..."));
|
|
7018
7420
|
const configPath = import_path11.default.join(targetDir, "pinme.toml");
|
|
7019
7421
|
const config = import_fs_extra6.default.readFileSync(configPath, "utf-8");
|
|
7020
7422
|
let updatedConfig = config.replace(
|
|
7021
7423
|
/project_name = ".*"/,
|
|
7022
7424
|
`project_name = "${workerData.project_name}"`
|
|
7023
7425
|
);
|
|
7024
|
-
updatedConfig = updatedConfig.replace(
|
|
7025
|
-
/^VITE_WORKER_URL = ".*"$/m,
|
|
7026
|
-
`VITE_WORKER_URL = "${workerData.api_domain}"`
|
|
7027
|
-
);
|
|
7028
|
-
updatedConfig = updatedConfig.replace(
|
|
7029
|
-
/# database_id = ".*"/,
|
|
7030
|
-
`database_id = "${workerData.uuid}"`
|
|
7031
|
-
);
|
|
7032
7426
|
import_fs_extra6.default.writeFileSync(configPath, updatedConfig);
|
|
7033
|
-
console.log(
|
|
7034
|
-
console.log(
|
|
7035
|
-
console.log(
|
|
7427
|
+
console.log(import_chalk17.default.green(` Updated pinme.toml`));
|
|
7428
|
+
console.log(import_chalk17.default.gray(` metadata: ${workerData.metadata}`));
|
|
7429
|
+
console.log(import_chalk17.default.gray(` VITE_API_URL: ${workerData.api_domain}`));
|
|
7036
7430
|
const backendDir = import_path11.default.join(targetDir, "backend");
|
|
7037
7431
|
if (import_fs_extra6.default.existsSync(backendDir) && workerData.metadata) {
|
|
7038
7432
|
const metadataContent = typeof workerData.metadata === "string" ? workerData.metadata : JSON.stringify(workerData.metadata, null, 2);
|
|
@@ -7040,52 +7434,101 @@ Directory "${projectName}" already exists.`));
|
|
|
7040
7434
|
import_path11.default.join(backendDir, "metadata.json"),
|
|
7041
7435
|
metadataContent
|
|
7042
7436
|
);
|
|
7043
|
-
console.log(
|
|
7437
|
+
console.log(import_chalk17.default.green(` Saved metadata.json`));
|
|
7438
|
+
}
|
|
7439
|
+
const wranglerPath = import_path11.default.join(backendDir, "wrangler.toml");
|
|
7440
|
+
if (import_fs_extra6.default.existsSync(wranglerPath) && workerData.api_key) {
|
|
7441
|
+
let wranglerContent = import_fs_extra6.default.readFileSync(wranglerPath, "utf-8");
|
|
7442
|
+
wranglerContent = wranglerContent.replace(
|
|
7443
|
+
/^name = ".*"$/m,
|
|
7444
|
+
`name = "${workerData.project_name}"`
|
|
7445
|
+
);
|
|
7446
|
+
import_fs_extra6.default.writeFileSync(wranglerPath, wranglerContent);
|
|
7447
|
+
console.log(import_chalk17.default.green(` Updated backend/wrangler.toml API_KEY`));
|
|
7044
7448
|
}
|
|
7045
7449
|
const envExamplePath = import_path11.default.join(targetDir, "frontend", ".env.example");
|
|
7046
7450
|
const envPath = import_path11.default.join(targetDir, "frontend", ".env");
|
|
7047
7451
|
if (import_fs_extra6.default.existsSync(envExamplePath)) {
|
|
7048
7452
|
let envContent = import_fs_extra6.default.readFileSync(envExamplePath, "utf-8");
|
|
7049
7453
|
envContent = envContent.replace(/your-project/g, workerData.project_name);
|
|
7050
|
-
envContent = envContent.replace(
|
|
7051
|
-
/^VITE_WORKER_URL=.*$/m,
|
|
7052
|
-
`VITE_WORKER_URL=${workerData.api_domain}`
|
|
7053
|
-
);
|
|
7054
7454
|
envContent = envContent.replace(
|
|
7055
7455
|
/^VITE_API_URL=.*$/m,
|
|
7056
7456
|
`VITE_API_URL=${workerData.api_domain}`
|
|
7057
7457
|
);
|
|
7058
7458
|
import_fs_extra6.default.writeFileSync(envPath, envContent);
|
|
7059
|
-
console.log(
|
|
7459
|
+
console.log(import_chalk17.default.green(` Created frontend/.env file`));
|
|
7460
|
+
}
|
|
7461
|
+
console.log(import_chalk17.default.blue("\n4. Building frontend..."));
|
|
7462
|
+
try {
|
|
7463
|
+
(0, import_child_process2.execSync)("npm install", {
|
|
7464
|
+
cwd: targetDir,
|
|
7465
|
+
stdio: "inherit"
|
|
7466
|
+
});
|
|
7467
|
+
console.log(import_chalk17.default.green(" Project dependencies installed"));
|
|
7468
|
+
} catch (error) {
|
|
7469
|
+
throw createCommandError("project dependency install", "npm install", error, [
|
|
7470
|
+
"Check network connectivity and npm registry availability.",
|
|
7471
|
+
"Inspect the generated workspace `package.json` files for dependency conflicts."
|
|
7472
|
+
]);
|
|
7473
|
+
}
|
|
7474
|
+
const frontendDir = import_path11.default.join(targetDir, "frontend");
|
|
7475
|
+
if (import_fs_extra6.default.existsSync(frontendDir)) {
|
|
7476
|
+
try {
|
|
7477
|
+
(0, import_child_process2.execSync)("npm run build:frontend", {
|
|
7478
|
+
cwd: targetDir,
|
|
7479
|
+
stdio: "inherit"
|
|
7480
|
+
});
|
|
7481
|
+
console.log(import_chalk17.default.green(" Frontend built"));
|
|
7482
|
+
} catch (error) {
|
|
7483
|
+
throw createCommandError("frontend build", "npm run build:frontend", error, [
|
|
7484
|
+
"Fix the frontend build error shown above, then rerun `pinme create`."
|
|
7485
|
+
]);
|
|
7486
|
+
}
|
|
7487
|
+
console.log(import_chalk17.default.blue(" Uploading to IPFS..."));
|
|
7488
|
+
try {
|
|
7489
|
+
(0, import_child_process2.execSync)("pinme upload ./dist", {
|
|
7490
|
+
cwd: frontendDir,
|
|
7491
|
+
stdio: "inherit",
|
|
7492
|
+
env: {
|
|
7493
|
+
...process.env,
|
|
7494
|
+
PINME_PROJECT_NAME: workerData.project_name
|
|
7495
|
+
}
|
|
7496
|
+
});
|
|
7497
|
+
console.log(import_chalk17.default.green(" Frontend uploaded to IPFS"));
|
|
7498
|
+
} catch (error) {
|
|
7499
|
+
console.log(import_chalk17.default.yellow(" Warning: IPFS upload failed, you can upload manually later"));
|
|
7500
|
+
}
|
|
7060
7501
|
}
|
|
7061
|
-
console.log(
|
|
7062
|
-
console.log(
|
|
7502
|
+
console.log(import_chalk17.default.green("\nProject created successfully."));
|
|
7503
|
+
console.log(import_chalk17.default.gray(`
|
|
7063
7504
|
Project Details:`));
|
|
7064
|
-
console.log(
|
|
7065
|
-
console.log(
|
|
7066
|
-
console.log(
|
|
7505
|
+
console.log(import_chalk17.default.gray(` API Domain: ${workerData.api_domain}`));
|
|
7506
|
+
console.log(import_chalk17.default.gray(` Project Name: ${workerData.project_name}`));
|
|
7507
|
+
console.log(import_chalk17.default.gray(`
|
|
7067
7508
|
Next steps:`));
|
|
7068
|
-
console.log(
|
|
7069
|
-
console.log(
|
|
7509
|
+
console.log(import_chalk17.default.gray(` cd ${projectName}`));
|
|
7510
|
+
console.log(import_chalk17.default.gray(` pinme save`));
|
|
7070
7511
|
process.exit(0);
|
|
7071
7512
|
} catch (error) {
|
|
7072
|
-
|
|
7073
|
-
Error: ${error.message || error}`));
|
|
7513
|
+
printCliError(error, "Project creation failed.");
|
|
7074
7514
|
process.exit(1);
|
|
7075
7515
|
}
|
|
7076
7516
|
}
|
|
7077
7517
|
|
|
7078
7518
|
// bin/save.ts
|
|
7079
|
-
var
|
|
7519
|
+
var import_chalk18 = __toESM(require("chalk"));
|
|
7080
7520
|
var import_fs_extra7 = __toESM(require("fs-extra"));
|
|
7081
7521
|
var import_path12 = __toESM(require("path"));
|
|
7082
|
-
var
|
|
7522
|
+
var import_child_process3 = require("child_process");
|
|
7083
7523
|
var PROJECT_DIR2 = process.cwd();
|
|
7084
|
-
var API_BASE2 = "https://pinme.
|
|
7524
|
+
var API_BASE2 = "https://pinme.dev/api/v4";
|
|
7085
7525
|
function loadConfig() {
|
|
7086
7526
|
const configPath = import_path12.default.join(PROJECT_DIR2, "pinme.toml");
|
|
7087
7527
|
if (!import_fs_extra7.default.existsSync(configPath)) {
|
|
7088
|
-
throw
|
|
7528
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
7529
|
+
"Run this command from the Pinme project root.",
|
|
7530
|
+
"If the project has not been initialized yet, create or restore `pinme.toml` first."
|
|
7531
|
+
]);
|
|
7089
7532
|
}
|
|
7090
7533
|
const configContent = import_fs_extra7.default.readFileSync(configPath, "utf-8");
|
|
7091
7534
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7096,67 +7539,52 @@ function loadConfig() {
|
|
|
7096
7539
|
function getMetadata() {
|
|
7097
7540
|
const metadataPath = import_path12.default.join(PROJECT_DIR2, "backend", "metadata.json");
|
|
7098
7541
|
if (!import_fs_extra7.default.existsSync(metadataPath)) {
|
|
7099
|
-
console.log(
|
|
7542
|
+
console.log(import_chalk18.default.yellow(" Warning: metadata.json not found, using empty metadata"));
|
|
7100
7543
|
return {};
|
|
7101
7544
|
}
|
|
7102
7545
|
return import_fs_extra7.default.readJsonSync(metadataPath);
|
|
7103
7546
|
}
|
|
7104
7547
|
function buildWorker() {
|
|
7105
|
-
console.log(
|
|
7548
|
+
console.log(import_chalk18.default.blue("Building worker..."));
|
|
7106
7549
|
try {
|
|
7107
|
-
(0,
|
|
7550
|
+
(0, import_child_process3.execSync)("npm run build:worker", {
|
|
7108
7551
|
cwd: PROJECT_DIR2,
|
|
7109
7552
|
stdio: "inherit"
|
|
7110
7553
|
});
|
|
7111
|
-
console.log(
|
|
7554
|
+
console.log(import_chalk18.default.green("Worker built"));
|
|
7112
7555
|
} catch (error) {
|
|
7113
|
-
throw
|
|
7556
|
+
throw createCommandError("worker build", "npm run build:worker", error, [
|
|
7557
|
+
"Fix the build error shown above, then rerun `pinme save`."
|
|
7558
|
+
]);
|
|
7114
7559
|
}
|
|
7115
7560
|
}
|
|
7116
7561
|
function installDependencies() {
|
|
7117
|
-
console.log(
|
|
7562
|
+
console.log(import_chalk18.default.blue("Installing dependencies..."));
|
|
7118
7563
|
try {
|
|
7119
|
-
(0,
|
|
7564
|
+
(0, import_child_process3.execSync)("npm install", {
|
|
7120
7565
|
cwd: PROJECT_DIR2,
|
|
7121
7566
|
stdio: "inherit"
|
|
7122
7567
|
});
|
|
7123
|
-
console.log(
|
|
7568
|
+
console.log(import_chalk18.default.green("Project dependencies installed"));
|
|
7124
7569
|
} catch (error) {
|
|
7125
|
-
throw
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
try {
|
|
7130
|
-
(0, import_child_process2.execSync)("npm install", {
|
|
7131
|
-
cwd: backendDir,
|
|
7132
|
-
stdio: "inherit"
|
|
7133
|
-
});
|
|
7134
|
-
console.log(import_chalk17.default.green("Backend dependencies installed"));
|
|
7135
|
-
} catch (error) {
|
|
7136
|
-
throw new Error(`Backend dependencies install failed: ${error.message}`);
|
|
7137
|
-
}
|
|
7138
|
-
}
|
|
7139
|
-
const frontendDir = import_path12.default.join(PROJECT_DIR2, "frontend");
|
|
7140
|
-
if (import_fs_extra7.default.existsSync(import_path12.default.join(frontendDir, "package.json"))) {
|
|
7141
|
-
try {
|
|
7142
|
-
(0, import_child_process2.execSync)("npm install", {
|
|
7143
|
-
cwd: frontendDir,
|
|
7144
|
-
stdio: "inherit"
|
|
7145
|
-
});
|
|
7146
|
-
console.log(import_chalk17.default.green("Frontend dependencies installed"));
|
|
7147
|
-
} catch (error) {
|
|
7148
|
-
throw new Error(`Frontend dependencies install failed: ${error.message}`);
|
|
7149
|
-
}
|
|
7570
|
+
throw createCommandError("project dependency install", "npm install", error, [
|
|
7571
|
+
"Check network connectivity and npm registry availability.",
|
|
7572
|
+
"If `package-lock.json` is stale or conflicted, resolve that before retrying."
|
|
7573
|
+
]);
|
|
7150
7574
|
}
|
|
7151
7575
|
}
|
|
7152
7576
|
function getBuiltWorker() {
|
|
7153
7577
|
const distWorkerDir = import_path12.default.join(PROJECT_DIR2, "dist-worker");
|
|
7154
7578
|
if (!import_fs_extra7.default.existsSync(distWorkerDir)) {
|
|
7155
|
-
throw
|
|
7579
|
+
throw createConfigError("Built worker output not found: `dist-worker/`.", [
|
|
7580
|
+
"Make sure `npm run build:worker` completed successfully."
|
|
7581
|
+
]);
|
|
7156
7582
|
}
|
|
7157
7583
|
const workerJsPath = import_path12.default.join(distWorkerDir, "worker.js");
|
|
7158
7584
|
if (!import_fs_extra7.default.existsSync(workerJsPath)) {
|
|
7159
|
-
throw
|
|
7585
|
+
throw createConfigError("Built worker entry file not found: `dist-worker/worker.js`.", [
|
|
7586
|
+
"Check the worker build output and bundler config."
|
|
7587
|
+
]);
|
|
7160
7588
|
}
|
|
7161
7589
|
const modulePaths = [];
|
|
7162
7590
|
const files = import_fs_extra7.default.readdirSync(distWorkerDir);
|
|
@@ -7168,7 +7596,7 @@ function getBuiltWorker() {
|
|
|
7168
7596
|
return { workerJsPath, modulePaths };
|
|
7169
7597
|
}
|
|
7170
7598
|
function getSqlFiles() {
|
|
7171
|
-
const sqlDir = import_path12.default.join(PROJECT_DIR2, "
|
|
7599
|
+
const sqlDir = import_path12.default.join(PROJECT_DIR2, "db");
|
|
7172
7600
|
if (!import_fs_extra7.default.existsSync(sqlDir)) {
|
|
7173
7601
|
return [];
|
|
7174
7602
|
}
|
|
@@ -7176,16 +7604,16 @@ function getSqlFiles() {
|
|
|
7176
7604
|
return files.map((f) => import_path12.default.join(sqlDir, f));
|
|
7177
7605
|
}
|
|
7178
7606
|
async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName) {
|
|
7179
|
-
var _a, _b
|
|
7180
|
-
console.log(
|
|
7181
|
-
console.log(
|
|
7182
|
-
console.log(
|
|
7183
|
-
console.log(
|
|
7184
|
-
console.log(
|
|
7185
|
-
console.log(
|
|
7607
|
+
var _a, _b;
|
|
7608
|
+
console.log(import_chalk18.default.blue("Saving worker to platform..."));
|
|
7609
|
+
console.log(import_chalk18.default.gray(`Project: ${projectName}`));
|
|
7610
|
+
console.log(import_chalk18.default.gray(`workerJsPath: ${workerJsPath}`));
|
|
7611
|
+
console.log(import_chalk18.default.gray(`modulePaths: ${modulePaths}`));
|
|
7612
|
+
console.log(import_chalk18.default.gray(`sqlFiles: ${sqlFiles}`));
|
|
7613
|
+
console.log(import_chalk18.default.gray(`metadata: ${metadata}`));
|
|
7186
7614
|
const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
|
|
7187
7615
|
const headers = getAuthHeaders();
|
|
7188
|
-
console.log(
|
|
7616
|
+
console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
|
|
7189
7617
|
try {
|
|
7190
7618
|
const FormData4 = (await import("formdata-node")).FormData;
|
|
7191
7619
|
const Blob2 = (await import("formdata-node")).Blob;
|
|
@@ -7210,61 +7638,76 @@ async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, project
|
|
|
7210
7638
|
formData.append("sql_file", new Blob2([content], {
|
|
7211
7639
|
type: "application/sql"
|
|
7212
7640
|
}), filename);
|
|
7213
|
-
console.log(
|
|
7641
|
+
console.log(import_chalk18.default.gray(` Including SQL: ${filename}`));
|
|
7214
7642
|
}
|
|
7215
7643
|
const response = await axios_default.put(apiUrl, formData, {
|
|
7216
7644
|
headers: { ...headers },
|
|
7217
7645
|
timeout: 12e4
|
|
7218
7646
|
});
|
|
7219
|
-
console.log(
|
|
7647
|
+
console.log(import_chalk18.default.gray(` Response: ${JSON.stringify(response.data)}`));
|
|
7220
7648
|
if (response.data) {
|
|
7221
|
-
console.log(
|
|
7649
|
+
console.log(import_chalk18.default.green("Worker saved"));
|
|
7222
7650
|
if ((_b = (_a = response.data) == null ? void 0 : _a.data) == null ? void 0 : _b.sql_results) {
|
|
7223
7651
|
for (const result of response.data.data.sql_results) {
|
|
7224
|
-
console.log(
|
|
7652
|
+
console.log(import_chalk18.default.gray(` SQL ${result.filename}: ${result.status}`));
|
|
7225
7653
|
}
|
|
7226
7654
|
}
|
|
7227
7655
|
} else {
|
|
7228
|
-
throw
|
|
7656
|
+
throw createApiError("worker save", { response: { data: response.data } }, [
|
|
7657
|
+
`Project: ${projectName}`,
|
|
7658
|
+
`Endpoint: ${apiUrl}`
|
|
7659
|
+
], [
|
|
7660
|
+
"Verify the project exists and your account has permission to update it."
|
|
7661
|
+
]);
|
|
7229
7662
|
}
|
|
7230
7663
|
} catch (error) {
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7664
|
+
throw createApiError("worker save", error, [
|
|
7665
|
+
`Project: ${projectName}`,
|
|
7666
|
+
`Endpoint: ${apiUrl}`
|
|
7667
|
+
], [
|
|
7668
|
+
"Check whether backend metadata, SQL files, or worker bundle contains invalid content."
|
|
7669
|
+
]);
|
|
7235
7670
|
}
|
|
7236
7671
|
}
|
|
7237
7672
|
function buildFrontend() {
|
|
7238
|
-
console.log(
|
|
7673
|
+
console.log(import_chalk18.default.blue("Building frontend..."));
|
|
7239
7674
|
try {
|
|
7240
|
-
(0,
|
|
7675
|
+
(0, import_child_process3.execSync)("npm run build:frontend", {
|
|
7241
7676
|
cwd: PROJECT_DIR2,
|
|
7242
7677
|
stdio: "inherit"
|
|
7243
7678
|
});
|
|
7244
|
-
console.log(
|
|
7679
|
+
console.log(import_chalk18.default.green("Frontend built"));
|
|
7245
7680
|
} catch (error) {
|
|
7246
|
-
throw
|
|
7681
|
+
throw createCommandError("frontend build", "npm run build:frontend", error, [
|
|
7682
|
+
"Fix the frontend build error shown above, then rerun `pinme save`."
|
|
7683
|
+
]);
|
|
7247
7684
|
}
|
|
7248
7685
|
}
|
|
7249
|
-
function deployFrontend() {
|
|
7250
|
-
console.log(
|
|
7686
|
+
function deployFrontend(projectName) {
|
|
7687
|
+
console.log(import_chalk18.default.blue("Deploying frontend to IPFS..."));
|
|
7251
7688
|
try {
|
|
7252
|
-
(0,
|
|
7689
|
+
(0, import_child_process3.execSync)("pinme upload ./frontend/dist", {
|
|
7253
7690
|
cwd: PROJECT_DIR2,
|
|
7254
|
-
stdio: "inherit"
|
|
7691
|
+
stdio: "inherit",
|
|
7692
|
+
env: {
|
|
7693
|
+
...process.env,
|
|
7694
|
+
PINME_PROJECT_NAME: projectName
|
|
7695
|
+
}
|
|
7255
7696
|
});
|
|
7256
|
-
console.log(
|
|
7697
|
+
console.log(import_chalk18.default.green("Frontend deployed to IPFS"));
|
|
7257
7698
|
} catch (error) {
|
|
7258
|
-
throw
|
|
7699
|
+
throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
|
|
7700
|
+
"Make sure `frontend/dist` exists and `pinme upload` works in this environment."
|
|
7701
|
+
]);
|
|
7259
7702
|
}
|
|
7260
7703
|
}
|
|
7261
7704
|
async function saveCmd(options) {
|
|
7262
7705
|
try {
|
|
7263
7706
|
const headers = getAuthHeaders();
|
|
7264
7707
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7708
|
+
throw createConfigError("No valid local login session was found.", [
|
|
7709
|
+
"Run `pinme login` and retry."
|
|
7710
|
+
]);
|
|
7268
7711
|
}
|
|
7269
7712
|
const projectDir = options.projectName || options.name ? import_path12.default.join(PROJECT_DIR2, options.projectName || options.name) : PROJECT_DIR2;
|
|
7270
7713
|
const tokenFileSrc = import_path12.default.join(PROJECT_DIR2, ".token.json");
|
|
@@ -7272,48 +7715,51 @@ async function saveCmd(options) {
|
|
|
7272
7715
|
if (import_fs_extra7.default.existsSync(tokenFileSrc) && !import_fs_extra7.default.existsSync(tokenFileDst)) {
|
|
7273
7716
|
import_fs_extra7.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7274
7717
|
}
|
|
7275
|
-
console.log(
|
|
7276
|
-
console.log(
|
|
7718
|
+
console.log(import_chalk18.default.blue("Deploying to platform...\n"));
|
|
7719
|
+
console.log(import_chalk18.default.gray(`Project dir: ${PROJECT_DIR2}`));
|
|
7277
7720
|
const config = loadConfig();
|
|
7278
7721
|
const projectName = config.project_name;
|
|
7279
7722
|
if (!projectName) {
|
|
7280
|
-
throw
|
|
7723
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
7724
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
7725
|
+
]);
|
|
7281
7726
|
}
|
|
7282
|
-
console.log(
|
|
7727
|
+
console.log(import_chalk18.default.gray(`Project: ${projectName}`));
|
|
7283
7728
|
const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
|
|
7284
|
-
console.log(
|
|
7285
|
-
console.log(
|
|
7729
|
+
console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
|
|
7730
|
+
console.log(import_chalk18.default.blue("\n--- Backend ---"));
|
|
7286
7731
|
installDependencies();
|
|
7287
7732
|
buildWorker();
|
|
7288
7733
|
const metadata = getMetadata();
|
|
7289
7734
|
const { workerJsPath, modulePaths } = getBuiltWorker();
|
|
7290
|
-
console.log(
|
|
7291
|
-
console.log(
|
|
7735
|
+
console.log(import_chalk18.default.gray(`Worker JS: ${workerJsPath}`));
|
|
7736
|
+
console.log(import_chalk18.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
|
|
7292
7737
|
const sqlFiles = getSqlFiles();
|
|
7293
|
-
console.log(
|
|
7738
|
+
console.log(import_chalk18.default.gray(`SQL files: ${JSON.stringify(sqlFiles)}`));
|
|
7294
7739
|
await saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName);
|
|
7295
|
-
console.log(
|
|
7740
|
+
console.log(import_chalk18.default.blue("\n--- Frontend ---"));
|
|
7296
7741
|
buildFrontend();
|
|
7297
|
-
deployFrontend();
|
|
7298
|
-
console.log(
|
|
7742
|
+
deployFrontend(projectName);
|
|
7743
|
+
console.log(import_chalk18.default.green("\nDeployment complete."));
|
|
7299
7744
|
process.exit(0);
|
|
7300
7745
|
} catch (error) {
|
|
7301
|
-
|
|
7302
|
-
\u274C Error: ${error.message}`));
|
|
7746
|
+
printCliError(error, "Save failed.");
|
|
7303
7747
|
process.exit(1);
|
|
7304
7748
|
}
|
|
7305
7749
|
}
|
|
7306
7750
|
|
|
7307
7751
|
// bin/updateDb.ts
|
|
7308
|
-
var
|
|
7752
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
7309
7753
|
var import_fs_extra8 = __toESM(require("fs-extra"));
|
|
7310
7754
|
var import_path13 = __toESM(require("path"));
|
|
7311
7755
|
var PROJECT_DIR3 = process.cwd();
|
|
7312
|
-
var API_BASE3 = "https://pinme.
|
|
7756
|
+
var API_BASE3 = "https://pinme.dev/api/v4";
|
|
7313
7757
|
function loadConfig2() {
|
|
7314
7758
|
const configPath = import_path13.default.join(PROJECT_DIR3, "pinme.toml");
|
|
7315
7759
|
if (!import_fs_extra8.default.existsSync(configPath)) {
|
|
7316
|
-
throw
|
|
7760
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
7761
|
+
"Run this command from the Pinme project root."
|
|
7762
|
+
]);
|
|
7317
7763
|
}
|
|
7318
7764
|
const configContent = import_fs_extra8.default.readFileSync(configPath, "utf-8");
|
|
7319
7765
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7322,24 +7768,27 @@ function loadConfig2() {
|
|
|
7322
7768
|
};
|
|
7323
7769
|
}
|
|
7324
7770
|
function getSqlFiles2() {
|
|
7325
|
-
const sqlDir = import_path13.default.join(PROJECT_DIR3, "
|
|
7771
|
+
const sqlDir = import_path13.default.join(PROJECT_DIR3, "db");
|
|
7326
7772
|
if (!import_fs_extra8.default.existsSync(sqlDir)) {
|
|
7327
|
-
throw
|
|
7773
|
+
throw createConfigError("SQL directory not found: `db/`.", [
|
|
7774
|
+
"Create a `db/` directory and add at least one `.sql` migration file."
|
|
7775
|
+
]);
|
|
7328
7776
|
}
|
|
7329
7777
|
const files = import_fs_extra8.default.readdirSync(sqlDir).filter((f) => f.endsWith(".sql")).sort();
|
|
7330
7778
|
if (files.length === 0) {
|
|
7331
|
-
throw
|
|
7779
|
+
throw createConfigError("No `.sql` files were found in `db/`.", [
|
|
7780
|
+
"Add one or more migration files before running `pinme update-db`."
|
|
7781
|
+
]);
|
|
7332
7782
|
}
|
|
7333
7783
|
return files.map((f) => import_path13.default.join(sqlDir, f));
|
|
7334
7784
|
}
|
|
7335
7785
|
async function updateDb(sqlFiles, projectName) {
|
|
7336
|
-
|
|
7337
|
-
console.log(
|
|
7338
|
-
console.log(
|
|
7339
|
-
console.log(import_chalk18.default.gray(`SQL files: ${sqlFiles.length}`));
|
|
7786
|
+
console.log(import_chalk19.default.blue("Importing SQL files to database..."));
|
|
7787
|
+
console.log(import_chalk19.default.gray(`Project: ${projectName}`));
|
|
7788
|
+
console.log(import_chalk19.default.gray(`SQL files: ${sqlFiles.length}`));
|
|
7340
7789
|
const apiUrl = `${API_BASE3}/update_db?project_name=${encodeURIComponent(projectName)}`;
|
|
7341
7790
|
const headers = getAuthHeaders();
|
|
7342
|
-
console.log(
|
|
7791
|
+
console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
|
|
7343
7792
|
try {
|
|
7344
7793
|
const FormData4 = (await import("formdata-node")).FormData;
|
|
7345
7794
|
const Blob2 = (await import("formdata-node")).Blob;
|
|
@@ -7350,49 +7799,57 @@ async function updateDb(sqlFiles, projectName) {
|
|
|
7350
7799
|
const content = import_fs_extra8.default.readFileSync(sqlFile);
|
|
7351
7800
|
totalSize += content.length;
|
|
7352
7801
|
if (totalSize > 10 * 1024 * 1024) {
|
|
7353
|
-
throw
|
|
7802
|
+
throw createConfigError("Total SQL payload exceeds the 10MB platform limit.", [
|
|
7803
|
+
"Split migrations into smaller batches, then rerun `pinme update-db`."
|
|
7804
|
+
]);
|
|
7354
7805
|
}
|
|
7355
7806
|
formData.append("file", new Blob2([content], {
|
|
7356
7807
|
type: "application/sql"
|
|
7357
7808
|
}), filename);
|
|
7358
|
-
console.log(
|
|
7809
|
+
console.log(import_chalk19.default.gray(` Including: ${filename} (${content.length} bytes)`));
|
|
7359
7810
|
}
|
|
7360
7811
|
const response = await axios_default.post(apiUrl, formData, {
|
|
7361
7812
|
headers: { ...headers },
|
|
7362
7813
|
timeout: 12e4
|
|
7363
7814
|
});
|
|
7364
|
-
console.log(
|
|
7815
|
+
console.log(import_chalk19.default.gray(` Response: ${JSON.stringify(response.data)}`));
|
|
7365
7816
|
if (response.data.code === 200) {
|
|
7366
|
-
console.log(
|
|
7817
|
+
console.log(import_chalk19.default.green("SQL files imported successfully!"));
|
|
7367
7818
|
const results = response.data.data.results;
|
|
7368
7819
|
for (const result of results) {
|
|
7369
7820
|
if (result.status === "complete") {
|
|
7370
|
-
console.log(
|
|
7821
|
+
console.log(import_chalk19.default.green(` COMPLETE ${result.filename}: ${result.num_queries} queries, ${result.duration}ms`));
|
|
7371
7822
|
if (result.changes !== void 0) {
|
|
7372
|
-
console.log(
|
|
7823
|
+
console.log(import_chalk19.default.gray(` Changes: ${result.changes}, Read: ${result.rows_read}, Written: ${result.rows_written}`));
|
|
7373
7824
|
}
|
|
7374
7825
|
} else if (result.status === "error") {
|
|
7375
|
-
console.log(
|
|
7826
|
+
console.log(import_chalk19.default.red(` ERROR ${result.filename}: ${result.error}`));
|
|
7376
7827
|
}
|
|
7377
7828
|
}
|
|
7378
7829
|
} else {
|
|
7379
|
-
|
|
7380
|
-
|
|
7830
|
+
throw createApiError("database update", { response: { data: response.data } }, [
|
|
7831
|
+
`Project: ${projectName}`,
|
|
7832
|
+
`Endpoint: ${apiUrl}`
|
|
7833
|
+
], [
|
|
7834
|
+
"Inspect the SQL result list above to identify the failing migration file."
|
|
7835
|
+
]);
|
|
7381
7836
|
}
|
|
7382
7837
|
} catch (error) {
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7838
|
+
throw createApiError("database update", error, [
|
|
7839
|
+
`Project: ${projectName}`,
|
|
7840
|
+
`Endpoint: ${apiUrl}`
|
|
7841
|
+
], [
|
|
7842
|
+
"Validate the SQL syntax and check whether any migration is re-applying an existing schema change."
|
|
7843
|
+
]);
|
|
7387
7844
|
}
|
|
7388
7845
|
}
|
|
7389
7846
|
async function updateDbCmd(options) {
|
|
7390
7847
|
try {
|
|
7391
7848
|
const headers = getAuthHeaders();
|
|
7392
7849
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7850
|
+
throw createConfigError("No valid local login session was found.", [
|
|
7851
|
+
"Run `pinme login` and retry."
|
|
7852
|
+
]);
|
|
7396
7853
|
}
|
|
7397
7854
|
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;
|
|
7398
7855
|
const tokenFileSrc = import_path13.default.join(PROJECT_DIR3, ".token.json");
|
|
@@ -7400,37 +7857,40 @@ async function updateDbCmd(options) {
|
|
|
7400
7857
|
if (import_fs_extra8.default.existsSync(tokenFileSrc) && !import_fs_extra8.default.existsSync(tokenFileDst)) {
|
|
7401
7858
|
import_fs_extra8.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7402
7859
|
}
|
|
7403
|
-
console.log(
|
|
7404
|
-
console.log(
|
|
7860
|
+
console.log(import_chalk19.default.blue("Importing SQL to database...\n"));
|
|
7861
|
+
console.log(import_chalk19.default.gray(`Project dir: ${PROJECT_DIR3}`));
|
|
7405
7862
|
const config = loadConfig2();
|
|
7406
7863
|
const projectName = config.project_name;
|
|
7407
7864
|
if (!projectName) {
|
|
7408
|
-
throw
|
|
7865
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
7866
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
7867
|
+
]);
|
|
7409
7868
|
}
|
|
7410
|
-
console.log(
|
|
7869
|
+
console.log(import_chalk19.default.gray(`Project: ${projectName}`));
|
|
7411
7870
|
const sqlFiles = getSqlFiles2();
|
|
7412
|
-
console.log(
|
|
7871
|
+
console.log(import_chalk19.default.gray(`Found ${sqlFiles.length} SQL file(s) in db`));
|
|
7413
7872
|
await updateDb(sqlFiles, projectName);
|
|
7414
|
-
console.log(
|
|
7873
|
+
console.log(import_chalk19.default.green("\nDatabase update complete."));
|
|
7415
7874
|
process.exit(0);
|
|
7416
7875
|
} catch (error) {
|
|
7417
|
-
|
|
7418
|
-
\u274C Error: ${error.message}`));
|
|
7876
|
+
printCliError(error, "Database update failed.");
|
|
7419
7877
|
process.exit(1);
|
|
7420
7878
|
}
|
|
7421
7879
|
}
|
|
7422
7880
|
|
|
7423
7881
|
// bin/updateWorker.ts
|
|
7424
|
-
var
|
|
7882
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
7425
7883
|
var import_fs_extra9 = __toESM(require("fs-extra"));
|
|
7426
7884
|
var import_path14 = __toESM(require("path"));
|
|
7427
|
-
var
|
|
7885
|
+
var import_child_process4 = require("child_process");
|
|
7428
7886
|
var PROJECT_DIR4 = process.cwd();
|
|
7429
|
-
var API_BASE4 = "https://pinme.
|
|
7887
|
+
var API_BASE4 = "https://pinme.dev/api/v4";
|
|
7430
7888
|
function loadConfig3() {
|
|
7431
7889
|
const configPath = import_path14.default.join(PROJECT_DIR4, "pinme.toml");
|
|
7432
7890
|
if (!import_fs_extra9.default.existsSync(configPath)) {
|
|
7433
|
-
throw
|
|
7891
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
7892
|
+
"Run this command from the Pinme project root."
|
|
7893
|
+
]);
|
|
7434
7894
|
}
|
|
7435
7895
|
const configContent = import_fs_extra9.default.readFileSync(configPath, "utf-8");
|
|
7436
7896
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7441,30 +7901,38 @@ function loadConfig3() {
|
|
|
7441
7901
|
function getMetadata2() {
|
|
7442
7902
|
const metadataPath = import_path14.default.join(PROJECT_DIR4, "backend", "metadata.json");
|
|
7443
7903
|
if (!import_fs_extra9.default.existsSync(metadataPath)) {
|
|
7444
|
-
throw
|
|
7904
|
+
throw createConfigError("`backend/metadata.json` not found.", [
|
|
7905
|
+
"Create `backend/metadata.json` or restore it from the project template."
|
|
7906
|
+
]);
|
|
7445
7907
|
}
|
|
7446
7908
|
return import_fs_extra9.default.readJsonSync(metadataPath);
|
|
7447
7909
|
}
|
|
7448
7910
|
function buildWorker2() {
|
|
7449
|
-
console.log(
|
|
7911
|
+
console.log(import_chalk20.default.blue("Building worker..."));
|
|
7450
7912
|
try {
|
|
7451
|
-
(0,
|
|
7913
|
+
(0, import_child_process4.execSync)("npm run build:worker", {
|
|
7452
7914
|
cwd: PROJECT_DIR4,
|
|
7453
7915
|
stdio: "inherit"
|
|
7454
7916
|
});
|
|
7455
|
-
console.log(
|
|
7917
|
+
console.log(import_chalk20.default.green("Worker built"));
|
|
7456
7918
|
} catch (error) {
|
|
7457
|
-
throw
|
|
7919
|
+
throw createCommandError("worker build", "npm run build:worker", error, [
|
|
7920
|
+
"Fix the build error shown above, then rerun `pinme update-worker`."
|
|
7921
|
+
]);
|
|
7458
7922
|
}
|
|
7459
7923
|
}
|
|
7460
7924
|
function getBuiltWorker2() {
|
|
7461
7925
|
const distWorkerDir = import_path14.default.join(PROJECT_DIR4, "dist-worker");
|
|
7462
7926
|
if (!import_fs_extra9.default.existsSync(distWorkerDir)) {
|
|
7463
|
-
throw
|
|
7927
|
+
throw createConfigError("Built worker output not found: `dist-worker/`.", [
|
|
7928
|
+
"Make sure `npm run build:worker` completed successfully."
|
|
7929
|
+
]);
|
|
7464
7930
|
}
|
|
7465
7931
|
const workerJsPath = import_path14.default.join(distWorkerDir, "worker.js");
|
|
7466
7932
|
if (!import_fs_extra9.default.existsSync(workerJsPath)) {
|
|
7467
|
-
throw
|
|
7933
|
+
throw createConfigError("Built worker entry file not found: `dist-worker/worker.js`.", [
|
|
7934
|
+
"Check the worker build output and bundler config."
|
|
7935
|
+
]);
|
|
7468
7936
|
}
|
|
7469
7937
|
const modulePaths = [];
|
|
7470
7938
|
const files = import_fs_extra9.default.readdirSync(distWorkerDir);
|
|
@@ -7476,15 +7944,14 @@ function getBuiltWorker2() {
|
|
|
7476
7944
|
return { workerJsPath, modulePaths };
|
|
7477
7945
|
}
|
|
7478
7946
|
async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
|
|
7479
|
-
|
|
7480
|
-
console.log(
|
|
7481
|
-
console.log(
|
|
7482
|
-
console.log(
|
|
7483
|
-
console.log(
|
|
7484
|
-
console.log(import_chalk19.default.gray(`metadata: ${metadata}`));
|
|
7947
|
+
console.log(import_chalk20.default.blue("Updating worker on platform..."));
|
|
7948
|
+
console.log(import_chalk20.default.gray(`Project: ${projectName}`));
|
|
7949
|
+
console.log(import_chalk20.default.gray(`workerJsPath: ${workerJsPath}`));
|
|
7950
|
+
console.log(import_chalk20.default.gray(`modulePaths: ${modulePaths}`));
|
|
7951
|
+
console.log(import_chalk20.default.gray(`metadata: ${metadata}`));
|
|
7485
7952
|
const apiUrl = `${API_BASE4}/update_worker?project_name=${encodeURIComponent(projectName)}`;
|
|
7486
7953
|
const headers = getAuthHeaders();
|
|
7487
|
-
console.log(
|
|
7954
|
+
console.log(import_chalk20.default.gray(`API URL: ${apiUrl}`));
|
|
7488
7955
|
try {
|
|
7489
7956
|
const FormData4 = (await import("formdata-node")).FormData;
|
|
7490
7957
|
const Blob2 = (await import("formdata-node")).Blob;
|
|
@@ -7507,51 +7974,58 @@ async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
|
|
|
7507
7974
|
headers: { ...headers },
|
|
7508
7975
|
timeout: 12e4
|
|
7509
7976
|
});
|
|
7510
|
-
console.log(
|
|
7977
|
+
console.log(import_chalk20.default.gray(` Response: ${JSON.stringify(response.data)}`));
|
|
7511
7978
|
if (response.data) {
|
|
7512
|
-
console.log(
|
|
7979
|
+
console.log(import_chalk20.default.green("Worker updated"));
|
|
7513
7980
|
const data = response.data.data;
|
|
7514
7981
|
if (data.worker_id) {
|
|
7515
|
-
console.log(
|
|
7982
|
+
console.log(import_chalk20.default.gray(` Worker ID: ${data.worker_id}`));
|
|
7516
7983
|
}
|
|
7517
7984
|
if (data.deployment_id) {
|
|
7518
|
-
console.log(
|
|
7985
|
+
console.log(import_chalk20.default.gray(` Deployment ID: ${data.deployment_id}`));
|
|
7519
7986
|
}
|
|
7520
7987
|
if (data.entry_point) {
|
|
7521
|
-
console.log(
|
|
7988
|
+
console.log(import_chalk20.default.gray(` Entry Point: ${data.entry_point}`));
|
|
7522
7989
|
}
|
|
7523
7990
|
if (data.created_on) {
|
|
7524
|
-
console.log(
|
|
7991
|
+
console.log(import_chalk20.default.gray(` Created: ${data.created_on}`));
|
|
7525
7992
|
}
|
|
7526
7993
|
if (data.modified_on) {
|
|
7527
|
-
console.log(
|
|
7994
|
+
console.log(import_chalk20.default.gray(` Modified: ${data.modified_on}`));
|
|
7528
7995
|
}
|
|
7529
7996
|
if (data.startup_time_ms !== void 0) {
|
|
7530
|
-
console.log(
|
|
7997
|
+
console.log(import_chalk20.default.gray(` Startup Time: ${data.startup_time_ms}ms`));
|
|
7531
7998
|
}
|
|
7532
7999
|
if (data.has_modules !== void 0) {
|
|
7533
|
-
console.log(
|
|
8000
|
+
console.log(import_chalk20.default.gray(` Has Modules: ${data.has_modules}`));
|
|
7534
8001
|
}
|
|
7535
8002
|
if (data.domain) {
|
|
7536
|
-
console.log(
|
|
8003
|
+
console.log(import_chalk20.default.gray(` Domain: ${data.domain}`));
|
|
7537
8004
|
}
|
|
7538
8005
|
} else {
|
|
7539
|
-
throw
|
|
8006
|
+
throw createApiError("worker update", { response: { data: response.data } }, [
|
|
8007
|
+
`Project: ${projectName}`,
|
|
8008
|
+
`Endpoint: ${apiUrl}`
|
|
8009
|
+
], [
|
|
8010
|
+
"Verify the project exists and your account has permission to update it."
|
|
8011
|
+
]);
|
|
7540
8012
|
}
|
|
7541
8013
|
} catch (error) {
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
8014
|
+
throw createApiError("worker update", error, [
|
|
8015
|
+
`Project: ${projectName}`,
|
|
8016
|
+
`Endpoint: ${apiUrl}`
|
|
8017
|
+
], [
|
|
8018
|
+
"Check whether `backend/metadata.json` and the built worker bundle are valid."
|
|
8019
|
+
]);
|
|
7546
8020
|
}
|
|
7547
8021
|
}
|
|
7548
8022
|
async function updateWorkerCmd(options) {
|
|
7549
8023
|
try {
|
|
7550
8024
|
const headers = getAuthHeaders();
|
|
7551
8025
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
8026
|
+
throw createConfigError("No valid local login session was found.", [
|
|
8027
|
+
"Run `pinme login` and retry."
|
|
8028
|
+
]);
|
|
7555
8029
|
}
|
|
7556
8030
|
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;
|
|
7557
8031
|
const tokenFileSrc = import_path14.default.join(PROJECT_DIR4, ".token.json");
|
|
@@ -7559,41 +8033,44 @@ async function updateWorkerCmd(options) {
|
|
|
7559
8033
|
if (import_fs_extra9.default.existsSync(tokenFileSrc) && !import_fs_extra9.default.existsSync(tokenFileDst)) {
|
|
7560
8034
|
import_fs_extra9.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7561
8035
|
}
|
|
7562
|
-
console.log(
|
|
7563
|
-
console.log(
|
|
8036
|
+
console.log(import_chalk20.default.blue("Updating worker...\n"));
|
|
8037
|
+
console.log(import_chalk20.default.gray(`Project dir: ${PROJECT_DIR4}`));
|
|
7564
8038
|
const config = loadConfig3();
|
|
7565
8039
|
const projectName = config.project_name;
|
|
7566
8040
|
if (!projectName) {
|
|
7567
|
-
throw
|
|
8041
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
8042
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
8043
|
+
]);
|
|
7568
8044
|
}
|
|
7569
|
-
console.log(
|
|
7570
|
-
console.log(
|
|
8045
|
+
console.log(import_chalk20.default.gray(`Project: ${projectName}`));
|
|
8046
|
+
console.log(import_chalk20.default.blue("\n--- Worker Update ---"));
|
|
7571
8047
|
buildWorker2();
|
|
7572
8048
|
const metadata = getMetadata2();
|
|
7573
8049
|
const { workerJsPath, modulePaths } = getBuiltWorker2();
|
|
7574
|
-
console.log(
|
|
7575
|
-
console.log(
|
|
7576
|
-
console.log(
|
|
8050
|
+
console.log(import_chalk20.default.gray(`Worker JS: ${workerJsPath}`));
|
|
8051
|
+
console.log(import_chalk20.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
|
|
8052
|
+
console.log(import_chalk20.default.gray(`SQL files: ignored (not processed for update_worker)`));
|
|
7577
8053
|
await updateWorker(workerJsPath, modulePaths, metadata, projectName);
|
|
7578
|
-
console.log(
|
|
8054
|
+
console.log(import_chalk20.default.green("\nWorker update complete."));
|
|
7579
8055
|
process.exit(0);
|
|
7580
8056
|
} catch (error) {
|
|
7581
|
-
|
|
7582
|
-
\u274C Error: ${error.message}`));
|
|
8057
|
+
printCliError(error, "Worker update failed.");
|
|
7583
8058
|
process.exit(1);
|
|
7584
8059
|
}
|
|
7585
8060
|
}
|
|
7586
8061
|
|
|
7587
8062
|
// bin/updateWeb.ts
|
|
7588
|
-
var
|
|
8063
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
7589
8064
|
var import_fs_extra10 = __toESM(require("fs-extra"));
|
|
7590
8065
|
var import_path15 = __toESM(require("path"));
|
|
7591
|
-
var
|
|
8066
|
+
var import_child_process5 = require("child_process");
|
|
7592
8067
|
var PROJECT_DIR5 = process.cwd();
|
|
7593
8068
|
function loadConfig4() {
|
|
7594
8069
|
const configPath = import_path15.default.join(PROJECT_DIR5, "pinme.toml");
|
|
7595
8070
|
if (!import_fs_extra10.default.existsSync(configPath)) {
|
|
7596
|
-
throw
|
|
8071
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
8072
|
+
"Run this command from the Pinme project root."
|
|
8073
|
+
]);
|
|
7597
8074
|
}
|
|
7598
8075
|
const configContent = import_fs_extra10.default.readFileSync(configPath, "utf-8");
|
|
7599
8076
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7602,36 +8079,44 @@ function loadConfig4() {
|
|
|
7602
8079
|
};
|
|
7603
8080
|
}
|
|
7604
8081
|
function buildFrontend2() {
|
|
7605
|
-
console.log(
|
|
8082
|
+
console.log(import_chalk21.default.blue("Building frontend..."));
|
|
7606
8083
|
try {
|
|
7607
|
-
(0,
|
|
8084
|
+
(0, import_child_process5.execSync)("npm run build:frontend", {
|
|
7608
8085
|
cwd: PROJECT_DIR5,
|
|
7609
8086
|
stdio: "inherit"
|
|
7610
8087
|
});
|
|
7611
|
-
console.log(
|
|
8088
|
+
console.log(import_chalk21.default.green("Frontend built"));
|
|
7612
8089
|
} catch (error) {
|
|
7613
|
-
throw
|
|
8090
|
+
throw createCommandError("frontend build", "npm run build:frontend", error, [
|
|
8091
|
+
"Fix the frontend build error shown above, then rerun `pinme update-web`."
|
|
8092
|
+
]);
|
|
7614
8093
|
}
|
|
7615
8094
|
}
|
|
7616
|
-
function deployFrontend2() {
|
|
7617
|
-
console.log(
|
|
8095
|
+
function deployFrontend2(projectName) {
|
|
8096
|
+
console.log(import_chalk21.default.blue("Deploying frontend to IPFS..."));
|
|
7618
8097
|
try {
|
|
7619
|
-
(0,
|
|
8098
|
+
(0, import_child_process5.execSync)("pinme upload ./frontend/dist", {
|
|
7620
8099
|
cwd: PROJECT_DIR5,
|
|
7621
|
-
stdio: "inherit"
|
|
8100
|
+
stdio: "inherit",
|
|
8101
|
+
env: {
|
|
8102
|
+
...process.env,
|
|
8103
|
+
PINME_PROJECT_NAME: projectName
|
|
8104
|
+
}
|
|
7622
8105
|
});
|
|
7623
|
-
console.log(
|
|
8106
|
+
console.log(import_chalk21.default.green("Frontend deployed to IPFS"));
|
|
7624
8107
|
} catch (error) {
|
|
7625
|
-
throw
|
|
8108
|
+
throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
|
|
8109
|
+
"Make sure `frontend/dist` exists and `pinme upload` can run successfully."
|
|
8110
|
+
]);
|
|
7626
8111
|
}
|
|
7627
8112
|
}
|
|
7628
8113
|
async function updateWebCmd(options) {
|
|
7629
8114
|
try {
|
|
7630
8115
|
const headers = getAuthHeaders();
|
|
7631
8116
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
8117
|
+
throw createConfigError("No valid local login session was found.", [
|
|
8118
|
+
"Run `pinme login` and retry."
|
|
8119
|
+
]);
|
|
7635
8120
|
}
|
|
7636
8121
|
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;
|
|
7637
8122
|
const tokenFileSrc = import_path15.default.join(PROJECT_DIR5, ".token.json");
|
|
@@ -7639,22 +8124,118 @@ async function updateWebCmd(options) {
|
|
|
7639
8124
|
if (import_fs_extra10.default.existsSync(tokenFileSrc) && !import_fs_extra10.default.existsSync(tokenFileDst)) {
|
|
7640
8125
|
import_fs_extra10.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7641
8126
|
}
|
|
7642
|
-
console.log(
|
|
7643
|
-
console.log(
|
|
8127
|
+
console.log(import_chalk21.default.blue("Updating web (frontend)...\n"));
|
|
8128
|
+
console.log(import_chalk21.default.gray(`Project dir: ${PROJECT_DIR5}`));
|
|
7644
8129
|
const config = loadConfig4();
|
|
7645
8130
|
const projectName = config.project_name;
|
|
7646
8131
|
if (!projectName) {
|
|
7647
|
-
throw
|
|
8132
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
8133
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
8134
|
+
]);
|
|
7648
8135
|
}
|
|
7649
|
-
console.log(
|
|
7650
|
-
console.log(
|
|
8136
|
+
console.log(import_chalk21.default.gray(`Project: ${projectName}`));
|
|
8137
|
+
console.log(import_chalk21.default.blue("\n--- Frontend Update ---"));
|
|
7651
8138
|
buildFrontend2();
|
|
7652
|
-
deployFrontend2();
|
|
7653
|
-
console.log(
|
|
8139
|
+
deployFrontend2(projectName);
|
|
8140
|
+
console.log(import_chalk21.default.green("\nWeb update complete."));
|
|
8141
|
+
process.exit(0);
|
|
8142
|
+
} catch (error) {
|
|
8143
|
+
printCliError(error, "Web update failed.");
|
|
8144
|
+
process.exit(1);
|
|
8145
|
+
}
|
|
8146
|
+
}
|
|
8147
|
+
|
|
8148
|
+
// bin/delete.ts
|
|
8149
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
8150
|
+
var import_inquirer9 = __toESM(require("inquirer"));
|
|
8151
|
+
var import_fs_extra11 = __toESM(require("fs-extra"));
|
|
8152
|
+
var import_path16 = __toESM(require("path"));
|
|
8153
|
+
var API_BASE5 = "https://pinme.dev/api/v4";
|
|
8154
|
+
function getProjectName() {
|
|
8155
|
+
const configPath = import_path16.default.join(process.cwd(), "pinme.toml");
|
|
8156
|
+
if (!import_fs_extra11.default.existsSync(configPath)) {
|
|
8157
|
+
return null;
|
|
8158
|
+
}
|
|
8159
|
+
const config = import_fs_extra11.default.readFileSync(configPath, "utf-8");
|
|
8160
|
+
const match = config.match(/project_name\s*=\s*"([^"]+)"/);
|
|
8161
|
+
return (match == null ? void 0 : match[1]) || null;
|
|
8162
|
+
}
|
|
8163
|
+
async function deleteCmd(options) {
|
|
8164
|
+
var _a, _b;
|
|
8165
|
+
try {
|
|
8166
|
+
const headers = getAuthHeaders();
|
|
8167
|
+
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
8168
|
+
console.log(import_chalk22.default.yellow("\n\u26A0\uFE0F You are not logged in."));
|
|
8169
|
+
console.log(import_chalk22.default.gray("Please run: pinme login"));
|
|
8170
|
+
process.exit(1);
|
|
8171
|
+
}
|
|
8172
|
+
console.log(import_chalk22.default.blue("Deleting project...\n"));
|
|
8173
|
+
let projectName = options.name || getProjectName();
|
|
8174
|
+
if (!projectName) {
|
|
8175
|
+
console.log(import_chalk22.default.red("\n\u274C Error: Cannot find project name."));
|
|
8176
|
+
console.log(import_chalk22.default.yellow(" Please make sure you are in the project directory."));
|
|
8177
|
+
console.log(import_chalk22.default.gray(" The project directory should contain a pinme.toml file."));
|
|
8178
|
+
console.log(import_chalk22.default.gray("\n Or specify the project name:"));
|
|
8179
|
+
console.log(import_chalk22.default.gray(" cd /path/to/your-project"));
|
|
8180
|
+
console.log(import_chalk22.default.gray(" pinme delete"));
|
|
8181
|
+
process.exit(1);
|
|
8182
|
+
}
|
|
8183
|
+
console.log(import_chalk22.default.gray(`Project: ${projectName}`));
|
|
8184
|
+
console.log(import_chalk22.default.gray(`Directory: ${process.cwd()}`));
|
|
8185
|
+
if (!options.force) {
|
|
8186
|
+
const answers = await import_inquirer9.default.prompt([
|
|
8187
|
+
{
|
|
8188
|
+
type: "confirm",
|
|
8189
|
+
name: "confirm",
|
|
8190
|
+
message: `Are you sure you want to delete project "${projectName}"? This will remove Worker, domain binding, and D1 database.`,
|
|
8191
|
+
default: false
|
|
8192
|
+
}
|
|
8193
|
+
]);
|
|
8194
|
+
if (!answers.confirm) {
|
|
8195
|
+
console.log(import_chalk22.default.gray("Cancelled."));
|
|
8196
|
+
process.exit(0);
|
|
8197
|
+
}
|
|
8198
|
+
}
|
|
8199
|
+
console.log(import_chalk22.default.blue("Deleting project on platform..."));
|
|
8200
|
+
const apiUrl = `${API_BASE5}/delete_project`;
|
|
8201
|
+
console.log(import_chalk22.default.gray(`API URL: ${apiUrl}`));
|
|
8202
|
+
console.log(import_chalk22.default.gray(`Project name: ${projectName}`));
|
|
8203
|
+
const response = await axios_default.post(apiUrl, {
|
|
8204
|
+
project_name: projectName
|
|
8205
|
+
}, {
|
|
8206
|
+
headers: {
|
|
8207
|
+
...headers,
|
|
8208
|
+
"Content-Type": "application/json"
|
|
8209
|
+
}
|
|
8210
|
+
}).catch((error) => {
|
|
8211
|
+
var _a2, _b2;
|
|
8212
|
+
if (error.response) {
|
|
8213
|
+
console.log(import_chalk22.default.red(` Response status: ${(_a2 = error.response) == null ? void 0 : _a2.status}`));
|
|
8214
|
+
console.log(import_chalk22.default.red(` Response data: ${JSON.stringify((_b2 = error.response) == null ? void 0 : _b2.data)}`));
|
|
8215
|
+
} else {
|
|
8216
|
+
console.log(import_chalk22.default.red("No Response"));
|
|
8217
|
+
}
|
|
8218
|
+
throw error;
|
|
8219
|
+
});
|
|
8220
|
+
const data = response.data;
|
|
8221
|
+
if (data.code === 200) {
|
|
8222
|
+
console.log(import_chalk22.default.green("\n\u2705 Project deleted successfully!"));
|
|
8223
|
+
console.log(import_chalk22.default.gray(`
|
|
8224
|
+
Project: ${data.data.project_name}`));
|
|
8225
|
+
console.log(import_chalk22.default.gray(` Domain deleted: ${data.data.domain_deleted ? "\u2705" : "\u274C"}`));
|
|
8226
|
+
console.log(import_chalk22.default.gray(` Worker deleted: ${data.data.worker_deleted ? "\u2705" : "\u274C"}`));
|
|
8227
|
+
console.log(import_chalk22.default.gray(` Database deleted: ${data.data.database_deleted ? "\u2705" : "\u274C"}`));
|
|
8228
|
+
console.log(import_chalk22.default.gray("\nLocal files are kept unchanged."));
|
|
8229
|
+
} else {
|
|
8230
|
+
const errorMsg = (data == null ? void 0 : data.msg) || "Failed to delete project";
|
|
8231
|
+
throw new Error(errorMsg);
|
|
8232
|
+
}
|
|
7654
8233
|
process.exit(0);
|
|
7655
8234
|
} catch (error) {
|
|
7656
|
-
console.
|
|
7657
|
-
|
|
8235
|
+
console.log(import_chalk22.default.red(error));
|
|
8236
|
+
const errorMsg = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) || error.message || "Failed to delete project";
|
|
8237
|
+
console.error(import_chalk22.default.red(`
|
|
8238
|
+
\u274C Error: ${errorMsg}`));
|
|
7658
8239
|
process.exit(1);
|
|
7659
8240
|
}
|
|
7660
8241
|
}
|
|
@@ -7664,9 +8245,9 @@ import_dotenv.default.config();
|
|
|
7664
8245
|
checkNodeVersion();
|
|
7665
8246
|
function showBanner() {
|
|
7666
8247
|
console.log(
|
|
7667
|
-
|
|
8248
|
+
import_chalk23.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
|
|
7668
8249
|
);
|
|
7669
|
-
console.log(
|
|
8250
|
+
console.log(import_chalk23.default.cyan("A command-line tool for uploading files to IPFS\n"));
|
|
7670
8251
|
}
|
|
7671
8252
|
var program = new import_commander.Command();
|
|
7672
8253
|
program.name("pinme").version(version).option("-v, --version", "output the current version");
|
|
@@ -7689,6 +8270,7 @@ program.command("save").description("Deploy the project (frontend + backend)").a
|
|
|
7689
8270
|
program.command("update-db").description("Execute database migration").action(() => updateDbCmd());
|
|
7690
8271
|
program.command("update-worker").description("Execute worker migration").action(() => updateWorkerCmd());
|
|
7691
8272
|
program.command("update-web").description("Deploy frontend to IPFS").action((options) => updateWebCmd(options));
|
|
8273
|
+
program.command("delete").description("Delete a project (Worker, domain, D1 database)").argument("[name]", "Project name").option("-f, --force", "Skip confirmation").action((name, options) => deleteCmd({ name, force: options == null ? void 0 : options.force }));
|
|
7692
8274
|
program.command("domain").description("Alias for 'my-domains' command").action(() => myDomainsCmd());
|
|
7693
8275
|
program.command("list").description("show upload history").option(
|
|
7694
8276
|
"-l, --limit <number>",
|