@flowcore/cli 2.10.1 → 2.12.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
@@ -10,6 +10,20 @@
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.12.0](https://github.com/flowcore-io/flowcore-cli/compare/v2.11.0...v2.12.0) (2024-03-28)
14
+
15
+
16
+ ### Features
17
+
18
+ * update versions and links for flowcore cli and plugins. added support for client credentials ([f87c389](https://github.com/flowcore-io/flowcore-cli/commit/f87c38957584e7d82bb793963d069c256c72646c))
19
+
20
+ ## [2.11.0](https://github.com/flowcore-io/flowcore-cli/compare/v2.10.1...v2.11.0) (2024-03-08)
21
+
22
+
23
+ ### Features
24
+
25
+ * update versions and links for flowcore cli and plugins ([cd7e7e0](https://github.com/flowcore-io/flowcore-cli/commit/cd7e7e03ce6e4090c64668ad6a9108e3f5fa7994))
26
+
13
27
  ## [2.10.1](https://github.com/flowcore-io/flowcore-cli/compare/v2.10.0...v2.10.1) (2024-03-07)
14
28
 
15
29
 
package/README.md CHANGED
@@ -18,7 +18,7 @@ $ npm install -g @flowcore/cli
18
18
  $ flowcore COMMAND
19
19
  running command...
20
20
  $ flowcore (--version)
21
- @flowcore/cli/2.10.1 linux-x64 node-v20.11.1
21
+ @flowcore/cli/2.12.0 linux-x64 node-v20.11.1
22
22
  $ flowcore --help [COMMAND]
23
23
  USAGE
24
24
  $ flowcore COMMAND
@@ -75,7 +75,7 @@ EXAMPLES
75
75
  $ flowcore apply -f ./path/to/manifest.yml
76
76
  ```
77
77
 
78
- _See code: [src/commands/apply.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.10.1/src/commands/apply.ts)_
78
+ _See code: [src/commands/apply.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.12.0/src/commands/apply.ts)_
79
79
 
80
80
  ## `flowcore autocomplete [SHELL]`
81
81
 
@@ -136,7 +136,7 @@ EXAMPLES
136
136
  $ flowcore config set -l https://auth.flowcore.io/realms/flowcore/.well-known/openid-configuration -c my-client-id -p
137
137
  ```
138
138
 
139
- _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/config/set.ts)_
139
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.1.0/src/commands/config/set.ts)_
140
140
 
141
141
  ## `flowcore config show`
142
142
 
@@ -156,7 +156,7 @@ EXAMPLES
156
156
  $ flowcore config show
157
157
  ```
158
158
 
159
- _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/config/show.ts)_
159
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.1.0/src/commands/config/show.ts)_
160
160
 
161
161
  ## `flowcore data-core apply`
162
162
 
@@ -185,7 +185,7 @@ EXAMPLES
185
185
  $ cat <<EOF | flowcore data-core apply -f -
186
186
  ```
187
187
 
188
- _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.1.0/src/commands/data-core/apply.ts)_
188
+ _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.2.1/src/commands/data-core/apply.ts)_
189
189
 
190
190
  ## `flowcore data-core generate event-type FLOWTYPE`
191
191
 
@@ -212,7 +212,7 @@ EXAMPLES
212
212
  $ flowcore data-core generate event-type flow-type-name -n event-type-name -d "description of the event type" -f example.yaml
213
213
  ```
214
214
 
215
- _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.1.0/src/commands/data-core/generate/event-type.ts)_
215
+ _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.2.1/src/commands/data-core/generate/event-type.ts)_
216
216
 
217
217
  ## `flowcore data-core generate flow-type`
218
218
 
@@ -239,7 +239,7 @@ EXAMPLES
239
239
  $ flowcore data-core generate flow-type -n flow-type-name -d "description of the flow type" -f example.yaml
240
240
  ```
241
241
 
242
- _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.1.0/src/commands/data-core/generate/flow-type.ts)_
242
+ _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.2.1/src/commands/data-core/generate/flow-type.ts)_
243
243
 
244
244
  ## `flowcore data-core generate manifest`
245
245
 
@@ -271,7 +271,7 @@ EXAMPLES
271
271
  $ flowcore data-core generate manifest -t flowcore -n data-core-name -f example.yaml
272
272
  ```
273
273
 
274
- _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.1.0/src/commands/data-core/generate/manifest.ts)_
274
+ _See code: [@flowcore/cli-plugin-data-core](https://github.com/flowcore/flowcore-cli-data-core/blob/v2.2.1/src/commands/data-core/generate/manifest.ts)_
275
275
 
276
276
  ## `flowcore help [COMMANDS]`
277
277
 
@@ -314,7 +314,7 @@ EXAMPLES
314
314
  $ flowcore login --port 8080
315
315
  ```
316
316
 
317
- _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/login.ts)_
317
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.1.0/src/commands/login.ts)_
318
318
 
319
319
  ## `flowcore plugins`
320
320
 
@@ -623,7 +623,7 @@ EXAMPLES
623
623
  $ cat <<EOF | flowcore scenario apply -f -
624
624
  ```
625
625
 
626
- _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.1/src/commands/scenario/apply.ts)_
626
+ _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.2/src/commands/scenario/apply.ts)_
627
627
 
628
628
  ## `flowcore scenario generate manifest`
629
629
 
@@ -655,7 +655,7 @@ EXAMPLES
655
655
  $ flowcore scenario generate manifest -t flowcore -n scenario-name -f example.yaml
656
656
  ```
657
657
 
658
- _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.1/src/commands/scenario/generate/manifest.ts)_
658
+ _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.2/src/commands/scenario/generate/manifest.ts)_
659
659
 
660
660
  ## `flowcore scenario generate transformer`
661
661
 
@@ -682,7 +682,7 @@ EXAMPLES
682
682
  $ flowcore scenario generate transformer -n flow-type-name -d "description of the transformer" -f example.yaml
683
683
  ```
684
684
 
685
- _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.1/src/commands/scenario/generate/transformer.ts)_
685
+ _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.2/src/commands/scenario/generate/transformer.ts)_
686
686
 
687
687
  ## `flowcore scenario local`
688
688
 
@@ -714,7 +714,7 @@ EXAMPLES
714
714
  $ cat <<EOF | flowcore scenario local -f -
715
715
  ```
716
716
 
717
- _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.1/src/commands/scenario/local.ts)_
717
+ _See code: [@flowcore/cli-plugin-scenario](https://github.com/flowcore/flowcore-cli-plugin-scenario/blob/v2.6.2/src/commands/scenario/local.ts)_
718
718
 
719
719
  ## `flowcore stream STREAM`
720
720
 
@@ -722,8 +722,8 @@ Stream events from a datacore running on the Flowcore Platform
722
722
 
723
723
  ```
724
724
  USAGE
725
- $ flowcore stream STREAM [--profile <value>] [-d <value>] [-H <value>] [-j] [-l] [-m <value>] [-o
726
- http|log] [-p] [-c] [-s <value>] [-t <value>]
725
+ $ flowcore stream STREAM [--profile <value>] [-j] [-l] [-m <value>] [-o http|log] [-p] [-c] [-s <value>]
726
+ [-d <value>] [-H <value>] [-t <value>]
727
727
 
728
728
  ARGUMENTS
729
729
  STREAM stream url to connect to
@@ -755,7 +755,7 @@ EXAMPLES
755
755
  $ flowcore stream https://flowcore.io/<org>/<data core>/<flow type>/[<event type1>,<event type2>,<event type3>].stream -o log -s 3m
756
756
  ```
757
757
 
758
- _See code: [src/commands/stream.ts](https://github.com/flowcore-io/flowcore-cli/blob/v2.10.1/src/commands/stream.ts)_
758
+ _See code: [@flowcore/cli-plugin-core](https://github.com/flowcore/flowcore-cli-plugin-core/blob/v1.1.2/src/commands/stream.ts)_
759
759
 
760
760
  ## `flowcore version`
761
761
 
@@ -792,5 +792,5 @@ DESCRIPTION
792
792
  Check what user you are logged in as
793
793
  ```
794
794
 
795
- _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.0.5/src/commands/whoami.ts)_
795
+ _See code: [@flowcore/cli-plugin-config](https://github.com/flowcore/flowcore-cli-plugin-config/blob/v1.1.0/src/commands/whoami.ts)_
796
796
  <!-- commandsstop -->
@@ -46,132 +46,7 @@
46
46
  "commands",
47
47
  "apply.js"
48
48
  ]
49
- },
50
- "stream": {
51
- "aliases": [],
52
- "args": {
53
- "STREAM": {
54
- "description": "stream url to connect to",
55
- "name": "STREAM",
56
- "required": true
57
- }
58
- },
59
- "description": "Stream events from a datacore running on the Flowcore Platform",
60
- "examples": [
61
- "<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/<event type>.stream",
62
- "<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/<event type>.stream -s 1y",
63
- "<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/<event type>.stream -o log -s 3m --json > some.json",
64
- "<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/[<event type1>,<event type2>,<event type3>].stream -o log -s 3m"
65
- ],
66
- "flags": {
67
- "profile": {
68
- "description": "Specify the configuration profile to use",
69
- "name": "profile",
70
- "hasDynamicHelp": false,
71
- "multiple": false,
72
- "type": "option"
73
- },
74
- "destination": {
75
- "char": "d",
76
- "description": "Destination to send events to",
77
- "name": "destination",
78
- "default": "http://localhost:3000/transform",
79
- "hasDynamicHelp": false,
80
- "multiple": false,
81
- "type": "option"
82
- },
83
- "header": {
84
- "char": "H",
85
- "description": "header to send with the request, example: (-H 'Authorization: Bearer TOKEN')",
86
- "name": "header",
87
- "default": [],
88
- "hasDynamicHelp": false,
89
- "multiple": true,
90
- "type": "option"
91
- },
92
- "json": {
93
- "char": "j",
94
- "description": "Output json only",
95
- "name": "json",
96
- "allowNo": false,
97
- "type": "boolean"
98
- },
99
- "live": {
100
- "char": "l",
101
- "description": "Change to live mode when reaching last time bucket",
102
- "name": "live",
103
- "allowNo": true,
104
- "type": "boolean"
105
- },
106
- "max": {
107
- "char": "m",
108
- "description": "Maximum number of events to send to the destination",
109
- "name": "max",
110
- "default": 0,
111
- "hasDynamicHelp": false,
112
- "multiple": false,
113
- "type": "option"
114
- },
115
- "output": {
116
- "char": "o",
117
- "description": "Output format",
118
- "name": "output",
119
- "default": "http",
120
- "hasDynamicHelp": false,
121
- "multiple": false,
122
- "options": [
123
- "http",
124
- "log"
125
- ],
126
- "type": "option"
127
- },
128
- "payload": {
129
- "char": "p",
130
- "description": "Only send the event payload to the destination",
131
- "name": "payload",
132
- "allowNo": false,
133
- "type": "boolean"
134
- },
135
- "scan": {
136
- "char": "c",
137
- "description": "Scan the full time range",
138
- "name": "scan",
139
- "allowNo": false,
140
- "type": "boolean"
141
- },
142
- "start": {
143
- "char": "s",
144
- "description": "Start time bucket to stream from, example: (1y, 1m, 1w, 1d, 1h, now)",
145
- "name": "start",
146
- "hasDynamicHelp": false,
147
- "multiple": false,
148
- "type": "option"
149
- },
150
- "timeout": {
151
- "char": "t",
152
- "description": "Timeout in milliseconds to wait for a response from the destination",
153
- "name": "timeout",
154
- "default": 5000,
155
- "hasDynamicHelp": false,
156
- "multiple": false,
157
- "type": "option"
158
- }
159
- },
160
- "hasDynamicHelp": false,
161
- "hiddenAliases": [],
162
- "id": "stream",
163
- "pluginAlias": "@flowcore/cli",
164
- "pluginName": "@flowcore/cli",
165
- "pluginType": "core",
166
- "strict": true,
167
- "enableJsonFlag": false,
168
- "isESM": true,
169
- "relativePath": [
170
- "dist",
171
- "commands",
172
- "stream.js"
173
- ]
174
49
  }
175
50
  },
176
- "version": "2.10.1"
51
+ "version": "2.12.0"
177
52
  }
package/package.json CHANGED
@@ -5,9 +5,10 @@
5
5
  },
6
6
  "dependencies": {
7
7
  "@datastructures-js/queue": "^4.2.3",
8
- "@flowcore/cli-plugin-config": "^1.0.5",
9
- "@flowcore/cli-plugin-data-core": "^2.1.0",
10
- "@flowcore/cli-plugin-scenario": "^2.6.1",
8
+ "@flowcore/cli-plugin-config": "^1.1.0",
9
+ "@flowcore/cli-plugin-core": "^1.1.2",
10
+ "@flowcore/cli-plugin-data-core": "^2.2.1",
11
+ "@flowcore/cli-plugin-scenario": "^2.6.2",
11
12
  "@flowcore/time-bucket": "^1.1.0",
12
13
  "@oclif/core": "^3",
13
14
  "@oclif/plugin-autocomplete": "^3.0.2",
@@ -72,7 +73,8 @@
72
73
  "@oclif/plugin-not-found",
73
74
  "@flowcore/cli-plugin-config",
74
75
  "@flowcore/cli-plugin-data-core",
75
- "@flowcore/cli-plugin-scenario"
76
+ "@flowcore/cli-plugin-scenario",
77
+ "@flowcore/cli-plugin-core"
76
78
  ],
77
79
  "topicSeparator": " "
78
80
  },
@@ -90,7 +92,7 @@
90
92
  "prestart": "npm run build",
91
93
  "update-schema": "rover graph introspect https://graph.api.staging.flowcore.io/graphql -o schema.gql"
92
94
  },
93
- "version": "2.10.1",
95
+ "version": "2.12.0",
94
96
  "bugs": "https://github.com/flowcore-io/flowcore-cli/issues",
95
97
  "keywords": [
96
98
  "flowcore",
@@ -1,27 +0,0 @@
1
- import { BaseCommand } from "@flowcore/cli-plugin-config";
2
- export default class Stream extends BaseCommand<typeof Stream> {
3
- static args: {
4
- STREAM: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
5
- };
6
- static description: string;
7
- static examples: string[];
8
- static flags: {
9
- destination: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
10
- header: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string[], import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
- json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
12
- live: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
13
- max: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
14
- output: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
15
- payload: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
16
- scan: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
17
- start: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
- timeout: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
19
- };
20
- run(): Promise<void>;
21
- private calculateBuckets;
22
- private calculateTimeDifferenceInHours;
23
- private fetchTimeBuckets;
24
- private processEvents;
25
- private setTimeBucket;
26
- private streamEvents;
27
- }
@@ -1,348 +0,0 @@
1
- import { Queue } from "@datastructures-js/queue";
2
- import { BaseCommand, LOGIN_CODES, ValidateLogin } from "@flowcore/cli-plugin-config";
3
- import { Args, Flags, ux } from '@oclif/core';
4
- import { TimeUuid } from "cassandra-uuid";
5
- import dayjs from "dayjs";
6
- import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js";
7
- import utc from "dayjs/plugin/utc.js";
8
- import _ from "lodash";
9
- import { Subject } from "rxjs";
10
- import { QueryGraphQL } from "../utils/graphql.util.js";
11
- import { FETCH_DATA_CORE_GQL_QUERY } from "../utils/queries/fetch-data-core.gql.js";
12
- import { FETCH_EVENT_TYPE_RANGE_GQL_QUERY } from "../utils/queries/fetch-event-type-range.gql.js";
13
- import { FETCH_EVENTS_GQL_QUERY } from "../utils/queries/fetch-events.gql.js";
14
- import { FETCH_CATALOG_INDEXES_QUERY } from "../utils/queries/fetch-indexes.gql.js";
15
- import { TIME_BUCKET_HOUR_PATTERN, TIME_BUCKET_PATTERN, createTimebucket, createTimebucketDayjs } from "../utils/timebucket.util.js";
16
- dayjs.extend(utc);
17
- dayjs.extend(isSameOrBefore);
18
- export default class Stream extends BaseCommand {
19
- static args = {
20
- STREAM: Args.string({ description: 'stream url to connect to', required: true }),
21
- };
22
- static description = 'Stream events from a datacore running on the Flowcore Platform';
23
- static examples = [
24
- '<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/<event type>.stream',
25
- '<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/<event type>.stream -s 1y',
26
- '<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/<event type>.stream -o log -s 3m --json > some.json',
27
- '<%= config.bin %> <%= command.id %> https://flowcore.io/<org>/<data core>/<flow type>/[<event type1>,<event type2>,<event type3>].stream -o log -s 3m',
28
- ];
29
- static flags = {
30
- destination: Flags.string({ char: 'd', default: "http://localhost:3000/transform", description: 'Destination to send events to' }),
31
- header: Flags.string({ char: 'H', default: [], description: 'header to send with the request, example: (-H \'Authorization: Bearer TOKEN\')', multiple: true }),
32
- json: Flags.boolean({ char: 'j', description: 'Output json only' }),
33
- live: Flags.boolean({ allowNo: true, char: 'l', default: true, description: 'Change to live mode when reaching last time bucket' }),
34
- max: Flags.integer({ char: 'm', default: 0, description: 'Maximum number of events to send to the destination' }),
35
- output: Flags.string({ char: 'o', default: 'http', description: 'Output format', options: ['http', 'log'] }),
36
- payload: Flags.boolean({ char: 'p', default: false, description: 'Only send the event payload to the destination' }),
37
- scan: Flags.boolean({ char: 'c', default: false, description: 'Scan the full time range' }),
38
- start: Flags.string({ char: 's', description: 'Start time bucket to stream from, example: (1y, 1m, 1w, 1d, 1h, now)' }),
39
- timeout: Flags.integer({ char: 't', default: 5000, description: 'Timeout in milliseconds to wait for a response from the destination' }),
40
- };
41
- async run() {
42
- const { args, flags } = await this.parse(Stream);
43
- for (const header of flags.header) {
44
- const parts = header.split(": ");
45
- if (parts.length !== 2) {
46
- ux.error(`Invalid header: ${header}. (correct example: -H 'X-Custom-Header: some value')`);
47
- }
48
- }
49
- const parts = args.STREAM.replace(/https?:\/\//i, "").split("/");
50
- if (parts.length !== 5) {
51
- ux.error(`Invalid stream url, ${args.STREAM}`);
52
- }
53
- const newProfile = this.cliConfiguration.switchProfile(args.STREAM);
54
- if (newProfile) {
55
- ux.log(`Using profile ${ux.colorize("yellow", newProfile)} based on stream url`);
56
- }
57
- const config = this.cliConfiguration.getConfig();
58
- const loginValidator = new ValidateLogin(config.login.url);
59
- const validateLogin = await loginValidator.validate(config, this.cliConfiguration, !this.flags.json);
60
- const { api, auth } = config;
61
- if (validateLogin.status !== LOGIN_CODES.LOGIN_SUCCESS || !auth) {
62
- ux.error(`Not logged in, please run ${ux.colorize("yellow", "flowcore login")} first`);
63
- }
64
- if (!api.url) {
65
- ux.error("No api url configured");
66
- }
67
- const graphqlClient = new QueryGraphQL(api.url, auth.accessToken, async () => {
68
- if (!await loginValidator.isExpired(config, this.cliConfiguration, !this.flags.json)) {
69
- return false;
70
- }
71
- return config.auth.accessToken;
72
- });
73
- const org = parts[1];
74
- const dataCore = parts[2];
75
- const aggregator = parts[3];
76
- const eventTypes = parts[4].replace(/\.stream$/i, "").replace("[", "").replace("]", "").split(",");
77
- const fetchDataCoreResponse = await graphqlClient.client.request(FETCH_DATA_CORE_GQL_QUERY, {
78
- dataCore,
79
- organization: org,
80
- });
81
- if (fetchDataCoreResponse.organization.datacores.length === 0) {
82
- ux.error(`Data core ${dataCore} not found for organization ${org}`);
83
- }
84
- const dataCoreId = fetchDataCoreResponse.organization.datacores[0].id;
85
- const eventRangeRequest = await graphqlClient.client.request(FETCH_EVENT_TYPE_RANGE_GQL_QUERY, {
86
- aggregator,
87
- dataCoreId,
88
- });
89
- let firstTimeBucket = eventRangeRequest.datacore.flowtypes.find(ft => ft.aggregator === aggregator)?.events.find(e => eventTypes.includes(e.name))?.catalog.range.firstTimeBucket;
90
- let afterEventId;
91
- if (!firstTimeBucket && !flags.start) {
92
- firstTimeBucket = createTimebucket(dayjs.utc());
93
- !this.flags.json && this.warn(`First time bucket not found, setting to current time (${ux.colorize("yellowBright", firstTimeBucket)})`);
94
- }
95
- if (flags.start === "now") {
96
- afterEventId = TimeUuid.now();
97
- firstTimeBucket = createTimebucket(dayjs.utc());
98
- !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket and event id to now (${ux.colorize("yellowBright", firstTimeBucket)}), (${ux.colorize("yellowBright", afterEventId)})`));
99
- }
100
- else if (flags.start) {
101
- firstTimeBucket = this.setTimeBucket(dayjs.utc(), flags.start);
102
- !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", flags.start)} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
103
- }
104
- if (!firstTimeBucket) {
105
- firstTimeBucket = this.setTimeBucket(dayjs.utc(), "1d");
106
- !this.flags.json && this.log(ux.colorize("green", `Setting first time bucket to ${ux.colorize("yellow", "1d")} ago (${ux.colorize("yellowBright", firstTimeBucket)})`));
107
- }
108
- let lastTimeBucket = flags.start === "now"
109
- ? firstTimeBucket
110
- : eventRangeRequest.datacore.flowtypes.find(ft => ft.aggregator === aggregator)?.events.find(e => eventTypes.includes(e.name))?.catalog.range.lastTimeBucket;
111
- if (!lastTimeBucket) {
112
- lastTimeBucket = createTimebucket(dayjs.utc());
113
- !this.flags.json && this.warn(`Last time bucket not found, setting to current time (${ux.colorize("yellowBright", lastTimeBucket)})`);
114
- }
115
- const observer = new Subject();
116
- !this.flags.json && this.log(ux.colorize("blackBright", `Starting to stream events for ${dataCoreId} - ${aggregator} - ${eventTypes}, press ${ux.colorize("whiteBright", "ctrl+c")} to stop`));
117
- // eslint-disable-next-line no-void
118
- void this.streamEvents(dataCoreId, aggregator, eventTypes, firstTimeBucket, lastTimeBucket, graphqlClient, observer, flags.live, afterEventId, flags.max);
119
- await this.processEvents(observer, flags.destination, flags.output, flags.header, flags.payload);
120
- }
121
- calculateBuckets(timediff, startTimeBucket) {
122
- return _.times(timediff + 1, (n) => dayjs(startTimeBucket).add(n, "hour").format(TIME_BUCKET_PATTERN));
123
- }
124
- calculateTimeDifferenceInHours(lastTimeBucket, startTimeBucket, firstTimeBucket) {
125
- const timediff = dayjs(lastTimeBucket, TIME_BUCKET_HOUR_PATTERN).diff(startTimeBucket, "hour");
126
- if (timediff < 0) {
127
- ux.error(`Invalid time range, start time bucket (${ux.colorize("yellow", firstTimeBucket)}) is after last time bucket (${ux.colorize("yellow", lastTimeBucket)})`);
128
- }
129
- return timediff;
130
- }
131
- async fetchTimeBuckets(dataCoreId, aggregator, eventTypes, startTimeBucket, lastTimeBucket, graphqlClient) {
132
- !this.flags.json && ux.action.start("Fetching time buckets");
133
- let timeBuckets = [];
134
- for (const eventType of eventTypes) {
135
- let cursor = null;
136
- do {
137
- // eslint-disable-next-line no-await-in-loop
138
- await graphqlClient.validateToken();
139
- try {
140
- // eslint-disable-next-line no-await-in-loop
141
- const response = await graphqlClient.client.request(FETCH_CATALOG_INDEXES_QUERY, {
142
- aggregator,
143
- cursor: cursor || undefined,
144
- dataCoreId,
145
- eventType,
146
- fromTimeBucket: startTimeBucket.format(TIME_BUCKET_PATTERN),
147
- toTimeBucket: lastTimeBucket,
148
- });
149
- cursor = response.datacore.fetchIndexes.cursor;
150
- timeBuckets.push(...response.datacore.fetchIndexes.timeBuckets);
151
- }
152
- catch (error) {
153
- // don't display error if token is expired
154
- if (error instanceof Error && error.message.includes("Token is expired")) {
155
- continue;
156
- }
157
- this.warn(`Error fetching events: ${error}`);
158
- }
159
- } while (cursor);
160
- }
161
- timeBuckets = _.uniq(timeBuckets);
162
- !this.flags.json && ux.action.stop(`Found ${timeBuckets.length} time buckets`);
163
- if (timeBuckets.length === 0) {
164
- !this.flags.json && this.warn("No time buckets found, setting to scan based on requested time range");
165
- const timediff = this.calculateTimeDifferenceInHours(lastTimeBucket, startTimeBucket, createTimebucket(dayjs.utc()));
166
- timeBuckets = this.calculateBuckets(timediff, startTimeBucket);
167
- }
168
- return timeBuckets;
169
- }
170
- async processEvents(observer, destination, output, header = [], payload = false) {
171
- let done = false;
172
- let events = [];
173
- const warn = this.flags.json ? () => { } : this.warn.bind(this);
174
- observer.subscribe({
175
- complete() {
176
- warn("Stream completed");
177
- done = true;
178
- },
179
- error(error) {
180
- warn(`Stream error occurred with error ${error}`);
181
- done = true;
182
- },
183
- next(value) {
184
- events.push(value);
185
- }
186
- });
187
- // eslint-disable-next-line no-unmodified-loop-condition
188
- while (!done || events.length > 0) {
189
- const processingQueue = Queue.fromArray(events);
190
- events = [];
191
- while (!processingQueue.isEmpty()) {
192
- const event = processingQueue.dequeue();
193
- const outputPayload = payload ? event.payload : event;
194
- if (output === "log") {
195
- this.flags.json && this.flags.output !== "log" ? this.log(JSON.stringify({
196
- event: outputPayload,
197
- type: "input",
198
- })) : this.log(JSON.stringify(outputPayload));
199
- continue;
200
- }
201
- !this.flags.json && this.log(`Sending event to ${destination}: ${event.eventId}`);
202
- try {
203
- const headers = {};
204
- for (const h of header) {
205
- const [name, value] = h.split(": ");
206
- headers[name] = value;
207
- }
208
- // eslint-disable-next-line no-await-in-loop
209
- const result = await Promise.race([fetch(destination, {
210
- body: JSON.stringify(outputPayload),
211
- headers: {
212
- "Content-Type": "application/json",
213
- ...headers,
214
- },
215
- method: "POST",
216
- }),
217
- new Promise((resolve, reject) => { setTimeout(() => reject(new Error("Timeout waiting for response")), this.flags.timeout); }),]);
218
- if (!result.ok) {
219
- !this.flags.json && this.warn(`Error sending event to ${destination}: ${result.statusText}`);
220
- }
221
- if (result.body) {
222
- this.flags.json ? this.log(JSON.stringify({
223
- // eslint-disable-next-line no-await-in-loop
224
- event: (await result.json()),
225
- type: "output",
226
- // eslint-disable-next-line no-await-in-loop
227
- })) : this.log(`Response from ${destination}: ${JSON.stringify(await result.json())}`);
228
- }
229
- }
230
- catch (error) {
231
- !this.flags.json && this.warn(`Error sending event to ${destination}: ${error}`);
232
- }
233
- }
234
- if (events.length === 0) {
235
- // eslint-disable-next-line no-await-in-loop
236
- await new Promise((resolve) => { setTimeout(resolve, 200); });
237
- }
238
- }
239
- }
240
- setTimeBucket(date, start) {
241
- const parts = start.match(/(\d+)([dhmwy])/i);
242
- if (!parts) {
243
- ux.error(`Invalid start time bucket, generated from ${start}`);
244
- }
245
- switch (parts[2]) {
246
- case "y": {
247
- return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "year"));
248
- }
249
- case "m": {
250
- return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "month"));
251
- }
252
- case "w": {
253
- return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "week"));
254
- }
255
- case "d": {
256
- return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "day"));
257
- }
258
- case "h": {
259
- return createTimebucket(date.subtract(Number.parseInt(parts[1], 10), "hour"));
260
- }
261
- default: {
262
- ux.error("Invalid start time bucket");
263
- }
264
- }
265
- }
266
- async streamEvents(dataCoreId, aggregator, eventTypes, firstTimeBucket, lastTimeBucket, graphqlClient, observer, live, afterEventId, maxEvents = 0) {
267
- const startTimeBucket = dayjs(firstTimeBucket, TIME_BUCKET_HOUR_PATTERN);
268
- const currentTime = () => dayjs.utc();
269
- let liveMode = false;
270
- let lastEventId = afterEventId ?? null;
271
- const timediff = this.calculateTimeDifferenceInHours(lastTimeBucket, startTimeBucket, firstTimeBucket);
272
- let timeBuckets = [];
273
- timeBuckets = this.flags.scan ? this.calculateBuckets(timediff, startTimeBucket) : (await this.fetchTimeBuckets(dataCoreId, aggregator, eventTypes, startTimeBucket, lastTimeBucket, graphqlClient));
274
- let eventsCount = 0;
275
- // eslint-disable-next-line no-constant-condition
276
- while (true) {
277
- const timeBucket = timeBuckets.shift();
278
- if (!timeBucket) {
279
- ux.error("No time bucket found");
280
- }
281
- if (!this.flags.json) {
282
- ux.action.start(`Fetching events for ${dayjs(timeBucket, TIME_BUCKET_PATTERN)}`);
283
- }
284
- let cursor = null;
285
- let found = false;
286
- do {
287
- if (!this.flags.json) {
288
- ux.action.status = `(${timeBucket}), cursor: ${cursor}`;
289
- }
290
- // eslint-disable-next-line no-await-in-loop
291
- await graphqlClient.validateToken();
292
- try {
293
- // eslint-disable-next-line no-await-in-loop
294
- const response = await graphqlClient.client.request(FETCH_EVENTS_GQL_QUERY, {
295
- afterEventId: lastEventId || undefined,
296
- aggregator,
297
- cursor: cursor || undefined,
298
- dataCoreId,
299
- eventTypes,
300
- timeBucket,
301
- ...(maxEvents > 0 ? { pageSize: maxEvents - eventsCount } : {})
302
- });
303
- cursor = response.datacore.fetchEvents.cursor;
304
- for (const event of response.datacore.fetchEvents.events) {
305
- found = true;
306
- observer.next(event);
307
- lastEventId = event.eventId;
308
- eventsCount++;
309
- // eslint-disable-next-line max-depth
310
- if (maxEvents > 0 && eventsCount >= maxEvents) {
311
- observer.complete();
312
- // eslint-disable-next-line max-depth
313
- if (!this.flags.json) {
314
- ux.action.stop(`Fetched total event count of ${eventsCount}, stopping`);
315
- }
316
- return;
317
- }
318
- }
319
- }
320
- catch (error) {
321
- // don't display error if token is expired
322
- if (error instanceof Error && error.message.includes("Token is expired")) {
323
- continue;
324
- }
325
- this.warn(`Error fetching events: ${error}`);
326
- }
327
- } while (cursor);
328
- if (timeBuckets.length === 0) {
329
- if (!live) {
330
- observer.complete();
331
- if (!this.flags.json) {
332
- ux.action.stop("Fetched all events, stopping");
333
- }
334
- return;
335
- }
336
- if (!liveMode) {
337
- !this.flags.json && this.warn("Reached last time bucket, switching to live mode");
338
- liveMode = true;
339
- }
340
- timeBuckets.push(createTimebucketDayjs(currentTime()).format(TIME_BUCKET_PATTERN));
341
- }
342
- if (liveMode && !found) {
343
- // eslint-disable-next-line no-await-in-loop
344
- await new Promise((resolve) => { setTimeout(resolve, 1000); });
345
- }
346
- }
347
- }
348
- }
@@ -1,18 +0,0 @@
1
- export interface SourceEvent {
2
- /** aggregator name (e.g. "website A") */
3
- aggregator: string;
4
- /** uuid of the data core */
5
- dataCore: string;
6
- /** time uuid of the event, when it was stored */
7
- eventId: string;
8
- /** event type (e.g. "letter clicked") */
9
- eventType: string;
10
- /** metadata related to the event (e.g. url, user id, etc.) */
11
- metadata: unknown;
12
- /** event data serialized to a string */
13
- payload: unknown;
14
- /** timebucket of the event, when it was stored */
15
- timeBucket: string;
16
- /** event timestamp, when this event is valid */
17
- validTime: string;
18
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,8 +0,0 @@
1
- import { GraphQLClient } from "graphql-request";
2
- export declare class QueryGraphQL {
3
- client: GraphQLClient;
4
- private readonly revalidate;
5
- private readonly url;
6
- constructor(url: string, token: string, revalidateClient: () => Promise<false | string>);
7
- validateToken(): Promise<void>;
8
- }
@@ -1,25 +0,0 @@
1
- import { GraphQLClient } from "graphql-request";
2
- export class QueryGraphQL {
3
- client;
4
- revalidate;
5
- url;
6
- constructor(url, token, revalidateClient) {
7
- this.client = new GraphQLClient(url, {
8
- headers: {
9
- authorization: `Bearer ${token}`,
10
- },
11
- });
12
- this.revalidate = revalidateClient;
13
- this.url = url;
14
- }
15
- async validateToken() {
16
- const newToken = await this.revalidate();
17
- if (newToken !== false) {
18
- this.client = new GraphQLClient(this.url, {
19
- headers: {
20
- authorization: `Bearer ${newToken}`,
21
- },
22
- });
23
- }
24
- }
25
- }
@@ -1,12 +0,0 @@
1
- export type FetchDataCoreResponse = {
2
- organization: {
3
- datacores: {
4
- id: string;
5
- }[];
6
- };
7
- };
8
- export type FetchDataCoreQueryInput = {
9
- dataCore: string;
10
- organization: string;
11
- };
12
- export declare const FETCH_DATA_CORE_GQL_QUERY: string;
@@ -1,10 +0,0 @@
1
- import { gql } from "graphql-request";
2
- export const FETCH_DATA_CORE_GQL_QUERY = gql `
3
- query FLOWCORE_CLI_FETCH_DATA_CORE($organization: String!, $dataCore: String!) {
4
- organization(search: {org: $organization}) {
5
- datacores(search: { name: $dataCore }) {
6
- id
7
- }
8
- }
9
- }
10
- `;
@@ -1,21 +0,0 @@
1
- export type FetchEventTypeRangeResponse = {
2
- datacore: {
3
- flowtypes: {
4
- aggregator: string;
5
- events: {
6
- catalog: {
7
- range: {
8
- firstTimeBucket: string;
9
- lastTimeBucket: string;
10
- };
11
- };
12
- name: string;
13
- }[];
14
- }[];
15
- };
16
- };
17
- export type FetchEventTypeRangeQueryInput = {
18
- aggregator: string;
19
- dataCoreId: string;
20
- };
21
- export declare const FETCH_EVENT_TYPE_RANGE_GQL_QUERY: string;
@@ -1,19 +0,0 @@
1
- import { gql } from "graphql-request";
2
- export const FETCH_EVENT_TYPE_RANGE_GQL_QUERY = gql `
3
- query FLOWCORE_CLI_FETCH_EVENT_TYPE_RANGE($dataCoreId: ID!, $aggregator: String!) {
4
- datacore(search: {id: $dataCoreId}) {
5
- flowtypes(search: {aggregator: $aggregator }) {
6
- aggregator
7
- events {
8
- name
9
- catalog {
10
- range {
11
- firstTimeBucket
12
- lastTimeBucket
13
- }
14
- }
15
- }
16
- }
17
- }
18
- }
19
- `;
@@ -1,28 +0,0 @@
1
- export type FetchEventsResponse = {
2
- datacore: {
3
- fetchEvents: {
4
- cursor: string;
5
- events: {
6
- aggregator: string;
7
- dataCore: string;
8
- eventId: string;
9
- eventType: string;
10
- metadata: string;
11
- payload: string;
12
- timeBucket: string;
13
- validTime: string;
14
- }[];
15
- };
16
- };
17
- };
18
- export type FetchEventsQueryInput = {
19
- afterEventId?: string;
20
- aggregator: string;
21
- beforeEventId?: string;
22
- cursor?: string;
23
- dataCoreId: string;
24
- eventTypes: string[];
25
- pageSize?: number;
26
- timeBucket: string;
27
- };
28
- export declare const FETCH_EVENTS_GQL_QUERY: string;
@@ -1,28 +0,0 @@
1
- import { gql } from "graphql-request";
2
- export const FETCH_EVENTS_GQL_QUERY = gql `
3
- query FLOWCORE_CLI_FETCH_EVENTS($dataCoreId: ID!, $aggregator: String!, $eventTypes: [String!]!, $timeBucket: String!, $cursor: String, $afterEventId: String, $beforeEventId: String, $pageSize: Int) {
4
- datacore(search: {id: $dataCoreId}) {
5
- fetchEvents(input: {
6
- aggregator: $aggregator,
7
- eventTypes: $eventTypes,
8
- timeBucket: $timeBucket
9
- cursor: $cursor
10
- afterEventId: $afterEventId
11
- beforeEventId: $beforeEventId
12
- pageSize: $pageSize
13
- }) {
14
- events {
15
- eventId
16
- timeBucket
17
- eventType
18
- aggregator
19
- dataCore
20
- metadata
21
- payload
22
- validTime
23
- }
24
- cursor
25
- }
26
- }
27
- }
28
- `;
@@ -1,18 +0,0 @@
1
- export type FetchCatalogIndexesResponse = {
2
- datacore: {
3
- fetchIndexes: {
4
- cursor: string;
5
- timeBuckets: string[];
6
- };
7
- };
8
- };
9
- export type FetchCatalogIndexesInput = {
10
- aggregator: string;
11
- cursor?: string;
12
- dataCoreId: string;
13
- eventType: string;
14
- fromTimeBucket?: string;
15
- pageSize?: number;
16
- toTimeBucket?: string;
17
- };
18
- export declare const FETCH_CATALOG_INDEXES_QUERY: string;
@@ -1,18 +0,0 @@
1
- import { gql } from "graphql-request";
2
- export const FETCH_CATALOG_INDEXES_QUERY = gql `
3
- query FLOWCORE_CLI_FETCH_CATALOG_INDEXES($dataCoreId: ID!, $aggregator: String!, $eventType: String!, $cursor: String, $fromTimeBucket: String, $toTimeBucket: String, $pageSize: Int) {
4
- datacore(search: {id: $dataCoreId}) {
5
- fetchIndexes(input: {
6
- aggregator: $aggregator,
7
- eventType: $eventType,
8
- cursor: $cursor
9
- fromTimeBucket: $fromTimeBucket
10
- toTimeBucket: $toTimeBucket
11
- pageSize: $pageSize
12
- }) {
13
- timeBuckets
14
- cursor
15
- }
16
- }
17
- }
18
- `;
@@ -1,5 +0,0 @@
1
- import { Dayjs } from "dayjs";
2
- export declare const TIME_BUCKET_PATTERN = "YYYYMMDDHHmmss";
3
- export declare const TIME_BUCKET_HOUR_PATTERN = "YYYYMMDDHH";
4
- export declare const createTimebucket: (date: Dayjs) => string;
5
- export declare const createTimebucketDayjs: (date: Dayjs) => Dayjs;
@@ -1,11 +0,0 @@
1
- import { TimeBucket } from "@flowcore/time-bucket";
2
- export const TIME_BUCKET_PATTERN = "YYYYMMDDHHmmss";
3
- export const TIME_BUCKET_HOUR_PATTERN = "YYYYMMDDHH";
4
- export const createTimebucket = (date) => {
5
- const timeBucket = TimeBucket.create(TIME_BUCKET_HOUR_PATTERN, TIME_BUCKET_PATTERN);
6
- return timeBucket(date).format(TIME_BUCKET_PATTERN);
7
- };
8
- export const createTimebucketDayjs = (date) => {
9
- const timeBucket = TimeBucket.create(TIME_BUCKET_HOUR_PATTERN, TIME_BUCKET_PATTERN);
10
- return timeBucket(date);
11
- };