@flowcore/cli 1.0.1 → 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,20 @@
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
+
17
+ ## [1.0.2](https://github.com/flowcore-io/flowcore-cli/compare/v1.0.1...v1.0.2) (2024-01-09)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * dont set start if it is defined ([72a275d](https://github.com/flowcore-io/flowcore-cli/commit/72a275d4b63195a4e594581550df8bd1fa6a6c8b))
23
+
10
24
  ## [1.0.1](https://github.com/flowcore-io/flowcore-cli/compare/v1.0.0...v1.0.1) (2024-01-09)
11
25
 
12
26
 
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.1 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.1/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.1/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.1/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.1/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.1/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,17 +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)})`);
70
+ }
71
+ if (flags.start) {
72
+ firstTimeBucket = this.setTimeBucket(dayjs(), flags.start);
73
+ !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", flags.start)} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
74
+ }
75
+ if (!firstTimeBucket) {
76
+ firstTimeBucket = this.setTimeBucket(dayjs(), "1d");
77
+ !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", "1d")} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
69
78
  }
70
- firstTimeBucket = this.setTimeBucket(dayjs(), flags.start || "1d");
71
- ux.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", flags.start || "1d")} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
72
79
  let lastTimeBucket = eventRangeRequest.datacore.flowtypes.find(ft => ft.aggregator === aggregator)?.events.find(e => e.name === eventType)?.catalog.range.lastTimeBucket;
73
80
  if (!lastTimeBucket) {
74
81
  lastTimeBucket = createTimebucket(dayjs());
75
- 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)})`);
76
83
  }
77
84
  const observer = new Subject();
78
- 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`));
79
86
  // eslint-disable-next-line no-void
80
87
  void this.streanEvents(dataCoreId, aggregator, eventType, firstTimeBucket, lastTimeBucket, graphqlClient, observer, flags.live);
81
88
  await this.processEvents(observer, flags.destination, flags.output);
@@ -83,13 +90,14 @@ export default class Stream extends BaseCommand {
83
90
  async processEvents(observer, destination, output) {
84
91
  let done = false;
85
92
  let events = [];
93
+ const warn = this.flags.json ? () => { } : this.warn.bind(this);
86
94
  observer.subscribe({
87
95
  complete() {
88
- ux.warn("Stream completed");
96
+ warn("Stream completed");
89
97
  done = true;
90
98
  },
91
99
  error(error) {
92
- ux.warn(`Stream error occurred with error ${error}`);
100
+ warn(`Stream error occurred with error ${error}`);
93
101
  done = true;
94
102
  },
95
103
  next(value) {
@@ -103,10 +111,13 @@ export default class Stream extends BaseCommand {
103
111
  while (!processingQueue.isEmpty()) {
104
112
  const event = processingQueue.dequeue();
105
113
  if (output === "log") {
106
- 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));
107
118
  continue;
108
119
  }
109
- this.debug(`Sending event to ${destination}: ${event.eventId}`);
120
+ this.log(`Sending event to ${destination}: ${event.eventId}`);
110
121
  try {
111
122
  // eslint-disable-next-line no-await-in-loop
112
123
  const result = await fetch(destination, {
@@ -117,15 +128,19 @@ export default class Stream extends BaseCommand {
117
128
  method: "POST",
118
129
  });
119
130
  if (!result.ok) {
120
- this.warn(`Error sending event to ${destination}: ${result.statusText}`);
131
+ !this.flags.json && this.warn(`Error sending event to ${destination}: ${result.statusText}`);
121
132
  }
122
133
  if (result.body) {
123
- // eslint-disable-next-line no-await-in-loop
124
- 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())}`);
125
140
  }
126
141
  }
127
142
  catch (error) {
128
- this.warn(`Error sending event to ${destination}: ${error}`);
143
+ !this.flags.json && this.warn(`Error sending event to ${destination}: ${error}`);
129
144
  }
130
145
  }
131
146
  if (events.length === 0) {
@@ -153,7 +168,7 @@ export default class Stream extends BaseCommand {
153
168
  return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "hour"));
154
169
  }
155
170
  default: {
156
- this.error("Invalid start time bucket");
171
+ ux.error("Invalid start time bucket");
157
172
  }
158
173
  }
159
174
  }
@@ -165,11 +180,15 @@ export default class Stream extends BaseCommand {
165
180
  // eslint-disable-next-line no-constant-condition
166
181
  while (true) {
167
182
  const timeBucket = createTimebucket(startTimeBucket);
168
- ux.action.start(`Fetching events for ${startTimeBucket}`);
183
+ if (!this.flags.json) {
184
+ ux.action.start(`Fetching events for ${startTimeBucket}`);
185
+ }
169
186
  let cursor = null;
170
187
  let found = false;
171
188
  do {
172
- ux.action.status = `(${timeBucket}), cursor: ${cursor}`;
189
+ if (!this.flags.json) {
190
+ ux.action.status = `(${timeBucket}), cursor: ${cursor}`;
191
+ }
173
192
  // eslint-disable-next-line no-await-in-loop
174
193
  await graphqlClient.validateToken();
175
194
  try {
@@ -193,7 +212,7 @@ export default class Stream extends BaseCommand {
193
212
  if (error instanceof Error && error.message.includes("Token is expired")) {
194
213
  continue;
195
214
  }
196
- ux.warn(`Error fetching events: ${error}`);
215
+ this.warn(`Error fetching events: ${error}`);
197
216
  }
198
217
  } while (cursor);
199
218
  if (dayjs(timeBucket, TIME_BUCKET_HOUR_PATTERN).isBefore(currentTime, "hour")) {
@@ -202,11 +221,13 @@ export default class Stream extends BaseCommand {
202
221
  if (timeBucket === lastTimeBucket) {
203
222
  if (!live) {
204
223
  observer.complete();
205
- ux.action.stop("Fetched all events, stopping");
224
+ if (!this.flags.json) {
225
+ ux.action.stop("Fetched all events, stopping");
226
+ }
206
227
  return;
207
228
  }
208
229
  if (!liveMode) {
209
- ux.warn("Reached last time bucket, switching to live mode");
230
+ !this.flags.json && this.warn("Reached last time bucket, switching to live mode");
210
231
  startTimeBucket = createTimebucketDayjs(currentTime);
211
232
  liveMode = true;
212
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.1"
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.1",
89
+ "version": "1.1.0",
90
90
  "bugs": "https://github.com/flowcore-io/flowcore-cli/issues",
91
91
  "keywords": [
92
92
  "flowcore",