@flowcore/cli 2.0.1 → 2.1.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.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,22 @@
10
10
 
11
11
  * added description to start that includes week ([58687a7](https://github.com/flowcore-io/flowcore-cli/commit/58687a7bbb66aaa5d6da26af88e555cbb1e72467))
12
12
 
13
+ ## [2.1.1](https://github.com/flowcore-io/flowcore-cli/compare/v2.1.0...v2.1.1) (2024-02-15)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * removed whoami from cli and moved to config plugin, bumped config plugin version ([784ace4](https://github.com/flowcore-io/flowcore-cli/commit/784ace4cfe386f2ead98ccc8bed5d2ec25b01767))
19
+
20
+ ## [2.1.0](https://github.com/flowcore-io/flowcore-cli/compare/v2.0.1...v2.1.0) (2024-02-15)
21
+
22
+
23
+ ### Features
24
+
25
+ * added config as a separate plugin ([4098793](https://github.com/flowcore-io/flowcore-cli/commit/40987938a60470b1c8082e813cb96baba089c5b6))
26
+ * removed login from cli, moved to config plugin ([3789e06](https://github.com/flowcore-io/flowcore-cli/commit/3789e06b4938bc1b7429d3133ea8fe1054f7418f))
27
+ * switch login profile automatically when providing a stream url ([8172d2d](https://github.com/flowcore-io/flowcore-cli/commit/8172d2dd765dc44f714a82c4a53f7c6c258000b9))
28
+
13
29
  ## [2.0.1](https://github.com/flowcore-io/flowcore-cli/compare/v2.0.0...v2.0.1) (2024-01-15)
14
30
 
15
31
 
package/README.md CHANGED
@@ -3,6 +3,7 @@ Flowcore CLI
3
3
 
4
4
  Flowcore CLI is a command line interface for interacting with the Flowcore Platform.
5
5
 
6
+ [![Version](https://img.shields.io/npm/v/@flowcore/cli-plugin-config)](https://npmjs.org/package/@flowcore/cli-plugin-config)
6
7
  [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
7
8
  [![Build and Release](https://github.com/flowcore-io/flowcore-cli/actions/workflows/build.yml/badge.svg)](https://github.com/flowcore-io/flowcore-cli/actions/workflows/build.yml)
8
9
 
@@ -17,7 +18,7 @@ $ npm install -g @flowcore/cli
17
18
  $ flowcore COMMAND
18
19
  running command...
19
20
  $ flowcore (--version)
20
- @flowcore/cli/2.0.1 linux-x64 node-v20.10.0
21
+ @flowcore/cli/2.1.1 linux-x64 node-v20.11.0
21
22
  $ flowcore --help [COMMAND]
22
23
  USAGE
23
24
  $ flowcore COMMAND
@@ -74,7 +75,7 @@ EXAMPLES
74
75
  $ flowcore autocomplete --refresh-cache
75
76
  ```
76
77
 
77
- _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.0.3/src/commands/autocomplete/index.ts)_
78
+ _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.0.8/src/commands/autocomplete/index.ts)_
78
79
 
79
80
  ## `flowcore config set`
80
81
 
@@ -82,9 +83,10 @@ Configure the cli
82
83
 
83
84
  ```
84
85
  USAGE
85
- $ flowcore config set [--profile <value>] [-c <value>] [-n <value>] [-l <value>] [-p] [-u <value>]
86
+ $ flowcore config set [--profile <value>] [-b <value>] [-c <value>] [-n <value>] [-l <value>] [-p] [-u <value>]
86
87
 
87
88
  FLAGS
89
+ -b, --baseUrl=<value> base url to the flowcore platform
88
90
  -c, --clientId=<value> client id to use for the login
89
91
  -l, --loginUrl=<value> url to discover the openid configuration
90
92
  -n, --clientSecret=<value> name to print
@@ -103,7 +105,7 @@ EXAMPLES
103
105
  $ flowcore config set -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -p
104
106
  ```
105
107
 
106
- _See code: [src/commands/config/set.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.0.1/src/commands/config/set.ts)_
108
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/config/set.ts)_
107
109
 
108
110
  ## `flowcore config show`
109
111
 
@@ -123,7 +125,7 @@ EXAMPLES
123
125
  $ flowcore config show
124
126
  ```
125
127
 
126
- _See code: [src/commands/config/show.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.0.1/src/commands/config/show.ts)_
128
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/config/show.ts)_
127
129
 
128
130
  ## `flowcore help [COMMANDS]`
129
131
 
@@ -166,7 +168,7 @@ EXAMPLES
166
168
  $ flowcore login --port 8080
167
169
  ```
168
170
 
169
- _See code: [src/commands/login.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.0.1/src/commands/login.ts)_
171
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/login.ts)_
170
172
 
171
173
  ## `flowcore plugins`
172
174
 
@@ -189,7 +191,7 @@ EXAMPLES
189
191
  $ flowcore plugins
190
192
  ```
191
193
 
192
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/index.ts)_
194
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/index.ts)_
193
195
 
194
196
  ## `flowcore plugins:install PLUGIN...`
195
197
 
@@ -258,7 +260,7 @@ EXAMPLES
258
260
  $ flowcore plugins inspect myplugin
259
261
  ```
260
262
 
261
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/inspect.ts)_
263
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/inspect.ts)_
262
264
 
263
265
  ## `flowcore plugins:install PLUGIN...`
264
266
 
@@ -302,7 +304,7 @@ EXAMPLES
302
304
  $ flowcore plugins install someuser/someplugin
303
305
  ```
304
306
 
305
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/install.ts)_
307
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/install.ts)_
306
308
 
307
309
  ## `flowcore plugins:link PLUGIN`
308
310
 
@@ -332,7 +334,7 @@ EXAMPLES
332
334
  $ flowcore plugins link myplugin
333
335
  ```
334
336
 
335
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/link.ts)_
337
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/link.ts)_
336
338
 
337
339
  ## `flowcore plugins:uninstall PLUGIN...`
338
340
 
@@ -366,10 +368,14 @@ Remove all user-installed and linked plugins.
366
368
 
367
369
  ```
368
370
  USAGE
369
- $ flowcore plugins reset
371
+ $ flowcore plugins reset [--hard] [--reinstall]
372
+
373
+ FLAGS
374
+ --hard Delete node_modules and package manager related files in addition to uninstalling plugins.
375
+ --reinstall Reinstall all plugins after uninstalling.
370
376
  ```
371
377
 
372
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/reset.ts)_
378
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/reset.ts)_
373
379
 
374
380
  ## `flowcore plugins:uninstall PLUGIN...`
375
381
 
@@ -397,7 +403,7 @@ EXAMPLES
397
403
  $ flowcore plugins uninstall myplugin
398
404
  ```
399
405
 
400
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/uninstall.ts)_
406
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/uninstall.ts)_
401
407
 
402
408
  ## `flowcore plugins:uninstall PLUGIN...`
403
409
 
@@ -441,7 +447,7 @@ DESCRIPTION
441
447
  Update installed plugins.
442
448
  ```
443
449
 
444
- _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.1.10/src/commands/plugins/update.ts)_
450
+ _See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v4.2.2/src/commands/plugins/update.ts)_
445
451
 
446
452
  ## `flowcore stream STREAM`
447
453
 
@@ -479,7 +485,7 @@ EXAMPLES
479
485
  $ flowcore stream https://flowcore.io/<org>/<data core>/<flow type>/[<event type1>,<event type2>,<event type3>].stream -o log -s 3m
480
486
  ```
481
487
 
482
- _See code: [src/commands/stream.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.0.1/src/commands/stream.ts)_
488
+ _See code: [src/commands/stream.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.1.1/src/commands/stream.ts)_
483
489
 
484
490
  ## `flowcore version`
485
491
 
@@ -499,7 +505,7 @@ FLAG DESCRIPTIONS
499
505
  Additionally shows the architecture, node version, operating system, and versions of plugins that the CLI is using.
500
506
  ```
501
507
 
502
- _See code: [@oclif/plugin-version](https://github.com/oclif/plugin-version/blob/v2.0.9/src/commands/version.ts)_
508
+ _See code: [@oclif/plugin-version](https://github.com/oclif/plugin-version/blob/v2.0.12/src/commands/version.ts)_
503
509
 
504
510
  ## `flowcore whoami`
505
511
 
@@ -516,5 +522,5 @@ DESCRIPTION
516
522
  Check what user you are logged in as
517
523
  ```
518
524
 
519
- _See code: [src/commands/whoami.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.0.1/src/commands/whoami.ts)_
525
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/whoami.ts)_
520
526
  <!-- commandsstop -->
@@ -1,4 +1,4 @@
1
- import { BaseCommand } from "../base-command.js";
1
+ import { BaseCommand } from "@flowcore/cli-plugin-config";
2
2
  export default class Stream extends BaseCommand<typeof Stream> {
3
3
  static args: {
4
4
  STREAM: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
@@ -1,18 +1,17 @@
1
1
  import { Queue } from "@datastructures-js/queue";
2
+ import { BaseCommand, LOGIN_CODES, ValidateLogin } from "@flowcore/cli-plugin-config";
2
3
  import { Args, Flags, ux } from '@oclif/core';
3
4
  import dayjs from "dayjs";
4
5
  import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js";
5
6
  import utc from "dayjs/plugin/utc.js";
6
7
  import _ from "lodash";
7
8
  import { Subject } from "rxjs";
8
- import { BaseCommand } from "../base-command.js";
9
9
  import { QueryGraphQL } from "../utils/graphql.util.js";
10
10
  import { FETCH_DATA_CORE_GQL_QUERY } from "../utils/queries/fetch-data-core.gql.js";
11
11
  import { FETCH_EVENT_TYPE_RANGE_GQL_QUERY } from "../utils/queries/fetch-event-type-range.gql.js";
12
12
  import { FETCH_EVENTS_GQL_QUERY } from "../utils/queries/fetch-events.gql.js";
13
13
  import { FETCH_CATALOG_INDEXES_QUERY } from "../utils/queries/fetch-indexes.gql.js";
14
14
  import { TIME_BUCKET_HOUR_PATTERN, TIME_BUCKET_PATTERN, createTimebucket, createTimebucketDayjs } from "../utils/timebucket.util.js";
15
- import { LOGIN_CODES, ValidateLogin } from "../utils/validate-login.util.js";
16
15
  dayjs.extend(utc);
17
16
  dayjs.extend(isSameOrBefore);
18
17
  export default class Stream extends BaseCommand {
@@ -36,6 +35,15 @@ export default class Stream extends BaseCommand {
36
35
  timeout: Flags.integer({ char: 't', default: 5000, description: 'Timeout in milliseconds to wait for a response from the destination' }),
37
36
  };
38
37
  async run() {
38
+ const { args, flags } = await this.parse(Stream);
39
+ const parts = args.STREAM.replace(/https?:\/\//i, "").split("/");
40
+ if (parts.length !== 5) {
41
+ ux.error(`Invalid stream url, ${args.STREAM}`);
42
+ }
43
+ const newProfile = this.cliConfiguration.switchProfile(args.STREAM);
44
+ if (newProfile) {
45
+ ux.log(`Using profile ${ux.colorize("yellow", newProfile)} based on stream url`);
46
+ }
39
47
  const config = this.cliConfiguration.getConfig();
40
48
  const loginValidator = new ValidateLogin(config.login.url);
41
49
  const validateLogin = await loginValidator.validate(config, this.cliConfiguration, !this.flags.json);
@@ -52,11 +60,6 @@ export default class Stream extends BaseCommand {
52
60
  }
53
61
  return config.auth.accessToken;
54
62
  });
55
- const { args, flags } = await this.parse(Stream);
56
- const parts = args.STREAM.replace(/https?:\/\//i, "").split("/");
57
- if (parts.length !== 5) {
58
- ux.error(`Invalid stream url, ${args.STREAM}`);
59
- }
60
63
  const org = parts[1];
61
64
  const dataCore = parts[2];
62
65
  const aggregator = parts[3];
@@ -1,46 +1,5 @@
1
1
  {
2
2
  "commands": {
3
- "login": {
4
- "aliases": [],
5
- "args": {},
6
- "description": "login to the Flowcore Platform",
7
- "examples": [
8
- "<%= config.bin %> <%= command.id %>",
9
- "<%= config.bin %> <%= command.id %> --port 8080"
10
- ],
11
- "flags": {
12
- "profile": {
13
- "description": "Specify the configuration profile to use",
14
- "name": "profile",
15
- "hasDynamicHelp": false,
16
- "multiple": false,
17
- "type": "option"
18
- },
19
- "port": {
20
- "char": "p",
21
- "description": "port to listen for the callback",
22
- "name": "port",
23
- "default": 3000,
24
- "hasDynamicHelp": false,
25
- "multiple": false,
26
- "type": "option"
27
- }
28
- },
29
- "hasDynamicHelp": false,
30
- "hiddenAliases": [],
31
- "id": "login",
32
- "pluginAlias": "@flowcore/cli",
33
- "pluginName": "@flowcore/cli",
34
- "pluginType": "core",
35
- "strict": true,
36
- "enableJsonFlag": false,
37
- "isESM": true,
38
- "relativePath": [
39
- "dist",
40
- "commands",
41
- "login.js"
42
- ]
43
- },
44
3
  "stream": {
45
4
  "aliases": [],
46
5
  "args": {
@@ -140,140 +99,7 @@
140
99
  "commands",
141
100
  "stream.js"
142
101
  ]
143
- },
144
- "whoami": {
145
- "aliases": [],
146
- "args": {},
147
- "description": "Check what user you are logged in as",
148
- "flags": {
149
- "profile": {
150
- "description": "Specify the configuration profile to use",
151
- "name": "profile",
152
- "hasDynamicHelp": false,
153
- "multiple": false,
154
- "type": "option"
155
- }
156
- },
157
- "hasDynamicHelp": false,
158
- "hiddenAliases": [],
159
- "id": "whoami",
160
- "pluginAlias": "@flowcore/cli",
161
- "pluginName": "@flowcore/cli",
162
- "pluginType": "core",
163
- "strict": true,
164
- "enableJsonFlag": false,
165
- "isESM": true,
166
- "relativePath": [
167
- "dist",
168
- "commands",
169
- "whoami.js"
170
- ]
171
- },
172
- "config:set": {
173
- "aliases": [],
174
- "args": {},
175
- "description": "Configure the cli",
176
- "examples": [
177
- "<%= config.bin %> <%= command.id %> -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -s my-client-secret",
178
- "<%= config.bin %> <%= command.id %> -u https://graph.api.flowcore.io/graphql",
179
- "<%= config.bin %> <%= command.id %> -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -p"
180
- ],
181
- "flags": {
182
- "profile": {
183
- "description": "Specify the configuration profile to use",
184
- "name": "profile",
185
- "hasDynamicHelp": false,
186
- "multiple": false,
187
- "type": "option"
188
- },
189
- "clientId": {
190
- "char": "c",
191
- "description": "client id to use for the login",
192
- "name": "clientId",
193
- "hasDynamicHelp": false,
194
- "multiple": false,
195
- "type": "option"
196
- },
197
- "clientSecret": {
198
- "char": "n",
199
- "description": "name to print",
200
- "name": "clientSecret",
201
- "hasDynamicHelp": false,
202
- "multiple": false,
203
- "type": "option"
204
- },
205
- "loginUrl": {
206
- "char": "l",
207
- "description": "url to discover the openid configuration",
208
- "name": "loginUrl",
209
- "hasDynamicHelp": false,
210
- "multiple": false,
211
- "type": "option"
212
- },
213
- "port": {
214
- "char": "p",
215
- "description": "prompt for port to listen for the callback",
216
- "name": "port",
217
- "allowNo": false,
218
- "type": "boolean"
219
- },
220
- "url": {
221
- "char": "u",
222
- "description": "url to the flowcore platform api",
223
- "name": "url",
224
- "hasDynamicHelp": false,
225
- "multiple": false,
226
- "type": "option"
227
- }
228
- },
229
- "hasDynamicHelp": false,
230
- "hiddenAliases": [],
231
- "id": "config:set",
232
- "pluginAlias": "@flowcore/cli",
233
- "pluginName": "@flowcore/cli",
234
- "pluginType": "core",
235
- "strict": true,
236
- "enableJsonFlag": false,
237
- "isESM": true,
238
- "relativePath": [
239
- "dist",
240
- "commands",
241
- "config",
242
- "set.js"
243
- ]
244
- },
245
- "config:show": {
246
- "aliases": [],
247
- "args": {},
248
- "description": "Show the configured login url",
249
- "examples": [
250
- "<%= config.bin %> <%= command.id %>"
251
- ],
252
- "flags": {
253
- "profile": {
254
- "description": "Specify the configuration profile to use",
255
- "name": "profile",
256
- "hasDynamicHelp": false,
257
- "multiple": false,
258
- "type": "option"
259
- }
260
- },
261
- "hasDynamicHelp": false,
262
- "hiddenAliases": [],
263
- "id": "config:show",
264
- "pluginAlias": "@flowcore/cli",
265
- "pluginName": "@flowcore/cli",
266
- "pluginType": "core",
267
- "strict": true,
268
- "enableJsonFlag": false,
269
- "isESM": true,
270
- "relativePath": [
271
- "dist",
272
- "commands",
273
- "config",
274
- "show.js"
275
- ]
276
102
  }
277
103
  },
278
- "version": "2.0.1"
104
+ "version": "2.1.1"
279
105
  }
package/package.json CHANGED
@@ -5,6 +5,7 @@
5
5
  },
6
6
  "dependencies": {
7
7
  "@datastructures-js/queue": "^4.2.3",
8
+ "@flowcore/cli-plugin-config": "^1.0.5",
8
9
  "@flowcore/time-bucket": "^1.1.0",
9
10
  "@oclif/core": "^3",
10
11
  "@oclif/plugin-autocomplete": "^3.0.2",
@@ -16,14 +17,11 @@
16
17
  "cross-fetch": "^4.0.0",
17
18
  "dayjs": "^1.11.10",
18
19
  "enquirer": "^2.4.1",
19
- "express": "^4.18.2",
20
20
  "graphql": "^16.8.1",
21
21
  "graphql-request": "^6.1.0",
22
22
  "jwt-decode": "^4.0.0",
23
23
  "lodash": "^4.17.21",
24
24
  "merge": "^2.1.1",
25
- "open": "^9.1.0",
26
- "openid-client": "^5.6.1",
27
25
  "rxjs": "^7.8.1",
28
26
  "session": "^0.1.0"
29
27
  },
@@ -68,7 +66,8 @@
68
66
  "@oclif/plugin-version",
69
67
  "@oclif/plugin-plugins",
70
68
  "@oclif/plugin-autocomplete",
71
- "@oclif/plugin-not-found"
69
+ "@oclif/plugin-not-found",
70
+ "@flowcore/cli-plugin-config"
72
71
  ],
73
72
  "topicSeparator": " "
74
73
  },
@@ -86,7 +85,7 @@
86
85
  "prestart": "npm run build",
87
86
  "update-schema": "rover graph introspect https://graph.api.staging.flowcore.io/graphql -o schema.gql"
88
87
  },
89
- "version": "2.0.1",
88
+ "version": "2.1.1",
90
89
  "bugs": "https://github.com/flowcore-io/flowcore-cli/issues",
91
90
  "keywords": [
92
91
  "flowcore",
@@ -1,17 +0,0 @@
1
- import { Command, Interfaces } from '@oclif/core';
2
- import { CliConfiguration } from "./utils/config.util.js";
3
- export type Flags<T extends typeof Command> = Interfaces.InferredFlags<typeof BaseCommand['baseFlags'] & T['flags']>;
4
- export type Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>;
5
- export declare abstract class BaseCommand<T extends typeof Command> extends Command {
6
- static baseFlags: {
7
- profile: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
8
- };
9
- protected args: Args<T>;
10
- protected cliConfiguration: CliConfiguration;
11
- protected flags: Flags<T>;
12
- protected catch(err: Error & {
13
- exitCode?: number;
14
- }): Promise<unknown>;
15
- protected finally(_: Error | undefined): Promise<unknown>;
16
- protected init(): Promise<void>;
17
- }
@@ -1,32 +0,0 @@
1
- // src/baseCommand.ts
2
- import { Command, Flags } from '@oclif/core';
3
- import { CliConfiguration } from "./utils/config.util.js";
4
- export class BaseCommand extends Command {
5
- // define flags that can be inherited by any command that extends BaseCommand
6
- static baseFlags = {
7
- 'profile': Flags.string({
8
- description: 'Specify the configuration profile to use',
9
- }),
10
- };
11
- args;
12
- cliConfiguration = new CliConfiguration();
13
- flags;
14
- async catch(err) {
15
- return super.catch(err);
16
- }
17
- async finally(_) {
18
- return super.finally(_);
19
- }
20
- async init() {
21
- await super.init();
22
- const { args, flags } = await this.parse({
23
- args: this.ctor.args,
24
- baseFlags: super.ctor.baseFlags,
25
- flags: this.ctor.flags,
26
- strict: this.ctor.strict,
27
- });
28
- this.cliConfiguration.init(flags.profile || "default", this.config.configDir);
29
- this.flags = flags;
30
- this.args = args;
31
- }
32
- }
@@ -1,13 +0,0 @@
1
- import { BaseCommand } from "../../base-command.js";
2
- export default class Set extends BaseCommand<typeof Set> {
3
- static description: string;
4
- static examples: string[];
5
- static flags: {
6
- clientId: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
- clientSecret: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
- loginUrl: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
9
- port: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
- url: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
- };
12
- run(): Promise<void>;
13
- }
@@ -1,45 +0,0 @@
1
- import { Flags } from '@oclif/core';
2
- import pkg from "enquirer";
3
- import _ from "lodash";
4
- import { BaseCommand } from "../../base-command.js";
5
- const { prompt } = pkg;
6
- export default class Set extends BaseCommand {
7
- static description = 'Configure the cli';
8
- static examples = [
9
- '<%= config.bin %> <%= command.id %> -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -s my-client-secret',
10
- '<%= config.bin %> <%= command.id %> -u https://graph.api.flowcore.io/graphql',
11
- '<%= config.bin %> <%= command.id %> -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -p',
12
- ];
13
- static flags = {
14
- clientId: Flags.string({ char: 'c', description: 'client id to use for the login' }),
15
- clientSecret: Flags.string({ char: 'n', description: 'name to print' }),
16
- loginUrl: Flags.string({ char: 'l', description: 'url to discover the openid configuration' }),
17
- port: Flags.boolean({ char: 'p', description: 'prompt for port to listen for the callback' }),
18
- url: Flags.string({ char: 'u', description: 'url to the flowcore platform api' }),
19
- };
20
- async run() {
21
- const { flags } = await this.parse(Set);
22
- let callbackPort;
23
- if (flags.port) {
24
- const port = await prompt([{
25
- choices: ["3000", "4000", "5000", "6000"],
26
- message: "Select a port to listen for the callback",
27
- name: "callbackPort",
28
- type: "select"
29
- }]);
30
- callbackPort = port.callbackPort;
31
- }
32
- console.log(flags);
33
- this.cliConfiguration.setConfig({
34
- ...(flags.url && { api: {
35
- url: flags.url,
36
- } }),
37
- login: {
38
- ...(callbackPort && { callbackPort }),
39
- ...(flags.loginUrl && { url: flags.loginUrl }),
40
- ..._.omit(flags, ["port", "url", "loginUrl"]),
41
- }
42
- });
43
- this.cliConfiguration.displayConfigTable(this.log.bind(this));
44
- }
45
- }
@@ -1,6 +0,0 @@
1
- import { BaseCommand } from "../../base-command.js";
2
- export default class LoginShow extends BaseCommand<typeof LoginShow> {
3
- static description: string;
4
- static examples: string[];
5
- run(): Promise<void>;
6
- }
@@ -1,11 +0,0 @@
1
- import { BaseCommand } from "../../base-command.js";
2
- export default class LoginShow extends BaseCommand {
3
- static description = 'Show the configured login url';
4
- static examples = [
5
- '<%= config.bin %> <%= command.id %>',
6
- ];
7
- async run() {
8
- this.log(`Showing configuration for ${this.cliConfiguration.getSelectedProfile()}`);
9
- this.cliConfiguration.displayConfigTable(this.log.bind(this));
10
- }
11
- }
@@ -1,19 +0,0 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import * as http from "node:http";
3
- import { BaseClient } from "openid-client";
4
- import { BaseCommand } from "../base-command.js";
5
- export default class Login extends BaseCommand<typeof Login> {
6
- static description: string;
7
- static examples: string[];
8
- static flags: {
9
- port: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
- };
11
- protected client: BaseClient | undefined;
12
- protected server: http.Server | undefined;
13
- protected catch(err: Error & {
14
- exitCode?: number;
15
- }): Promise<unknown>;
16
- protected init(): Promise<void>;
17
- run(): Promise<void>;
18
- private writeToken;
19
- }
@@ -1,146 +0,0 @@
1
- import { Flags } from '@oclif/core';
2
- import express from 'express';
3
- import open from "open";
4
- import { Issuer, generators } from "openid-client";
5
- import { BaseCommand } from "../base-command.js";
6
- export default class Login extends BaseCommand {
7
- static description = 'login to the Flowcore Platform';
8
- static examples = [
9
- '<%= config.bin %> <%= command.id %>',
10
- '<%= config.bin %> <%= command.id %> --port 8080',
11
- ];
12
- static flags = {
13
- port: Flags.integer({ char: 'p', default: 3000, description: 'port to listen for the callback' }),
14
- };
15
- client;
16
- server;
17
- catch(err) {
18
- this.server?.close();
19
- return super.catch(err);
20
- }
21
- async init() {
22
- await super.init();
23
- try {
24
- const { login } = this.cliConfiguration.getConfig();
25
- const oidcIssuer = await Issuer.discover(login.url);
26
- this.client = new oidcIssuer.Client({
27
- // eslint-disable-next-line camelcase
28
- client_id: login.clientId,
29
- // eslint-disable-next-line camelcase
30
- ...(login.clientSecret && { client_secret: login.clientSecret }),
31
- // eslint-disable-next-line camelcase
32
- redirect_uris: [`http://localhost:${login.callbackPort}/callback`],
33
- // eslint-disable-next-line camelcase
34
- response_types: ['code'],
35
- // eslint-disable-next-line camelcase
36
- token_endpoint_auth_method: 'none',
37
- });
38
- }
39
- catch (error) {
40
- this.error(`Failed to discover the openid configuration: ${error}`);
41
- }
42
- }
43
- async run() {
44
- if (!this.client) {
45
- this.error("No client configured");
46
- }
47
- const { login } = this.cliConfiguration.getConfig();
48
- const codeVerifier = generators.codeVerifier();
49
- const codeChallenge = generators.codeChallenge(codeVerifier);
50
- const loginUrl = this.client.authorizationUrl({
51
- // eslint-disable-next-line camelcase
52
- code_challenge: codeChallenge,
53
- // eslint-disable-next-line camelcase
54
- code_challenge_method: 'S256',
55
- scope: 'openid profile email flowcore_user offline_access',
56
- });
57
- const app = express();
58
- app.get('/callback', async (req, res) => {
59
- const params = this.client.callbackParams(req);
60
- // eslint-disable-next-line camelcase
61
- const tokenSet = await this.client.callback(`http://localhost:${port}/callback`, params, { code_verifier: codeVerifier });
62
- if (!tokenSet.claims()) {
63
- this.error("No claims in token set");
64
- }
65
- if (tokenSet.claims()) {
66
- this.log(`Logged in as ${tokenSet.claims().preferred_username}`);
67
- }
68
- this.writeToken(tokenSet);
69
- const claims = tokenSet.claims();
70
- res.send(`
71
- <!DOCTYPE html>
72
- <html lang="en">
73
- <head>
74
- <meta charset="UTF-8">
75
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
76
- <link rel="icon" href="https://flowcore.com/favicon.ico" type="image/x-icon" sizes="any">
77
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
78
- <title>Login Successful</title>
79
- <style>
80
- body {
81
- font-family: Arial, sans-serif;
82
- background-color: #000000;
83
- color: #FFFFFF;
84
- text-align: center;
85
- padding: 50px;
86
- }
87
-
88
- h1 {
89
- font-size: 32px;
90
- margin-bottom: 20px;
91
- }
92
-
93
- p {
94
- font-size: 16px;
95
- margin-bottom: 30px;
96
- }
97
-
98
- .success-icon {
99
- color: #66bd6a;
100
- font-size: 48px;
101
- margin-bottom: 20px;
102
- }
103
-
104
- .button {
105
- background-color: #ff4ba2;
106
- color: #FFFFFF;
107
- padding: 10px 20px;
108
- font-size: 18px;
109
- border: none;
110
- border-radius: 4px;
111
- cursor: pointer;
112
- }
113
-
114
- .button:hover {
115
- background-color: #1976D2;
116
- }
117
- </style>
118
- </head>
119
- <body>
120
- <div class="success-icon">
121
- <i class="fa fa-check-circle"></i>
122
- </div>
123
- <h1>Login Successful</h1>
124
- <p>Hello ${claims.preferred_username}! You have successfully logged in. You can now close this window.</p>
125
- <button class="button" onclick="window.close();">Close Window</button>
126
- </body>
127
- </html>
128
- `);
129
- this.server?.close();
130
- });
131
- const port = login.callbackPort;
132
- await open(loginUrl, { wait: false });
133
- this.server = app.listen(port, () => {
134
- this.log(`Listening for authentication callback on port ${port}`);
135
- });
136
- }
137
- writeToken(tokenSet) {
138
- this.cliConfiguration.setConfig({
139
- auth: {
140
- accessToken: tokenSet.access_token,
141
- idToken: tokenSet.id_token,
142
- refreshToken: tokenSet.refresh_token,
143
- }
144
- });
145
- }
146
- }
@@ -1,5 +0,0 @@
1
- import { BaseCommand } from "../base-command.js";
2
- export default class Whoami extends BaseCommand<typeof Whoami> {
3
- static description: string;
4
- run(): Promise<void>;
5
- }
@@ -1,25 +0,0 @@
1
- import { BaseCommand } from "../base-command.js";
2
- import { LOGIN_CODES, ValidateLogin } from "../utils/validate-login.util.js";
3
- export default class Whoami extends BaseCommand {
4
- static description = 'Check what user you are logged in as';
5
- async run() {
6
- const config = this.cliConfiguration.getConfig();
7
- const { auth, login } = config;
8
- if (!login.url) {
9
- this.error("No login url configured");
10
- }
11
- if (!auth) {
12
- this.error("Not logged in");
13
- }
14
- const validator = new ValidateLogin(login.url);
15
- const result = await validator.validate(config, this.cliConfiguration);
16
- if (result.status === LOGIN_CODES.LOGIN_SUCCESS) {
17
- this.log(`Logged in as ${result.name} (${result.flowcore_user_id})`);
18
- return;
19
- }
20
- if (result.status === LOGIN_CODES.LOGIN_EXPIRED) {
21
- this.error("Login expired, please login again");
22
- }
23
- this.error("Not logged in");
24
- }
25
- }
@@ -1,31 +0,0 @@
1
- export declare const CONFIG_FILE_NAME = "credentials.json";
2
- export declare class CliConfiguration {
3
- private config;
4
- private configPath;
5
- private selectedProfile;
6
- private static generateConfigPath;
7
- displayConfigTable(log: (message?: string, ...args: unknown[]) => void): void;
8
- getConfig(): CliConfig;
9
- getSelectedProfile(): string;
10
- init(profile: string, path: string): void;
11
- setConfig(newConfig: unknown): void;
12
- private ensureConfigIsValid;
13
- }
14
- export type CliConfig = {
15
- api: {
16
- url: string;
17
- };
18
- auth?: {
19
- accessToken: string;
20
- idToken?: string;
21
- refreshToken?: string;
22
- };
23
- login: {
24
- callbackPort: number;
25
- clientId: string;
26
- clientSecret?: string;
27
- url: string;
28
- };
29
- };
30
- export declare const createDefaultConfig: (configPath: string) => void;
31
- export declare const loadConfig: (configPath: string) => CliConfig;
@@ -1,108 +0,0 @@
1
- import { ux } from "@oclif/core";
2
- import _ from "lodash";
3
- import { merge, recursive } from "merge";
4
- import * as fs from "node:fs";
5
- import * as path from "node:path";
6
- import { getObjectPaths } from "./object-path.util.js";
7
- export const CONFIG_FILE_NAME = "credentials.json";
8
- export class CliConfiguration {
9
- config = {};
10
- configPath = "";
11
- selectedProfile = "";
12
- static generateConfigPath(configDir) {
13
- return `${configDir}/${CONFIG_FILE_NAME}`;
14
- }
15
- displayConfigTable(log) {
16
- const maskedValues = new Set([
17
- "login.clientSecret",
18
- "auth.accessToken",
19
- "auth.idToken",
20
- "auth.refreshToken",
21
- ]);
22
- const objectPaths = getObjectPaths(this.config);
23
- ux.table(objectPaths.map(oMap => maskedValues.has(oMap) ?
24
- ({ path: oMap, value: "*******" }) : ({ path: oMap, value: _.get(this.config, oMap) })), {
25
- path: {},
26
- value: {
27
- get: (row) => row.value ?? "not configured",
28
- header: 'Value'
29
- }
30
- }, {
31
- printLine: log,
32
- });
33
- }
34
- getConfig() {
35
- return this.config;
36
- }
37
- getSelectedProfile() {
38
- return this.selectedProfile;
39
- }
40
- init(profile, path) {
41
- this.configPath = CliConfiguration.generateConfigPath(path);
42
- this.selectedProfile = profile;
43
- this.ensureConfigIsValid();
44
- }
45
- setConfig(newConfig) {
46
- this.config = recursive(this.config, newConfig);
47
- const existingConfig = JSON.parse(fs.readFileSync(this.configPath, "utf8"));
48
- fs.writeFileSync(this.configPath, JSON.stringify(recursive(existingConfig, {
49
- [this.selectedProfile]: this.config,
50
- }), null, 2));
51
- }
52
- ensureConfigIsValid() {
53
- const defaultConfig = {
54
- api: {
55
- url: "https://graph.api.flowcore.io/graphql",
56
- },
57
- login: {
58
- callbackPort: 3000,
59
- clientId: "flowcore-cli",
60
- url: "https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration",
61
- }
62
- };
63
- if (!fs.existsSync(path.dirname(this.configPath))) {
64
- fs.mkdirSync(path.dirname(this.configPath), { recursive: true });
65
- }
66
- if (fs.existsSync(this.configPath)) {
67
- const existingConfig = JSON.parse(fs.readFileSync(this.configPath, "utf8"));
68
- this.config = existingConfig[this.selectedProfile] ? recursive(defaultConfig, existingConfig[this.selectedProfile]) : defaultConfig;
69
- fs.writeFileSync(this.configPath, JSON.stringify(recursive(existingConfig, {
70
- [this.selectedProfile]: this.config,
71
- }), null, 2));
72
- }
73
- else {
74
- this.config = defaultConfig;
75
- fs.writeFileSync(this.configPath, JSON.stringify({
76
- [this.selectedProfile]: this.config,
77
- }, null, 2));
78
- }
79
- }
80
- }
81
- export const createDefaultConfig = (configPath) => {
82
- const config = {
83
- api: {
84
- url: "https://graph.api.flowcore.io/graphql",
85
- },
86
- login: {
87
- callbackPort: 3000,
88
- clientId: "flowcoreweb",
89
- url: "https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration",
90
- }
91
- };
92
- if (!fs.existsSync(path.dirname(configPath))) {
93
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
94
- }
95
- if (fs.existsSync(configPath)) {
96
- const existingConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
97
- fs.writeFileSync(configPath, JSON.stringify(merge(config, existingConfig), null, 2));
98
- }
99
- else {
100
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
101
- }
102
- };
103
- export const loadConfig = (configPath) => {
104
- if (!fs.existsSync(configPath)) {
105
- createDefaultConfig(configPath);
106
- }
107
- return JSON.parse(fs.readFileSync(configPath, "utf8"));
108
- };
@@ -1 +0,0 @@
1
- export declare function getObjectPaths(obj: unknown, parentKey?: string): string[];
@@ -1,17 +0,0 @@
1
- export function getObjectPaths(obj, parentKey) {
2
- let paths = [];
3
- for (const key in obj) {
4
- if (Object.hasOwn(obj, key)) {
5
- const path = parentKey ? `${parentKey}.${key}` : key;
6
- const value = obj[key];
7
- if (typeof value === 'object' && value !== null) {
8
- const nestedPaths = getObjectPaths(value, path);
9
- paths = [...paths, ...nestedPaths];
10
- }
11
- else {
12
- paths.push(path);
13
- }
14
- }
15
- }
16
- return paths;
17
- }
@@ -1,24 +0,0 @@
1
- import { CliConfig, CliConfiguration } from "./config.util.js";
2
- export type UserInfo = {
3
- family_name: string;
4
- flowcore_user_id: string;
5
- given_name: string;
6
- name: string;
7
- preferred_username: string;
8
- };
9
- export declare enum LOGIN_CODES {
10
- LOGIN_EXPIRED = 2,
11
- LOGIN_FAILED = 0,
12
- LOGIN_SUCCESS = 1
13
- }
14
- export declare class ValidateLogin {
15
- private readonly url;
16
- constructor(url: string);
17
- isExpired(config: CliConfig, client: CliConfiguration, displayProgress?: boolean): Promise<boolean>;
18
- tryRefreshToken(config: CliConfig, client: CliConfiguration): Promise<CliConfig>;
19
- validate(config: CliConfig, client: CliConfiguration, displayProgress?: boolean): Promise<{
20
- status: LOGIN_CODES;
21
- } | UserInfo & {
22
- status: LOGIN_CODES;
23
- }>;
24
- }
@@ -1,115 +0,0 @@
1
- import { ux } from "@oclif/core";
2
- import { jwtDecode } from "jwt-decode";
3
- export var LOGIN_CODES;
4
- (function (LOGIN_CODES) {
5
- LOGIN_CODES[LOGIN_CODES["LOGIN_EXPIRED"] = 2] = "LOGIN_EXPIRED";
6
- LOGIN_CODES[LOGIN_CODES["LOGIN_FAILED"] = 0] = "LOGIN_FAILED";
7
- LOGIN_CODES[LOGIN_CODES["LOGIN_SUCCESS"] = 1] = "LOGIN_SUCCESS";
8
- })(LOGIN_CODES || (LOGIN_CODES = {}));
9
- export class ValidateLogin {
10
- url;
11
- constructor(url) {
12
- this.url = url;
13
- }
14
- async isExpired(config, client, displayProgress = true) {
15
- const decoded = jwtDecode(config.auth?.accessToken ?? "");
16
- if (decoded.exp === undefined) {
17
- throw new Error("Invalid id token");
18
- }
19
- if (decoded.exp * 1000 < Date.now() - 5000) {
20
- try {
21
- if (displayProgress) {
22
- ux.action.start("Refreshing token");
23
- }
24
- config = await this.tryRefreshToken(config, client);
25
- if (displayProgress) {
26
- ux.action.stop("Refreshed token");
27
- }
28
- return true;
29
- }
30
- catch (error) {
31
- ux.error(`Failed to refresh token: ${error}`);
32
- }
33
- }
34
- return false;
35
- }
36
- async tryRefreshToken(config, client) {
37
- if (config.auth?.refreshToken === undefined) {
38
- throw new Error("No refresh token");
39
- }
40
- const response = await fetch(this.url);
41
- const json = await response.json();
42
- if (json.token_endpoint === undefined) {
43
- throw new Error("No token_endpoint in openid configuration");
44
- }
45
- const body = new URLSearchParams();
46
- body.append("grant_type", "refresh_token");
47
- body.append("refresh_token", config.auth.refreshToken);
48
- body.append("client_id", config.login.clientId);
49
- body.append("client_secret", config.login.clientSecret ?? "");
50
- const result = await fetch(json.token_endpoint, {
51
- body,
52
- method: "POST",
53
- });
54
- if (result.status !== 200) {
55
- throw new Error("Failed to refresh token");
56
- }
57
- const resultJson = await result.json();
58
- client.setConfig({
59
- auth: {
60
- ...config.auth,
61
- accessToken: resultJson.access_token,
62
- idToken: resultJson.id_token,
63
- refreshToken: resultJson.refresh_token,
64
- }
65
- });
66
- return client.getConfig();
67
- }
68
- async validate(config, client, displayProgress = true) {
69
- const response = await fetch(this.url);
70
- const json = await response.json();
71
- if (json.userinfo_endpoint === undefined) {
72
- throw new Error("No userinfo_endpoint in openid configuration");
73
- }
74
- if (config.auth === undefined) {
75
- return {
76
- status: LOGIN_CODES.LOGIN_FAILED,
77
- };
78
- }
79
- if (config.auth.accessToken === undefined) {
80
- return {
81
- status: LOGIN_CODES.LOGIN_FAILED,
82
- };
83
- }
84
- try {
85
- await this.isExpired(config, client, displayProgress);
86
- }
87
- catch {
88
- return {
89
- status: LOGIN_CODES.LOGIN_EXPIRED,
90
- };
91
- }
92
- try {
93
- const result = await fetch(json.userinfo_endpoint, {
94
- headers: {
95
- "Authorization": `Bearer ${config?.auth?.accessToken}`,
96
- }
97
- });
98
- if (result.status !== 200) {
99
- return {
100
- status: LOGIN_CODES.LOGIN_FAILED,
101
- };
102
- }
103
- return {
104
- ...await result.json(),
105
- status: LOGIN_CODES.LOGIN_SUCCESS,
106
- };
107
- }
108
- catch (error) {
109
- console.error(error);
110
- return {
111
- status: LOGIN_CODES.LOGIN_FAILED,
112
- };
113
- }
114
- }
115
- }