pinme 2.0.0-beta.2 → 2.0.0-beta.20
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 +1546 -956
- 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.20";
|
|
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;
|
|
5319
|
-
}
|
|
5320
|
-
.close-btn {
|
|
5321
|
-
background: #3b82f6;
|
|
5322
|
-
color: white;
|
|
5323
|
-
border: none;
|
|
5324
|
-
padding: 0.75rem 2rem;
|
|
5325
|
-
border-radius: 6px;
|
|
5326
|
-
font-size: 1rem;
|
|
5327
|
-
cursor: pointer;
|
|
5328
|
-
transition: background 0.2s;
|
|
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);
|
|
5329
5431
|
}
|
|
5330
|
-
.
|
|
5331
|
-
|
|
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;
|
|
5332
5442
|
}
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
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>`;
|
|
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}`);
|
|
5447
|
+
}
|
|
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");
|
|
@@ -5860,45 +6080,45 @@ var upload_default = async (options) => {
|
|
|
5860
6080
|
console.log(import_chalk5.default.green(`Domain available: ${displayDomain}`));
|
|
5861
6081
|
} catch (e) {
|
|
5862
6082
|
if (e.message === "Token expired") {
|
|
5863
|
-
return;
|
|
6083
|
+
return;
|
|
6084
|
+
}
|
|
6085
|
+
throw e;
|
|
6086
|
+
}
|
|
6087
|
+
}
|
|
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);
|
|
5864
6117
|
}
|
|
5865
6118
|
throw e;
|
|
5866
6119
|
}
|
|
5867
6120
|
}
|
|
5868
|
-
console.log(import_chalk5.default.
|
|
5869
|
-
try {
|
|
5870
|
-
const result = await uploadToIpfsSplit_default(absolutePath);
|
|
5871
|
-
if (result) {
|
|
5872
|
-
const uid = getUid();
|
|
5873
|
-
const encryptedCID = encryptHash(result.contentHash, secretKey, uid);
|
|
5874
|
-
console.log(
|
|
5875
|
-
import_chalk5.default.cyan(
|
|
5876
|
-
import_figlet.default.textSync("Successful", { horizontalLayout: "full" })
|
|
5877
|
-
)
|
|
5878
|
-
);
|
|
5879
|
-
console.log(import_chalk5.default.cyan(`URL:`));
|
|
5880
|
-
console.log(import_chalk5.default.cyan(`${URL3}${encryptedCID}`));
|
|
5881
|
-
if (domainArg) {
|
|
5882
|
-
console.log(
|
|
5883
|
-
import_chalk5.default.blue(
|
|
5884
|
-
`Binding domain: ${displayDomain} with CID: ${result.contentHash}`
|
|
5885
|
-
)
|
|
5886
|
-
);
|
|
5887
|
-
try {
|
|
5888
|
-
await bindDomain(domainArg, result.contentHash, isDns, authConfig);
|
|
5889
|
-
} catch (e) {
|
|
5890
|
-
if (e.message === "Token expired") {
|
|
5891
|
-
process.exit(1);
|
|
5892
|
-
}
|
|
5893
|
-
throw e;
|
|
5894
|
-
}
|
|
5895
|
-
}
|
|
5896
|
-
console.log(import_chalk5.default.green("\n\u{1F389} upload successful, program exit"));
|
|
5897
|
-
}
|
|
5898
|
-
} catch (error) {
|
|
5899
|
-
console.error(import_chalk5.default.red(`Error: ${error.message}`));
|
|
5900
|
-
process.exit(1);
|
|
5901
|
-
}
|
|
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);
|
|
@@ -6929,23 +7148,174 @@ Login failed: ${(e == null ? void 0 : e.message) || e}`));
|
|
|
6929
7148
|
}
|
|
6930
7149
|
|
|
6931
7150
|
// bin/create.ts
|
|
6932
|
-
var
|
|
7151
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
6933
7152
|
var import_fs_extra6 = __toESM(require("fs-extra"));
|
|
6934
7153
|
var import_path11 = __toESM(require("path"));
|
|
6935
7154
|
var import_inquirer8 = __toESM(require("inquirer"));
|
|
6936
|
-
var
|
|
7155
|
+
var import_child_process2 = require("child_process");
|
|
7156
|
+
|
|
7157
|
+
// bin/utils/cliError.ts
|
|
7158
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
7159
|
+
var CliError = class extends Error {
|
|
7160
|
+
stage;
|
|
7161
|
+
details;
|
|
7162
|
+
suggestions;
|
|
7163
|
+
cause;
|
|
7164
|
+
constructor(options) {
|
|
7165
|
+
super(options.summary);
|
|
7166
|
+
this.name = "CliError";
|
|
7167
|
+
this.stage = options.stage;
|
|
7168
|
+
this.details = options.details || [];
|
|
7169
|
+
this.suggestions = options.suggestions || [];
|
|
7170
|
+
this.cause = options.cause;
|
|
7171
|
+
}
|
|
7172
|
+
};
|
|
7173
|
+
function stringifyValue(value) {
|
|
7174
|
+
if (value === void 0 || value === null) {
|
|
7175
|
+
return "";
|
|
7176
|
+
}
|
|
7177
|
+
if (typeof value === "string") {
|
|
7178
|
+
return value;
|
|
7179
|
+
}
|
|
7180
|
+
try {
|
|
7181
|
+
return JSON.stringify(value);
|
|
7182
|
+
} catch (error) {
|
|
7183
|
+
return String(value);
|
|
7184
|
+
}
|
|
7185
|
+
}
|
|
7186
|
+
function getApiMessage(data) {
|
|
7187
|
+
var _a, _b, _c;
|
|
7188
|
+
return ((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.error) || ((_c = (_b = data == null ? void 0 : data.errors) == null ? void 0 : _b[0]) == null ? void 0 : _c.message) || (data == null ? void 0 : data.message) || (data == null ? void 0 : data.msg) || (data == null ? void 0 : data.error);
|
|
7189
|
+
}
|
|
7190
|
+
function getBusinessCode(data) {
|
|
7191
|
+
if ((data == null ? void 0 : data.code) === void 0 || (data == null ? void 0 : data.code) === null) {
|
|
7192
|
+
return void 0;
|
|
7193
|
+
}
|
|
7194
|
+
return String(data.code);
|
|
7195
|
+
}
|
|
7196
|
+
function getBusinessMessage(data) {
|
|
7197
|
+
if (!(data == null ? void 0 : data.msg)) {
|
|
7198
|
+
return void 0;
|
|
7199
|
+
}
|
|
7200
|
+
return String(data.msg);
|
|
7201
|
+
}
|
|
7202
|
+
function dedupeSuggestions(suggestions) {
|
|
7203
|
+
return Array.from(new Set(suggestions.filter(Boolean)));
|
|
7204
|
+
}
|
|
7205
|
+
function createConfigError(summary, suggestions = []) {
|
|
7206
|
+
return new CliError({
|
|
7207
|
+
summary,
|
|
7208
|
+
stage: "configuration",
|
|
7209
|
+
suggestions
|
|
7210
|
+
});
|
|
7211
|
+
}
|
|
7212
|
+
function createCommandError(stage, command, error, suggestions = []) {
|
|
7213
|
+
const exitCode = (error == null ? void 0 : error.status) ?? (error == null ? void 0 : error.code);
|
|
7214
|
+
const signal = error == null ? void 0 : error.signal;
|
|
7215
|
+
const detailLines = [`Command: ${command}`];
|
|
7216
|
+
if (exitCode !== void 0) {
|
|
7217
|
+
detailLines.push(`Exit code: ${exitCode}`);
|
|
7218
|
+
}
|
|
7219
|
+
if (signal) {
|
|
7220
|
+
detailLines.push(`Signal: ${signal}`);
|
|
7221
|
+
}
|
|
7222
|
+
if (error == null ? void 0 : error.message) {
|
|
7223
|
+
detailLines.push(`Reason: ${error.message}`);
|
|
7224
|
+
}
|
|
7225
|
+
return new CliError({
|
|
7226
|
+
summary: `${stage} failed.`,
|
|
7227
|
+
stage,
|
|
7228
|
+
details: detailLines,
|
|
7229
|
+
suggestions,
|
|
7230
|
+
cause: error
|
|
7231
|
+
});
|
|
7232
|
+
}
|
|
7233
|
+
function createApiError(stage, error, context = [], suggestions = []) {
|
|
7234
|
+
var _a, _b;
|
|
7235
|
+
const status = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status;
|
|
7236
|
+
const responseData = (_b = error == null ? void 0 : error.response) == null ? void 0 : _b.data;
|
|
7237
|
+
const errorCode = error == null ? void 0 : error.code;
|
|
7238
|
+
const apiMessage = getApiMessage(responseData);
|
|
7239
|
+
const businessCode = getBusinessCode(responseData);
|
|
7240
|
+
const businessMessage = getBusinessMessage(responseData);
|
|
7241
|
+
const summary = apiMessage || (error == null ? void 0 : error.message) || `${stage} failed.`;
|
|
7242
|
+
const detailLines = [...context];
|
|
7243
|
+
if (status) {
|
|
7244
|
+
detailLines.push(`HTTP status: ${status}`);
|
|
7245
|
+
}
|
|
7246
|
+
if (businessCode) {
|
|
7247
|
+
detailLines.push(`Business code: ${businessCode}`);
|
|
7248
|
+
}
|
|
7249
|
+
if (businessMessage && businessMessage !== apiMessage) {
|
|
7250
|
+
detailLines.push(`Business message: ${businessMessage}`);
|
|
7251
|
+
}
|
|
7252
|
+
if (apiMessage && apiMessage !== summary) {
|
|
7253
|
+
detailLines.push(`Error message: ${apiMessage}`);
|
|
7254
|
+
}
|
|
7255
|
+
if (errorCode && errorCode !== "ERR_BAD_REQUEST" && !responseData) {
|
|
7256
|
+
detailLines.push(`Error code: ${errorCode}`);
|
|
7257
|
+
}
|
|
7258
|
+
if (!responseData && (error == null ? void 0 : error.message) && error.message !== apiMessage) {
|
|
7259
|
+
detailLines.push(`Reason: ${error.message}`);
|
|
7260
|
+
}
|
|
7261
|
+
return new CliError({
|
|
7262
|
+
summary,
|
|
7263
|
+
stage,
|
|
7264
|
+
details: detailLines,
|
|
7265
|
+
suggestions: dedupeSuggestions(suggestions),
|
|
7266
|
+
cause: error
|
|
7267
|
+
});
|
|
7268
|
+
}
|
|
7269
|
+
function normalizeCliError(error, fallbackSummary, suggestions = []) {
|
|
7270
|
+
if (error instanceof CliError) {
|
|
7271
|
+
return error;
|
|
7272
|
+
}
|
|
7273
|
+
if (error instanceof Error) {
|
|
7274
|
+
return new CliError({
|
|
7275
|
+
summary: error.message || fallbackSummary,
|
|
7276
|
+
suggestions: dedupeSuggestions(suggestions),
|
|
7277
|
+
cause: error
|
|
7278
|
+
});
|
|
7279
|
+
}
|
|
7280
|
+
return new CliError({
|
|
7281
|
+
summary: fallbackSummary,
|
|
7282
|
+
details: [`Raw error: ${stringifyValue(error)}`],
|
|
7283
|
+
suggestions: dedupeSuggestions(suggestions),
|
|
7284
|
+
cause: error
|
|
7285
|
+
});
|
|
7286
|
+
}
|
|
7287
|
+
function printCliError(error, fallbackSummary) {
|
|
7288
|
+
const cliError = normalizeCliError(error, fallbackSummary);
|
|
7289
|
+
console.error(import_chalk16.default.red(`
|
|
7290
|
+
Error: ${cliError.message}`));
|
|
7291
|
+
if (cliError.stage) {
|
|
7292
|
+
console.error(import_chalk16.default.gray(`Stage: ${cliError.stage}`));
|
|
7293
|
+
}
|
|
7294
|
+
for (const detail of cliError.details) {
|
|
7295
|
+
console.error(import_chalk16.default.gray(detail));
|
|
7296
|
+
}
|
|
7297
|
+
if (cliError.suggestions.length > 0) {
|
|
7298
|
+
console.error(import_chalk16.default.yellow("\nNext steps:"));
|
|
7299
|
+
for (const suggestion of cliError.suggestions) {
|
|
7300
|
+
console.error(import_chalk16.default.yellow(`- ${suggestion}`));
|
|
7301
|
+
}
|
|
7302
|
+
}
|
|
7303
|
+
}
|
|
7304
|
+
|
|
7305
|
+
// bin/create.ts
|
|
6937
7306
|
var PROJECT_DIR = process.cwd();
|
|
6938
|
-
var API_BASE = "https://pinme.
|
|
7307
|
+
var API_BASE = "https://pinme.dev/api/v4";
|
|
7308
|
+
var TEMPLATE_REPO = "glitternetwork/pinme-worker-template";
|
|
7309
|
+
var TEMPLATE_ZIP_URL = `https://github.com/${TEMPLATE_REPO}/archive/refs/heads/main.zip`;
|
|
6939
7310
|
async function createCmd(options) {
|
|
6940
|
-
var _a, _b, _c, _d, _e, _f;
|
|
6941
7311
|
try {
|
|
6942
7312
|
const headers = getAuthHeaders();
|
|
6943
7313
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
7314
|
+
throw createConfigError("No valid local login session was found.", [
|
|
7315
|
+
"Run `pinme login` and retry."
|
|
7316
|
+
]);
|
|
6947
7317
|
}
|
|
6948
|
-
console.log(
|
|
7318
|
+
console.log(import_chalk17.default.blue("Creating new project from template...\n"));
|
|
6949
7319
|
let projectName = options.name;
|
|
6950
7320
|
if (!projectName) {
|
|
6951
7321
|
const answers = await import_inquirer8.default.prompt([
|
|
@@ -6966,7 +7336,7 @@ async function createCmd(options) {
|
|
|
6966
7336
|
}
|
|
6967
7337
|
const targetDir = import_path11.default.join(PROJECT_DIR, projectName);
|
|
6968
7338
|
if (import_fs_extra6.default.existsSync(targetDir) && !options.force) {
|
|
6969
|
-
console.log(
|
|
7339
|
+
console.log(import_chalk17.default.yellow(`
|
|
6970
7340
|
Directory "${projectName}" already exists.`));
|
|
6971
7341
|
const answers = await import_inquirer8.default.prompt([
|
|
6972
7342
|
{
|
|
@@ -6977,16 +7347,16 @@ Directory "${projectName}" already exists.`));
|
|
|
6977
7347
|
}
|
|
6978
7348
|
]);
|
|
6979
7349
|
if (!answers.overwrite) {
|
|
6980
|
-
console.log(
|
|
7350
|
+
console.log(import_chalk17.default.gray("Cancelled."));
|
|
6981
7351
|
process.exit(0);
|
|
6982
7352
|
}
|
|
6983
7353
|
import_fs_extra6.default.removeSync(targetDir);
|
|
6984
7354
|
}
|
|
6985
|
-
console.log(
|
|
7355
|
+
console.log(import_chalk17.default.blue("\n1. Creating worker and database..."));
|
|
6986
7356
|
const apiUrl = `${API_BASE}/create_worker`;
|
|
6987
|
-
console.log(
|
|
7357
|
+
console.log(import_chalk17.default.gray(`API URL: ${apiUrl}`));
|
|
6988
7358
|
const normalizedProjectName = projectName.toLowerCase();
|
|
6989
|
-
console.log(
|
|
7359
|
+
console.log(import_chalk17.default.gray(`Project name: ${normalizedProjectName}`));
|
|
6990
7360
|
let workerData;
|
|
6991
7361
|
try {
|
|
6992
7362
|
const response = await axios_default.post(apiUrl, {
|
|
@@ -6999,40 +7369,72 @@ Directory "${projectName}" already exists.`));
|
|
|
6999
7369
|
});
|
|
7000
7370
|
const data = response.data;
|
|
7001
7371
|
if (data.code !== 200) {
|
|
7002
|
-
|
|
7003
|
-
|
|
7372
|
+
throw createApiError("project creation", { response: { status: response.status, data } }, [
|
|
7373
|
+
`Project name: ${normalizedProjectName}`,
|
|
7374
|
+
`Endpoint: ${apiUrl}`
|
|
7375
|
+
]);
|
|
7004
7376
|
}
|
|
7005
7377
|
workerData = data.data;
|
|
7006
|
-
console.log(
|
|
7007
|
-
console.log(
|
|
7008
|
-
console.log(
|
|
7009
|
-
console.log(
|
|
7378
|
+
console.log(import_chalk17.default.gray(` API Response: ${JSON.stringify(workerData)}`));
|
|
7379
|
+
console.log(import_chalk17.default.green(` API Domain: ${workerData.api_domain}`));
|
|
7380
|
+
console.log(import_chalk17.default.green(` Project Name: ${workerData.project_name}`));
|
|
7381
|
+
console.log(import_chalk17.default.green(` D1 UUID: ${workerData.uuid}`));
|
|
7010
7382
|
} catch (error) {
|
|
7011
|
-
|
|
7012
|
-
|
|
7383
|
+
throw createApiError("project creation", error, [
|
|
7384
|
+
`Project name: ${normalizedProjectName}`,
|
|
7385
|
+
`Endpoint: ${apiUrl}`
|
|
7386
|
+
]);
|
|
7387
|
+
}
|
|
7388
|
+
console.log(import_chalk17.default.blue("\n2. Downloading template from repository..."));
|
|
7389
|
+
const zipPath = import_path11.default.join(PROJECT_DIR, "template.zip");
|
|
7390
|
+
let downloadSuccess = false;
|
|
7391
|
+
for (let attempt = 1; attempt <= 3 && !downloadSuccess; attempt++) {
|
|
7392
|
+
try {
|
|
7393
|
+
console.log(import_chalk17.default.gray(` Download attempt ${attempt}/3...`));
|
|
7394
|
+
(0, import_child_process2.execSync)(`curl -L --retry 3 --retry-delay 2 -o "${zipPath}" "${TEMPLATE_ZIP_URL}"`, {
|
|
7395
|
+
stdio: "inherit"
|
|
7396
|
+
});
|
|
7397
|
+
if (!import_fs_extra6.default.existsSync(zipPath) || import_fs_extra6.default.statSync(zipPath).size < 100) {
|
|
7398
|
+
throw new Error("Downloaded file is too small or empty");
|
|
7399
|
+
}
|
|
7400
|
+
downloadSuccess = true;
|
|
7401
|
+
} catch (downloadError) {
|
|
7402
|
+
console.log(import_chalk17.default.yellow(` Attempt ${attempt} failed: ${downloadError.message}`));
|
|
7403
|
+
if (import_fs_extra6.default.existsSync(zipPath)) {
|
|
7404
|
+
import_fs_extra6.default.removeSync(zipPath);
|
|
7405
|
+
}
|
|
7406
|
+
if (attempt === 3) {
|
|
7407
|
+
throw new Error(`Failed to download template after 3 attempts: ${downloadError.message}`);
|
|
7408
|
+
}
|
|
7409
|
+
}
|
|
7410
|
+
}
|
|
7411
|
+
try {
|
|
7412
|
+
(0, import_child_process2.execSync)(`unzip -o "${zipPath}" -d "${PROJECT_DIR}"`, {
|
|
7413
|
+
stdio: "inherit"
|
|
7414
|
+
});
|
|
7415
|
+
const subDir = import_path11.default.join(PROJECT_DIR, "pinme-worker-template-main");
|
|
7416
|
+
if (import_fs_extra6.default.existsSync(subDir)) {
|
|
7417
|
+
import_fs_extra6.default.copySync(subDir, targetDir);
|
|
7418
|
+
import_fs_extra6.default.removeSync(subDir);
|
|
7419
|
+
}
|
|
7420
|
+
import_fs_extra6.default.removeSync(zipPath);
|
|
7421
|
+
console.log(import_chalk17.default.green(` Template downloaded to: ${targetDir}`));
|
|
7422
|
+
} catch (error) {
|
|
7423
|
+
throw createCommandError("template extraction", `unzip -o "${zipPath}" -d "${PROJECT_DIR}"`, error, [
|
|
7424
|
+
"Check whether `unzip` is available and the downloaded template archive is valid."
|
|
7425
|
+
]);
|
|
7013
7426
|
}
|
|
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..."));
|
|
7427
|
+
console.log(import_chalk17.default.blue("\n3. Updating configuration..."));
|
|
7018
7428
|
const configPath = import_path11.default.join(targetDir, "pinme.toml");
|
|
7019
7429
|
const config = import_fs_extra6.default.readFileSync(configPath, "utf-8");
|
|
7020
7430
|
let updatedConfig = config.replace(
|
|
7021
7431
|
/project_name = ".*"/,
|
|
7022
7432
|
`project_name = "${workerData.project_name}"`
|
|
7023
7433
|
);
|
|
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
7434
|
import_fs_extra6.default.writeFileSync(configPath, updatedConfig);
|
|
7033
|
-
console.log(
|
|
7034
|
-
console.log(
|
|
7035
|
-
console.log(
|
|
7435
|
+
console.log(import_chalk17.default.green(` Updated pinme.toml`));
|
|
7436
|
+
console.log(import_chalk17.default.gray(` metadata: ${workerData.metadata}`));
|
|
7437
|
+
console.log(import_chalk17.default.gray(` VITE_API_URL: ${workerData.api_domain}`));
|
|
7036
7438
|
const backendDir = import_path11.default.join(targetDir, "backend");
|
|
7037
7439
|
if (import_fs_extra6.default.existsSync(backendDir) && workerData.metadata) {
|
|
7038
7440
|
const metadataContent = typeof workerData.metadata === "string" ? workerData.metadata : JSON.stringify(workerData.metadata, null, 2);
|
|
@@ -7040,52 +7442,101 @@ Directory "${projectName}" already exists.`));
|
|
|
7040
7442
|
import_path11.default.join(backendDir, "metadata.json"),
|
|
7041
7443
|
metadataContent
|
|
7042
7444
|
);
|
|
7043
|
-
console.log(
|
|
7445
|
+
console.log(import_chalk17.default.green(` Saved metadata.json`));
|
|
7446
|
+
}
|
|
7447
|
+
const wranglerPath = import_path11.default.join(backendDir, "wrangler.toml");
|
|
7448
|
+
if (import_fs_extra6.default.existsSync(wranglerPath) && workerData.api_key) {
|
|
7449
|
+
let wranglerContent = import_fs_extra6.default.readFileSync(wranglerPath, "utf-8");
|
|
7450
|
+
wranglerContent = wranglerContent.replace(
|
|
7451
|
+
/^name = ".*"$/m,
|
|
7452
|
+
`name = "${workerData.project_name}"`
|
|
7453
|
+
);
|
|
7454
|
+
import_fs_extra6.default.writeFileSync(wranglerPath, wranglerContent);
|
|
7455
|
+
console.log(import_chalk17.default.green(` Updated backend/wrangler.toml API_KEY`));
|
|
7044
7456
|
}
|
|
7045
7457
|
const envExamplePath = import_path11.default.join(targetDir, "frontend", ".env.example");
|
|
7046
7458
|
const envPath = import_path11.default.join(targetDir, "frontend", ".env");
|
|
7047
7459
|
if (import_fs_extra6.default.existsSync(envExamplePath)) {
|
|
7048
7460
|
let envContent = import_fs_extra6.default.readFileSync(envExamplePath, "utf-8");
|
|
7049
7461
|
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
7462
|
envContent = envContent.replace(
|
|
7055
7463
|
/^VITE_API_URL=.*$/m,
|
|
7056
7464
|
`VITE_API_URL=${workerData.api_domain}`
|
|
7057
7465
|
);
|
|
7058
7466
|
import_fs_extra6.default.writeFileSync(envPath, envContent);
|
|
7059
|
-
console.log(
|
|
7467
|
+
console.log(import_chalk17.default.green(` Created frontend/.env file`));
|
|
7468
|
+
}
|
|
7469
|
+
console.log(import_chalk17.default.blue("\n4. Building frontend..."));
|
|
7470
|
+
try {
|
|
7471
|
+
(0, import_child_process2.execSync)("npm install", {
|
|
7472
|
+
cwd: targetDir,
|
|
7473
|
+
stdio: "inherit"
|
|
7474
|
+
});
|
|
7475
|
+
console.log(import_chalk17.default.green(" Project dependencies installed"));
|
|
7476
|
+
} catch (error) {
|
|
7477
|
+
throw createCommandError("project dependency install", "npm install", error, [
|
|
7478
|
+
"Check network connectivity and npm registry availability.",
|
|
7479
|
+
"Inspect the generated workspace `package.json` files for dependency conflicts."
|
|
7480
|
+
]);
|
|
7481
|
+
}
|
|
7482
|
+
const frontendDir = import_path11.default.join(targetDir, "frontend");
|
|
7483
|
+
if (import_fs_extra6.default.existsSync(frontendDir)) {
|
|
7484
|
+
try {
|
|
7485
|
+
(0, import_child_process2.execSync)("npm run build:frontend", {
|
|
7486
|
+
cwd: targetDir,
|
|
7487
|
+
stdio: "inherit"
|
|
7488
|
+
});
|
|
7489
|
+
console.log(import_chalk17.default.green(" Frontend built"));
|
|
7490
|
+
} catch (error) {
|
|
7491
|
+
throw createCommandError("frontend build", "npm run build:frontend", error, [
|
|
7492
|
+
"Fix the frontend build error shown above, then rerun `pinme create`."
|
|
7493
|
+
]);
|
|
7494
|
+
}
|
|
7495
|
+
console.log(import_chalk17.default.blue(" Uploading to IPFS..."));
|
|
7496
|
+
try {
|
|
7497
|
+
(0, import_child_process2.execSync)("pinme upload ./dist", {
|
|
7498
|
+
cwd: frontendDir,
|
|
7499
|
+
stdio: "inherit",
|
|
7500
|
+
env: {
|
|
7501
|
+
...process.env,
|
|
7502
|
+
PINME_PROJECT_NAME: workerData.project_name
|
|
7503
|
+
}
|
|
7504
|
+
});
|
|
7505
|
+
console.log(import_chalk17.default.green(" Frontend uploaded to IPFS"));
|
|
7506
|
+
} catch (error) {
|
|
7507
|
+
console.log(import_chalk17.default.yellow(" Warning: IPFS upload failed, you can upload manually later"));
|
|
7508
|
+
}
|
|
7060
7509
|
}
|
|
7061
|
-
console.log(
|
|
7062
|
-
console.log(
|
|
7510
|
+
console.log(import_chalk17.default.green("\nProject created successfully."));
|
|
7511
|
+
console.log(import_chalk17.default.gray(`
|
|
7063
7512
|
Project Details:`));
|
|
7064
|
-
console.log(
|
|
7065
|
-
console.log(
|
|
7066
|
-
console.log(
|
|
7513
|
+
console.log(import_chalk17.default.gray(` API Domain: ${workerData.api_domain}`));
|
|
7514
|
+
console.log(import_chalk17.default.gray(` Project Name: ${workerData.project_name}`));
|
|
7515
|
+
console.log(import_chalk17.default.gray(`
|
|
7067
7516
|
Next steps:`));
|
|
7068
|
-
console.log(
|
|
7069
|
-
console.log(
|
|
7517
|
+
console.log(import_chalk17.default.gray(` cd ${projectName}`));
|
|
7518
|
+
console.log(import_chalk17.default.gray(` pinme save`));
|
|
7070
7519
|
process.exit(0);
|
|
7071
7520
|
} catch (error) {
|
|
7072
|
-
|
|
7073
|
-
Error: ${error.message || error}`));
|
|
7521
|
+
printCliError(error, "Project creation failed.");
|
|
7074
7522
|
process.exit(1);
|
|
7075
7523
|
}
|
|
7076
7524
|
}
|
|
7077
7525
|
|
|
7078
7526
|
// bin/save.ts
|
|
7079
|
-
var
|
|
7527
|
+
var import_chalk18 = __toESM(require("chalk"));
|
|
7080
7528
|
var import_fs_extra7 = __toESM(require("fs-extra"));
|
|
7081
7529
|
var import_path12 = __toESM(require("path"));
|
|
7082
|
-
var
|
|
7530
|
+
var import_child_process3 = require("child_process");
|
|
7083
7531
|
var PROJECT_DIR2 = process.cwd();
|
|
7084
|
-
var API_BASE2 = "https://pinme.
|
|
7532
|
+
var API_BASE2 = "https://pinme.dev/api/v4";
|
|
7085
7533
|
function loadConfig() {
|
|
7086
7534
|
const configPath = import_path12.default.join(PROJECT_DIR2, "pinme.toml");
|
|
7087
7535
|
if (!import_fs_extra7.default.existsSync(configPath)) {
|
|
7088
|
-
throw
|
|
7536
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
7537
|
+
"Run this command from the Pinme project root.",
|
|
7538
|
+
"If the project has not been initialized yet, create or restore `pinme.toml` first."
|
|
7539
|
+
]);
|
|
7089
7540
|
}
|
|
7090
7541
|
const configContent = import_fs_extra7.default.readFileSync(configPath, "utf-8");
|
|
7091
7542
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7096,67 +7547,52 @@ function loadConfig() {
|
|
|
7096
7547
|
function getMetadata() {
|
|
7097
7548
|
const metadataPath = import_path12.default.join(PROJECT_DIR2, "backend", "metadata.json");
|
|
7098
7549
|
if (!import_fs_extra7.default.existsSync(metadataPath)) {
|
|
7099
|
-
console.log(
|
|
7550
|
+
console.log(import_chalk18.default.yellow(" Warning: metadata.json not found, using empty metadata"));
|
|
7100
7551
|
return {};
|
|
7101
7552
|
}
|
|
7102
7553
|
return import_fs_extra7.default.readJsonSync(metadataPath);
|
|
7103
7554
|
}
|
|
7104
7555
|
function buildWorker() {
|
|
7105
|
-
console.log(
|
|
7556
|
+
console.log(import_chalk18.default.blue("Building worker..."));
|
|
7106
7557
|
try {
|
|
7107
|
-
(0,
|
|
7558
|
+
(0, import_child_process3.execSync)("npm run build:worker", {
|
|
7108
7559
|
cwd: PROJECT_DIR2,
|
|
7109
7560
|
stdio: "inherit"
|
|
7110
7561
|
});
|
|
7111
|
-
console.log(
|
|
7562
|
+
console.log(import_chalk18.default.green("Worker built"));
|
|
7112
7563
|
} catch (error) {
|
|
7113
|
-
throw
|
|
7564
|
+
throw createCommandError("worker build", "npm run build:worker", error, [
|
|
7565
|
+
"Fix the build error shown above, then rerun `pinme save`."
|
|
7566
|
+
]);
|
|
7114
7567
|
}
|
|
7115
7568
|
}
|
|
7116
7569
|
function installDependencies() {
|
|
7117
|
-
console.log(
|
|
7570
|
+
console.log(import_chalk18.default.blue("Installing dependencies..."));
|
|
7118
7571
|
try {
|
|
7119
|
-
(0,
|
|
7572
|
+
(0, import_child_process3.execSync)("npm install", {
|
|
7120
7573
|
cwd: PROJECT_DIR2,
|
|
7121
7574
|
stdio: "inherit"
|
|
7122
7575
|
});
|
|
7123
|
-
console.log(
|
|
7576
|
+
console.log(import_chalk18.default.green("Project dependencies installed"));
|
|
7124
7577
|
} 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
|
-
}
|
|
7578
|
+
throw createCommandError("project dependency install", "npm install", error, [
|
|
7579
|
+
"Check network connectivity and npm registry availability.",
|
|
7580
|
+
"If `package-lock.json` is stale or conflicted, resolve that before retrying."
|
|
7581
|
+
]);
|
|
7150
7582
|
}
|
|
7151
7583
|
}
|
|
7152
7584
|
function getBuiltWorker() {
|
|
7153
7585
|
const distWorkerDir = import_path12.default.join(PROJECT_DIR2, "dist-worker");
|
|
7154
7586
|
if (!import_fs_extra7.default.existsSync(distWorkerDir)) {
|
|
7155
|
-
throw
|
|
7587
|
+
throw createConfigError("Built worker output not found: `dist-worker/`.", [
|
|
7588
|
+
"Make sure `npm run build:worker` completed successfully."
|
|
7589
|
+
]);
|
|
7156
7590
|
}
|
|
7157
7591
|
const workerJsPath = import_path12.default.join(distWorkerDir, "worker.js");
|
|
7158
7592
|
if (!import_fs_extra7.default.existsSync(workerJsPath)) {
|
|
7159
|
-
throw
|
|
7593
|
+
throw createConfigError("Built worker entry file not found: `dist-worker/worker.js`.", [
|
|
7594
|
+
"Check the worker build output and bundler config."
|
|
7595
|
+
]);
|
|
7160
7596
|
}
|
|
7161
7597
|
const modulePaths = [];
|
|
7162
7598
|
const files = import_fs_extra7.default.readdirSync(distWorkerDir);
|
|
@@ -7168,7 +7604,7 @@ function getBuiltWorker() {
|
|
|
7168
7604
|
return { workerJsPath, modulePaths };
|
|
7169
7605
|
}
|
|
7170
7606
|
function getSqlFiles() {
|
|
7171
|
-
const sqlDir = import_path12.default.join(PROJECT_DIR2, "
|
|
7607
|
+
const sqlDir = import_path12.default.join(PROJECT_DIR2, "db");
|
|
7172
7608
|
if (!import_fs_extra7.default.existsSync(sqlDir)) {
|
|
7173
7609
|
return [];
|
|
7174
7610
|
}
|
|
@@ -7176,16 +7612,16 @@ function getSqlFiles() {
|
|
|
7176
7612
|
return files.map((f) => import_path12.default.join(sqlDir, f));
|
|
7177
7613
|
}
|
|
7178
7614
|
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(
|
|
7615
|
+
var _a, _b;
|
|
7616
|
+
console.log(import_chalk18.default.blue("Saving worker to platform..."));
|
|
7617
|
+
console.log(import_chalk18.default.gray(`Project: ${projectName}`));
|
|
7618
|
+
console.log(import_chalk18.default.gray(`workerJsPath: ${workerJsPath}`));
|
|
7619
|
+
console.log(import_chalk18.default.gray(`modulePaths: ${modulePaths}`));
|
|
7620
|
+
console.log(import_chalk18.default.gray(`sqlFiles: ${sqlFiles}`));
|
|
7621
|
+
console.log(import_chalk18.default.gray(`metadata: ${metadata}`));
|
|
7186
7622
|
const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
|
|
7187
7623
|
const headers = getAuthHeaders();
|
|
7188
|
-
console.log(
|
|
7624
|
+
console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
|
|
7189
7625
|
try {
|
|
7190
7626
|
const FormData4 = (await import("formdata-node")).FormData;
|
|
7191
7627
|
const Blob2 = (await import("formdata-node")).Blob;
|
|
@@ -7210,61 +7646,76 @@ async function saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, project
|
|
|
7210
7646
|
formData.append("sql_file", new Blob2([content], {
|
|
7211
7647
|
type: "application/sql"
|
|
7212
7648
|
}), filename);
|
|
7213
|
-
console.log(
|
|
7649
|
+
console.log(import_chalk18.default.gray(` Including SQL: ${filename}`));
|
|
7214
7650
|
}
|
|
7215
7651
|
const response = await axios_default.put(apiUrl, formData, {
|
|
7216
7652
|
headers: { ...headers },
|
|
7217
7653
|
timeout: 12e4
|
|
7218
7654
|
});
|
|
7219
|
-
console.log(
|
|
7655
|
+
console.log(import_chalk18.default.gray(` Response: ${JSON.stringify(response.data)}`));
|
|
7220
7656
|
if (response.data) {
|
|
7221
|
-
console.log(
|
|
7657
|
+
console.log(import_chalk18.default.green("Worker saved"));
|
|
7222
7658
|
if ((_b = (_a = response.data) == null ? void 0 : _a.data) == null ? void 0 : _b.sql_results) {
|
|
7223
7659
|
for (const result of response.data.data.sql_results) {
|
|
7224
|
-
console.log(
|
|
7660
|
+
console.log(import_chalk18.default.gray(` SQL ${result.filename}: ${result.status}`));
|
|
7225
7661
|
}
|
|
7226
7662
|
}
|
|
7227
7663
|
} else {
|
|
7228
|
-
throw
|
|
7664
|
+
throw createApiError("worker save", { response: { data: response.data } }, [
|
|
7665
|
+
`Project: ${projectName}`,
|
|
7666
|
+
`Endpoint: ${apiUrl}`
|
|
7667
|
+
], [
|
|
7668
|
+
"Verify the project exists and your account has permission to update it."
|
|
7669
|
+
]);
|
|
7229
7670
|
}
|
|
7230
7671
|
} catch (error) {
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7672
|
+
throw createApiError("worker save", error, [
|
|
7673
|
+
`Project: ${projectName}`,
|
|
7674
|
+
`Endpoint: ${apiUrl}`
|
|
7675
|
+
], [
|
|
7676
|
+
"Check whether backend metadata, SQL files, or worker bundle contains invalid content."
|
|
7677
|
+
]);
|
|
7235
7678
|
}
|
|
7236
7679
|
}
|
|
7237
7680
|
function buildFrontend() {
|
|
7238
|
-
console.log(
|
|
7681
|
+
console.log(import_chalk18.default.blue("Building frontend..."));
|
|
7239
7682
|
try {
|
|
7240
|
-
(0,
|
|
7683
|
+
(0, import_child_process3.execSync)("npm run build:frontend", {
|
|
7241
7684
|
cwd: PROJECT_DIR2,
|
|
7242
7685
|
stdio: "inherit"
|
|
7243
7686
|
});
|
|
7244
|
-
console.log(
|
|
7687
|
+
console.log(import_chalk18.default.green("Frontend built"));
|
|
7245
7688
|
} catch (error) {
|
|
7246
|
-
throw
|
|
7689
|
+
throw createCommandError("frontend build", "npm run build:frontend", error, [
|
|
7690
|
+
"Fix the frontend build error shown above, then rerun `pinme save`."
|
|
7691
|
+
]);
|
|
7247
7692
|
}
|
|
7248
7693
|
}
|
|
7249
|
-
function deployFrontend() {
|
|
7250
|
-
console.log(
|
|
7694
|
+
function deployFrontend(projectName) {
|
|
7695
|
+
console.log(import_chalk18.default.blue("Deploying frontend to IPFS..."));
|
|
7251
7696
|
try {
|
|
7252
|
-
(0,
|
|
7697
|
+
(0, import_child_process3.execSync)("pinme upload ./frontend/dist", {
|
|
7253
7698
|
cwd: PROJECT_DIR2,
|
|
7254
|
-
stdio: "inherit"
|
|
7699
|
+
stdio: "inherit",
|
|
7700
|
+
env: {
|
|
7701
|
+
...process.env,
|
|
7702
|
+
PINME_PROJECT_NAME: projectName
|
|
7703
|
+
}
|
|
7255
7704
|
});
|
|
7256
|
-
console.log(
|
|
7705
|
+
console.log(import_chalk18.default.green("Frontend deployed to IPFS"));
|
|
7257
7706
|
} catch (error) {
|
|
7258
|
-
throw
|
|
7707
|
+
throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
|
|
7708
|
+
"Make sure `frontend/dist` exists and `pinme upload` works in this environment."
|
|
7709
|
+
]);
|
|
7259
7710
|
}
|
|
7260
7711
|
}
|
|
7261
7712
|
async function saveCmd(options) {
|
|
7262
7713
|
try {
|
|
7263
7714
|
const headers = getAuthHeaders();
|
|
7264
7715
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7716
|
+
throw createConfigError("No valid local login session was found.", [
|
|
7717
|
+
"Run `pinme login` and retry."
|
|
7718
|
+
]);
|
|
7268
7719
|
}
|
|
7269
7720
|
const projectDir = options.projectName || options.name ? import_path12.default.join(PROJECT_DIR2, options.projectName || options.name) : PROJECT_DIR2;
|
|
7270
7721
|
const tokenFileSrc = import_path12.default.join(PROJECT_DIR2, ".token.json");
|
|
@@ -7272,48 +7723,51 @@ async function saveCmd(options) {
|
|
|
7272
7723
|
if (import_fs_extra7.default.existsSync(tokenFileSrc) && !import_fs_extra7.default.existsSync(tokenFileDst)) {
|
|
7273
7724
|
import_fs_extra7.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7274
7725
|
}
|
|
7275
|
-
console.log(
|
|
7276
|
-
console.log(
|
|
7726
|
+
console.log(import_chalk18.default.blue("Deploying to platform...\n"));
|
|
7727
|
+
console.log(import_chalk18.default.gray(`Project dir: ${PROJECT_DIR2}`));
|
|
7277
7728
|
const config = loadConfig();
|
|
7278
7729
|
const projectName = config.project_name;
|
|
7279
7730
|
if (!projectName) {
|
|
7280
|
-
throw
|
|
7731
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
7732
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
7733
|
+
]);
|
|
7281
7734
|
}
|
|
7282
|
-
console.log(
|
|
7735
|
+
console.log(import_chalk18.default.gray(`Project: ${projectName}`));
|
|
7283
7736
|
const apiUrl = `${API_BASE2}/save_worker?project_name=${encodeURIComponent(projectName)}`;
|
|
7284
|
-
console.log(
|
|
7285
|
-
console.log(
|
|
7737
|
+
console.log(import_chalk18.default.gray(`API URL: ${apiUrl}`));
|
|
7738
|
+
console.log(import_chalk18.default.blue("\n--- Backend ---"));
|
|
7286
7739
|
installDependencies();
|
|
7287
7740
|
buildWorker();
|
|
7288
7741
|
const metadata = getMetadata();
|
|
7289
7742
|
const { workerJsPath, modulePaths } = getBuiltWorker();
|
|
7290
|
-
console.log(
|
|
7291
|
-
console.log(
|
|
7743
|
+
console.log(import_chalk18.default.gray(`Worker JS: ${workerJsPath}`));
|
|
7744
|
+
console.log(import_chalk18.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
|
|
7292
7745
|
const sqlFiles = getSqlFiles();
|
|
7293
|
-
console.log(
|
|
7746
|
+
console.log(import_chalk18.default.gray(`SQL files: ${JSON.stringify(sqlFiles)}`));
|
|
7294
7747
|
await saveWorker(workerJsPath, modulePaths, sqlFiles, metadata, projectName);
|
|
7295
|
-
console.log(
|
|
7748
|
+
console.log(import_chalk18.default.blue("\n--- Frontend ---"));
|
|
7296
7749
|
buildFrontend();
|
|
7297
|
-
deployFrontend();
|
|
7298
|
-
console.log(
|
|
7750
|
+
deployFrontend(projectName);
|
|
7751
|
+
console.log(import_chalk18.default.green("\nDeployment complete."));
|
|
7299
7752
|
process.exit(0);
|
|
7300
7753
|
} catch (error) {
|
|
7301
|
-
|
|
7302
|
-
\u274C Error: ${error.message}`));
|
|
7754
|
+
printCliError(error, "Save failed.");
|
|
7303
7755
|
process.exit(1);
|
|
7304
7756
|
}
|
|
7305
7757
|
}
|
|
7306
7758
|
|
|
7307
7759
|
// bin/updateDb.ts
|
|
7308
|
-
var
|
|
7760
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
7309
7761
|
var import_fs_extra8 = __toESM(require("fs-extra"));
|
|
7310
7762
|
var import_path13 = __toESM(require("path"));
|
|
7311
7763
|
var PROJECT_DIR3 = process.cwd();
|
|
7312
|
-
var API_BASE3 = "https://pinme.
|
|
7764
|
+
var API_BASE3 = "https://pinme.dev/api/v4";
|
|
7313
7765
|
function loadConfig2() {
|
|
7314
7766
|
const configPath = import_path13.default.join(PROJECT_DIR3, "pinme.toml");
|
|
7315
7767
|
if (!import_fs_extra8.default.existsSync(configPath)) {
|
|
7316
|
-
throw
|
|
7768
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
7769
|
+
"Run this command from the Pinme project root."
|
|
7770
|
+
]);
|
|
7317
7771
|
}
|
|
7318
7772
|
const configContent = import_fs_extra8.default.readFileSync(configPath, "utf-8");
|
|
7319
7773
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7322,24 +7776,27 @@ function loadConfig2() {
|
|
|
7322
7776
|
};
|
|
7323
7777
|
}
|
|
7324
7778
|
function getSqlFiles2() {
|
|
7325
|
-
const sqlDir = import_path13.default.join(PROJECT_DIR3, "
|
|
7779
|
+
const sqlDir = import_path13.default.join(PROJECT_DIR3, "db");
|
|
7326
7780
|
if (!import_fs_extra8.default.existsSync(sqlDir)) {
|
|
7327
|
-
throw
|
|
7781
|
+
throw createConfigError("SQL directory not found: `db/`.", [
|
|
7782
|
+
"Create a `db/` directory and add at least one `.sql` migration file."
|
|
7783
|
+
]);
|
|
7328
7784
|
}
|
|
7329
7785
|
const files = import_fs_extra8.default.readdirSync(sqlDir).filter((f) => f.endsWith(".sql")).sort();
|
|
7330
7786
|
if (files.length === 0) {
|
|
7331
|
-
throw
|
|
7787
|
+
throw createConfigError("No `.sql` files were found in `db/`.", [
|
|
7788
|
+
"Add one or more migration files before running `pinme update-db`."
|
|
7789
|
+
]);
|
|
7332
7790
|
}
|
|
7333
7791
|
return files.map((f) => import_path13.default.join(sqlDir, f));
|
|
7334
7792
|
}
|
|
7335
7793
|
async function updateDb(sqlFiles, projectName) {
|
|
7336
|
-
|
|
7337
|
-
console.log(
|
|
7338
|
-
console.log(
|
|
7339
|
-
console.log(import_chalk18.default.gray(`SQL files: ${sqlFiles.length}`));
|
|
7794
|
+
console.log(import_chalk19.default.blue("Importing SQL files to database..."));
|
|
7795
|
+
console.log(import_chalk19.default.gray(`Project: ${projectName}`));
|
|
7796
|
+
console.log(import_chalk19.default.gray(`SQL files: ${sqlFiles.length}`));
|
|
7340
7797
|
const apiUrl = `${API_BASE3}/update_db?project_name=${encodeURIComponent(projectName)}`;
|
|
7341
7798
|
const headers = getAuthHeaders();
|
|
7342
|
-
console.log(
|
|
7799
|
+
console.log(import_chalk19.default.gray(`API URL: ${apiUrl}`));
|
|
7343
7800
|
try {
|
|
7344
7801
|
const FormData4 = (await import("formdata-node")).FormData;
|
|
7345
7802
|
const Blob2 = (await import("formdata-node")).Blob;
|
|
@@ -7350,49 +7807,57 @@ async function updateDb(sqlFiles, projectName) {
|
|
|
7350
7807
|
const content = import_fs_extra8.default.readFileSync(sqlFile);
|
|
7351
7808
|
totalSize += content.length;
|
|
7352
7809
|
if (totalSize > 10 * 1024 * 1024) {
|
|
7353
|
-
throw
|
|
7810
|
+
throw createConfigError("Total SQL payload exceeds the 10MB platform limit.", [
|
|
7811
|
+
"Split migrations into smaller batches, then rerun `pinme update-db`."
|
|
7812
|
+
]);
|
|
7354
7813
|
}
|
|
7355
7814
|
formData.append("file", new Blob2([content], {
|
|
7356
7815
|
type: "application/sql"
|
|
7357
7816
|
}), filename);
|
|
7358
|
-
console.log(
|
|
7817
|
+
console.log(import_chalk19.default.gray(` Including: ${filename} (${content.length} bytes)`));
|
|
7359
7818
|
}
|
|
7360
7819
|
const response = await axios_default.post(apiUrl, formData, {
|
|
7361
7820
|
headers: { ...headers },
|
|
7362
7821
|
timeout: 12e4
|
|
7363
7822
|
});
|
|
7364
|
-
console.log(
|
|
7823
|
+
console.log(import_chalk19.default.gray(` Response: ${JSON.stringify(response.data)}`));
|
|
7365
7824
|
if (response.data.code === 200) {
|
|
7366
|
-
console.log(
|
|
7825
|
+
console.log(import_chalk19.default.green("SQL files imported successfully!"));
|
|
7367
7826
|
const results = response.data.data.results;
|
|
7368
7827
|
for (const result of results) {
|
|
7369
7828
|
if (result.status === "complete") {
|
|
7370
|
-
console.log(
|
|
7829
|
+
console.log(import_chalk19.default.green(` COMPLETE ${result.filename}: ${result.num_queries} queries, ${result.duration}ms`));
|
|
7371
7830
|
if (result.changes !== void 0) {
|
|
7372
|
-
console.log(
|
|
7831
|
+
console.log(import_chalk19.default.gray(` Changes: ${result.changes}, Read: ${result.rows_read}, Written: ${result.rows_written}`));
|
|
7373
7832
|
}
|
|
7374
7833
|
} else if (result.status === "error") {
|
|
7375
|
-
console.log(
|
|
7834
|
+
console.log(import_chalk19.default.red(` ERROR ${result.filename}: ${result.error}`));
|
|
7376
7835
|
}
|
|
7377
7836
|
}
|
|
7378
7837
|
} else {
|
|
7379
|
-
|
|
7380
|
-
|
|
7838
|
+
throw createApiError("database update", { response: { data: response.data } }, [
|
|
7839
|
+
`Project: ${projectName}`,
|
|
7840
|
+
`Endpoint: ${apiUrl}`
|
|
7841
|
+
], [
|
|
7842
|
+
"Inspect the SQL result list above to identify the failing migration file."
|
|
7843
|
+
]);
|
|
7381
7844
|
}
|
|
7382
7845
|
} catch (error) {
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7846
|
+
throw createApiError("database update", error, [
|
|
7847
|
+
`Project: ${projectName}`,
|
|
7848
|
+
`Endpoint: ${apiUrl}`
|
|
7849
|
+
], [
|
|
7850
|
+
"Validate the SQL syntax and check whether any migration is re-applying an existing schema change."
|
|
7851
|
+
]);
|
|
7387
7852
|
}
|
|
7388
7853
|
}
|
|
7389
7854
|
async function updateDbCmd(options) {
|
|
7390
7855
|
try {
|
|
7391
7856
|
const headers = getAuthHeaders();
|
|
7392
7857
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7858
|
+
throw createConfigError("No valid local login session was found.", [
|
|
7859
|
+
"Run `pinme login` and retry."
|
|
7860
|
+
]);
|
|
7396
7861
|
}
|
|
7397
7862
|
const projectDir = (options == null ? void 0 : options.projectName) || (options == null ? void 0 : options.name) ? import_path13.default.join(PROJECT_DIR3, options.projectName || options.name) : PROJECT_DIR3;
|
|
7398
7863
|
const tokenFileSrc = import_path13.default.join(PROJECT_DIR3, ".token.json");
|
|
@@ -7400,37 +7865,40 @@ async function updateDbCmd(options) {
|
|
|
7400
7865
|
if (import_fs_extra8.default.existsSync(tokenFileSrc) && !import_fs_extra8.default.existsSync(tokenFileDst)) {
|
|
7401
7866
|
import_fs_extra8.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7402
7867
|
}
|
|
7403
|
-
console.log(
|
|
7404
|
-
console.log(
|
|
7868
|
+
console.log(import_chalk19.default.blue("Importing SQL to database...\n"));
|
|
7869
|
+
console.log(import_chalk19.default.gray(`Project dir: ${PROJECT_DIR3}`));
|
|
7405
7870
|
const config = loadConfig2();
|
|
7406
7871
|
const projectName = config.project_name;
|
|
7407
7872
|
if (!projectName) {
|
|
7408
|
-
throw
|
|
7873
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
7874
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
7875
|
+
]);
|
|
7409
7876
|
}
|
|
7410
|
-
console.log(
|
|
7877
|
+
console.log(import_chalk19.default.gray(`Project: ${projectName}`));
|
|
7411
7878
|
const sqlFiles = getSqlFiles2();
|
|
7412
|
-
console.log(
|
|
7879
|
+
console.log(import_chalk19.default.gray(`Found ${sqlFiles.length} SQL file(s) in db`));
|
|
7413
7880
|
await updateDb(sqlFiles, projectName);
|
|
7414
|
-
console.log(
|
|
7881
|
+
console.log(import_chalk19.default.green("\nDatabase update complete."));
|
|
7415
7882
|
process.exit(0);
|
|
7416
7883
|
} catch (error) {
|
|
7417
|
-
|
|
7418
|
-
\u274C Error: ${error.message}`));
|
|
7884
|
+
printCliError(error, "Database update failed.");
|
|
7419
7885
|
process.exit(1);
|
|
7420
7886
|
}
|
|
7421
7887
|
}
|
|
7422
7888
|
|
|
7423
7889
|
// bin/updateWorker.ts
|
|
7424
|
-
var
|
|
7890
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
7425
7891
|
var import_fs_extra9 = __toESM(require("fs-extra"));
|
|
7426
7892
|
var import_path14 = __toESM(require("path"));
|
|
7427
|
-
var
|
|
7893
|
+
var import_child_process4 = require("child_process");
|
|
7428
7894
|
var PROJECT_DIR4 = process.cwd();
|
|
7429
|
-
var API_BASE4 = "https://pinme.
|
|
7895
|
+
var API_BASE4 = "https://pinme.dev/api/v4";
|
|
7430
7896
|
function loadConfig3() {
|
|
7431
7897
|
const configPath = import_path14.default.join(PROJECT_DIR4, "pinme.toml");
|
|
7432
7898
|
if (!import_fs_extra9.default.existsSync(configPath)) {
|
|
7433
|
-
throw
|
|
7899
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
7900
|
+
"Run this command from the Pinme project root."
|
|
7901
|
+
]);
|
|
7434
7902
|
}
|
|
7435
7903
|
const configContent = import_fs_extra9.default.readFileSync(configPath, "utf-8");
|
|
7436
7904
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7441,30 +7909,38 @@ function loadConfig3() {
|
|
|
7441
7909
|
function getMetadata2() {
|
|
7442
7910
|
const metadataPath = import_path14.default.join(PROJECT_DIR4, "backend", "metadata.json");
|
|
7443
7911
|
if (!import_fs_extra9.default.existsSync(metadataPath)) {
|
|
7444
|
-
throw
|
|
7912
|
+
throw createConfigError("`backend/metadata.json` not found.", [
|
|
7913
|
+
"Create `backend/metadata.json` or restore it from the project template."
|
|
7914
|
+
]);
|
|
7445
7915
|
}
|
|
7446
7916
|
return import_fs_extra9.default.readJsonSync(metadataPath);
|
|
7447
7917
|
}
|
|
7448
7918
|
function buildWorker2() {
|
|
7449
|
-
console.log(
|
|
7919
|
+
console.log(import_chalk20.default.blue("Building worker..."));
|
|
7450
7920
|
try {
|
|
7451
|
-
(0,
|
|
7921
|
+
(0, import_child_process4.execSync)("npm run build:worker", {
|
|
7452
7922
|
cwd: PROJECT_DIR4,
|
|
7453
7923
|
stdio: "inherit"
|
|
7454
7924
|
});
|
|
7455
|
-
console.log(
|
|
7925
|
+
console.log(import_chalk20.default.green("Worker built"));
|
|
7456
7926
|
} catch (error) {
|
|
7457
|
-
throw
|
|
7927
|
+
throw createCommandError("worker build", "npm run build:worker", error, [
|
|
7928
|
+
"Fix the build error shown above, then rerun `pinme update-worker`."
|
|
7929
|
+
]);
|
|
7458
7930
|
}
|
|
7459
7931
|
}
|
|
7460
7932
|
function getBuiltWorker2() {
|
|
7461
7933
|
const distWorkerDir = import_path14.default.join(PROJECT_DIR4, "dist-worker");
|
|
7462
7934
|
if (!import_fs_extra9.default.existsSync(distWorkerDir)) {
|
|
7463
|
-
throw
|
|
7935
|
+
throw createConfigError("Built worker output not found: `dist-worker/`.", [
|
|
7936
|
+
"Make sure `npm run build:worker` completed successfully."
|
|
7937
|
+
]);
|
|
7464
7938
|
}
|
|
7465
7939
|
const workerJsPath = import_path14.default.join(distWorkerDir, "worker.js");
|
|
7466
7940
|
if (!import_fs_extra9.default.existsSync(workerJsPath)) {
|
|
7467
|
-
throw
|
|
7941
|
+
throw createConfigError("Built worker entry file not found: `dist-worker/worker.js`.", [
|
|
7942
|
+
"Check the worker build output and bundler config."
|
|
7943
|
+
]);
|
|
7468
7944
|
}
|
|
7469
7945
|
const modulePaths = [];
|
|
7470
7946
|
const files = import_fs_extra9.default.readdirSync(distWorkerDir);
|
|
@@ -7476,15 +7952,14 @@ function getBuiltWorker2() {
|
|
|
7476
7952
|
return { workerJsPath, modulePaths };
|
|
7477
7953
|
}
|
|
7478
7954
|
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}`));
|
|
7955
|
+
console.log(import_chalk20.default.blue("Updating worker on platform..."));
|
|
7956
|
+
console.log(import_chalk20.default.gray(`Project: ${projectName}`));
|
|
7957
|
+
console.log(import_chalk20.default.gray(`workerJsPath: ${workerJsPath}`));
|
|
7958
|
+
console.log(import_chalk20.default.gray(`modulePaths: ${modulePaths}`));
|
|
7959
|
+
console.log(import_chalk20.default.gray(`metadata: ${metadata}`));
|
|
7485
7960
|
const apiUrl = `${API_BASE4}/update_worker?project_name=${encodeURIComponent(projectName)}`;
|
|
7486
7961
|
const headers = getAuthHeaders();
|
|
7487
|
-
console.log(
|
|
7962
|
+
console.log(import_chalk20.default.gray(`API URL: ${apiUrl}`));
|
|
7488
7963
|
try {
|
|
7489
7964
|
const FormData4 = (await import("formdata-node")).FormData;
|
|
7490
7965
|
const Blob2 = (await import("formdata-node")).Blob;
|
|
@@ -7507,51 +7982,58 @@ async function updateWorker(workerJsPath, modulePaths, metadata, projectName) {
|
|
|
7507
7982
|
headers: { ...headers },
|
|
7508
7983
|
timeout: 12e4
|
|
7509
7984
|
});
|
|
7510
|
-
console.log(
|
|
7985
|
+
console.log(import_chalk20.default.gray(` Response: ${JSON.stringify(response.data)}`));
|
|
7511
7986
|
if (response.data) {
|
|
7512
|
-
console.log(
|
|
7987
|
+
console.log(import_chalk20.default.green("Worker updated"));
|
|
7513
7988
|
const data = response.data.data;
|
|
7514
7989
|
if (data.worker_id) {
|
|
7515
|
-
console.log(
|
|
7990
|
+
console.log(import_chalk20.default.gray(` Worker ID: ${data.worker_id}`));
|
|
7516
7991
|
}
|
|
7517
7992
|
if (data.deployment_id) {
|
|
7518
|
-
console.log(
|
|
7993
|
+
console.log(import_chalk20.default.gray(` Deployment ID: ${data.deployment_id}`));
|
|
7519
7994
|
}
|
|
7520
7995
|
if (data.entry_point) {
|
|
7521
|
-
console.log(
|
|
7996
|
+
console.log(import_chalk20.default.gray(` Entry Point: ${data.entry_point}`));
|
|
7522
7997
|
}
|
|
7523
7998
|
if (data.created_on) {
|
|
7524
|
-
console.log(
|
|
7999
|
+
console.log(import_chalk20.default.gray(` Created: ${data.created_on}`));
|
|
7525
8000
|
}
|
|
7526
8001
|
if (data.modified_on) {
|
|
7527
|
-
console.log(
|
|
8002
|
+
console.log(import_chalk20.default.gray(` Modified: ${data.modified_on}`));
|
|
7528
8003
|
}
|
|
7529
8004
|
if (data.startup_time_ms !== void 0) {
|
|
7530
|
-
console.log(
|
|
8005
|
+
console.log(import_chalk20.default.gray(` Startup Time: ${data.startup_time_ms}ms`));
|
|
7531
8006
|
}
|
|
7532
8007
|
if (data.has_modules !== void 0) {
|
|
7533
|
-
console.log(
|
|
8008
|
+
console.log(import_chalk20.default.gray(` Has Modules: ${data.has_modules}`));
|
|
7534
8009
|
}
|
|
7535
8010
|
if (data.domain) {
|
|
7536
|
-
console.log(
|
|
8011
|
+
console.log(import_chalk20.default.gray(` Domain: ${data.domain}`));
|
|
7537
8012
|
}
|
|
7538
8013
|
} else {
|
|
7539
|
-
throw
|
|
8014
|
+
throw createApiError("worker update", { response: { data: response.data } }, [
|
|
8015
|
+
`Project: ${projectName}`,
|
|
8016
|
+
`Endpoint: ${apiUrl}`
|
|
8017
|
+
], [
|
|
8018
|
+
"Verify the project exists and your account has permission to update it."
|
|
8019
|
+
]);
|
|
7540
8020
|
}
|
|
7541
8021
|
} catch (error) {
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
8022
|
+
throw createApiError("worker update", error, [
|
|
8023
|
+
`Project: ${projectName}`,
|
|
8024
|
+
`Endpoint: ${apiUrl}`
|
|
8025
|
+
], [
|
|
8026
|
+
"Check whether `backend/metadata.json` and the built worker bundle are valid."
|
|
8027
|
+
]);
|
|
7546
8028
|
}
|
|
7547
8029
|
}
|
|
7548
8030
|
async function updateWorkerCmd(options) {
|
|
7549
8031
|
try {
|
|
7550
8032
|
const headers = getAuthHeaders();
|
|
7551
8033
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
8034
|
+
throw createConfigError("No valid local login session was found.", [
|
|
8035
|
+
"Run `pinme login` and retry."
|
|
8036
|
+
]);
|
|
7555
8037
|
}
|
|
7556
8038
|
const projectDir = (options == null ? void 0 : options.projectName) || (options == null ? void 0 : options.name) ? import_path14.default.join(PROJECT_DIR4, options.projectName || options.name) : PROJECT_DIR4;
|
|
7557
8039
|
const tokenFileSrc = import_path14.default.join(PROJECT_DIR4, ".token.json");
|
|
@@ -7559,41 +8041,44 @@ async function updateWorkerCmd(options) {
|
|
|
7559
8041
|
if (import_fs_extra9.default.existsSync(tokenFileSrc) && !import_fs_extra9.default.existsSync(tokenFileDst)) {
|
|
7560
8042
|
import_fs_extra9.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7561
8043
|
}
|
|
7562
|
-
console.log(
|
|
7563
|
-
console.log(
|
|
8044
|
+
console.log(import_chalk20.default.blue("Updating worker...\n"));
|
|
8045
|
+
console.log(import_chalk20.default.gray(`Project dir: ${PROJECT_DIR4}`));
|
|
7564
8046
|
const config = loadConfig3();
|
|
7565
8047
|
const projectName = config.project_name;
|
|
7566
8048
|
if (!projectName) {
|
|
7567
|
-
throw
|
|
8049
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
8050
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
8051
|
+
]);
|
|
7568
8052
|
}
|
|
7569
|
-
console.log(
|
|
7570
|
-
console.log(
|
|
8053
|
+
console.log(import_chalk20.default.gray(`Project: ${projectName}`));
|
|
8054
|
+
console.log(import_chalk20.default.blue("\n--- Worker Update ---"));
|
|
7571
8055
|
buildWorker2();
|
|
7572
8056
|
const metadata = getMetadata2();
|
|
7573
8057
|
const { workerJsPath, modulePaths } = getBuiltWorker2();
|
|
7574
|
-
console.log(
|
|
7575
|
-
console.log(
|
|
7576
|
-
console.log(
|
|
8058
|
+
console.log(import_chalk20.default.gray(`Worker JS: ${workerJsPath}`));
|
|
8059
|
+
console.log(import_chalk20.default.gray(`Module paths: ${JSON.stringify(modulePaths)}`));
|
|
8060
|
+
console.log(import_chalk20.default.gray(`SQL files: ignored (not processed for update_worker)`));
|
|
7577
8061
|
await updateWorker(workerJsPath, modulePaths, metadata, projectName);
|
|
7578
|
-
console.log(
|
|
8062
|
+
console.log(import_chalk20.default.green("\nWorker update complete."));
|
|
7579
8063
|
process.exit(0);
|
|
7580
8064
|
} catch (error) {
|
|
7581
|
-
|
|
7582
|
-
\u274C Error: ${error.message}`));
|
|
8065
|
+
printCliError(error, "Worker update failed.");
|
|
7583
8066
|
process.exit(1);
|
|
7584
8067
|
}
|
|
7585
8068
|
}
|
|
7586
8069
|
|
|
7587
8070
|
// bin/updateWeb.ts
|
|
7588
|
-
var
|
|
8071
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
7589
8072
|
var import_fs_extra10 = __toESM(require("fs-extra"));
|
|
7590
8073
|
var import_path15 = __toESM(require("path"));
|
|
7591
|
-
var
|
|
8074
|
+
var import_child_process5 = require("child_process");
|
|
7592
8075
|
var PROJECT_DIR5 = process.cwd();
|
|
7593
8076
|
function loadConfig4() {
|
|
7594
8077
|
const configPath = import_path15.default.join(PROJECT_DIR5, "pinme.toml");
|
|
7595
8078
|
if (!import_fs_extra10.default.existsSync(configPath)) {
|
|
7596
|
-
throw
|
|
8079
|
+
throw createConfigError("`pinme.toml` not found in the current directory.", [
|
|
8080
|
+
"Run this command from the Pinme project root."
|
|
8081
|
+
]);
|
|
7597
8082
|
}
|
|
7598
8083
|
const configContent = import_fs_extra10.default.readFileSync(configPath, "utf-8");
|
|
7599
8084
|
const projectNameMatch = configContent.match(/project_name\s*=\s*"([^"]+)"/);
|
|
@@ -7602,36 +8087,44 @@ function loadConfig4() {
|
|
|
7602
8087
|
};
|
|
7603
8088
|
}
|
|
7604
8089
|
function buildFrontend2() {
|
|
7605
|
-
console.log(
|
|
8090
|
+
console.log(import_chalk21.default.blue("Building frontend..."));
|
|
7606
8091
|
try {
|
|
7607
|
-
(0,
|
|
8092
|
+
(0, import_child_process5.execSync)("npm run build:frontend", {
|
|
7608
8093
|
cwd: PROJECT_DIR5,
|
|
7609
8094
|
stdio: "inherit"
|
|
7610
8095
|
});
|
|
7611
|
-
console.log(
|
|
8096
|
+
console.log(import_chalk21.default.green("Frontend built"));
|
|
7612
8097
|
} catch (error) {
|
|
7613
|
-
throw
|
|
8098
|
+
throw createCommandError("frontend build", "npm run build:frontend", error, [
|
|
8099
|
+
"Fix the frontend build error shown above, then rerun `pinme update-web`."
|
|
8100
|
+
]);
|
|
7614
8101
|
}
|
|
7615
8102
|
}
|
|
7616
|
-
function deployFrontend2() {
|
|
7617
|
-
console.log(
|
|
8103
|
+
function deployFrontend2(projectName) {
|
|
8104
|
+
console.log(import_chalk21.default.blue("Deploying frontend to IPFS..."));
|
|
7618
8105
|
try {
|
|
7619
|
-
(0,
|
|
8106
|
+
(0, import_child_process5.execSync)("pinme upload ./frontend/dist", {
|
|
7620
8107
|
cwd: PROJECT_DIR5,
|
|
7621
|
-
stdio: "inherit"
|
|
8108
|
+
stdio: "inherit",
|
|
8109
|
+
env: {
|
|
8110
|
+
...process.env,
|
|
8111
|
+
PINME_PROJECT_NAME: projectName
|
|
8112
|
+
}
|
|
7622
8113
|
});
|
|
7623
|
-
console.log(
|
|
8114
|
+
console.log(import_chalk21.default.green("Frontend deployed to IPFS"));
|
|
7624
8115
|
} catch (error) {
|
|
7625
|
-
throw
|
|
8116
|
+
throw createCommandError("frontend deploy", "pinme upload ./frontend/dist", error, [
|
|
8117
|
+
"Make sure `frontend/dist` exists and `pinme upload` can run successfully."
|
|
8118
|
+
]);
|
|
7626
8119
|
}
|
|
7627
8120
|
}
|
|
7628
8121
|
async function updateWebCmd(options) {
|
|
7629
8122
|
try {
|
|
7630
8123
|
const headers = getAuthHeaders();
|
|
7631
8124
|
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
8125
|
+
throw createConfigError("No valid local login session was found.", [
|
|
8126
|
+
"Run `pinme login` and retry."
|
|
8127
|
+
]);
|
|
7635
8128
|
}
|
|
7636
8129
|
const projectDir = (options == null ? void 0 : options.projectName) || (options == null ? void 0 : options.name) ? import_path15.default.join(PROJECT_DIR5, options.projectName || options.name) : PROJECT_DIR5;
|
|
7637
8130
|
const tokenFileSrc = import_path15.default.join(PROJECT_DIR5, ".token.json");
|
|
@@ -7639,22 +8132,118 @@ async function updateWebCmd(options) {
|
|
|
7639
8132
|
if (import_fs_extra10.default.existsSync(tokenFileSrc) && !import_fs_extra10.default.existsSync(tokenFileDst)) {
|
|
7640
8133
|
import_fs_extra10.default.copySync(tokenFileSrc, tokenFileDst);
|
|
7641
8134
|
}
|
|
7642
|
-
console.log(
|
|
7643
|
-
console.log(
|
|
8135
|
+
console.log(import_chalk21.default.blue("Updating web (frontend)...\n"));
|
|
8136
|
+
console.log(import_chalk21.default.gray(`Project dir: ${PROJECT_DIR5}`));
|
|
7644
8137
|
const config = loadConfig4();
|
|
7645
8138
|
const projectName = config.project_name;
|
|
7646
8139
|
if (!projectName) {
|
|
7647
|
-
throw
|
|
8140
|
+
throw createConfigError("`project_name` is missing in `pinme.toml`.", [
|
|
8141
|
+
'Set `project_name = "your-project-name"` in `pinme.toml`.'
|
|
8142
|
+
]);
|
|
7648
8143
|
}
|
|
7649
|
-
console.log(
|
|
7650
|
-
console.log(
|
|
8144
|
+
console.log(import_chalk21.default.gray(`Project: ${projectName}`));
|
|
8145
|
+
console.log(import_chalk21.default.blue("\n--- Frontend Update ---"));
|
|
7651
8146
|
buildFrontend2();
|
|
7652
|
-
deployFrontend2();
|
|
7653
|
-
console.log(
|
|
8147
|
+
deployFrontend2(projectName);
|
|
8148
|
+
console.log(import_chalk21.default.green("\nWeb update complete."));
|
|
8149
|
+
process.exit(0);
|
|
8150
|
+
} catch (error) {
|
|
8151
|
+
printCliError(error, "Web update failed.");
|
|
8152
|
+
process.exit(1);
|
|
8153
|
+
}
|
|
8154
|
+
}
|
|
8155
|
+
|
|
8156
|
+
// bin/delete.ts
|
|
8157
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
8158
|
+
var import_inquirer9 = __toESM(require("inquirer"));
|
|
8159
|
+
var import_fs_extra11 = __toESM(require("fs-extra"));
|
|
8160
|
+
var import_path16 = __toESM(require("path"));
|
|
8161
|
+
var API_BASE5 = "https://pinme.dev/api/v4";
|
|
8162
|
+
function getProjectName() {
|
|
8163
|
+
const configPath = import_path16.default.join(process.cwd(), "pinme.toml");
|
|
8164
|
+
if (!import_fs_extra11.default.existsSync(configPath)) {
|
|
8165
|
+
return null;
|
|
8166
|
+
}
|
|
8167
|
+
const config = import_fs_extra11.default.readFileSync(configPath, "utf-8");
|
|
8168
|
+
const match = config.match(/project_name\s*=\s*"([^"]+)"/);
|
|
8169
|
+
return (match == null ? void 0 : match[1]) || null;
|
|
8170
|
+
}
|
|
8171
|
+
async function deleteCmd(options) {
|
|
8172
|
+
var _a, _b;
|
|
8173
|
+
try {
|
|
8174
|
+
const headers = getAuthHeaders();
|
|
8175
|
+
if (!headers["authentication-tokens"] || !headers["token-address"]) {
|
|
8176
|
+
console.log(import_chalk22.default.yellow("\n\u26A0\uFE0F You are not logged in."));
|
|
8177
|
+
console.log(import_chalk22.default.gray("Please run: pinme login"));
|
|
8178
|
+
process.exit(1);
|
|
8179
|
+
}
|
|
8180
|
+
console.log(import_chalk22.default.blue("Deleting project...\n"));
|
|
8181
|
+
let projectName = options.name || getProjectName();
|
|
8182
|
+
if (!projectName) {
|
|
8183
|
+
console.log(import_chalk22.default.red("\n\u274C Error: Cannot find project name."));
|
|
8184
|
+
console.log(import_chalk22.default.yellow(" Please make sure you are in the project directory."));
|
|
8185
|
+
console.log(import_chalk22.default.gray(" The project directory should contain a pinme.toml file."));
|
|
8186
|
+
console.log(import_chalk22.default.gray("\n Or specify the project name:"));
|
|
8187
|
+
console.log(import_chalk22.default.gray(" cd /path/to/your-project"));
|
|
8188
|
+
console.log(import_chalk22.default.gray(" pinme delete"));
|
|
8189
|
+
process.exit(1);
|
|
8190
|
+
}
|
|
8191
|
+
console.log(import_chalk22.default.gray(`Project: ${projectName}`));
|
|
8192
|
+
console.log(import_chalk22.default.gray(`Directory: ${process.cwd()}`));
|
|
8193
|
+
if (!options.force) {
|
|
8194
|
+
const answers = await import_inquirer9.default.prompt([
|
|
8195
|
+
{
|
|
8196
|
+
type: "confirm",
|
|
8197
|
+
name: "confirm",
|
|
8198
|
+
message: `Are you sure you want to delete project "${projectName}"? This will remove Worker, domain binding, and D1 database.`,
|
|
8199
|
+
default: false
|
|
8200
|
+
}
|
|
8201
|
+
]);
|
|
8202
|
+
if (!answers.confirm) {
|
|
8203
|
+
console.log(import_chalk22.default.gray("Cancelled."));
|
|
8204
|
+
process.exit(0);
|
|
8205
|
+
}
|
|
8206
|
+
}
|
|
8207
|
+
console.log(import_chalk22.default.blue("Deleting project on platform..."));
|
|
8208
|
+
const apiUrl = `${API_BASE5}/delete_project`;
|
|
8209
|
+
console.log(import_chalk22.default.gray(`API URL: ${apiUrl}`));
|
|
8210
|
+
console.log(import_chalk22.default.gray(`Project name: ${projectName}`));
|
|
8211
|
+
const response = await axios_default.post(apiUrl, {
|
|
8212
|
+
project_name: projectName
|
|
8213
|
+
}, {
|
|
8214
|
+
headers: {
|
|
8215
|
+
...headers,
|
|
8216
|
+
"Content-Type": "application/json"
|
|
8217
|
+
}
|
|
8218
|
+
}).catch((error) => {
|
|
8219
|
+
var _a2, _b2;
|
|
8220
|
+
if (error.response) {
|
|
8221
|
+
console.log(import_chalk22.default.red(` Response status: ${(_a2 = error.response) == null ? void 0 : _a2.status}`));
|
|
8222
|
+
console.log(import_chalk22.default.red(` Response data: ${JSON.stringify((_b2 = error.response) == null ? void 0 : _b2.data)}`));
|
|
8223
|
+
} else {
|
|
8224
|
+
console.log(import_chalk22.default.red("No Response"));
|
|
8225
|
+
}
|
|
8226
|
+
throw error;
|
|
8227
|
+
});
|
|
8228
|
+
const data = response.data;
|
|
8229
|
+
if (data.code === 200) {
|
|
8230
|
+
console.log(import_chalk22.default.green("\n\u2705 Project deleted successfully!"));
|
|
8231
|
+
console.log(import_chalk22.default.gray(`
|
|
8232
|
+
Project: ${data.data.project_name}`));
|
|
8233
|
+
console.log(import_chalk22.default.gray(` Domain deleted: ${data.data.domain_deleted ? "\u2705" : "\u274C"}`));
|
|
8234
|
+
console.log(import_chalk22.default.gray(` Worker deleted: ${data.data.worker_deleted ? "\u2705" : "\u274C"}`));
|
|
8235
|
+
console.log(import_chalk22.default.gray(` Database deleted: ${data.data.database_deleted ? "\u2705" : "\u274C"}`));
|
|
8236
|
+
console.log(import_chalk22.default.gray("\nLocal files are kept unchanged."));
|
|
8237
|
+
} else {
|
|
8238
|
+
const errorMsg = (data == null ? void 0 : data.msg) || "Failed to delete project";
|
|
8239
|
+
throw new Error(errorMsg);
|
|
8240
|
+
}
|
|
7654
8241
|
process.exit(0);
|
|
7655
8242
|
} catch (error) {
|
|
7656
|
-
console.
|
|
7657
|
-
|
|
8243
|
+
console.log(import_chalk22.default.red(error));
|
|
8244
|
+
const errorMsg = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) || error.message || "Failed to delete project";
|
|
8245
|
+
console.error(import_chalk22.default.red(`
|
|
8246
|
+
\u274C Error: ${errorMsg}`));
|
|
7658
8247
|
process.exit(1);
|
|
7659
8248
|
}
|
|
7660
8249
|
}
|
|
@@ -7664,9 +8253,9 @@ import_dotenv.default.config();
|
|
|
7664
8253
|
checkNodeVersion();
|
|
7665
8254
|
function showBanner() {
|
|
7666
8255
|
console.log(
|
|
7667
|
-
|
|
8256
|
+
import_chalk23.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
|
|
7668
8257
|
);
|
|
7669
|
-
console.log(
|
|
8258
|
+
console.log(import_chalk23.default.cyan("A command-line tool for uploading files to IPFS\n"));
|
|
7670
8259
|
}
|
|
7671
8260
|
var program = new import_commander.Command();
|
|
7672
8261
|
program.name("pinme").version(version).option("-v, --version", "output the current version");
|
|
@@ -7689,6 +8278,7 @@ program.command("save").description("Deploy the project (frontend + backend)").a
|
|
|
7689
8278
|
program.command("update-db").description("Execute database migration").action(() => updateDbCmd());
|
|
7690
8279
|
program.command("update-worker").description("Execute worker migration").action(() => updateWorkerCmd());
|
|
7691
8280
|
program.command("update-web").description("Deploy frontend to IPFS").action((options) => updateWebCmd(options));
|
|
8281
|
+
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
8282
|
program.command("domain").description("Alias for 'my-domains' command").action(() => myDomainsCmd());
|
|
7693
8283
|
program.command("list").description("show upload history").option(
|
|
7694
8284
|
"-l, --limit <number>",
|