para-cli 1.18.7 → 1.19.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 (4) hide show
  1. package/README.md +30 -6
  2. package/index.js +140 -13
  3. package/package.json +7 -7
  4. package/para-cli.js +21 -3
package/README.md CHANGED
@@ -17,9 +17,9 @@ This is the command-line tool for interacting with a Para server.
17
17
  ## Installation
18
18
 
19
19
  ```sh
20
- $ npm install -g para-cli
21
- $ para-cli setup
22
- $ para-cli ping
20
+ npm install -g para-cli
21
+ para-cli setup
22
+ para-cli ping
23
23
  ```
24
24
 
25
25
  ## Usage
@@ -41,6 +41,7 @@ $ para-cli ping
41
41
  setup Initial setup, prompts you to enter your Para API keys and endpoint
42
42
  apps Returns a list of all Para apps
43
43
  select <appid> Selects a Para app as a target for all subsequent read/write requests.
44
+ endpoints [add|remove] List and select Para server endpoints, add new or remove an exiting one.
44
45
  create <file|glob> [--id] [--type] Persists files as Para objects and makes them searchable
45
46
  read --id 123 [--id 345 ...] Fetches objects with the given ids
46
47
  update <file.json|glob> ... Updates Para objects with the data from a JSON file (must contain id field)
@@ -83,6 +84,9 @@ $ para-cli ping
83
84
  $ para-cli search "*" --type article --page all
84
85
  $ para-cli new-key
85
86
  $ para-cli new-app "mynewapp" --name "Full app name"
87
+ $ para-cli apps
88
+ $ para-cli select scoold
89
+ $ para-cli endpoints
86
90
 
87
91
  ```
88
92
 
@@ -95,7 +99,7 @@ The plan is to add more functionality in the near future.
95
99
 
96
100
  **Quick start:**
97
101
  ```
98
- $ para-cli setup
102
+ para-cli setup
99
103
  ```
100
104
 
101
105
  The configuration file is located in `~/.config/para-cli-nodejs/config.json` and contains the keys used to authenticate
@@ -115,12 +119,32 @@ Here's an example `config.json` file:
115
119
  Once configured you can test your connection to the server:
116
120
 
117
121
  ```
118
- $ para-cli ping
122
+ para-cli ping
119
123
  ```
120
124
 
121
125
  To get the currently authenticated app/user object run:
122
126
  ```
123
- $ para-cli me
127
+ para-cli me
128
+ ```
129
+
130
+ ## Switching between apps and endpoints
131
+
132
+ Para CLI can be configured to work with multiple Para servers and apps. Here's how to add additional Para server endpoints:
133
+ ```
134
+ para-cli endpoints add
135
+ ```
136
+ To select a specific endpoint run:
137
+ ```
138
+ para-cli endpoints
139
+ ```
140
+
141
+ After selecting the Para server you wish to connect to, you can list and select apps within it:
142
+ ```
143
+ para-cli apps
144
+ ```
145
+ Select the 'scoold' app, for example:
146
+ ```
147
+ para-cli select scoold
124
148
  ```
125
149
 
126
150
  ## Para Docs
package/index.js CHANGED
@@ -38,6 +38,7 @@ import { globbySync } from 'globby';
38
38
  import chalk from 'chalk';
39
39
  import { Promise } from 'rsvp';
40
40
  import apiClient from 'superagent';
41
+ import { URL } from 'url';
41
42
  import { ParaClient, ParaObject, Pager } from 'para-client-js';
42
43
 
43
44
  const { cyan, red, yellow, green } = chalk;
@@ -56,7 +57,7 @@ export function setup(config) {
56
57
  rl.question(cyan.bold('Para Access Key: '), function (accessKey) {
57
58
  rl.question(cyan.bold('Para Secret Key: '), function (secretKey) {
58
59
  rl.question(cyan.bold('Para Endpoint: '), function (endpoint) {
59
- var access = (accessKey || config.get('accessKey')).trim();
60
+ var access = (accessKey || config.get('accessKey') || "app:para").trim();
60
61
  var secret = (secretKey || config.get('secretKey')).trim();
61
62
  var endpoint = (endpoint || config.get('endpoint')).trim();
62
63
  newJWT(access, secret, endpoint, config);
@@ -427,9 +428,10 @@ export function rebuildIndex(pc, config, flags) {
427
428
  }
428
429
 
429
430
  export function listApps(config, flags, parentAccessKey, failureCallback) {
430
- var accessKey = flags.accessKey || process.env.PARA_ACCESS_KEY || config.get('accessKey');
431
- var secretKey = flags.secretKey || process.env.PARA_SECRET_KEY || config.get('secretKey');
432
- var endpoint = flags.endpoint || process.env.PARA_ENDPOINT || config.get('endpoint');
431
+ var selectedEndpoint = getSelectedEndpoint(config, flags);
432
+ var accessKey = selectedEndpoint.accessKey;
433
+ var secretKey = selectedEndpoint.secretKey;
434
+ var endpoint = selectedEndpoint.endpoint;
433
435
  var pc = new ParaClient(accessKey, secretKey, {endpoint: endpoint});
434
436
  var p = new Pager();
435
437
  var results = [];
@@ -440,7 +442,7 @@ export function listApps(config, flags, parentAccessKey, failureCallback) {
440
442
  }).then(function () {
441
443
  var apps = results.map(function (app) {return app.appIdentifier.trim();});
442
444
  if (apps.length) {
443
- console.log('Found', p.count, 'apps:', yellow('[') + green(apps.join(yellow('] ['))) + yellow(']'));
445
+ console.log('Found', p.count, 'apps on ' + cyan(endpoint) + ':', yellow('[') + green(apps.join(yellow('] ['))) + yellow(']'));
444
446
  console.log('Typing', cyan('para-cli select'), green(apps[0]), 'will switch to that app. Current app:',
445
447
  green(parentAccessKey));
446
448
  process.exit(0);
@@ -452,9 +454,11 @@ export function listApps(config, flags, parentAccessKey, failureCallback) {
452
454
  });
453
455
  }
454
456
 
455
- export function selectApp(pc, input, config, flags) {
456
- var accessKey = flags.accessKey || process.env.PARA_ACCESS_KEY || config.get('accessKey');
457
- var secretKey = flags.secretKey || process.env.PARA_SECRET_KEY || config.get('secretKey');
457
+ export function selectApp(input, config, flags) {
458
+ var selectedEndpoint = getSelectedEndpoint(config, flags);
459
+ var accessKey = selectedEndpoint.accessKey;
460
+ var secretKey = selectedEndpoint.secretKey;
461
+ var endpoint = selectedEndpoint.endpoint;
458
462
  if (accessKey === 'app:para' && secretKey) {
459
463
  var selectedApp = 'app:' + (input[1] || 'para').trim();
460
464
  if (selectedApp === 'app:para') {
@@ -465,28 +469,142 @@ export function selectApp(pc, input, config, flags) {
465
469
  var now = Math.round(new Date().getTime() / 1000);
466
470
  var jwt = sign(JSON.stringify({
467
471
  iat: now,
468
- exp: now + 60,
472
+ exp: now + 10,
469
473
  appid: accessKey,
470
474
  getCredentials: selectedApp
471
475
  }), secretKey, { algorithm: 'HS256' });
472
- pc.setAccessToken(jwt);
473
- pc.me(jwt).then(function (data) {
476
+ var paraClient = new ParaClient(accessKey, secretKey, { endpoint: endpoint });
477
+ paraClient.setAccessToken(jwt);
478
+ paraClient.me(jwt).then(function (data) {
474
479
  if (data && data.credentials) {
475
480
  config.set('selectedApp', data.credentials);
476
481
  console.log(green('✔'), 'Selected', green(selectedApp), 'as the current app.');
477
482
  } else {
478
483
  fail('That did not work -' + red(input[1]) + ' try updating Para to the latest version.');
479
484
  }
480
- pc.clearAccessToken();
481
485
  }).catch(function (err) {
482
486
  fail('App ' + red(input[1]) + ' not found!');
483
- pc.clearAccessToken();
484
487
  });
485
488
  } else {
486
489
  fail('This command only works when Para CLI is configured to use the keys for the root app.');
487
490
  }
488
491
  }
489
492
 
493
+ export function listEndpoints(config, flags, failureCallback) {
494
+ var accessKey = flags.accessKey || process.env.PARA_ACCESS_KEY || config.get('accessKey');
495
+ var secretKey = flags.secretKey || process.env.PARA_SECRET_KEY || config.get('secretKey');
496
+ var endpoint = flags.endpoint || process.env.PARA_ENDPOINT || config.get('endpoint');
497
+ var endpoints = config.get('endpoints') || [];
498
+ var list = [{endpoint: endpoint, accessKey: accessKey, secretKey: secretKey}].concat(endpoints);
499
+ if (list.length === 0) {
500
+ failureCallback();
501
+ return [];
502
+ }
503
+ for (var i = 0; i < list.length; i++) {
504
+ var ep = list[i];
505
+ var selected = (config.get('selectedEndpoint') || 0) === i;
506
+ var rootAppConfigured = ep.accessKey === 'app:para' && ep.secretKey.length > 10;
507
+ console.log(yellow((selected ? ' ➤' : ' '), (i + 1) + '. ') + cyan(ep.endpoint), rootAppConfigured ?
508
+ green('✔ root app configured') : red('root app not configured'));
509
+ }
510
+ return list;
511
+ }
512
+
513
+ export function addEndpoint(config) {
514
+ var endpoints = config.get('endpoints') || [];
515
+ var rl = createInterface({
516
+ input: process.stdin,
517
+ output: process.stdout
518
+ });
519
+ rl.question(cyan.bold('Para Endpoint: '), function (endpoint) {
520
+ if (!isValidUrl(endpoint)) {
521
+ fail('Endpoint must be a valid URL.');
522
+ rl.close();
523
+ return;
524
+ }
525
+ rl.question(cyan.bold('Para Secret Key (for root app app:para): '), function (secretKey) {
526
+ var pc = new ParaClient("app:para", secretKey, {endpoint: endpoint});
527
+ var endpoints = config.get('endpoints') || [];
528
+ var existing = false;
529
+ for (var i = 0; i < endpoints.length; i++) {
530
+ var ep = endpoints[i];
531
+ if (ep.endpoint === endpoint) {
532
+ ep.secretKey = secretKey;
533
+ existing = true;
534
+ }
535
+ }
536
+ if (!existing) {
537
+ endpoints.push({accessKey: 'app:para', secretKey: secretKey, endpoint: endpoint});
538
+ }
539
+ config.set('endpoints', endpoints);
540
+ ping(pc, config);
541
+ rl.close();
542
+ });
543
+ });
544
+ }
545
+
546
+ export function removeEndpoint(config, flags) {
547
+ var list = listEndpoints(config, flags, function () {console.log('No endpoints found.');});
548
+ var rl = createInterface({
549
+ input: process.stdin,
550
+ output: process.stdout
551
+ });
552
+
553
+ rl.question(yellow.bold('Type the number of the Para endpoint to remove: '), function (index) {
554
+ var selectedEndpoint = 0;
555
+ if (!isNaN(index) && index <= list.length && index >= 1) {
556
+ selectedEndpoint = index - 1;
557
+ }
558
+ var url = list[selectedEndpoint].endpoint;
559
+ if (selectedEndpoint === 0) {
560
+ config.set('accessKey', 'app:para');
561
+ config.set('secretKey', '');
562
+ config.set('endpoint', defaultConfig.endpoint);
563
+ } else {
564
+ if (selectedEndpoint === config.get('selectedEndpoint')) {
565
+ config.delete('selectedEndpoint');
566
+ config.delete('selectedApp');
567
+ }
568
+ list.splice(selectedEndpoint, 1);
569
+ list.shift();
570
+ config.set('endpoints', list);
571
+ }
572
+ console.log("Removed endpoint: " + cyan(url));
573
+ rl.close();
574
+ });
575
+ }
576
+
577
+ export function selectEndpoint(config, flags) {
578
+ var list = listEndpoints(config, flags, function () {console.log('No endpoints found.');});
579
+ var rl = createInterface({
580
+ input: process.stdin,
581
+ output: process.stdout
582
+ });
583
+ rl.question(yellow.bold('Type the number of the Para endpoint to select: '), function (index) {
584
+ var selectedEndpoint = 0;
585
+ if (!isNaN(index) && index <= list.length && index >= 1) {
586
+ selectedEndpoint = index - 1;
587
+ }
588
+ config.delete('selectedApp');
589
+ config.set('selectedEndpoint', selectedEndpoint);
590
+ console.log("Selected endpoint: " + cyan(list[selectedEndpoint].endpoint));
591
+ rl.close();
592
+ });
593
+ }
594
+
595
+ function getSelectedEndpoint(config, flags) {
596
+ var accessKey = flags.accessKey || process.env.PARA_ACCESS_KEY || config.get('accessKey');
597
+ var secretKey = flags.secretKey || process.env.PARA_SECRET_KEY || config.get('secretKey');
598
+ var endpoint = flags.endpoint || process.env.PARA_ENDPOINT || config.get('endpoint');
599
+ var endpoints = [{endpoint: endpoint, accessKey: accessKey, secretKey: secretKey}].concat(config.get('endpoints') || []);
600
+ try {
601
+ return endpoints[config.get('selectedEndpoint') || 0];
602
+ } catch (e) {
603
+ config.delete('selectedEndpoint');
604
+ return endpoints[0];
605
+ }
606
+ }
607
+
490
608
  function sendFileChunk(chunkId, textEncoded, json, id, flags, start, end, pc, decoder) {
491
609
  if (start > 0 && textEncoded[start] !== 32) {
492
610
  for (var i = 0; i < 100 && start - i >= 0; i++) {
@@ -604,6 +722,15 @@ function parseHTML(file) {
604
722
  };
605
723
  }
606
724
 
725
+ function isValidUrl(url) {
726
+ try {
727
+ new URL(url);
728
+ return true;
729
+ } catch (err) {
730
+ return false;
731
+ }
732
+ }
733
+
607
734
  function readFile(filePath) {
608
735
  return readFileSync(filePath, { encoding: 'utf8' });
609
736
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "para-cli",
3
- "version": "1.18.7",
3
+ "version": "1.19.1",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Command-line tool for Para backend servers",
6
6
  "homepage": "https://paraio.org",
@@ -24,25 +24,25 @@
24
24
  "api"
25
25
  ],
26
26
  "devDependencies": {
27
- "eslint": "^8.19.0"
27
+ "eslint": "^8.28.0"
28
28
  },
29
29
  "repository": "Erudika/para-cli",
30
30
  "dependencies": {
31
31
  "brace-expansion": "^2.0.1",
32
- "chalk": "^5.0.1",
33
- "conf": "^10.1.2",
32
+ "chalk": "^5.1.2",
33
+ "conf": "^10.2.0",
34
34
  "exit": "^0.1.2",
35
35
  "figlet": "^1.5.2",
36
36
  "get-stdin": "^9.0.0",
37
37
  "globby": "^13.1.2",
38
38
  "htmlparser2": "^8.0.1",
39
39
  "jsonwebtoken": "^8.5.1",
40
- "meow": "^10.1.3",
40
+ "meow": "^11.0.0",
41
41
  "mime-types": "^2.1.35",
42
- "para-client-js": "^1.37.14",
42
+ "para-client-js": "^1.38.0",
43
43
  "resolve": "^1.22.1",
44
44
  "striptags": "^3.2.0",
45
45
  "update-notifier": "^6.0.2",
46
- "yargs-parser": "^21.0.1"
46
+ "yargs-parser": "^21.1.1"
47
47
  }
48
48
  }
package/para-cli.js CHANGED
@@ -27,7 +27,10 @@ import Conf from 'conf';
27
27
  import figlet from 'figlet';
28
28
  import chalk from 'chalk';
29
29
  import meow from 'meow';
30
- import { defaultConfig, setup, listApps, selectApp, createAll, readAll, updateAll, deleteAll, search, newKeys, newJWT, newApp, ping, me, appSettings, rebuildIndex, exportData, importData } from './index.js';
30
+ import {
31
+ defaultConfig, setup, listApps, selectEndpoint, addEndpoint, removeEndpoint, selectApp, createAll, readAll,
32
+ updateAll, deleteAll, search, newKeys, newJWT, newApp, ping, me, appSettings, rebuildIndex, exportData, importData
33
+ } from './index.js';
31
34
 
32
35
  const { red, green, blue } = chalk;
33
36
  const { textSync } = figlet;
@@ -40,6 +43,7 @@ var cli = meow(`
40
43
  setup Initial setup, prompts you to enter your Para API keys and endpoint
41
44
  apps Returns a list of all Para apps
42
45
  select <appid> Selects a Para app as a target for all subsequent read/write requests.
46
+ endpoints [add|remove] List and select Para server endpoints, add new or remove an exiting one.
43
47
  create <file|glob> [--id] [--type] Persists files as Para objects and makes them searchable
44
48
  read --id 123 [--id 345 ...] Fetches objects with the given ids
45
49
  update <file.json|glob> ... Updates Para objects with the data from a JSON file (must contain id field)
@@ -82,7 +86,9 @@ var cli = meow(`
82
86
  $ para-cli search "*" --type article --page all
83
87
  $ para-cli new-key
84
88
  $ para-cli new-app "mynewapp" --name "Full app name"
85
-
89
+ $ para-cli apps
90
+ $ para-cli select scoold
91
+ $ para-cli endpoints
86
92
  `, {
87
93
  importMeta: import.meta,
88
94
  flags: {
@@ -111,12 +117,14 @@ var selectedApp = config.get('selectedApp');
111
117
  if (!flags.accessKey && !flags.secretKey && selectedApp && selectedApp.accessKey && selectedApp.accessKey.indexOf("app:") === 0) {
112
118
  accessKey = selectedApp.accessKey;
113
119
  secretKey = selectedApp.secretKey;
120
+ endpoint = selectedApp.endpoint;
114
121
  }
115
122
 
116
123
  if (!input[0]) {
117
124
  console.log(help);
118
125
  } else if (!accessKey || !secretKey) {
119
126
  console.error(red('Command ' + input[0] + ' failed! Blank credentials, running setup first...'));
127
+ console.log("Please enter the access key and secret key for the root app 'app:para' first.");
120
128
  process.exitCode = 1;
121
129
  setup(config);
122
130
  } else {
@@ -130,8 +138,18 @@ if (!input[0]) {
130
138
  listApps(config, flags, accessKey, function () {console.log('No apps found within', green(accessKey));});
131
139
  }
132
140
 
141
+ if (input[0] === 'endpoints') {
142
+ if (input.length > 1 && input[1] === 'add') {
143
+ addEndpoint(config);
144
+ } else if (input.length > 1 && input[1] === 'remove') {
145
+ removeEndpoint(config, flags);
146
+ } else {
147
+ selectEndpoint(config, flags);
148
+ }
149
+ }
150
+
133
151
  if (input[0] === 'select') {
134
- selectApp(pc, input, config, flags);
152
+ selectApp(input, config, flags);
135
153
  }
136
154
 
137
155
  if (input[0] === 'create') {