@flowcore/cli 1.0.2 → 1.1.0

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
@@ -7,6 +7,13 @@
7
7
 
8
8
 
9
9
 
10
+ ## [1.1.0](https://github.com/flowcore-io/flowcore-cli/compare/v1.0.2...v1.1.0) (2024-01-09)
11
+
12
+
13
+ ### Features
14
+
15
+ * added json output ([c97b83e](https://github.com/flowcore-io/flowcore-cli/commit/c97b83e5f3f5d6172ce76e70d6331bee497b44db))
16
+
10
17
  ## [1.0.2](https://github.com/flowcore-io/flowcore-cli/compare/v1.0.1...v1.0.2) (2024-01-09)
11
18
 
12
19
 
package/README.md CHANGED
@@ -17,7 +17,7 @@ $ npm install -g @flowcore/cli
17
17
  $ flowcore COMMAND
18
18
  running command...
19
19
  $ flowcore (--version)
20
- @flowcore/cli/1.0.2 linux-x64 node-v20.10.0
20
+ @flowcore/cli/1.1.0 linux-x64 node-v20.10.0
21
21
  $ flowcore --help [COMMAND]
22
22
  USAGE
23
23
  $ flowcore COMMAND
@@ -103,7 +103,7 @@ EXAMPLES
103
103
  $ flowcore config set -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -p
104
104
  ```
105
105
 
106
- _See code: [src/commands/config/set.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.0.2/src/commands/config/set.ts)_
106
+ _See code: [src/commands/config/set.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.1.0/src/commands/config/set.ts)_
107
107
 
108
108
  ## `flowcore config show`
109
109
 
@@ -123,7 +123,7 @@ EXAMPLES
123
123
  $ flowcore config show
124
124
  ```
125
125
 
126
- _See code: [src/commands/config/show.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.0.2/src/commands/config/show.ts)_
126
+ _See code: [src/commands/config/show.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.1.0/src/commands/config/show.ts)_
127
127
 
128
128
  ## `flowcore help [COMMANDS]`
129
129
 
@@ -166,7 +166,7 @@ EXAMPLES
166
166
  $ flowcore login --port 8080
167
167
  ```
168
168
 
169
- _See code: [src/commands/login.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.0.2/src/commands/login.ts)_
169
+ _See code: [src/commands/login.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.1.0/src/commands/login.ts)_
170
170
 
171
171
  ## `flowcore plugins`
172
172
 
@@ -449,14 +449,15 @@ Stream events from a datacore running on the Flowcore Platform
449
449
 
450
450
  ```
451
451
  USAGE
452
- $ flowcore stream STREAM [--profile <value>] [-d <value>] [-l] [-o http|log] [-s <value>]
452
+ $ flowcore stream STREAM [--profile <value>] [-d <value>] [-j] [-l] [-o http|log] [-s <value>]
453
453
 
454
454
  ARGUMENTS
455
455
  STREAM stream url to connect to
456
456
 
457
457
  FLAGS
458
458
  -d, --destination=<value> [default: http://localhost:3000/transform] Destination to send events to
459
- -l, --live Change to live mode when reaching last time bucket
459
+ -j, --json Output json only
460
+ -l, --[no-]live Change to live mode when reaching last time bucket
460
461
  -o, --output=<option> [default: http] Output format
461
462
  <options: http|log>
462
463
  -s, --start=<value> Start time bucket to stream from, example: (1y, 1m, 1d, 1h)
@@ -469,7 +470,7 @@ EXAMPLES
469
470
  $ flowcore stream https://staging.flowcore.io/flowcore/flowcore-platform/organization.0/event.organization.subscription.updated-requested.0.stream
470
471
  ```
471
472
 
472
- _See code: [src/commands/stream.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.0.2/src/commands/stream.ts)_
473
+ _See code: [src/commands/stream.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.1.0/src/commands/stream.ts)_
473
474
 
474
475
  ## `flowcore version`
475
476
 
@@ -506,5 +507,5 @@ DESCRIPTION
506
507
  Check what user you are logged in as
507
508
  ```
508
509
 
509
- _See code: [src/commands/whoami.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.0.2/src/commands/whoami.ts)_
510
+ _See code: [src/commands/whoami.ts](https://github.com/flowcore-io/flowcore-cli/blob/v1.1.0/src/commands/whoami.ts)_
510
511
  <!-- commandsstop -->
@@ -7,6 +7,7 @@ export default class Stream extends BaseCommand<typeof Stream> {
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  destination: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
+ json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
11
  live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
11
12
  output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
12
13
  start: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
@@ -23,14 +23,15 @@ export default class Stream extends BaseCommand {
23
23
  ];
24
24
  static flags = {
25
25
  destination: Flags.string({ char: 'd', default: "http://localhost:3000/transform", description: 'Destination to send events to' }),
26
- live: Flags.boolean({ char: 'l', default: true, description: 'Change to live mode when reaching last time bucket' }),
26
+ json: Flags.boolean({ char: 'j', description: 'Output json only' }),
27
+ live: Flags.boolean({ allowNo: true, char: 'l', default: true, description: 'Change to live mode when reaching last time bucket' }),
27
28
  output: Flags.string({ char: 'o', default: 'http', description: 'Output format', options: ['http', 'log'] }),
28
29
  start: Flags.string({ char: 's', description: 'Start time bucket to stream from, example: (1y, 1m, 1d, 1h)' }),
29
30
  };
30
31
  async run() {
31
32
  const config = this.cliConfiguration.getConfig();
32
33
  const loginValidator = new ValidateLogin(config.login.url);
33
- const validateLogin = await loginValidator.validate(config, this.cliConfiguration);
34
+ const validateLogin = await loginValidator.validate(config, this.cliConfiguration, !this.flags.json);
34
35
  const { api, auth } = config;
35
36
  if (validateLogin.status !== LOGIN_CODES.LOGIN_SUCCESS || !auth) {
36
37
  ux.error(`Not logged in, please run ${ux.colorize("yellow", "flowcore login")} first`);
@@ -39,7 +40,7 @@ export default class Stream extends BaseCommand {
39
40
  ux.error("No api url configured");
40
41
  }
41
42
  const graphqlClient = new QueryGraphQL(api.url, auth.accessToken, async () => {
42
- if (!await loginValidator.isExpired(config, this.cliConfiguration)) {
43
+ if (!await loginValidator.isExpired(config, this.cliConfiguration, !this.flags.json)) {
43
44
  return false;
44
45
  }
45
46
  return config.auth.accessToken;
@@ -65,23 +66,23 @@ export default class Stream extends BaseCommand {
65
66
  let firstTimeBucket = eventRangeRequest.datacore.flowtypes.find(ft => ft.aggregator === aggregator)?.events.find(e => e.name === eventType)?.catalog.range.firstTimeBucket;
66
67
  if (!firstTimeBucket && !flags.start) {
67
68
  firstTimeBucket = createTimebucket(dayjs());
68
- ux.warn(`First time bucket not found, setting to current time (${ux.colorize("yellowBright", firstTimeBucket)})`);
69
+ !this.flags.json && this.warn(`First time bucket not found, setting to current time (${ux.colorize("yellowBright", firstTimeBucket)})`);
69
70
  }
70
71
  if (flags.start) {
71
72
  firstTimeBucket = this.setTimeBucket(dayjs(), flags.start);
72
- ux.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", flags.start)} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
73
+ !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", flags.start)} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
73
74
  }
74
75
  if (!firstTimeBucket) {
75
76
  firstTimeBucket = this.setTimeBucket(dayjs(), "1d");
76
- ux.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", "1d")} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
77
+ !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", "1d")} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
77
78
  }
78
79
  let lastTimeBucket = eventRangeRequest.datacore.flowtypes.find(ft => ft.aggregator === aggregator)?.events.find(e => e.name === eventType)?.catalog.range.lastTimeBucket;
79
80
  if (!lastTimeBucket) {
80
81
  lastTimeBucket = createTimebucket(dayjs());
81
- this.warn(`Last time bucket not found, setting to current time (${ux.colorize("yellowBright", lastTimeBucket)})`);
82
+ !this.flags.json && this.warn(`Last time bucket not found, setting to current time (${ux.colorize("yellowBright", lastTimeBucket)})`);
82
83
  }
83
84
  const observer = new Subject();
84
- this.log(ux.colorize("blackBright", `Starting to stream events for ${dataCoreId} - ${aggregator} - ${eventType}, press ${ux.colorize("whiteBright", "ctrl+c")} to stop`));
85
+ !this.flags.json && this.log(ux.colorize("blackBright", `Starting to stream events for ${dataCoreId} - ${aggregator} - ${eventType}, press ${ux.colorize("whiteBright", "ctrl+c")} to stop`));
85
86
  // eslint-disable-next-line no-void
86
87
  void this.streanEvents(dataCoreId, aggregator, eventType, firstTimeBucket, lastTimeBucket, graphqlClient, observer, flags.live);
87
88
  await this.processEvents(observer, flags.destination, flags.output);
@@ -89,13 +90,14 @@ export default class Stream extends BaseCommand {
89
90
  async processEvents(observer, destination, output) {
90
91
  let done = false;
91
92
  let events = [];
93
+ const warn = this.flags.json ? () => { } : this.warn.bind(this);
92
94
  observer.subscribe({
93
95
  complete() {
94
- ux.warn("Stream completed");
96
+ warn("Stream completed");
95
97
  done = true;
96
98
  },
97
99
  error(error) {
98
- ux.warn(`Stream error occurred with error ${error}`);
100
+ warn(`Stream error occurred with error ${error}`);
99
101
  done = true;
100
102
  },
101
103
  next(value) {
@@ -109,10 +111,13 @@ export default class Stream extends BaseCommand {
109
111
  while (!processingQueue.isEmpty()) {
110
112
  const event = processingQueue.dequeue();
111
113
  if (output === "log") {
112
- ux.log(JSON.stringify(event));
114
+ this.flags.json ? this.log(JSON.stringify({
115
+ event,
116
+ type: "input",
117
+ }, null, 2)) : this.log(JSON.stringify(event));
113
118
  continue;
114
119
  }
115
- this.debug(`Sending event to ${destination}: ${event.eventId}`);
120
+ this.log(`Sending event to ${destination}: ${event.eventId}`);
116
121
  try {
117
122
  // eslint-disable-next-line no-await-in-loop
118
123
  const result = await fetch(destination, {
@@ -123,15 +128,19 @@ export default class Stream extends BaseCommand {
123
128
  method: "POST",
124
129
  });
125
130
  if (!result.ok) {
126
- this.warn(`Error sending event to ${destination}: ${result.statusText}`);
131
+ !this.flags.json && this.warn(`Error sending event to ${destination}: ${result.statusText}`);
127
132
  }
128
133
  if (result.body) {
129
- // eslint-disable-next-line no-await-in-loop
130
- ux.debug(`Response from ${destination}: ${await result.json()}`);
134
+ this.flags.json ? this.log(JSON.stringify({
135
+ // eslint-disable-next-line no-await-in-loop
136
+ event: (await result.json()),
137
+ type: "output",
138
+ // eslint-disable-next-line no-await-in-loop
139
+ }, null, 2)) : this.log(`Response from ${destination}: ${JSON.stringify(await result.json())}`);
131
140
  }
132
141
  }
133
142
  catch (error) {
134
- this.warn(`Error sending event to ${destination}: ${error}`);
143
+ !this.flags.json && this.warn(`Error sending event to ${destination}: ${error}`);
135
144
  }
136
145
  }
137
146
  if (events.length === 0) {
@@ -159,7 +168,7 @@ export default class Stream extends BaseCommand {
159
168
  return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "hour"));
160
169
  }
161
170
  default: {
162
- this.error("Invalid start time bucket");
171
+ ux.error("Invalid start time bucket");
163
172
  }
164
173
  }
165
174
  }
@@ -171,11 +180,15 @@ export default class Stream extends BaseCommand {
171
180
  // eslint-disable-next-line no-constant-condition
172
181
  while (true) {
173
182
  const timeBucket = createTimebucket(startTimeBucket);
174
- ux.action.start(`Fetching events for ${startTimeBucket}`);
183
+ if (!this.flags.json) {
184
+ ux.action.start(`Fetching events for ${startTimeBucket}`);
185
+ }
175
186
  let cursor = null;
176
187
  let found = false;
177
188
  do {
178
- ux.action.status = `(${timeBucket}), cursor: ${cursor}`;
189
+ if (!this.flags.json) {
190
+ ux.action.status = `(${timeBucket}), cursor: ${cursor}`;
191
+ }
179
192
  // eslint-disable-next-line no-await-in-loop
180
193
  await graphqlClient.validateToken();
181
194
  try {
@@ -199,7 +212,7 @@ export default class Stream extends BaseCommand {
199
212
  if (error instanceof Error && error.message.includes("Token is expired")) {
200
213
  continue;
201
214
  }
202
- ux.warn(`Error fetching events: ${error}`);
215
+ this.warn(`Error fetching events: ${error}`);
203
216
  }
204
217
  } while (cursor);
205
218
  if (dayjs(timeBucket, TIME_BUCKET_HOUR_PATTERN).isBefore(currentTime, "hour")) {
@@ -208,11 +221,13 @@ export default class Stream extends BaseCommand {
208
221
  if (timeBucket === lastTimeBucket) {
209
222
  if (!live) {
210
223
  observer.complete();
211
- ux.action.stop("Fetched all events, stopping");
224
+ if (!this.flags.json) {
225
+ ux.action.stop("Fetched all events, stopping");
226
+ }
212
227
  return;
213
228
  }
214
229
  if (!liveMode) {
215
- ux.warn("Reached last time bucket, switching to live mode");
230
+ !this.flags.json && this.warn("Reached last time bucket, switching to live mode");
216
231
  startTimeBucket = createTimebucketDayjs(currentTime);
217
232
  liveMode = true;
218
233
  }
@@ -14,9 +14,9 @@ export declare enum LOGIN_CODES {
14
14
  export declare class ValidateLogin {
15
15
  private readonly url;
16
16
  constructor(url: string);
17
- isExpired(config: CliConfig, client: CliConfiguration): Promise<boolean>;
17
+ isExpired(config: CliConfig, client: CliConfiguration, displayProgress?: boolean): Promise<boolean>;
18
18
  tryRefreshToken(config: CliConfig, client: CliConfiguration): Promise<CliConfig>;
19
- validate(config: CliConfig, client: CliConfiguration): Promise<{
19
+ validate(config: CliConfig, client: CliConfiguration, displayProgress?: boolean): Promise<{
20
20
  status: LOGIN_CODES;
21
21
  } | UserInfo & {
22
22
  status: LOGIN_CODES;
@@ -11,16 +11,20 @@ export class ValidateLogin {
11
11
  constructor(url) {
12
12
  this.url = url;
13
13
  }
14
- async isExpired(config, client) {
14
+ async isExpired(config, client, displayProgress = true) {
15
15
  const decoded = jwtDecode(config.auth?.accessToken ?? "");
16
16
  if (decoded.exp === undefined) {
17
17
  throw new Error("Invalid id token");
18
18
  }
19
19
  if (decoded.exp * 1000 < Date.now() - 5000) {
20
20
  try {
21
- ux.action.start("Refreshing token");
21
+ if (displayProgress) {
22
+ ux.action.start("Refreshing token");
23
+ }
22
24
  config = await this.tryRefreshToken(config, client);
23
- ux.action.stop("Refreshed token");
25
+ if (displayProgress) {
26
+ ux.action.stop("Refreshed token");
27
+ }
24
28
  return true;
25
29
  }
26
30
  catch (error) {
@@ -61,7 +65,7 @@ export class ValidateLogin {
61
65
  });
62
66
  return client.getConfig();
63
67
  }
64
- async validate(config, client) {
68
+ async validate(config, client, displayProgress = true) {
65
69
  const response = await fetch(this.url);
66
70
  const json = await response.json();
67
71
  if (json.userinfo_endpoint === undefined) {
@@ -78,7 +82,7 @@ export class ValidateLogin {
78
82
  };
79
83
  }
80
84
  try {
81
- await this.isExpired(config, client);
85
+ await this.isExpired(config, client, displayProgress);
82
86
  }
83
87
  catch {
84
88
  return {
@@ -71,11 +71,18 @@
71
71
  "multiple": false,
72
72
  "type": "option"
73
73
  },
74
+ "json": {
75
+ "char": "j",
76
+ "description": "Output json only",
77
+ "name": "json",
78
+ "allowNo": false,
79
+ "type": "boolean"
80
+ },
74
81
  "live": {
75
82
  "char": "l",
76
83
  "description": "Change to live mode when reaching last time bucket",
77
84
  "name": "live",
78
- "allowNo": false,
85
+ "allowNo": true,
79
86
  "type": "boolean"
80
87
  },
81
88
  "output": {
@@ -249,5 +256,5 @@
249
256
  ]
250
257
  }
251
258
  },
252
- "version": "1.0.2"
259
+ "version": "1.1.0"
253
260
  }
package/package.json CHANGED
@@ -86,7 +86,7 @@
86
86
  "prestart": "npm run build",
87
87
  "update-schema": "rover graph introspect https://graph.api.staging.flowcore.io/graphql -o schema.gql"
88
88
  },
89
- "version": "1.0.2",
89
+ "version": "1.1.0",
90
90
  "bugs": "https://github.com/flowcore-io/flowcore-cli/issues",
91
91
  "keywords": [
92
92
  "flowcore",