pinme 1.1.6-alpha.4 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +294 -10
  2. package/dist/index.js +278 -134
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -13,10 +13,17 @@
13
13
 
14
14
  # PinMe
15
15
 
16
- [PinMe](https://pinme.eth.limo/) is a one-command deploy tool that turns static sites into permanent, verifiable frontends by pinning to [IPFS](https://ipfs.tech/), writing contenthash to [ENS](https://ens.domains/) subnames, and serving through gateways like [eth.limo](https://eth.limo/)—no DNS, no servers.
16
+ [PinMe](https://pinme.eth.limo/) is a zero-config frontend deployment tool.
17
+ No servers. No accounts. No setup.
17
18
 
18
- Website:[https://pinme.eth.limo/](https://pinme.eth.limo/)
19
+ Build a static site, generate a page with AI, or export your frontend — then deploy instantly with a single command.
19
20
 
21
+ PinMe publishes your site as verifiable content, making silent tampering and accidental breakage far harder than traditional hosting.
22
+
23
+ You don’t manage servers, regions, or uptime.
24
+ PinMe handles availability and persistence for you.
25
+
26
+ Website: [https://pinme.eth.limo/](https://pinme.eth.limo/)
20
27
 
21
28
  ## Installation
22
29
 
@@ -42,6 +49,10 @@ pinme upload
42
49
 
43
50
  # Specify path directly
44
51
  pinme upload /path/to/file-or-directory
52
+
53
+ # Upload and bind to a domain
54
+ pinme upload /path/to/file-or-directory --domain <name>
55
+ pinme upload /path/to/file-or-directory -d <name>
45
56
  ```
46
57
 
47
58
  ### Remove files from IPFS
@@ -70,6 +81,43 @@ pinme list -l 5
70
81
  pinme list -c
71
82
  ```
72
83
 
84
+ ### Set AppKey for authentication
85
+
86
+ ```bash
87
+ # Interactive AppKey setup
88
+ pinme set-appkey
89
+
90
+ # Set AppKey directly
91
+ pinme set-appkey <AppKey>
92
+ ```
93
+
94
+ ### View AppKey information
95
+
96
+ ```bash
97
+ # Show current AppKey (masked for security)
98
+ pinme show-appkey
99
+
100
+ # Or use the shorthand command
101
+ pinme appkey
102
+ ```
103
+
104
+ ### Log out
105
+
106
+ ```bash
107
+ # Log out and clear authentication
108
+ pinme logout
109
+ ```
110
+
111
+ ### View your domains
112
+
113
+ ```bash
114
+ # List all domains owned by current account
115
+ pinme my-domains
116
+
117
+ # Or use the shorthand command
118
+ pinme domain
119
+ ```
120
+
73
121
  ### Get help
74
122
 
75
123
  ```bash
@@ -81,16 +129,19 @@ pinme help
81
129
 
82
130
  ### `upload`
83
131
 
84
- Upload a file or directory to the IPFS network.
132
+ Upload a file or directory to the IPFS network. Supports binding to a Pinme subdomain after upload.
85
133
 
86
134
  ```bash
87
- pinme upload [path]
135
+ pinme upload [path] [--domain <name>]
88
136
  ```
89
137
 
90
138
  **Options:**
139
+
91
140
  - `path`: Path to the file or directory to upload (optional, if not provided, interactive mode will be entered)
141
+ - `-d, --domain <name>`: Pinme subdomain to bind after upload (optional)
92
142
 
93
143
  **Examples:**
144
+
94
145
  ```bash
95
146
  # Interactive upload
96
147
  pinme upload
@@ -100,6 +151,10 @@ pinme upload ./example.jpg
100
151
 
101
152
  # Upload an entire directory
102
153
  pinme upload ./my-website
154
+
155
+ # Upload and bind to a domain
156
+ pinme upload ./my-website --domain my-site
157
+ pinme upload ./my-website -d my-site
103
158
  ```
104
159
 
105
160
  ### `rm`
@@ -111,9 +166,11 @@ pinme rm [hash]
111
166
  ```
112
167
 
113
168
  **Options:**
169
+
114
170
  - `hash`: IPFS content hash to remove (optional, if not provided, interactive mode will be entered)
115
171
 
116
172
  **Examples:**
173
+
117
174
  ```bash
118
175
  # Interactive removal
119
176
  pinme rm
@@ -134,10 +191,12 @@ pinme ls [options]
134
191
  ```
135
192
 
136
193
  **Options:**
194
+
137
195
  - `-l, --limit <number>`: Limit the number of records displayed
138
196
  - `-c, --clear`: Clear all upload history
139
197
 
140
198
  **Examples:**
199
+
141
200
  ```bash
142
201
  # Show the last 10 records
143
202
  pinme list
@@ -149,6 +208,105 @@ pinme ls -l 5
149
208
  pinme list -c
150
209
  ```
151
210
 
211
+ ### `set-appkey`
212
+
213
+ Set AppKey for authentication and automatically merge anonymous upload history to the current account.
214
+
215
+ ```bash
216
+ pinme set-appkey [AppKey]
217
+ ```
218
+
219
+ **Options:**
220
+
221
+ - `AppKey`: Your AppKey for authentication (optional, if not provided, interactive mode will be entered)
222
+
223
+ **Examples:**
224
+
225
+ ```bash
226
+ # Interactive AppKey setup
227
+ pinme set-appkey
228
+
229
+ # Set AppKey directly
230
+ pinme set-appkey your-app-key-here
231
+ ```
232
+
233
+ **Note:** After setting the AppKey, your anonymous upload history will be automatically merged to your account.
234
+
235
+ ### `show-appkey` / `appkey`
236
+
237
+ Display current AppKey information with masked sensitive data.
238
+
239
+ ```bash
240
+ pinme show-appkey
241
+ pinme appkey
242
+ ```
243
+
244
+ **Description:**
245
+
246
+ This command shows the current AppKey information including:
247
+ - Address (fully displayed)
248
+ - Token (masked for security)
249
+ - AppKey (masked for security)
250
+
251
+ **Examples:**
252
+
253
+ ```bash
254
+ # Show AppKey information
255
+ pinme show-appkey
256
+
257
+ # Shorthand command
258
+ pinme appkey
259
+ ```
260
+
261
+ **Note:** Sensitive information (token and AppKey) will be masked to protect your credentials. Only the address is fully displayed.
262
+
263
+ ### `logout`
264
+
265
+ Log out and clear authentication information from local storage.
266
+
267
+ ```bash
268
+ pinme logout
269
+ ```
270
+
271
+ **Description:**
272
+
273
+ This command logs out the current user and removes the authentication information from local storage. After logging out, you will need to set your AppKey again to use authenticated features.
274
+
275
+ **Examples:**
276
+
277
+ ```bash
278
+ # Log out
279
+ pinme logout
280
+ ```
281
+
282
+ **Note:** This action will remove your AppKey from local storage. You can set it again using `pinme set-appkey` command.
283
+
284
+ ### `my-domains` / `domain`
285
+
286
+ List all domains owned by the current account.
287
+
288
+ ```bash
289
+ pinme my-domains
290
+ pinme domain
291
+ ```
292
+
293
+ **Examples:**
294
+
295
+ ```bash
296
+ # List all domains
297
+ pinme my-domains
298
+
299
+ # Shorthand command
300
+ pinme domain
301
+ ```
302
+
303
+ This command displays information about each domain including:
304
+
305
+ - Domain name
306
+ - Domain type
307
+ - Bind time
308
+ - Expire time
309
+
152
310
  ### `help`
153
311
 
154
312
  Display help information.
@@ -158,9 +316,11 @@ pinme help [command]
158
316
  ```
159
317
 
160
318
  **Options:**
319
+
161
320
  - `command`: The specific command to view help for (optional)
162
321
 
163
322
  **Examples:**
323
+
164
324
  ```bash
165
325
  # Display general help
166
326
  pinme help
@@ -168,8 +328,8 @@ pinme help
168
328
 
169
329
  ## Upload Limits
170
330
 
171
- - Single file size limit: 20MB
172
- - Total directory size limit: 500MB
331
+ - Single file size limit: 200MB (free plan)
332
+ - Total directory size limit: 1GB (free plan)
173
333
 
174
334
  ## File Storage
175
335
 
@@ -181,10 +341,10 @@ Uploaded files are stored on the IPFS network and accessible through the Glitter
181
341
  ### Log Locations
182
342
 
183
343
  Logs and configuration files are stored in:
344
+
184
345
  - Linux/macOS: `~/.pinme/`
185
346
  - Windows: `%USERPROFILE%\.pinme\`
186
347
 
187
-
188
348
  ## License
189
349
 
190
350
  MIT License - See the [LICENSE](LICENSE) file for details
@@ -200,16 +360,140 @@ When uploading projects built with Vite, please note:
200
360
  ```js
201
361
  // vite.config.js
202
362
  export default {
203
- base: "./",
363
+ base: './',
204
364
  // other configurations...
205
- }
365
+ };
206
366
  ```
207
367
 
368
+ ## GitHub Actions Integration
369
+
370
+ PinMe can be integrated with GitHub Actions to automatically deploy your project when you push code to GitHub. This enables a fully automated CI/CD workflow.
371
+
372
+ ### Quick Setup
373
+
374
+ 1. **Add the workflow file** to your repository:
375
+
376
+ - Copy `.github/workflows/deploy.yml` from the PinMe repository to your project
377
+ - Or create `.github/workflows/deploy.yml` in your repository
378
+
379
+ 2. **Configure GitHub Secrets**:
380
+
381
+ - Go to your repository → Settings → Secrets and variables → Actions
382
+ - Add a new secret named `PINME_APPKEY` with your PinMe AppKey
383
+ - (Optional) Add `PINME_DOMAIN` to specify a custom domain name
384
+
385
+ 3. **Push to trigger deployment**:
386
+ - Push code to `main` or `master` branch to trigger automatic deployment
387
+ - Or manually trigger via Actions tab → "Deploy to PinMe" → Run workflow
388
+
389
+ ### Workflow Features
390
+
391
+ The GitHub Actions workflow automatically:
392
+
393
+ - ✅ Detects and installs project dependencies
394
+ - ✅ Builds your project (if a build script exists)
395
+ - ✅ Installs PinMe CLI
396
+ - ✅ Sets up authentication using your AppKey
397
+ - ✅ Auto-detects build output directory (`dist`, `build`, `public`, or `out`)
398
+ - ✅ Uploads to IPFS and binds to your domain
399
+ - ✅ Provides deployment summary with access URL
400
+
401
+ ### Configuration Options
402
+
403
+ #### Using GitHub Secrets
404
+
405
+ You can configure the following secrets in your repository:
406
+
407
+ - **`PINME_APPKEY`** (Required): Your PinMe AppKey for authentication
408
+
409
+ - Format: `<address>-<jwt>`
410
+ - Get your AppKey from [PinMe website](https://pinme.eth.limo/)
411
+
412
+ - **`PINME_DOMAIN`** (Optional): Default domain name to bind
413
+ - If not set, the workflow will generate a domain from your repository name
414
+ - Example: `my-awesome-project` → `https://my-awesome-project.pinit.eth.limo`
415
+
416
+ #### Manual Workflow Dispatch
417
+
418
+ You can also manually trigger the workflow with custom parameters:
419
+
420
+ 1. Go to Actions tab in your repository
421
+ 2. Select "Deploy to PinMe" workflow
422
+ 3. Click "Run workflow"
423
+ 4. Enter:
424
+ - **Domain**: Your desired PinMe domain name
425
+ - **Build Directory**: Your build output directory (default: `dist`)
426
+
427
+ ### Example Workflow
428
+
429
+ ```yaml
430
+ name: Deploy to PinMe
431
+
432
+ on:
433
+ push:
434
+ branches: [main, master]
435
+ workflow_dispatch:
436
+ inputs:
437
+ domain:
438
+ description: 'PinMe domain name'
439
+ required: true
440
+ build_dir:
441
+ description: 'Build directory'
442
+ default: 'dist'
443
+
444
+ jobs:
445
+ deploy:
446
+ runs-on: ubuntu-latest
447
+ steps:
448
+ - uses: actions/checkout@v4
449
+ - uses: actions/setup-node@v4
450
+ with:
451
+ node-version: '18'
452
+ - run: npm ci
453
+ - run: npm run build
454
+ - run: npm install -g pinme
455
+ - run: pinme set-appkey "${{ secrets.PINME_APPKEY }}"
456
+ - run: pinme upload dist --domain "${{ secrets.PINME_DOMAIN }}"
457
+ ```
458
+
459
+ ### Supported Build Tools
460
+
461
+ The workflow automatically detects and supports:
462
+
463
+ - **Vite**: Builds to `dist/`
464
+ - **Create React App**: Builds to `build/`
465
+ - **Next.js**: Builds to `out/` (with `output: 'export'`)
466
+ - **Vue CLI**: Builds to `dist/`
467
+ - **Angular**: Builds to `dist/`
468
+ - **Static sites**: Uses root directory or `public/`
469
+
470
+ ### Troubleshooting
471
+
472
+ **Build directory not found:**
473
+
474
+ - Ensure your build script outputs to a standard directory (`dist`, `build`, `public`, or `out`)
475
+ - Or set `PINME_DOMAIN` secret and use manual workflow dispatch to specify custom directory
476
+
477
+ **Authentication failed:**
478
+
479
+ - Verify your `PINME_APPKEY` secret is correctly set
480
+ - Ensure the AppKey format is correct: `<address>-<jwt>`
481
+
482
+ **Domain binding failed:**
483
+
484
+ - Check if the domain name is available
485
+ - Ensure you have permission to bind the domain
486
+ - Try a different domain name
487
+
488
+ ## Star History
489
+
490
+ [![Star History Chart](https://api.star-history.com/svg?repos=glitternetwork/pinme&type=Date)](https://star-history.com/#glitternetwork/pinme&Date)
491
+
208
492
  ## Contact Us
209
493
 
210
494
  If you have questions or suggestions, please contact us through:
211
495
 
212
- - GitHub Issues: [https://github.com/glitternetwork/pinme/issues](https://github.com/glitternetwork/pinme/issue)
496
+ - GitHub Issues: [https://github.com/glitternetwork/pinme/issues](https://github.com/glitternetwork/pinme/issues)
213
497
  - Email: [pinme@glitterprotocol.io](mailto:pinme@glitterprotocol.io)
214
498
 
215
499
  ---
package/dist/index.js CHANGED
@@ -1519,11 +1519,11 @@ function checkNodeVersion() {
1519
1519
 
1520
1520
  // bin/index.ts
1521
1521
  var import_commander = require("commander");
1522
- var import_chalk9 = __toESM(require("chalk"));
1522
+ var import_chalk11 = __toESM(require("chalk"));
1523
1523
  var import_figlet3 = __toESM(require("figlet"));
1524
1524
 
1525
1525
  // package.json
1526
- var version = "1.1.6-alpha.4";
1526
+ var version = "1.2.1";
1527
1527
 
1528
1528
  // bin/upload.ts
1529
1529
  var import_path6 = __toESM(require("path"));
@@ -4399,8 +4399,8 @@ var {
4399
4399
  } = axios_default;
4400
4400
 
4401
4401
  // bin/utils/uploadToIpfsSplit.ts
4402
- var import_fs_extra3 = __toESM(require("fs-extra"));
4403
- var import_path4 = __toESM(require("path"));
4402
+ var import_fs_extra4 = __toESM(require("fs-extra"));
4403
+ var import_path5 = __toESM(require("path"));
4404
4404
  var import_form_data2 = __toESM(require("form-data"));
4405
4405
  var import_ora = __toESM(require("ora"));
4406
4406
  var crypto = __toESM(require("crypto"));
@@ -4540,23 +4540,91 @@ var clearUploadHistory = () => {
4540
4540
  };
4541
4541
 
4542
4542
  // bin/utils/getDeviceId.ts
4543
+ var import_fs_extra3 = __toESM(require("fs-extra"));
4544
+ var import_path4 = __toESM(require("path"));
4545
+ var import_os3 = __toESM(require("os"));
4546
+ var import_uuid = require("uuid");
4547
+
4548
+ // bin/utils/auth.ts
4543
4549
  var import_fs_extra2 = __toESM(require("fs-extra"));
4544
- var import_path3 = __toESM(require("path"));
4545
4550
  var import_os2 = __toESM(require("os"));
4546
- var import_uuid = require("uuid");
4551
+ var import_path3 = __toESM(require("path"));
4552
+ var CONFIG_DIR = import_path3.default.join(import_os2.default.homedir(), ".pinme");
4553
+ var AUTH_FILE = import_path3.default.join(CONFIG_DIR, "auth.json");
4554
+ function ensureConfigDir() {
4555
+ if (!import_fs_extra2.default.existsSync(CONFIG_DIR)) {
4556
+ import_fs_extra2.default.mkdirSync(CONFIG_DIR, { recursive: true });
4557
+ }
4558
+ }
4559
+ function parseCombinedToken(combined) {
4560
+ const firstDash = combined.indexOf("-");
4561
+ if (firstDash <= 0 || firstDash === combined.length - 1) {
4562
+ throw new Error('Invalid token format. Expected "<address>-<jwt>".');
4563
+ }
4564
+ const address = combined.slice(0, firstDash).trim();
4565
+ const token = combined.slice(firstDash + 1).trim();
4566
+ if (!address || !token) {
4567
+ throw new Error("Invalid token content. Address or token is empty.");
4568
+ }
4569
+ return { address, token };
4570
+ }
4571
+ function setAuthToken(combined) {
4572
+ ensureConfigDir();
4573
+ const auth = parseCombinedToken(combined);
4574
+ import_fs_extra2.default.writeJsonSync(AUTH_FILE, auth, { spaces: 2 });
4575
+ return auth;
4576
+ }
4577
+ function clearAuthToken() {
4578
+ try {
4579
+ if (import_fs_extra2.default.existsSync(AUTH_FILE)) {
4580
+ import_fs_extra2.default.removeSync(AUTH_FILE);
4581
+ }
4582
+ } catch (error) {
4583
+ console.error(`Failed to clear auth token: ${error}`);
4584
+ }
4585
+ }
4586
+ function getAuthConfig() {
4587
+ try {
4588
+ if (!import_fs_extra2.default.existsSync(AUTH_FILE)) return null;
4589
+ const data = import_fs_extra2.default.readJsonSync(AUTH_FILE);
4590
+ if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
4591
+ return data;
4592
+ } catch {
4593
+ return null;
4594
+ }
4595
+ }
4596
+ function getAuthHeaders() {
4597
+ const conf = getAuthConfig();
4598
+ if (!conf) {
4599
+ throw new Error("Auth not set. Run: pinme set-appkey <AppKey>");
4600
+ }
4601
+ return {
4602
+ "token-address": conf.address,
4603
+ "authentication-tokens": conf.token
4604
+ };
4605
+ }
4606
+
4607
+ // bin/utils/getDeviceId.ts
4547
4608
  function getDeviceId() {
4548
- const configDir = import_path3.default.join(import_os2.default.homedir(), ".pinme");
4549
- const configFile = import_path3.default.join(configDir, "device-id");
4550
- if (!import_fs_extra2.default.existsSync(configDir)) {
4551
- import_fs_extra2.default.mkdirSync(configDir, { recursive: true });
4609
+ const configDir = import_path4.default.join(import_os3.default.homedir(), ".pinme");
4610
+ const configFile = import_path4.default.join(configDir, "device-id");
4611
+ if (!import_fs_extra3.default.existsSync(configDir)) {
4612
+ import_fs_extra3.default.mkdirSync(configDir, { recursive: true });
4552
4613
  }
4553
- if (import_fs_extra2.default.existsSync(configFile)) {
4554
- return import_fs_extra2.default.readFileSync(configFile, "utf8").trim();
4614
+ if (import_fs_extra3.default.existsSync(configFile)) {
4615
+ return import_fs_extra3.default.readFileSync(configFile, "utf8").trim();
4555
4616
  }
4556
4617
  const deviceId = (0, import_uuid.v4)();
4557
- import_fs_extra2.default.writeFileSync(configFile, deviceId);
4618
+ import_fs_extra3.default.writeFileSync(configFile, deviceId);
4558
4619
  return deviceId;
4559
4620
  }
4621
+ function getUid() {
4622
+ const auth = getAuthConfig();
4623
+ if (auth == null ? void 0 : auth.address) {
4624
+ return auth.address;
4625
+ }
4626
+ return getDeviceId();
4627
+ }
4560
4628
 
4561
4629
  // bin/utils/uploadToIpfsSplit.ts
4562
4630
  var IPFS_API_URL = "https://pinme.dev/api/v3";
@@ -4592,12 +4660,12 @@ var StepProgressBar = class {
4592
4660
  }
4593
4661
  completeStep() {
4594
4662
  }
4595
- // 开始模拟进度,用于在90%后继续显示进度
4663
+ // Start simulating progress to continue display after 90%
4596
4664
  startSimulatingProgress() {
4597
4665
  this.isSimulatingProgress = true;
4598
4666
  this.simulationStartTime = Date.now();
4599
4667
  }
4600
- // 停止模拟进度
4668
+ // Stop simulating progress
4601
4669
  stopSimulatingProgress() {
4602
4670
  this.isSimulatingProgress = false;
4603
4671
  }
@@ -4609,7 +4677,9 @@ var StepProgressBar = class {
4609
4677
  this.stopProgress();
4610
4678
  const totalTime = Math.floor((Date.now() - this.startTime) / 1e3);
4611
4679
  const progressBar = this.createProgressBar(1);
4612
- this.spinner.succeed(`Upload completed ${progressBar} 100% (${totalTime}s)`);
4680
+ this.spinner.succeed(
4681
+ `Upload completed ${progressBar} 100% (${totalTime}s)`
4682
+ );
4613
4683
  }
4614
4684
  fail(error) {
4615
4685
  this.stopProgress();
@@ -4639,7 +4709,10 @@ var StepProgressBar = class {
4639
4709
  }
4640
4710
  }
4641
4711
  calculateProgress(elapsed) {
4642
- return Math.min(elapsed / EXPECTED_UPLOAD_TIME * MAX_PROGRESS, MAX_PROGRESS);
4712
+ return Math.min(
4713
+ elapsed / EXPECTED_UPLOAD_TIME * MAX_PROGRESS,
4714
+ MAX_PROGRESS
4715
+ );
4643
4716
  }
4644
4717
  createProgressBar(progress, width = 20) {
4645
4718
  const percentage = Math.min(progress, 1);
@@ -4665,7 +4738,7 @@ var StepProgressBar = class {
4665
4738
  async function calculateMD5(filePath) {
4666
4739
  return new Promise((resolve, reject) => {
4667
4740
  const hash = crypto.createHash("md5");
4668
- const stream4 = import_fs_extra3.default.createReadStream(filePath);
4741
+ const stream4 = import_fs_extra4.default.createReadStream(filePath);
4669
4742
  stream4.on("data", hash.update.bind(hash));
4670
4743
  stream4.on("end", () => resolve(hash.digest("hex")));
4671
4744
  stream4.on("error", reject);
@@ -4674,20 +4747,20 @@ async function calculateMD5(filePath) {
4674
4747
  async function compressDirectory(sourcePath) {
4675
4748
  return new Promise((resolve, reject) => {
4676
4749
  const tempDir = require("os").tmpdir();
4677
- if (!import_fs_extra3.default.existsSync(tempDir)) {
4678
- import_fs_extra3.default.mkdirSync(tempDir, { recursive: true });
4750
+ if (!import_fs_extra4.default.existsSync(tempDir)) {
4751
+ import_fs_extra4.default.mkdirSync(tempDir, { recursive: true });
4679
4752
  }
4680
- const outputPath = import_path4.default.join(
4753
+ const outputPath = import_path5.default.join(
4681
4754
  tempDir,
4682
- `pinme_${import_path4.default.basename(sourcePath)}_${Date.now()}.zip`
4755
+ `pinme_${import_path5.default.basename(sourcePath)}_${Date.now()}.zip`
4683
4756
  );
4684
- const output = import_fs_extra3.default.createWriteStream(outputPath);
4757
+ const output = import_fs_extra4.default.createWriteStream(outputPath);
4685
4758
  const zlib2 = require("zlib");
4686
4759
  const gzip = zlib2.createGzip({ level: 9 });
4687
4760
  output.on("close", () => resolve(outputPath));
4688
4761
  gzip.on("error", reject);
4689
4762
  gzip.pipe(output);
4690
- const stats = import_fs_extra3.default.statSync(sourcePath);
4763
+ const stats = import_fs_extra4.default.statSync(sourcePath);
4691
4764
  if (stats.isDirectory()) {
4692
4765
  const archive = require("archiver");
4693
4766
  const archiveStream = archive("zip", { zlib: { level: 9 } });
@@ -4696,14 +4769,14 @@ async function compressDirectory(sourcePath) {
4696
4769
  archiveStream.directory(sourcePath, false);
4697
4770
  archiveStream.finalize();
4698
4771
  } else {
4699
- const fileStream = import_fs_extra3.default.createReadStream(sourcePath);
4772
+ const fileStream = import_fs_extra4.default.createReadStream(sourcePath);
4700
4773
  fileStream.pipe(gzip);
4701
4774
  }
4702
4775
  });
4703
4776
  }
4704
4777
  async function initChunkSession(filePath, deviceId, isDirectory = false) {
4705
- const stats = import_fs_extra3.default.statSync(filePath);
4706
- const fileName = import_path4.default.basename(filePath);
4778
+ const stats = import_fs_extra4.default.statSync(filePath);
4779
+ const fileName = import_path5.default.basename(filePath);
4707
4780
  const fileSize = stats.size;
4708
4781
  const md5 = await calculateMD5(filePath);
4709
4782
  try {
@@ -4804,7 +4877,7 @@ async function delayWithAbortCheck(delay, signal) {
4804
4877
  });
4805
4878
  }
4806
4879
  async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, deviceId, progressBar) {
4807
- const fileData = import_fs_extra3.default.readFileSync(filePath);
4880
+ const fileData = import_fs_extra4.default.readFileSync(filePath);
4808
4881
  const abortController = new AbortController();
4809
4882
  let completedCount = 0;
4810
4883
  let hasFatalError = false;
@@ -4839,10 +4912,14 @@ async function uploadFileChunks(filePath, sessionId, totalChunks, chunkSize, dev
4839
4912
  });
4840
4913
  try {
4841
4914
  const results = await Promise.allSettled(uploadTasks.map((task) => task()));
4842
- const failedResults = results.filter((result) => result.status === "rejected");
4915
+ const failedResults = results.filter(
4916
+ (result) => result.status === "rejected"
4917
+ );
4843
4918
  if (failedResults.length > 0) {
4844
4919
  const firstFailure = failedResults[0];
4845
- throw new Error(firstFailure.reason.message || "Error occurred during upload");
4920
+ throw new Error(
4921
+ firstFailure.reason.message || "Error occurred during upload"
4922
+ );
4846
4923
  }
4847
4924
  if (hasFatalError) {
4848
4925
  throw new Error(fatalError || "Unknown error occurred during upload");
@@ -4935,10 +5012,12 @@ async function uploadDirectoryInChunks(directoryPath, deviceId) {
4935
5012
  const sizeCheck = checkDirectorySizeLimit(directoryPath);
4936
5013
  if (sizeCheck.exceeds) {
4937
5014
  throw new Error(
4938
- `Directory ${directoryPath} exceeds size limit ${formatSize(sizeCheck.limit)} (size: ${formatSize(sizeCheck.size)})`
5015
+ `Directory ${directoryPath} exceeds size limit ${formatSize(
5016
+ sizeCheck.limit
5017
+ )} (size: ${formatSize(sizeCheck.size)})`
4939
5018
  );
4940
5019
  }
4941
- const progressBar = new StepProgressBar(import_path4.default.basename(directoryPath), true);
5020
+ const progressBar = new StepProgressBar(import_path5.default.basename(directoryPath), true);
4942
5021
  try {
4943
5022
  progressBar.startStep(0, "Preparing compression");
4944
5023
  const compressedPath = await compressDirectory(directoryPath);
@@ -4963,12 +5042,12 @@ async function uploadDirectoryInChunks(directoryPath, deviceId) {
4963
5042
  const result = await monitorChunkProgress(traceId, deviceId, progressBar);
4964
5043
  progressBar.completeStep();
4965
5044
  try {
4966
- import_fs_extra3.default.unlinkSync(compressedPath);
5045
+ import_fs_extra4.default.unlinkSync(compressedPath);
4967
5046
  } catch (error) {
4968
5047
  }
4969
5048
  const uploadData = {
4970
5049
  path: directoryPath,
4971
- filename: import_path4.default.basename(directoryPath),
5050
+ filename: import_path5.default.basename(directoryPath),
4972
5051
  contentHash: (result == null ? void 0 : result.hash) || "unknown",
4973
5052
  size: sizeCheck.size,
4974
5053
  fileCount: 0,
@@ -4990,10 +5069,12 @@ async function uploadFileInChunks(filePath, deviceId) {
4990
5069
  const sizeCheck = checkFileSizeLimit(filePath);
4991
5070
  if (sizeCheck.exceeds) {
4992
5071
  throw new Error(
4993
- `File ${filePath} exceeds size limit ${formatSize(sizeCheck.limit)} (size: ${formatSize(sizeCheck.size)})`
5072
+ `File ${filePath} exceeds size limit ${formatSize(
5073
+ sizeCheck.limit
5074
+ )} (size: ${formatSize(sizeCheck.size)})`
4994
5075
  );
4995
5076
  }
4996
- const fileName = import_path4.default.basename(filePath);
5077
+ const fileName = import_path5.default.basename(filePath);
4997
5078
  const progressBar = new StepProgressBar(fileName, false);
4998
5079
  try {
4999
5080
  progressBar.startStep(0, "Initializing session");
@@ -5037,12 +5118,12 @@ async function uploadFileInChunks(filePath, deviceId) {
5037
5118
  }
5038
5119
  }
5039
5120
  async function uploadToIpfsSplit_default(filePath) {
5040
- const deviceId = getDeviceId();
5121
+ const deviceId = getUid();
5041
5122
  if (!deviceId) {
5042
5123
  throw new Error("Device ID not found");
5043
5124
  }
5044
5125
  try {
5045
- const isDirectory = import_fs_extra3.default.statSync(filePath).isDirectory();
5126
+ const isDirectory = import_fs_extra4.default.statSync(filePath).isDirectory();
5046
5127
  const result = isDirectory ? await uploadDirectoryInChunks(filePath, deviceId) : await uploadFileInChunks(filePath, deviceId);
5047
5128
  if (result == null ? void 0 : result.hash) {
5048
5129
  return {
@@ -5063,58 +5144,6 @@ var import_crypto_js = __toESM(require("crypto-js"));
5063
5144
 
5064
5145
  // bin/utils/pinmeApi.ts
5065
5146
  var import_chalk3 = __toESM(require("chalk"));
5066
-
5067
- // bin/utils/auth.ts
5068
- var import_fs_extra4 = __toESM(require("fs-extra"));
5069
- var import_os3 = __toESM(require("os"));
5070
- var import_path5 = __toESM(require("path"));
5071
- var CONFIG_DIR = import_path5.default.join(import_os3.default.homedir(), ".pinme");
5072
- var AUTH_FILE = import_path5.default.join(CONFIG_DIR, "auth.json");
5073
- function ensureConfigDir() {
5074
- if (!import_fs_extra4.default.existsSync(CONFIG_DIR)) {
5075
- import_fs_extra4.default.mkdirSync(CONFIG_DIR, { recursive: true });
5076
- }
5077
- }
5078
- function parseCombinedToken(combined) {
5079
- const firstDash = combined.indexOf("-");
5080
- if (firstDash <= 0 || firstDash === combined.length - 1) {
5081
- throw new Error('Invalid token format. Expected "<address>-<jwt>".');
5082
- }
5083
- const address = combined.slice(0, firstDash).trim();
5084
- const token = combined.slice(firstDash + 1).trim();
5085
- if (!address || !token) {
5086
- throw new Error("Invalid token content. Address or token is empty.");
5087
- }
5088
- return { address, token };
5089
- }
5090
- function setAuthToken(combined) {
5091
- ensureConfigDir();
5092
- const auth = parseCombinedToken(combined);
5093
- import_fs_extra4.default.writeJsonSync(AUTH_FILE, auth, { spaces: 2 });
5094
- return auth;
5095
- }
5096
- function getAuthConfig() {
5097
- try {
5098
- if (!import_fs_extra4.default.existsSync(AUTH_FILE)) return null;
5099
- const data = import_fs_extra4.default.readJsonSync(AUTH_FILE);
5100
- if (!(data == null ? void 0 : data.address) || !(data == null ? void 0 : data.token)) return null;
5101
- return data;
5102
- } catch {
5103
- return null;
5104
- }
5105
- }
5106
- function getAuthHeaders() {
5107
- const conf = getAuthConfig();
5108
- if (!conf) {
5109
- throw new Error("Auth not set. Run: pinme set-appkey <AppKey>");
5110
- }
5111
- return {
5112
- "token-address": conf.address,
5113
- "authentication-tokens": conf.token
5114
- };
5115
- }
5116
-
5117
- // bin/utils/pinmeApi.ts
5118
5147
  var DEFAULT_BASE = process.env.PINME_API_BASE || "http://ipfs-proxy.opena.chat/api/v4";
5119
5148
  function createClient() {
5120
5149
  const headers = getAuthHeaders();
@@ -5222,13 +5251,6 @@ function getDomainFromArgs() {
5222
5251
  }
5223
5252
  return null;
5224
5253
  }
5225
- function getUid() {
5226
- const auth = getAuthConfig();
5227
- if (auth == null ? void 0 : auth.address) {
5228
- return auth.address;
5229
- }
5230
- return getDeviceId();
5231
- }
5232
5254
  var upload_default = async (options) => {
5233
5255
  try {
5234
5256
  console.log(
@@ -5251,7 +5273,11 @@ var upload_default = async (options) => {
5251
5273
  if (domainArg) {
5252
5274
  const check = await checkDomainAvailable(domainArg);
5253
5275
  if (!check.is_valid) {
5254
- console.log(import_chalk4.default.red(`Domain not available: ${check.error || "unknown reason"}`));
5276
+ console.log(
5277
+ import_chalk4.default.red(
5278
+ `Domain not available: ${check.error || "unknown reason"}`
5279
+ )
5280
+ );
5255
5281
  return;
5256
5282
  }
5257
5283
  console.log(import_chalk4.default.green(`Domain available: ${domainArg}`));
@@ -5270,11 +5296,19 @@ var upload_default = async (options) => {
5270
5296
  console.log(import_chalk4.default.cyan(`URL:`));
5271
5297
  console.log(import_chalk4.default.cyan(`${URL2}${encryptedCID}`));
5272
5298
  if (domainArg) {
5273
- console.log(import_chalk4.default.blue(`Binding domain: ${domainArg} with CID: ${result.contentHash}`));
5299
+ console.log(
5300
+ import_chalk4.default.blue(
5301
+ `Binding domain: ${domainArg} with CID: ${result.contentHash}`
5302
+ )
5303
+ );
5274
5304
  const ok = await bindPinmeDomain(domainArg, result.contentHash);
5275
5305
  if (ok) {
5276
5306
  console.log(import_chalk4.default.green(`Bind success: ${domainArg}`));
5277
- console.log(import_chalk4.default.white(`Visit (Pinme subdomain example): https://${domainArg}.pinit.eth.limo`));
5307
+ console.log(
5308
+ import_chalk4.default.white(
5309
+ `Visit (Pinme subdomain example): https://${domainArg}.pinit.eth.limo`
5310
+ )
5311
+ );
5278
5312
  } else {
5279
5313
  console.log(import_chalk4.default.red("Binding failed. Please try again later."));
5280
5314
  }
@@ -5302,7 +5336,11 @@ var upload_default = async (options) => {
5302
5336
  if (domainArg) {
5303
5337
  const check = await checkDomainAvailable(domainArg);
5304
5338
  if (!check.is_valid) {
5305
- console.log(import_chalk4.default.red(`Domain not available: ${check.error || "unknown reason"}`));
5339
+ console.log(
5340
+ import_chalk4.default.red(
5341
+ `Domain not available: ${check.error || "unknown reason"}`
5342
+ )
5343
+ );
5306
5344
  return;
5307
5345
  }
5308
5346
  console.log(import_chalk4.default.green(`Domain available: ${domainArg}`));
@@ -5321,11 +5359,19 @@ var upload_default = async (options) => {
5321
5359
  console.log(import_chalk4.default.cyan(`URL:`));
5322
5360
  console.log(import_chalk4.default.cyan(`${URL2}${encryptedCID}`));
5323
5361
  if (domainArg) {
5324
- console.log(import_chalk4.default.blue(`Binding domain: ${domainArg} with CID: ${result.contentHash}`));
5362
+ console.log(
5363
+ import_chalk4.default.blue(
5364
+ `Binding domain: ${domainArg} with CID: ${result.contentHash}`
5365
+ )
5366
+ );
5325
5367
  const ok = await bindPinmeDomain(domainArg, result.contentHash);
5326
5368
  if (ok) {
5327
5369
  console.log(import_chalk4.default.green(`Bind success: ${domainArg}`));
5328
- console.log(import_chalk4.default.white(`Visit (Pinme subdomain example): https://${domainArg}.pinit.eth.limo`));
5370
+ console.log(
5371
+ import_chalk4.default.white(
5372
+ `Visit (Pinme subdomain example): https://${domainArg}.pinit.eth.limo`
5373
+ )
5374
+ );
5329
5375
  } else {
5330
5376
  console.log(import_chalk4.default.red("Binding failed. Please try again later."));
5331
5377
  }
@@ -5353,7 +5399,7 @@ var import_chalk5 = __toESM(require("chalk"));
5353
5399
  var ipfsApiUrl = "https://pinme.dev/api/v3";
5354
5400
  async function removeFromIpfs(value, type = "hash") {
5355
5401
  try {
5356
- const uid = getDeviceId();
5402
+ const uid = getUid();
5357
5403
  console.log(import_chalk5.default.blue(`Removing content from IPFS: ${value}...`));
5358
5404
  const queryParams = new URLSearchParams({
5359
5405
  uid
@@ -5363,14 +5409,21 @@ async function removeFromIpfs(value, type = "hash") {
5363
5409
  } else {
5364
5410
  queryParams.append("arg", value);
5365
5411
  }
5366
- const response = await axios_default.post(`${ipfsApiUrl}/block/rm?${queryParams.toString()}`, {
5367
- timeout: 3e4
5368
- // 30 seconds timeout
5369
- });
5412
+ const response = await axios_default.post(
5413
+ `${ipfsApiUrl}/block/rm?${queryParams.toString()}`,
5414
+ {
5415
+ timeout: 3e4
5416
+ // 30 seconds timeout
5417
+ }
5418
+ );
5370
5419
  const { code, msg, data } = response.data;
5371
5420
  if (code === 200) {
5372
5421
  console.log(import_chalk5.default.green("\u2713 Removal successful!"));
5373
- console.log(import_chalk5.default.cyan(`Content ${type}: ${value} has been removed from IPFS network`));
5422
+ console.log(
5423
+ import_chalk5.default.cyan(
5424
+ `Content ${type}: ${value} has been removed from IPFS network`
5425
+ )
5426
+ );
5374
5427
  return true;
5375
5428
  } else {
5376
5429
  console.log(import_chalk5.default.red("\u2717 Removal failed"));
@@ -5381,17 +5434,31 @@ async function removeFromIpfs(value, type = "hash") {
5381
5434
  console.log(import_chalk5.default.red("\u2717 Removal failed", error));
5382
5435
  if (error.response) {
5383
5436
  const { status, data } = error.response;
5384
- console.log(import_chalk5.default.red(`HTTP Error ${status}: ${(data == null ? void 0 : data.msg) || "Server error"}`));
5437
+ console.log(
5438
+ import_chalk5.default.red(`HTTP Error ${status}: ${(data == null ? void 0 : data.msg) || "Server error"}`)
5439
+ );
5385
5440
  if (status === 404) {
5386
- console.log(import_chalk5.default.yellow("Content not found on the network or already removed"));
5441
+ console.log(
5442
+ import_chalk5.default.yellow("Content not found on the network or already removed")
5443
+ );
5387
5444
  } else if (status === 403) {
5388
- console.log(import_chalk5.default.yellow("Permission denied - you may not have access to remove this content"));
5445
+ console.log(
5446
+ import_chalk5.default.yellow(
5447
+ "Permission denied - you may not have access to remove this content"
5448
+ )
5449
+ );
5389
5450
  } else if (status === 500) {
5390
- console.log(import_chalk5.default.yellow("Server internal error - please try again later"));
5451
+ console.log(
5452
+ import_chalk5.default.yellow("Server internal error - please try again later")
5453
+ );
5391
5454
  }
5392
5455
  } else if (error.request) {
5393
- console.log(import_chalk5.default.red("Network error: Unable to connect to IPFS service"));
5394
- console.log(import_chalk5.default.yellow("Please check your internet connection and try again"));
5456
+ console.log(
5457
+ import_chalk5.default.red("Network error: Unable to connect to IPFS service")
5458
+ );
5459
+ console.log(
5460
+ import_chalk5.default.yellow("Please check your internet connection and try again")
5461
+ );
5395
5462
  } else {
5396
5463
  console.log(import_chalk5.default.red(`Error: ${error.message}`));
5397
5464
  }
@@ -5579,32 +5646,93 @@ async function setAppKeyCmd() {
5579
5646
  }
5580
5647
  }
5581
5648
 
5582
- // bin/my-domains.ts
5649
+ // bin/logout.ts
5583
5650
  var import_chalk8 = __toESM(require("chalk"));
5651
+ var import_inquirer4 = __toESM(require("inquirer"));
5652
+ async function logoutCmd() {
5653
+ try {
5654
+ const auth = getAuthConfig();
5655
+ if (!auth) {
5656
+ console.log(import_chalk8.default.yellow("No active session found. You are already logged out."));
5657
+ return;
5658
+ }
5659
+ const answer = await import_inquirer4.default.prompt([
5660
+ {
5661
+ type: "confirm",
5662
+ name: "confirm",
5663
+ message: `Are you sure you want to log out? (Current address: ${auth.address})`,
5664
+ default: false
5665
+ }
5666
+ ]);
5667
+ if (!answer.confirm) {
5668
+ console.log(import_chalk8.default.blue("Logout cancelled."));
5669
+ return;
5670
+ }
5671
+ clearAuthToken();
5672
+ console.log(import_chalk8.default.green("Successfully logged out."));
5673
+ console.log(import_chalk8.default.gray(`Address ${auth.address} has been removed from local storage.`));
5674
+ } catch (e) {
5675
+ console.log(import_chalk8.default.red(`Failed to logout: ${(e == null ? void 0 : e.message) || e}`));
5676
+ }
5677
+ }
5678
+
5679
+ // bin/show-appkey.ts
5680
+ var import_chalk9 = __toESM(require("chalk"));
5681
+ function showAppKeyCmd() {
5682
+ try {
5683
+ const auth = getAuthConfig();
5684
+ if (!auth) {
5685
+ console.log(import_chalk9.default.yellow("No AppKey found. Please set your AppKey first."));
5686
+ console.log(import_chalk9.default.gray("Run: pinme set-appkey <AppKey>"));
5687
+ return;
5688
+ }
5689
+ console.log(import_chalk9.default.green("Current AppKey Information:"));
5690
+ console.log(import_chalk9.default.cyan(` Address: ${auth.address}`));
5691
+ const token = auth.token;
5692
+ if (token.length > 12) {
5693
+ const maskedToken = `${token.substring(0, 8)}${"*".repeat(token.length - 12)}${token.substring(token.length - 4)}`;
5694
+ console.log(import_chalk9.default.cyan(` Token: ${maskedToken}`));
5695
+ } else {
5696
+ console.log(import_chalk9.default.cyan(` Token: ${"*".repeat(token.length)}`));
5697
+ }
5698
+ const combined = `${auth.address}-${auth.token}`;
5699
+ if (combined.length > 20) {
5700
+ const maskedAppKey = `${combined.substring(0, 12)}${"*".repeat(combined.length - 16)}${combined.substring(combined.length - 4)}`;
5701
+ console.log(import_chalk9.default.cyan(` AppKey: ${maskedAppKey}`));
5702
+ } else {
5703
+ console.log(import_chalk9.default.cyan(` AppKey: ${"*".repeat(combined.length)}`));
5704
+ }
5705
+ } catch (e) {
5706
+ console.log(import_chalk9.default.red(`Failed to show AppKey: ${(e == null ? void 0 : e.message) || e}`));
5707
+ }
5708
+ }
5709
+
5710
+ // bin/my-domains.ts
5711
+ var import_chalk10 = __toESM(require("chalk"));
5584
5712
  var import_dayjs2 = __toESM(require("dayjs"));
5585
5713
  async function myDomainsCmd() {
5586
5714
  try {
5587
5715
  const list = await getMyDomains();
5588
5716
  if (!list.length) {
5589
- console.log(import_chalk8.default.yellow("No bound domains found."));
5717
+ console.log(import_chalk10.default.yellow("No bound domains found."));
5590
5718
  return;
5591
5719
  }
5592
- console.log(import_chalk8.default.cyan("My domains:"));
5593
- console.log(import_chalk8.default.cyan("-".repeat(80)));
5720
+ console.log(import_chalk10.default.cyan("My domains:"));
5721
+ console.log(import_chalk10.default.cyan("-".repeat(80)));
5594
5722
  list.forEach((item, i) => {
5595
- console.log(import_chalk8.default.green(`${i + 1}. ${item.domain_name}`));
5596
- console.log(import_chalk8.default.white(` Type: ${item.domain_type}`));
5723
+ console.log(import_chalk10.default.green(`${i + 1}. ${item.domain_name}`));
5724
+ console.log(import_chalk10.default.white(` Type: ${item.domain_type}`));
5597
5725
  if (item.bind_time) {
5598
- console.log(import_chalk8.default.white(` Bind time: ${(0, import_dayjs2.default)(item.bind_time * 1e3).format("YYYY-MM-DD HH:mm:ss")}`));
5726
+ console.log(import_chalk10.default.white(` Bind time: ${(0, import_dayjs2.default)(item.bind_time * 1e3).format("YYYY-MM-DD HH:mm:ss")}`));
5599
5727
  }
5600
5728
  if (typeof item.expire_time === "number") {
5601
5729
  const label = item.expire_time === 0 ? "Never" : (0, import_dayjs2.default)(item.expire_time * 1e3).format("YYYY-MM-DD HH:mm:ss");
5602
- console.log(import_chalk8.default.white(` Expire time: ${label}`));
5730
+ console.log(import_chalk10.default.white(` Expire time: ${label}`));
5603
5731
  }
5604
- console.log(import_chalk8.default.cyan("-".repeat(80)));
5732
+ console.log(import_chalk10.default.cyan("-".repeat(80)));
5605
5733
  });
5606
5734
  } catch (e) {
5607
- console.log(import_chalk8.default.red(`Failed to fetch domains: ${(e == null ? void 0 : e.message) || e}`));
5735
+ console.log(import_chalk10.default.red(`Failed to fetch domains: ${(e == null ? void 0 : e.message) || e}`));
5608
5736
  }
5609
5737
  }
5610
5738
 
@@ -5613,27 +5741,39 @@ import_dotenv.default.config();
5613
5741
  checkNodeVersion();
5614
5742
  function showBanner() {
5615
5743
  console.log(
5616
- import_chalk9.default.cyan(
5617
- import_figlet3.default.textSync("Pinme", { horizontalLayout: "full" })
5618
- )
5744
+ import_chalk11.default.cyan(import_figlet3.default.textSync("Pinme", { horizontalLayout: "full" }))
5619
5745
  );
5620
- console.log(import_chalk9.default.cyan("A command-line tool for uploading files to IPFS\n"));
5746
+ console.log(import_chalk11.default.cyan("A command-line tool for uploading files to IPFS\n"));
5621
5747
  }
5622
5748
  var program = new import_commander.Command();
5623
5749
  program.name("pinme").version(version).option("-v, --version", "output the current version");
5624
- program.command("upload").description("upload a file or directory to IPFS. Supports --domain to bind after upload").option("-d, --domain <name>", "Pinme subdomain").action(() => upload_default());
5750
+ program.command("upload").description(
5751
+ "upload a file or directory to IPFS. Supports --domain to bind after upload"
5752
+ ).option("-d, --domain <name>", "Pinme subdomain").action(() => upload_default());
5625
5753
  program.command("rm").description("remove a file from IPFS network").action(() => remove_default());
5626
- program.command("set-appkey").description("Set AppKey for authentication, and auto-merge anonymous history").action(() => setAppKeyCmd());
5754
+ program.command("set-appkey").description(
5755
+ "Set AppKey for authentication, and auto-merge anonymous history"
5756
+ ).action(() => setAppKeyCmd());
5757
+ program.command("logout").description("log out and clear authentication").action(() => logoutCmd());
5758
+ program.command("show-appkey").alias("appkey").description("show current AppKey information (masked)").action(() => showAppKeyCmd());
5627
5759
  program.command("my-domains").alias("domain").description("List domains owned by current account").action(() => myDomainsCmd());
5628
5760
  program.command("domain").description("Alias for 'my-domains' command").action(() => myDomainsCmd());
5629
- program.command("list").description("show upload history").option("-l, --limit <number>", "limit the number of records to show", parseInt).option("-c, --clear", "clear all upload history").action((options) => {
5761
+ program.command("list").description("show upload history").option(
5762
+ "-l, --limit <number>",
5763
+ "limit the number of records to show",
5764
+ parseInt
5765
+ ).option("-c, --clear", "clear all upload history").action((options) => {
5630
5766
  if (options.clear) {
5631
5767
  clearUploadHistory();
5632
5768
  } else {
5633
5769
  displayUploadHistory(options.limit || 10);
5634
5770
  }
5635
5771
  });
5636
- program.command("ls").description("alias for 'list' command").option("-l, --limit <number>", "limit the number of records to show", parseInt).option("-c, --clear", "clear all upload history").action((options) => {
5772
+ program.command("ls").description("alias for 'list' command").option(
5773
+ "-l, --limit <number>",
5774
+ "limit the number of records to show",
5775
+ parseInt
5776
+ ).option("-c, --clear", "clear all upload history").action((options) => {
5637
5777
  if (options.clear) {
5638
5778
  clearUploadHistory();
5639
5779
  } else {
@@ -5651,13 +5791,17 @@ program.on("--help", () => {
5651
5791
  console.log(" $ pinme upload <path> --domain <name>");
5652
5792
  console.log(" $ pinme rm <hash>");
5653
5793
  console.log(" $ pinme set-appkey <AppKey>");
5794
+ console.log(" $ pinme show-appkey");
5795
+ console.log(" $ pinme logout");
5654
5796
  console.log(" $ pinme my-domains");
5655
5797
  console.log(" $ pinme domain");
5656
5798
  console.log(" $ pinme list -l 5");
5657
5799
  console.log(" $ pinme ls");
5658
5800
  console.log(" $ pinme help");
5659
5801
  console.log("");
5660
- console.log("For more information, visit: https://github.com/glitternetwork/pinme");
5802
+ console.log(
5803
+ "For more information, visit: https://github.com/glitternetwork/pinme"
5804
+ );
5661
5805
  });
5662
5806
  program.parse(process.argv);
5663
5807
  if (process.argv.length === 2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinme",
3
- "version": "1.1.6-alpha.4",
3
+ "version": "1.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },