pinme 1.2.4 → 1.2.5
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/README.md +121 -6
- package/dist/index.js +521 -92
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,6 +33,9 @@ Website: [https://pinme.eth.limo/](https://pinme.eth.limo/)
|
|
|
33
33
|
- [For AI](#for-ai)
|
|
34
34
|
- [Installation](#installation)
|
|
35
35
|
- [Usage](#usage)
|
|
36
|
+
- [Bind Domain](#bind-domain-requires-vip)
|
|
37
|
+
- [Command Details](#command-details)
|
|
38
|
+
- [VIP Membership](#vip-membership)
|
|
36
39
|
- [Common Static File Directories](#common-static-file-directories)
|
|
37
40
|
- [Error Handling](#error-handling)
|
|
38
41
|
- [Upload Limits](#upload-limits)
|
|
@@ -216,10 +219,30 @@ pinme upload
|
|
|
216
219
|
|
|
217
220
|
# Specify path directly
|
|
218
221
|
pinme upload /path/to/file-or-directory
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Bind Domain (requires VIP)
|
|
219
225
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
pinme
|
|
226
|
+
```bash
|
|
227
|
+
# Upload and bind to a domain (auto-detected: Pinme subdomain or DNS domain)
|
|
228
|
+
pinme bind <path> --domain <name>
|
|
229
|
+
pinme bind <path> -d <name>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Smart Auto-Detection:**
|
|
233
|
+
- Domains with a dot (e.g., `example.com`) → **DNS domain**
|
|
234
|
+
- Domains without a dot (e.g., `my-site`) → **Pinme subdomain**
|
|
235
|
+
|
|
236
|
+
**Examples:**
|
|
237
|
+
```bash
|
|
238
|
+
# Bind to a Pinme subdomain (auto-detected)
|
|
239
|
+
pinme bind ./dist --domain my-site
|
|
240
|
+
|
|
241
|
+
# Bind to a DNS domain (auto-detected by the dot)
|
|
242
|
+
pinme bind ./dist --domain example.com
|
|
243
|
+
|
|
244
|
+
# Force DNS mode if needed
|
|
245
|
+
pinme bind ./dist --domain my-site --dns
|
|
223
246
|
```
|
|
224
247
|
|
|
225
248
|
### Import CAR files
|
|
@@ -337,6 +360,51 @@ The selected directory must meet:
|
|
|
337
360
|
|
|
338
361
|
## Command Details
|
|
339
362
|
|
|
363
|
+
### `bind`
|
|
364
|
+
|
|
365
|
+
Upload files and bind them to a custom domain. **Domain binding requires VIP membership.**
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
pinme bind <path> [options]
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Options:**
|
|
372
|
+
- `path`: Path to the file or directory to upload (optional, interactive if not provided)
|
|
373
|
+
- `-d, --domain <name>`: Domain name to bind (required)
|
|
374
|
+
- `--dns`: Force DNS domain mode (optional, auto-detected from domain format)
|
|
375
|
+
|
|
376
|
+
**Examples:**
|
|
377
|
+
```bash
|
|
378
|
+
# Interactive mode (will prompt for path and domain)
|
|
379
|
+
pinme bind
|
|
380
|
+
|
|
381
|
+
# Bind to a Pinme subdomain (auto-detected: no dot in domain)
|
|
382
|
+
pinme bind ./dist --domain my-site
|
|
383
|
+
|
|
384
|
+
# Bind to a DNS domain (auto-detected: contains dot)
|
|
385
|
+
pinme bind ./dist --domain example.com
|
|
386
|
+
|
|
387
|
+
# Force DNS mode with --dns flag
|
|
388
|
+
pinme bind ./dist --domain my-site --dns
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Auto-Detection:**
|
|
392
|
+
- Domains with a dot (e.g., `example.com`) are automatically treated as **DNS domains**
|
|
393
|
+
- Domains without a dot (e.g., `my-site`) are automatically treated as **Pinme subdomains**
|
|
394
|
+
- Use `--dns` or `-D` flag to force DNS domain mode when needed
|
|
395
|
+
|
|
396
|
+
**Requirements:**
|
|
397
|
+
- VIP membership required for domain binding
|
|
398
|
+
- Valid AppKey must be set (run: `pinme set-appkey <AppKey>`)
|
|
399
|
+
- For DNS domains, you must own the domain
|
|
400
|
+
|
|
401
|
+
**URL Formats:**
|
|
402
|
+
- Pinme subdomain: `https://<name>.pinit.eth.limo`
|
|
403
|
+
- DNS domain: `https://<your-domain>`
|
|
404
|
+
|
|
405
|
+
**DNS Setup:**
|
|
406
|
+
After successful DNS domain binding, visit the [DNS Configuration Guide](https://pinme.eth.limo/#/docs?id=custom-domain) to complete DNS setup.
|
|
407
|
+
|
|
340
408
|
### `upload`
|
|
341
409
|
|
|
342
410
|
Upload a file or directory to the IPFS network.
|
|
@@ -347,20 +415,22 @@ pinme upload [path] [--domain <name>]
|
|
|
347
415
|
|
|
348
416
|
**Options:**
|
|
349
417
|
- `path`: Path to the file or directory to upload (optional, interactive if not provided)
|
|
350
|
-
- `-d, --domain <name>`: Pinme subdomain to bind after upload (optional)
|
|
418
|
+
- `-d, --domain <name>`: Pinme subdomain to bind after upload (optional, requires VIP)
|
|
351
419
|
|
|
352
420
|
**Examples:**
|
|
353
421
|
```bash
|
|
354
422
|
# Upload dist directory
|
|
355
423
|
pinme upload dist
|
|
356
424
|
|
|
357
|
-
# Upload
|
|
358
|
-
pinme upload dist
|
|
425
|
+
# Upload only (no domain binding)
|
|
426
|
+
pinme upload dist
|
|
359
427
|
|
|
360
428
|
# Upload a specific file
|
|
361
429
|
pinme upload ./example.jpg
|
|
362
430
|
```
|
|
363
431
|
|
|
432
|
+
**Note:** Domain binding during upload requires VIP. Use the `bind` command for domain binding.
|
|
433
|
+
|
|
364
434
|
### `import`
|
|
365
435
|
|
|
366
436
|
Import CAR (Content Addressable aRchive) files to the IPFS network. This command is specifically designed for importing CAR files while maintaining their original structure. Supports binding to a Pinme subdomain after import.
|
|
@@ -475,6 +545,51 @@ List all domains owned by the current account.
|
|
|
475
545
|
|
|
476
546
|
---
|
|
477
547
|
|
|
548
|
+
## VIP Membership
|
|
549
|
+
|
|
550
|
+
### Overview
|
|
551
|
+
|
|
552
|
+
VIP membership provides access to premium features including domain binding and custom DNS support.
|
|
553
|
+
|
|
554
|
+
### VIP Features
|
|
555
|
+
|
|
556
|
+
| Feature | Free | VIP |
|
|
557
|
+
|---------|------|-----|
|
|
558
|
+
| Upload files to IPFS | ✅ | ✅ |
|
|
559
|
+
| Preview URL | ✅ | ✅ |
|
|
560
|
+
| Pinme subdomain binding | ❌ | ✅ |
|
|
561
|
+
| Custom DNS domain binding | ❌ | ✅ |
|
|
562
|
+
| Priority support | ❌ | ✅ |
|
|
563
|
+
|
|
564
|
+
### Domain Binding Requirements
|
|
565
|
+
|
|
566
|
+
Domain binding (both Pinme subdomains and custom DNS domains) requires VIP membership.
|
|
567
|
+
|
|
568
|
+
**Before using domain binding:**
|
|
569
|
+
|
|
570
|
+
1. **Upgrade to VIP**
|
|
571
|
+
- Visit [PinMe website](https://pinme.eth.limo/) to upgrade
|
|
572
|
+
|
|
573
|
+
2. **Set AppKey**
|
|
574
|
+
```bash
|
|
575
|
+
pinme set-appkey <AppKey>
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
3. **Bind your domain**
|
|
579
|
+
```bash
|
|
580
|
+
# Bind to a Pinme subdomain
|
|
581
|
+
pinme bind ./dist --domain my-site
|
|
582
|
+
|
|
583
|
+
# Bind to a custom DNS domain
|
|
584
|
+
pinme bind ./dist --domain example.com --dns
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### Checking VIP Status
|
|
588
|
+
|
|
589
|
+
If you attempt to bind a domain without VIP, you'll see an error message. You can check your VIP status on the [PinMe website](https://pinme.eth.limo/).
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
478
593
|
## Error Handling
|
|
479
594
|
|
|
480
595
|
### Common Errors and Solutions
|
package/dist/index.js
CHANGED
|
@@ -97,7 +97,7 @@ var require_package = __commonJS({
|
|
|
97
97
|
var require_main = __commonJS({
|
|
98
98
|
"node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/lib/main.js"(exports2, module2) {
|
|
99
99
|
var fs9 = require("fs");
|
|
100
|
-
var
|
|
100
|
+
var path10 = require("path");
|
|
101
101
|
var os4 = require("os");
|
|
102
102
|
var crypto2 = require("crypto");
|
|
103
103
|
var packageJson = require_package();
|
|
@@ -208,7 +208,7 @@ 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 = path10.resolve(process.cwd(), ".env.vault");
|
|
212
212
|
}
|
|
213
213
|
if (fs9.existsSync(possibleVaultPath)) {
|
|
214
214
|
return possibleVaultPath;
|
|
@@ -216,7 +216,7 @@ var require_main = __commonJS({
|
|
|
216
216
|
return null;
|
|
217
217
|
}
|
|
218
218
|
function _resolveHome(envPath) {
|
|
219
|
-
return envPath[0] === "~" ?
|
|
219
|
+
return envPath[0] === "~" ? path10.join(os4.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 = path10.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 path11 of optionPaths) {
|
|
259
259
|
try {
|
|
260
|
-
const parsed = DotenvModule.parse(fs9.readFileSync(
|
|
260
|
+
const parsed = DotenvModule.parse(fs9.readFileSync(path11, { 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 ${path11} ${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_chalk14 = __toESM(require("chalk"));
|
|
1523
1523
|
var import_figlet5 = __toESM(require("figlet"));
|
|
1524
1524
|
|
|
1525
1525
|
// package.json
|
|
1526
|
-
var version = "1.2.
|
|
1526
|
+
var version = "1.2.5";
|
|
1527
1527
|
|
|
1528
1528
|
// bin/upload.ts
|
|
1529
1529
|
var import_path6 = __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(path10, key, dots) {
|
|
1972
|
+
if (!path10) return key;
|
|
1973
|
+
return path10.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, path10) {
|
|
2019
2019
|
let arr = value;
|
|
2020
|
-
if (value && !
|
|
2020
|
+
if (value && !path10 && 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(path10, 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, path10) {
|
|
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 " + path10.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
|
+
path10,
|
|
2060
2060
|
exposedHelpers
|
|
2061
2061
|
);
|
|
2062
2062
|
if (result === true) {
|
|
2063
|
-
build(el,
|
|
2063
|
+
build(el, path10 ? path10.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, path10, 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(path10, value, target, index) {
|
|
2254
|
+
let name = path10[index++];
|
|
2255
2255
|
const isNumericKey = Number.isFinite(+name);
|
|
2256
|
-
const isLast = index >=
|
|
2256
|
+
const isLast = index >= path10.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(path10, 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 path10;
|
|
3332
3332
|
try {
|
|
3333
|
-
|
|
3333
|
+
path10 = 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: path10,
|
|
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, path10, 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(path10)) {
|
|
3577
|
+
cookie.push("path=" + path10);
|
|
3578
3578
|
}
|
|
3579
3579
|
if (utils_default.isString(domain)) {
|
|
3580
3580
|
cookie.push("domain=" + domain);
|
|
@@ -5149,6 +5149,46 @@ var import_crypto_js = __toESM(require("crypto-js"));
|
|
|
5149
5149
|
// bin/utils/pinmeApi.ts
|
|
5150
5150
|
var import_chalk3 = __toESM(require("chalk"));
|
|
5151
5151
|
var DEFAULT_BASE = "https://pinme.dev/api/v4";
|
|
5152
|
+
var TOKEN_EXPIRED_CODES = [
|
|
5153
|
+
401,
|
|
5154
|
+
403,
|
|
5155
|
+
10001,
|
|
5156
|
+
10002,
|
|
5157
|
+
20001,
|
|
5158
|
+
"TOKEN_EXPIRED",
|
|
5159
|
+
"AUTH_FAILED"
|
|
5160
|
+
];
|
|
5161
|
+
var TOKEN_EXPIRED_MESSAGES = [
|
|
5162
|
+
"token expired",
|
|
5163
|
+
"invalid token",
|
|
5164
|
+
"authentication failed",
|
|
5165
|
+
"auth failed",
|
|
5166
|
+
"unauthorized",
|
|
5167
|
+
"\u767B\u5F55",
|
|
5168
|
+
"\u8FC7\u671F",
|
|
5169
|
+
"token",
|
|
5170
|
+
"\u9274\u6743"
|
|
5171
|
+
];
|
|
5172
|
+
function isTokenExpired(error) {
|
|
5173
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
5174
|
+
const status = (_a = error.response) == null ? void 0 : _a.status;
|
|
5175
|
+
const message = ((_c = (_b = error.response) == null ? void 0 : _b.data) == null ? void 0 : _c.msg) || ((_e = (_d = error.response) == null ? void 0 : _d.data) == null ? void 0 : _e.message) || error.message || "";
|
|
5176
|
+
const code = (_g = (_f = error.response) == null ? void 0 : _f.data) == null ? void 0 : _g.code;
|
|
5177
|
+
if (status && TOKEN_EXPIRED_CODES.includes(status)) {
|
|
5178
|
+
return true;
|
|
5179
|
+
}
|
|
5180
|
+
if (code && TOKEN_EXPIRED_CODES.includes(code)) {
|
|
5181
|
+
return true;
|
|
5182
|
+
}
|
|
5183
|
+
const lowerMessage = message.toLowerCase();
|
|
5184
|
+
return TOKEN_EXPIRED_MESSAGES.some(
|
|
5185
|
+
(m) => lowerMessage.includes(m.toLowerCase())
|
|
5186
|
+
);
|
|
5187
|
+
}
|
|
5188
|
+
function showTokenExpiredHint() {
|
|
5189
|
+
console.log(import_chalk3.default.red("\n\u26A0\uFE0F Token has expired or is invalid."));
|
|
5190
|
+
console.log(import_chalk3.default.yellow("Please re-run: pinme set-appkey <AppKey>\n"));
|
|
5191
|
+
}
|
|
5152
5192
|
function createClient() {
|
|
5153
5193
|
const headers = getAuthHeaders();
|
|
5154
5194
|
return axios_default.create({
|
|
@@ -5171,7 +5211,13 @@ async function bindAnonymousDevice(anonymousUid) {
|
|
|
5171
5211
|
});
|
|
5172
5212
|
return (data == null ? void 0 : data.code) === 200;
|
|
5173
5213
|
} catch (e) {
|
|
5174
|
-
|
|
5214
|
+
if (isTokenExpired(e)) {
|
|
5215
|
+
showTokenExpiredHint();
|
|
5216
|
+
return false;
|
|
5217
|
+
}
|
|
5218
|
+
console.log(
|
|
5219
|
+
import_chalk3.default.yellow(`Failed to trigger anonymous binding: ${(e == null ? void 0 : e.message) || e}`)
|
|
5220
|
+
);
|
|
5175
5221
|
return false;
|
|
5176
5222
|
}
|
|
5177
5223
|
}
|
|
@@ -5190,31 +5236,98 @@ async function checkDomainAvailable(domainName) {
|
|
|
5190
5236
|
return { is_valid: data.data.is_valid, error: (_a = data.data) == null ? void 0 : _a.error };
|
|
5191
5237
|
}
|
|
5192
5238
|
} catch (e) {
|
|
5239
|
+
if (isTokenExpired(e)) {
|
|
5240
|
+
showTokenExpiredHint();
|
|
5241
|
+
throw new Error("Token expired");
|
|
5242
|
+
}
|
|
5193
5243
|
}
|
|
5194
5244
|
}
|
|
5195
5245
|
return { is_valid: true };
|
|
5196
5246
|
}
|
|
5197
5247
|
async function bindPinmeDomain(domainName, hash) {
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5248
|
+
try {
|
|
5249
|
+
const client = createClient();
|
|
5250
|
+
const { data } = await client.post("/bind_pinme_domain", {
|
|
5251
|
+
domain_name: domainName,
|
|
5252
|
+
hash
|
|
5253
|
+
});
|
|
5254
|
+
return (data == null ? void 0 : data.code) === 200;
|
|
5255
|
+
} catch (e) {
|
|
5256
|
+
if (isTokenExpired(e)) {
|
|
5257
|
+
showTokenExpiredHint();
|
|
5258
|
+
throw new Error("Token expired");
|
|
5259
|
+
}
|
|
5260
|
+
throw e;
|
|
5261
|
+
}
|
|
5204
5262
|
}
|
|
5205
5263
|
async function getMyDomains() {
|
|
5206
5264
|
var _a;
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
if (
|
|
5211
|
-
|
|
5265
|
+
try {
|
|
5266
|
+
const client = createClient();
|
|
5267
|
+
const { data } = await client.get("/my_domains");
|
|
5268
|
+
if ((data == null ? void 0 : data.code) === 200) {
|
|
5269
|
+
if (Array.isArray(data == null ? void 0 : data.data)) {
|
|
5270
|
+
return data.data;
|
|
5271
|
+
}
|
|
5272
|
+
if (((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.list) && Array.isArray(data.data.list)) {
|
|
5273
|
+
return data.data.list;
|
|
5274
|
+
}
|
|
5212
5275
|
}
|
|
5213
|
-
if ((
|
|
5214
|
-
|
|
5276
|
+
if ((data == null ? void 0 : data.code) === 401 || (data == null ? void 0 : data.code) === 403) {
|
|
5277
|
+
showTokenExpiredHint();
|
|
5278
|
+
throw new Error("Token expired");
|
|
5215
5279
|
}
|
|
5280
|
+
return [];
|
|
5281
|
+
} catch (e) {
|
|
5282
|
+
if (isTokenExpired(e)) {
|
|
5283
|
+
showTokenExpiredHint();
|
|
5284
|
+
throw new Error("Token expired");
|
|
5285
|
+
}
|
|
5286
|
+
throw e;
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
async function bindDnsDomainV4(domainName, hash, tokenAddress, authToken) {
|
|
5290
|
+
try {
|
|
5291
|
+
const client = createClient();
|
|
5292
|
+
const { data } = await client.post(
|
|
5293
|
+
"/bind_dns",
|
|
5294
|
+
{
|
|
5295
|
+
domain_name: domainName,
|
|
5296
|
+
hash
|
|
5297
|
+
},
|
|
5298
|
+
{
|
|
5299
|
+
headers: {
|
|
5300
|
+
"x-auth-token": authToken,
|
|
5301
|
+
"x-token-address": tokenAddress
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
);
|
|
5305
|
+
return data;
|
|
5306
|
+
} catch (e) {
|
|
5307
|
+
if (isTokenExpired(e)) {
|
|
5308
|
+
showTokenExpiredHint();
|
|
5309
|
+
throw new Error("Token expired");
|
|
5310
|
+
}
|
|
5311
|
+
throw e;
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
async function isVip(tokenAddress, authToken) {
|
|
5315
|
+
try {
|
|
5316
|
+
const client = createClient();
|
|
5317
|
+
const { data } = await client.get("/is_vip", {
|
|
5318
|
+
headers: {
|
|
5319
|
+
"x-auth-token": authToken,
|
|
5320
|
+
"x-token-address": tokenAddress
|
|
5321
|
+
}
|
|
5322
|
+
});
|
|
5323
|
+
return data;
|
|
5324
|
+
} catch (e) {
|
|
5325
|
+
if (isTokenExpired(e)) {
|
|
5326
|
+
showTokenExpiredHint();
|
|
5327
|
+
throw new Error("Token expired");
|
|
5328
|
+
}
|
|
5329
|
+
throw e;
|
|
5216
5330
|
}
|
|
5217
|
-
return [];
|
|
5218
5331
|
}
|
|
5219
5332
|
var CAR_API_BASE = process.env.CAR_API_BASE || "https://pinme.dev/api/v4";
|
|
5220
5333
|
function createCarClient() {
|
|
@@ -5250,6 +5363,10 @@ async function requestCarExport(cid, uid) {
|
|
|
5250
5363
|
}
|
|
5251
5364
|
throw new Error((data == null ? void 0 : data.msg) || "Failed to request CAR export");
|
|
5252
5365
|
} catch (e) {
|
|
5366
|
+
if (isTokenExpired(e)) {
|
|
5367
|
+
showTokenExpiredHint();
|
|
5368
|
+
throw new Error("Token expired");
|
|
5369
|
+
}
|
|
5253
5370
|
if ((_b = (_a = e.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) {
|
|
5254
5371
|
throw new Error(e.response.data.msg);
|
|
5255
5372
|
}
|
|
@@ -5260,16 +5377,23 @@ async function checkCarExportStatus(taskId) {
|
|
|
5260
5377
|
var _a, _b;
|
|
5261
5378
|
try {
|
|
5262
5379
|
const client = createCarClient();
|
|
5263
|
-
const { data } = await client.get(
|
|
5264
|
-
|
|
5265
|
-
|
|
5380
|
+
const { data } = await client.get(
|
|
5381
|
+
"/car/export/status",
|
|
5382
|
+
{
|
|
5383
|
+
params: {
|
|
5384
|
+
task_id: taskId
|
|
5385
|
+
}
|
|
5266
5386
|
}
|
|
5267
|
-
|
|
5387
|
+
);
|
|
5268
5388
|
if ((data == null ? void 0 : data.code) === 200 && (data == null ? void 0 : data.data)) {
|
|
5269
5389
|
return data.data;
|
|
5270
5390
|
}
|
|
5271
5391
|
throw new Error((data == null ? void 0 : data.msg) || "Failed to check export status");
|
|
5272
5392
|
} catch (e) {
|
|
5393
|
+
if (isTokenExpired(e)) {
|
|
5394
|
+
showTokenExpiredHint();
|
|
5395
|
+
throw new Error("Token expired");
|
|
5396
|
+
}
|
|
5273
5397
|
if ((_b = (_a = e.response) == null ? void 0 : _a.data) == null ? void 0 : _b.msg) {
|
|
5274
5398
|
throw new Error(e.response.data.msg);
|
|
5275
5399
|
}
|
|
@@ -5281,6 +5405,35 @@ async function checkCarExportStatus(taskId) {
|
|
|
5281
5405
|
var URL2 = "https://pinme.eth.limo/#/preview/";
|
|
5282
5406
|
var secretKey = "pinme-secret-key";
|
|
5283
5407
|
checkNodeVersion();
|
|
5408
|
+
function isDnsDomain(domain) {
|
|
5409
|
+
return domain.includes(".");
|
|
5410
|
+
}
|
|
5411
|
+
function validateDnsDomain(domain) {
|
|
5412
|
+
const cleanDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
5413
|
+
const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9][a-zA-Z0-9-]*)*\.[a-zA-Z]{2,}$/;
|
|
5414
|
+
const parts = cleanDomain.split(".");
|
|
5415
|
+
if (parts.length < 2) {
|
|
5416
|
+
return { valid: false, message: "Invalid domain format. Please enter a complete domain (e.g., example.com)" };
|
|
5417
|
+
}
|
|
5418
|
+
for (const part of parts) {
|
|
5419
|
+
if (part.length === 0) {
|
|
5420
|
+
return { valid: false, message: "Invalid domain format. Consecutive dots are not allowed" };
|
|
5421
|
+
}
|
|
5422
|
+
if (part.length > 63) {
|
|
5423
|
+
return { valid: false, message: "Invalid domain format. Each label must be 63 characters or less" };
|
|
5424
|
+
}
|
|
5425
|
+
if (!/^[a-zA-Z0-9-]+$/.test(part)) {
|
|
5426
|
+
return { valid: false, message: "Invalid domain format. Domains can only contain letters, numbers, and hyphens" };
|
|
5427
|
+
}
|
|
5428
|
+
if (/^-|-$/.test(part)) {
|
|
5429
|
+
return { valid: false, message: "Invalid domain format. Labels cannot start or end with hyphens" };
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
if (!domainRegex.test(cleanDomain)) {
|
|
5433
|
+
return { valid: false, message: "Invalid domain format" };
|
|
5434
|
+
}
|
|
5435
|
+
return { valid: true };
|
|
5436
|
+
}
|
|
5284
5437
|
function encryptHash(contentHash, key, uid) {
|
|
5285
5438
|
try {
|
|
5286
5439
|
if (!key) {
|
|
@@ -5315,6 +5468,52 @@ function getDomainFromArgs() {
|
|
|
5315
5468
|
}
|
|
5316
5469
|
return null;
|
|
5317
5470
|
}
|
|
5471
|
+
function getDnsFromArgs() {
|
|
5472
|
+
const args = process.argv.slice(2);
|
|
5473
|
+
return args.includes("--dns") || args.includes("-D");
|
|
5474
|
+
}
|
|
5475
|
+
async function checkVipStatus(authConfig) {
|
|
5476
|
+
var _a;
|
|
5477
|
+
console.log(import_chalk4.default.blue("Checking VIP status..."));
|
|
5478
|
+
try {
|
|
5479
|
+
const vipResult = await isVip(authConfig.address, authConfig.token);
|
|
5480
|
+
if (!((_a = vipResult.data) == null ? void 0 : _a.is_vip)) {
|
|
5481
|
+
return false;
|
|
5482
|
+
}
|
|
5483
|
+
console.log(import_chalk4.default.green("VIP verified."));
|
|
5484
|
+
return true;
|
|
5485
|
+
} catch (e) {
|
|
5486
|
+
if (e.message === "Token expired") {
|
|
5487
|
+
throw e;
|
|
5488
|
+
}
|
|
5489
|
+
console.log(import_chalk4.default.yellow("Failed to check VIP status, continuing..."));
|
|
5490
|
+
return true;
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
async function bindDomain(domain, contentHash, isDns, authConfig) {
|
|
5494
|
+
const displayDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
5495
|
+
if (isDns) {
|
|
5496
|
+
console.log(import_chalk4.default.blue("Binding DNS domain..."));
|
|
5497
|
+
const dnsResult = await bindDnsDomainV4(displayDomain, contentHash, authConfig.address, authConfig.token);
|
|
5498
|
+
if (dnsResult.code !== 200) {
|
|
5499
|
+
console.log(import_chalk4.default.red(`DNS binding failed: ${dnsResult.msg}`));
|
|
5500
|
+
return false;
|
|
5501
|
+
}
|
|
5502
|
+
console.log(import_chalk4.default.green(`DNS bind success: ${displayDomain}`));
|
|
5503
|
+
console.log(import_chalk4.default.white(`Visit: https://${displayDomain}`));
|
|
5504
|
+
console.log(import_chalk4.default.cyan("\n\u{1F4DA} DNS Setup Guide: https://pinme.eth.limo/#/docs?id=custom-domain"));
|
|
5505
|
+
} else {
|
|
5506
|
+
console.log(import_chalk4.default.blue("Binding Pinme subdomain..."));
|
|
5507
|
+
const ok = await bindPinmeDomain(displayDomain, contentHash);
|
|
5508
|
+
if (!ok) {
|
|
5509
|
+
console.log(import_chalk4.default.red("Binding failed. Please try again later."));
|
|
5510
|
+
return false;
|
|
5511
|
+
}
|
|
5512
|
+
console.log(import_chalk4.default.green(`Bind success: ${displayDomain}`));
|
|
5513
|
+
console.log(import_chalk4.default.white(`Visit: https://${displayDomain}.pinit.eth.limo`));
|
|
5514
|
+
}
|
|
5515
|
+
return true;
|
|
5516
|
+
}
|
|
5318
5517
|
var upload_default = async (options) => {
|
|
5319
5518
|
try {
|
|
5320
5519
|
console.log(
|
|
@@ -5326,25 +5525,61 @@ var upload_default = async (options) => {
|
|
|
5326
5525
|
whitespaceBreak: true
|
|
5327
5526
|
})
|
|
5328
5527
|
);
|
|
5528
|
+
const authConfig = getAuthConfig();
|
|
5529
|
+
if (!authConfig) {
|
|
5530
|
+
console.log(import_chalk4.default.red("Please login first. Run: pinme set-appkey <AppKey>"));
|
|
5531
|
+
return;
|
|
5532
|
+
}
|
|
5329
5533
|
const argPath = process.argv[3];
|
|
5330
5534
|
const domainArg = getDomainFromArgs();
|
|
5535
|
+
const dnsArg = getDnsFromArgs();
|
|
5331
5536
|
if (argPath && !argPath.startsWith("-")) {
|
|
5332
5537
|
const absolutePath = checkPathSync(argPath);
|
|
5333
5538
|
if (!absolutePath) {
|
|
5334
5539
|
console.log(import_chalk4.default.red(`path ${argPath} does not exist`));
|
|
5335
5540
|
return;
|
|
5336
5541
|
}
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
)
|
|
5344
|
-
);
|
|
5542
|
+
const isDns = dnsArg || (domainArg ? isDnsDomain(domainArg) : false);
|
|
5543
|
+
const displayDomain = domainArg == null ? void 0 : domainArg.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
5544
|
+
if (isDns && domainArg) {
|
|
5545
|
+
const validation = validateDnsDomain(domainArg);
|
|
5546
|
+
if (!validation.valid) {
|
|
5547
|
+
console.log(import_chalk4.default.red(validation.message));
|
|
5345
5548
|
return;
|
|
5346
5549
|
}
|
|
5347
|
-
|
|
5550
|
+
}
|
|
5551
|
+
if (domainArg) {
|
|
5552
|
+
try {
|
|
5553
|
+
const isVipUser = await checkVipStatus(authConfig);
|
|
5554
|
+
if (!isVipUser) {
|
|
5555
|
+
console.log(import_chalk4.default.red("Domain binding requires VIP. Please upgrade to VIP first."));
|
|
5556
|
+
return;
|
|
5557
|
+
}
|
|
5558
|
+
} catch (e) {
|
|
5559
|
+
if (e.message === "Token expired") {
|
|
5560
|
+
return;
|
|
5561
|
+
}
|
|
5562
|
+
throw e;
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
if (domainArg) {
|
|
5566
|
+
try {
|
|
5567
|
+
const check = await checkDomainAvailable(displayDomain);
|
|
5568
|
+
if (!check.is_valid) {
|
|
5569
|
+
console.log(
|
|
5570
|
+
import_chalk4.default.red(
|
|
5571
|
+
`Domain not available: ${check.error || "unknown reason"}`
|
|
5572
|
+
)
|
|
5573
|
+
);
|
|
5574
|
+
return;
|
|
5575
|
+
}
|
|
5576
|
+
console.log(import_chalk4.default.green(`Domain available: ${displayDomain}`));
|
|
5577
|
+
} catch (e) {
|
|
5578
|
+
if (e.message === "Token expired") {
|
|
5579
|
+
return;
|
|
5580
|
+
}
|
|
5581
|
+
throw e;
|
|
5582
|
+
}
|
|
5348
5583
|
}
|
|
5349
5584
|
console.log(import_chalk4.default.blue(`uploading ${absolutePath} to ipfs...`));
|
|
5350
5585
|
try {
|
|
@@ -5362,19 +5597,16 @@ var upload_default = async (options) => {
|
|
|
5362
5597
|
if (domainArg) {
|
|
5363
5598
|
console.log(
|
|
5364
5599
|
import_chalk4.default.blue(
|
|
5365
|
-
`Binding domain: ${
|
|
5600
|
+
`Binding domain: ${displayDomain} with CID: ${result.contentHash}`
|
|
5366
5601
|
)
|
|
5367
5602
|
);
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
);
|
|
5376
|
-
} else {
|
|
5377
|
-
console.log(import_chalk4.default.red("Binding failed. Please try again later."));
|
|
5603
|
+
try {
|
|
5604
|
+
await bindDomain(domainArg, result.contentHash, isDns, authConfig);
|
|
5605
|
+
} catch (e) {
|
|
5606
|
+
if (e.message === "Token expired") {
|
|
5607
|
+
return;
|
|
5608
|
+
}
|
|
5609
|
+
throw e;
|
|
5378
5610
|
}
|
|
5379
5611
|
}
|
|
5380
5612
|
console.log(import_chalk4.default.green("\n\u{1F389} upload successful, program exit"));
|
|
@@ -5397,17 +5629,47 @@ var upload_default = async (options) => {
|
|
|
5397
5629
|
console.log(import_chalk4.default.red(`path ${answer.path} does not exist`));
|
|
5398
5630
|
return;
|
|
5399
5631
|
}
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
)
|
|
5407
|
-
);
|
|
5632
|
+
const isDns = dnsArg || (domainArg ? isDnsDomain(domainArg) : false);
|
|
5633
|
+
const displayDomain = domainArg == null ? void 0 : domainArg.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
5634
|
+
if (isDns && domainArg) {
|
|
5635
|
+
const validation = validateDnsDomain(domainArg);
|
|
5636
|
+
if (!validation.valid) {
|
|
5637
|
+
console.log(import_chalk4.default.red(validation.message));
|
|
5408
5638
|
return;
|
|
5409
5639
|
}
|
|
5410
|
-
|
|
5640
|
+
}
|
|
5641
|
+
if (domainArg) {
|
|
5642
|
+
try {
|
|
5643
|
+
const isVipUser = await checkVipStatus(authConfig);
|
|
5644
|
+
if (!isVipUser) {
|
|
5645
|
+
console.log(import_chalk4.default.red("Domain binding requires VIP. Please upgrade to VIP first."));
|
|
5646
|
+
return;
|
|
5647
|
+
}
|
|
5648
|
+
} catch (e) {
|
|
5649
|
+
if (e.message === "Token expired") {
|
|
5650
|
+
return;
|
|
5651
|
+
}
|
|
5652
|
+
throw e;
|
|
5653
|
+
}
|
|
5654
|
+
}
|
|
5655
|
+
if (domainArg) {
|
|
5656
|
+
try {
|
|
5657
|
+
const check = await checkDomainAvailable(displayDomain);
|
|
5658
|
+
if (!check.is_valid) {
|
|
5659
|
+
console.log(
|
|
5660
|
+
import_chalk4.default.red(
|
|
5661
|
+
`Domain not available: ${check.error || "unknown reason"}`
|
|
5662
|
+
)
|
|
5663
|
+
);
|
|
5664
|
+
return;
|
|
5665
|
+
}
|
|
5666
|
+
console.log(import_chalk4.default.green(`Domain available: ${displayDomain}`));
|
|
5667
|
+
} catch (e) {
|
|
5668
|
+
if (e.message === "Token expired") {
|
|
5669
|
+
return;
|
|
5670
|
+
}
|
|
5671
|
+
throw e;
|
|
5672
|
+
}
|
|
5411
5673
|
}
|
|
5412
5674
|
console.log(import_chalk4.default.blue(`uploading ${absolutePath} to ipfs...`));
|
|
5413
5675
|
try {
|
|
@@ -5425,19 +5687,16 @@ var upload_default = async (options) => {
|
|
|
5425
5687
|
if (domainArg) {
|
|
5426
5688
|
console.log(
|
|
5427
5689
|
import_chalk4.default.blue(
|
|
5428
|
-
`Binding domain: ${
|
|
5690
|
+
`Binding domain: ${displayDomain} with CID: ${result.contentHash}`
|
|
5429
5691
|
)
|
|
5430
5692
|
);
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
);
|
|
5439
|
-
} else {
|
|
5440
|
-
console.log(import_chalk4.default.red("Binding failed. Please try again later."));
|
|
5693
|
+
try {
|
|
5694
|
+
await bindDomain(domainArg, result.contentHash, isDns, authConfig);
|
|
5695
|
+
} catch (e) {
|
|
5696
|
+
if (e.message === "Token expired") {
|
|
5697
|
+
return;
|
|
5698
|
+
}
|
|
5699
|
+
throw e;
|
|
5441
5700
|
}
|
|
5442
5701
|
}
|
|
5443
5702
|
console.log(import_chalk4.default.green("\n\u{1F389} upload successful, program exit"));
|
|
@@ -6171,20 +6430,189 @@ async function myDomainsCmd() {
|
|
|
6171
6430
|
}
|
|
6172
6431
|
}
|
|
6173
6432
|
|
|
6433
|
+
// bin/bind.ts
|
|
6434
|
+
var import_path9 = __toESM(require("path"));
|
|
6435
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
6436
|
+
var import_inquirer7 = __toESM(require("inquirer"));
|
|
6437
|
+
function isDnsDomain2(domain) {
|
|
6438
|
+
return domain.includes(".");
|
|
6439
|
+
}
|
|
6440
|
+
function validateDnsDomain2(domain) {
|
|
6441
|
+
const cleanDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
6442
|
+
const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]*(\.[a-zA-Z0-9][a-zA-Z0-9-]*)*\.[a-zA-Z]{2,}$/;
|
|
6443
|
+
const parts = cleanDomain.split(".");
|
|
6444
|
+
if (parts.length < 2) {
|
|
6445
|
+
return { valid: false, message: "Invalid domain format. Please enter a complete domain (e.g., example.com)" };
|
|
6446
|
+
}
|
|
6447
|
+
for (const part of parts) {
|
|
6448
|
+
if (part.length === 0) {
|
|
6449
|
+
return { valid: false, message: "Invalid domain format. Consecutive dots are not allowed" };
|
|
6450
|
+
}
|
|
6451
|
+
if (part.length > 63) {
|
|
6452
|
+
return { valid: false, message: "Invalid domain format. Each label must be 63 characters or less" };
|
|
6453
|
+
}
|
|
6454
|
+
if (!/^[a-zA-Z0-9-]+$/.test(part)) {
|
|
6455
|
+
return { valid: false, message: "Invalid domain format. Domains can only contain letters, numbers, and hyphens" };
|
|
6456
|
+
}
|
|
6457
|
+
if (/^-|-$/.test(part)) {
|
|
6458
|
+
return { valid: false, message: "Invalid domain format. Labels cannot start or end with hyphens" };
|
|
6459
|
+
}
|
|
6460
|
+
}
|
|
6461
|
+
if (!domainRegex.test(cleanDomain)) {
|
|
6462
|
+
return { valid: false, message: "Invalid domain format" };
|
|
6463
|
+
}
|
|
6464
|
+
return { valid: true };
|
|
6465
|
+
}
|
|
6466
|
+
function parseArgs() {
|
|
6467
|
+
const args = process.argv.slice(2);
|
|
6468
|
+
const res = {};
|
|
6469
|
+
const idx = args.indexOf("bind");
|
|
6470
|
+
if (idx >= 0) {
|
|
6471
|
+
const maybePath = args[idx + 1];
|
|
6472
|
+
if (maybePath && !maybePath.startsWith("-")) res.targetPath = maybePath;
|
|
6473
|
+
}
|
|
6474
|
+
const dIdx = args.findIndex((a) => a === "--domain" || a === "-d");
|
|
6475
|
+
if (dIdx >= 0 && args[dIdx + 1]) {
|
|
6476
|
+
res.domain = args[dIdx + 1];
|
|
6477
|
+
}
|
|
6478
|
+
const dnsIdx = args.findIndex((a) => a === "--dns" || a === "-D");
|
|
6479
|
+
if (dnsIdx >= 0) {
|
|
6480
|
+
res.dns = true;
|
|
6481
|
+
}
|
|
6482
|
+
return res;
|
|
6483
|
+
}
|
|
6484
|
+
async function checkVipStatus2(authConfig) {
|
|
6485
|
+
var _a;
|
|
6486
|
+
console.log(import_chalk13.default.blue("Checking VIP status..."));
|
|
6487
|
+
try {
|
|
6488
|
+
const vipResult = await isVip(authConfig.address, authConfig.token);
|
|
6489
|
+
if (!((_a = vipResult.data) == null ? void 0 : _a.is_vip)) {
|
|
6490
|
+
return false;
|
|
6491
|
+
}
|
|
6492
|
+
console.log(import_chalk13.default.green("VIP verified."));
|
|
6493
|
+
return true;
|
|
6494
|
+
} catch (e) {
|
|
6495
|
+
if (e.message === "Token expired") {
|
|
6496
|
+
throw e;
|
|
6497
|
+
}
|
|
6498
|
+
console.log(import_chalk13.default.yellow("Failed to check VIP status, continuing..."));
|
|
6499
|
+
return true;
|
|
6500
|
+
}
|
|
6501
|
+
}
|
|
6502
|
+
async function bindCmd() {
|
|
6503
|
+
var _a;
|
|
6504
|
+
try {
|
|
6505
|
+
let { domain, targetPath, dns } = parseArgs();
|
|
6506
|
+
const authConfig = getAuthConfig();
|
|
6507
|
+
if (!authConfig) {
|
|
6508
|
+
console.log(import_chalk13.default.red("Please login first. Run: pinme set-appkey <AppKey>"));
|
|
6509
|
+
return;
|
|
6510
|
+
}
|
|
6511
|
+
if (!targetPath) {
|
|
6512
|
+
const ans = await import_inquirer7.default.prompt([
|
|
6513
|
+
{ type: "input", name: "path", message: "Enter the path to upload and bind: " }
|
|
6514
|
+
]);
|
|
6515
|
+
targetPath = ans.path;
|
|
6516
|
+
}
|
|
6517
|
+
if (!domain) {
|
|
6518
|
+
const ans = await import_inquirer7.default.prompt([
|
|
6519
|
+
{ type: "input", name: "domain", message: "Enter the domain to bind (e.g., my-site or example.com): " }
|
|
6520
|
+
]);
|
|
6521
|
+
domain = (_a = ans.domain) == null ? void 0 : _a.trim();
|
|
6522
|
+
}
|
|
6523
|
+
if (!targetPath || !domain) {
|
|
6524
|
+
console.log(import_chalk13.default.red("Missing parameters. Path and domain are required."));
|
|
6525
|
+
return;
|
|
6526
|
+
}
|
|
6527
|
+
const isDns = dns || isDnsDomain2(domain);
|
|
6528
|
+
console.log(isDns, "isDns");
|
|
6529
|
+
const displayDomain = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
|
|
6530
|
+
if (isDns) {
|
|
6531
|
+
const validation = validateDnsDomain2(domain);
|
|
6532
|
+
if (!validation.valid) {
|
|
6533
|
+
console.log(import_chalk13.default.red(validation.message));
|
|
6534
|
+
return;
|
|
6535
|
+
}
|
|
6536
|
+
}
|
|
6537
|
+
try {
|
|
6538
|
+
const isVipUser = await checkVipStatus2(authConfig);
|
|
6539
|
+
if (!isVipUser) {
|
|
6540
|
+
console.log(import_chalk13.default.red("Domain binding requires VIP. Please upgrade to VIP first."));
|
|
6541
|
+
return;
|
|
6542
|
+
}
|
|
6543
|
+
} catch (e) {
|
|
6544
|
+
if (e.message === "Token expired") {
|
|
6545
|
+
return;
|
|
6546
|
+
}
|
|
6547
|
+
throw e;
|
|
6548
|
+
}
|
|
6549
|
+
try {
|
|
6550
|
+
const check = await checkDomainAvailable(displayDomain);
|
|
6551
|
+
if (!check.is_valid) {
|
|
6552
|
+
console.log(import_chalk13.default.red(`Domain not available: ${check.error || "unknown reason"}`));
|
|
6553
|
+
return;
|
|
6554
|
+
}
|
|
6555
|
+
console.log(import_chalk13.default.green(`Domain available: ${displayDomain}`));
|
|
6556
|
+
} catch (e) {
|
|
6557
|
+
if (e.message === "Token expired") {
|
|
6558
|
+
return;
|
|
6559
|
+
}
|
|
6560
|
+
throw e;
|
|
6561
|
+
}
|
|
6562
|
+
const absolutePath = import_path9.default.resolve(targetPath);
|
|
6563
|
+
console.log(import_chalk13.default.blue(`Uploading: ${absolutePath}`));
|
|
6564
|
+
const up = await uploadToIpfsSplit_default(absolutePath);
|
|
6565
|
+
if (!(up == null ? void 0 : up.contentHash)) {
|
|
6566
|
+
console.log(import_chalk13.default.red("Upload failed, binding aborted."));
|
|
6567
|
+
return;
|
|
6568
|
+
}
|
|
6569
|
+
console.log(import_chalk13.default.green(`Upload success, CID: ${up.contentHash}`));
|
|
6570
|
+
try {
|
|
6571
|
+
if (isDns) {
|
|
6572
|
+
console.log(import_chalk13.default.blue("Binding DNS domain..."));
|
|
6573
|
+
const dnsResult = await bindDnsDomainV4(displayDomain, up.contentHash, authConfig.address, authConfig.token);
|
|
6574
|
+
if (dnsResult.code !== 200) {
|
|
6575
|
+
console.log(import_chalk13.default.red(`DNS binding failed: ${dnsResult.msg}`));
|
|
6576
|
+
return;
|
|
6577
|
+
}
|
|
6578
|
+
console.log(import_chalk13.default.green(`DNS bind success: ${displayDomain}`));
|
|
6579
|
+
console.log(import_chalk13.default.white(`Visit: https://${displayDomain}`));
|
|
6580
|
+
console.log(import_chalk13.default.cyan("\n\u{1F4DA} DNS Setup Guide: https://pinme.eth.limo/#/docs?id=custom-domain"));
|
|
6581
|
+
} else {
|
|
6582
|
+
console.log(import_chalk13.default.blue("Binding Pinme subdomain..."));
|
|
6583
|
+
const ok = await bindPinmeDomain(displayDomain, up.contentHash);
|
|
6584
|
+
if (!ok) {
|
|
6585
|
+
console.log(import_chalk13.default.red("Binding failed. Please try again later."));
|
|
6586
|
+
return;
|
|
6587
|
+
}
|
|
6588
|
+
console.log(import_chalk13.default.green(`Bind success: ${displayDomain}`));
|
|
6589
|
+
console.log(import_chalk13.default.white(`Visit: https://${displayDomain}.pinit.eth.limo`));
|
|
6590
|
+
}
|
|
6591
|
+
} catch (e) {
|
|
6592
|
+
if (e.message === "Token expired") {
|
|
6593
|
+
return;
|
|
6594
|
+
}
|
|
6595
|
+
throw e;
|
|
6596
|
+
}
|
|
6597
|
+
} catch (e) {
|
|
6598
|
+
console.log(import_chalk13.default.red(`Execution failed: ${(e == null ? void 0 : e.message) || e}`));
|
|
6599
|
+
}
|
|
6600
|
+
}
|
|
6601
|
+
|
|
6174
6602
|
// bin/index.ts
|
|
6175
6603
|
import_dotenv.default.config();
|
|
6176
6604
|
checkNodeVersion();
|
|
6177
6605
|
function showBanner() {
|
|
6178
6606
|
console.log(
|
|
6179
|
-
|
|
6607
|
+
import_chalk14.default.cyan(import_figlet5.default.textSync("Pinme", { horizontalLayout: "full" }))
|
|
6180
6608
|
);
|
|
6181
|
-
console.log(
|
|
6609
|
+
console.log(import_chalk14.default.cyan("A command-line tool for uploading files to IPFS\n"));
|
|
6182
6610
|
}
|
|
6183
6611
|
var program = new import_commander.Command();
|
|
6184
6612
|
program.name("pinme").version(version).option("-v, --version", "output the current version");
|
|
6185
6613
|
program.command("upload").description(
|
|
6186
6614
|
"upload a file or directory to IPFS. Supports --domain to bind after upload"
|
|
6187
|
-
).option("-d, --domain <name>", "
|
|
6615
|
+
).option("-d, --domain <name>", "Domain name to bind").option("--dns", "Force DNS domain mode").action(() => upload_default());
|
|
6188
6616
|
program.command("import").description("import a CAR file to IPFS. Supports --domain to bind after import").option("-d, --domain <name>", "Pinme subdomain").action(() => importCar_default());
|
|
6189
6617
|
program.command("export").description("export IPFS content as CAR file").option("-o, --output <path>", "output file path for CAR file").action(() => exportCar_default());
|
|
6190
6618
|
program.command("rm").description("remove a file from IPFS network").action(() => remove_default());
|
|
@@ -6194,6 +6622,7 @@ program.command("set-appkey").description(
|
|
|
6194
6622
|
program.command("logout").description("log out and clear authentication").action(() => logoutCmd());
|
|
6195
6623
|
program.command("show-appkey").alias("appkey").description("show current AppKey information (masked)").action(() => showAppKeyCmd());
|
|
6196
6624
|
program.command("my-domains").alias("domain").description("List domains owned by current account").action(() => myDomainsCmd());
|
|
6625
|
+
program.command("bind").description("Upload and bind to a domain (requires VIP)").option("-d, --domain <name>", "Domain name to bind").option("--dns", "Force DNS domain mode").action(() => bindCmd());
|
|
6197
6626
|
program.command("domain").description("Alias for 'my-domains' command").action(() => myDomainsCmd());
|
|
6198
6627
|
program.command("list").description("show upload history").option(
|
|
6199
6628
|
"-l, --limit <number>",
|