@speedkit/cli 4.27.0 → 4.27.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
@@ -1,3 +1,10 @@
1
+ ## [4.27.1](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.27.0...v4.27.1) (2026-09-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * transfer flags from query:prewarm to auto-prewarm ([0dc4179](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/0dc41795018edd86fdad4215e66218be28b91654))
7
+
1
8
  # [4.27.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.26.0...v4.27.0) (2026-09-11)
2
9
 
3
10
 
package/README.md CHANGED
@@ -21,7 +21,7 @@ $ npm install -g @speedkit/cli
21
21
  $ sk COMMAND
22
22
  running command...
23
23
  $ sk (--version)
24
- @speedkit/cli/4.27.0 linux-x64 node-v22.23.2
24
+ @speedkit/cli/4.27.1 linux-x64 node-v22.23.2
25
25
  $ sk --help [COMMAND]
26
26
  USAGE
27
27
  $ sk COMMAND
@@ -103,9 +103,9 @@ Build and execute the prewarm query for a customer config and start a prewarm jo
103
103
 
104
104
  ```
105
105
  USAGE
106
- $ sk auto-prewarm CUSTOMERPATH [-c <value>] [-d <value>] [--excludeNoindex] [--excludeSuspicious] [--explain]
107
- [--hardNavigationsOnly] [--match <value>...] [-p <value> | [--device desktop|mobile|tablet... | -v <value>...] | ]
108
- [-k] [-q] [--verbose]
106
+ $ sk auto-prewarm CUSTOMERPATH [--workgroup <value>] [-c <value>] [-d <value>] [--excludeNoindex]
107
+ [--excludeSuspicious] [--explain] [--hardNavigationsOnly] [--excludeNotFound] [--limit <value>] [--match <value>...]
108
+ [--minHits <value>] [-p <value> | [--device desktop|mobile|tablet... | -v <value>...] | ] [-k] [-q] [--verbose]
109
109
 
110
110
  ARGUMENTS
111
111
  CUSTOMERPATH The customer config path
@@ -122,14 +122,19 @@ FLAGS
122
122
  requested in. A class not named is left out
123
123
  <options: desktop|mobile|tablet>
124
124
  --excludeNoindex Exclude page impressions of pages marked noindex
125
+ --excludeNotFound Leave out urls the origin answers with a 404 more often than not
125
126
  --excludeSuspicious Exclude page impressions Speed Kit classified as suspicious
126
127
  --explain Account for every rule the query leaves out, reduces or approximates
127
128
  --hardNavigationsOnly Exclude soft (SPA) navigations
129
+ --limit=<value> Keep only the most requested urls
128
130
  --match=<value>... Keep only urls whose path matches this regular expression, e.g. '^/p/'. The path is
129
131
  matched with its query string, the way a version 1 pathname rule matches it, so
130
132
  '[?&]size=' works too. Repeat the flag to keep the urls matching any of several patterns,
131
133
  and start a pattern with (?i) to match case-insensitively
134
+ --minHits=<value> Keep only urls requested at least this often in the window
132
135
  --verbose Log information about failed requests
136
+ --workgroup=<value> [env: SK_ATHENA_WORKGROUP] Athena workgroup to run the query in, e.g. 'prewarming'.
137
+ Defaults to the account's default workgroup
133
138
 
134
139
  DESCRIPTION
135
140
  Build and execute the prewarm query for a customer config and start a prewarm job from the resulting URLs — no CSV
@@ -143,6 +148,10 @@ EXAMPLES
143
148
  $ sk auto-prewarm customers/decathlon.de --device desktop,mobile
144
149
 
145
150
  $ sk auto-prewarm customers/decathlon.de -v MOBILE,DESKTOP
151
+
152
+ $ sk auto-prewarm customers/decathlon.de --limit 5000 --minHits 5
153
+
154
+ $ sk auto-prewarm customers/decathlon.de --workgroup prewarming
146
155
  ```
147
156
 
148
157
  ## `sk autocomplete [SHELL]`
@@ -252,8 +261,8 @@ Build a parameter query that can be executed in Athena
252
261
 
253
262
  ```
254
263
  USAGE
255
- $ sk build-parameter-query CUSTOMERPATH [-c <value>] [-d <value>] [--excludeNoindex] [--excludeSuspicious] [--explain]
256
- [--hardNavigationsOnly] [-e] [-q] [--bySet] [--minImpressions <value>]
264
+ $ sk build-parameter-query CUSTOMERPATH [--workgroup <value>] [-c <value>] [-d <value>] [--excludeNoindex]
265
+ [--excludeSuspicious] [--explain] [--hardNavigationsOnly] [-e] [-q] [--bySet] [--minImpressions <value>]
257
266
 
258
267
  ARGUMENTS
259
268
  CUSTOMERPATH The customer config path
@@ -270,6 +279,8 @@ FLAGS
270
279
  --explain Account for every rule the query leaves out, reduces or approximates
271
280
  --hardNavigationsOnly Exclude soft (SPA) navigations
272
281
  --minImpressions=<value> Leave out parameters seen on fewer page impressions than this
282
+ --workgroup=<value> [env: SK_ATHENA_WORKGROUP] Athena workgroup to run the query in, e.g. 'prewarming'.
283
+ Defaults to the account's default workgroup
273
284
 
274
285
  DESCRIPTION
275
286
  Build a parameter query that can be executed in Athena
@@ -291,9 +302,9 @@ Build a prewarm query that can be executed in Athena
291
302
 
292
303
  ```
293
304
  USAGE
294
- $ sk build-prewarm-query CUSTOMERPATH [-c <value>] [-d <value>] [--excludeNoindex] [--excludeSuspicious] [--explain]
295
- [--hardNavigationsOnly] [-q] [--device desktop|mobile|tablet... | -v <value>...] [--count | -e] [--excludeNotFound]
296
- [--limit <value>] [--match <value>...] [--minHits <value>]
305
+ $ sk build-prewarm-query CUSTOMERPATH [--workgroup <value>] [-c <value>] [-d <value>] [--excludeNoindex]
306
+ [--excludeSuspicious] [--explain] [--hardNavigationsOnly] [-q] [--device desktop|mobile|tablet... | -v <value>...]
307
+ [--excludeNotFound] [--limit <value>] [--match <value>...] [--minHits <value>] [--count | -e]
297
308
 
298
309
  ARGUMENTS
299
310
  CUSTOMERPATH The customer config path
@@ -322,6 +333,8 @@ FLAGS
322
333
  '[?&]size=' works too. Repeat the flag to keep the urls matching any of several patterns,
323
334
  and start a pattern with (?i) to match case-insensitively
324
335
  --minHits=<value> Keep only urls requested at least this often in the window
336
+ --workgroup=<value> [env: SK_ATHENA_WORKGROUP] Athena workgroup to run the query in, e.g. 'prewarming'.
337
+ Defaults to the account's default workgroup
325
338
 
326
339
  DESCRIPTION
327
340
  Build a prewarm query that can be executed in Athena
@@ -825,8 +838,8 @@ Build a parameter query that can be executed in Athena
825
838
 
826
839
  ```
827
840
  USAGE
828
- $ sk query parameter CUSTOMERPATH [-c <value>] [-d <value>] [--excludeNoindex] [--excludeSuspicious] [--explain]
829
- [--hardNavigationsOnly] [-e] [-q] [--bySet] [--minImpressions <value>]
841
+ $ sk query parameter CUSTOMERPATH [--workgroup <value>] [-c <value>] [-d <value>] [--excludeNoindex]
842
+ [--excludeSuspicious] [--explain] [--hardNavigationsOnly] [-e] [-q] [--bySet] [--minImpressions <value>]
830
843
 
831
844
  ARGUMENTS
832
845
  CUSTOMERPATH The customer config path
@@ -843,6 +856,8 @@ FLAGS
843
856
  --explain Account for every rule the query leaves out, reduces or approximates
844
857
  --hardNavigationsOnly Exclude soft (SPA) navigations
845
858
  --minImpressions=<value> Leave out parameters seen on fewer page impressions than this
859
+ --workgroup=<value> [env: SK_ATHENA_WORKGROUP] Athena workgroup to run the query in, e.g. 'prewarming'.
860
+ Defaults to the account's default workgroup
846
861
 
847
862
  DESCRIPTION
848
863
  Build a parameter query that can be executed in Athena
@@ -864,9 +879,9 @@ Build a prewarm query that can be executed in Athena
864
879
 
865
880
  ```
866
881
  USAGE
867
- $ sk query prewarm CUSTOMERPATH [-c <value>] [-d <value>] [--excludeNoindex] [--excludeSuspicious] [--explain]
868
- [--hardNavigationsOnly] [-q] [--device desktop|mobile|tablet... | -v <value>...] [--count | -e] [--excludeNotFound]
869
- [--limit <value>] [--match <value>...] [--minHits <value>]
882
+ $ sk query prewarm CUSTOMERPATH [--workgroup <value>] [-c <value>] [-d <value>] [--excludeNoindex]
883
+ [--excludeSuspicious] [--explain] [--hardNavigationsOnly] [-q] [--device desktop|mobile|tablet... | -v <value>...]
884
+ [--excludeNotFound] [--limit <value>] [--match <value>...] [--minHits <value>] [--count | -e]
870
885
 
871
886
  ARGUMENTS
872
887
  CUSTOMERPATH The customer config path
@@ -895,6 +910,8 @@ FLAGS
895
910
  '[?&]size=' works too. Repeat the flag to keep the urls matching any of several patterns,
896
911
  and start a pattern with (?i) to match case-insensitively
897
912
  --minHits=<value> Keep only urls requested at least this often in the window
913
+ --workgroup=<value> [env: SK_ATHENA_WORKGROUP] Athena workgroup to run the query in, e.g. 'prewarming'.
914
+ Defaults to the account's default workgroup
898
915
 
899
916
  DESCRIPTION
900
917
  Build a prewarm query that can be executed in Athena
@@ -8,19 +8,23 @@ export default class AutoPrewarm extends Command {
8
8
  static description: string;
9
9
  static examples: string[];
10
10
  static flags: {
11
- match: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
12
- device: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
13
- variation: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
14
11
  variationPath: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
12
  keepParameterSorting: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
13
  quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
14
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ excludeNotFound: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
17
+ match: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
18
+ minHits: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
19
+ device: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
20
+ variation: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
18
21
  excludeNoindex: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
22
  excludeSuspicious: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
23
  explain: import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
24
  hardNavigationsOnly: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
25
  days: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
23
26
  configName: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
27
+ workgroup: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
24
28
  };
25
29
  run(): Promise<void>;
26
30
  }
@@ -1,5 +1,5 @@
1
1
  import { Command, Flags } from "@oclif/core";
2
- import { CLI_CONFIG_NAME, CLI_CUSTOMER_CONFIG, CLI_QUERY_DAYS, CLI_QUERY_FILTERS, CLI_QUERY_PREWARM, CLI_QUERY_VARIATIONS, CLIParameters, CLIParametersChar, CLIParametersExample, } from "../models/cli-parameters.js";
2
+ import { CLI_ATHENA, CLI_CONFIG_NAME, CLI_CUSTOMER_CONFIG, CLI_QUERY_DAYS, CLI_QUERY_FILTERS, CLI_QUERY_PREWARM_LIST, CLIParameters, CLIParametersChar, CLIParametersExample, } from "../models/cli-parameters.js";
3
3
  import { CliConfig } from "../helpers/cli-config.js";
4
4
  import { AutoPreWarmFactory } from "../services/prewarm/index.js";
5
5
  export default class AutoPrewarm extends Command {
@@ -10,16 +10,20 @@ export default class AutoPrewarm extends Command {
10
10
  `$ sk auto-prewarm ${CLIParametersExample.CustomerPath} -${CLIParametersChar.ConfigName} ${CLIParametersExample.ConfigName}`,
11
11
  `$ sk auto-prewarm ${CLIParametersExample.CustomerPath} --${CLIParameters.Device} ${CLIParametersExample.Devices}`,
12
12
  `$ sk auto-prewarm ${CLIParametersExample.CustomerPath} -${CLIParametersChar.Variation} ${CLIParametersExample.Variations}`,
13
+ `$ sk auto-prewarm ${CLIParametersExample.CustomerPath} --${CLIParameters.Limit} 5000 --${CLIParameters.MinHits} 5`,
14
+ `$ sk auto-prewarm ${CLIParametersExample.CustomerPath} --${CLIParameters.Workgroup} prewarming`,
13
15
  ];
14
16
  static flags = {
17
+ ...CLI_ATHENA,
15
18
  ...CLI_CONFIG_NAME,
16
19
  ...CLI_QUERY_DAYS,
17
20
  ...CLI_QUERY_FILTERS,
18
- // The same narrowing and the same splitting the query command offers; the
19
- // rest of the pre-warm flags shape a list this command does not write.
20
- [CLIParameters.Match]: CLI_QUERY_PREWARM[CLIParameters.Match],
21
- [CLIParameters.Device]: CLI_QUERY_VARIATIONS[CLIParameters.Device],
22
- [CLIParameters.Variation]: CLI_QUERY_VARIATIONS[CLIParameters.Variation],
21
+ // Every flag that shapes the pre-warm list, not a subset of them: this
22
+ // command builds the same query `sk query prewarm` does, and a list it
23
+ // could not narrow the same way could not be counted by that command
24
+ // either — the two would describe different runs. `--count` is not among
25
+ // them: this command warms the list rather than reporting its size.
26
+ ...CLI_QUERY_PREWARM_LIST,
23
27
  // A variations file says what `--variation` says, read from disk.
24
28
  [CLIParameters.VariationPath]: Flags.file({
25
29
  char: CLIParametersChar.VariationPath,
@@ -42,21 +46,25 @@ export default class AutoPrewarm extends Command {
42
46
  }),
43
47
  };
44
48
  async run() {
45
- const { args: { customerPath }, flags: { configName, days, device, excludeNoindex, excludeSuspicious, hardNavigationsOnly, keepParameterSorting, match, quiet, variation, variationPath, verbose, }, } = await this.parse(AutoPrewarm);
49
+ const { args: { customerPath }, flags: { configName, days, device, excludeNoindex, excludeNotFound, excludeSuspicious, hardNavigationsOnly, keepParameterSorting, limit, match, minHits, quiet, variation, variationPath, verbose, workgroup, }, } = await this.parse(AutoPrewarm);
46
50
  const service = await new AutoPreWarmFactory({
47
51
  customerPath,
48
52
  configName,
49
53
  days,
50
54
  device,
51
55
  excludeNoindex,
56
+ excludeNotFound,
52
57
  excludeSuspicious,
53
58
  hardNavigationsOnly,
59
+ limit,
54
60
  match,
61
+ minHits,
55
62
  variation,
56
63
  variationPath,
57
64
  sortParameters: !keepParameterSorting,
58
65
  quiet,
59
66
  verbose,
67
+ workgroup,
60
68
  isWindows: this.config.windows,
61
69
  }, new CliConfig(this.config).load()).getService();
62
70
  await service.run();
@@ -21,6 +21,7 @@ export default class QueryParameter extends Command {
21
21
  hardNavigationsOnly: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
22
  days: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
23
23
  configName: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
24
+ workgroup: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
24
25
  };
25
26
  run(): Promise<void>;
26
27
  }
@@ -1,5 +1,5 @@
1
1
  import { Command } from "@oclif/core";
2
- import { CLI_CONFIG_NAME, CLI_CUSTOMER_CONFIG, CLI_QUERY_DAYS, CLI_QUERY_FILTERS, CLI_QUERY_OUTPUT, CLI_QUERY_PARAMETER, CLIParameters, CLIParametersChar, CLIParametersExample, } from "../../models/cli-parameters.js";
2
+ import { CLI_ATHENA, CLI_CONFIG_NAME, CLI_CUSTOMER_CONFIG, CLI_QUERY_DAYS, CLI_QUERY_FILTERS, CLI_QUERY_OUTPUT, CLI_QUERY_PARAMETER, CLIParameters, CLIParametersChar, CLIParametersExample, } from "../../models/cli-parameters.js";
3
3
  import { QueryType } from "../../services/query-builder/query-builder-model.js";
4
4
  import { runQuery } from "../../services/query-builder/query-command.js";
5
5
  export default class QueryParameter extends Command {
@@ -14,6 +14,7 @@ export default class QueryParameter extends Command {
14
14
  `$ sk query parameter ${CLIParametersExample.CustomerPath} --${CLIParameters.Explain}`,
15
15
  ];
16
16
  static flags = {
17
+ ...CLI_ATHENA,
17
18
  ...CLI_CONFIG_NAME,
18
19
  ...CLI_QUERY_DAYS,
19
20
  ...CLI_QUERY_FILTERS,
@@ -26,6 +26,7 @@ export default class QueryPrewarm extends Command {
26
26
  hardNavigationsOnly: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
27
  days: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
28
28
  configName: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
29
+ workgroup: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
29
30
  };
30
31
  run(): Promise<void>;
31
32
  }
@@ -1,5 +1,5 @@
1
1
  import { Command } from "@oclif/core";
2
- import { CLI_CONFIG_NAME, CLI_CUSTOMER_CONFIG, CLI_QUERY_DAYS, CLI_QUERY_FILTERS, CLI_QUERY_OUTPUT, CLI_QUERY_PREWARM, CLIParameters, CLIParametersChar, CLIParametersExample, } from "../../models/cli-parameters.js";
2
+ import { CLI_ATHENA, CLI_CONFIG_NAME, CLI_CUSTOMER_CONFIG, CLI_QUERY_DAYS, CLI_QUERY_FILTERS, CLI_QUERY_OUTPUT, CLI_QUERY_PREWARM, CLIParameters, CLIParametersChar, CLIParametersExample, } from "../../models/cli-parameters.js";
3
3
  import { QueryType } from "../../services/query-builder/query-builder-model.js";
4
4
  import { runQuery } from "../../services/query-builder/query-command.js";
5
5
  export default class QueryPrewarm extends Command {
@@ -18,6 +18,7 @@ export default class QueryPrewarm extends Command {
18
18
  `$ sk query prewarm ${CLIParametersExample.CustomerPath} --${CLIParameters.Count}`,
19
19
  ];
20
20
  static flags = {
21
+ ...CLI_ATHENA,
21
22
  ...CLI_CONFIG_NAME,
22
23
  ...CLI_QUERY_DAYS,
23
24
  ...CLI_QUERY_FILTERS,
@@ -38,6 +38,7 @@ export declare enum CLIParameters {
38
38
  Variation = "variation",
39
39
  VariationPath = "variationPath",
40
40
  Verbose = "verbose",
41
+ Workgroup = "workgroup",
41
42
  useTestConfig = "useTestConfig"
42
43
  }
43
44
  export declare enum CLIParametersChar {
@@ -136,7 +137,27 @@ export declare const CLI_QUERY_VARIATIONS: {
136
137
  device: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
137
138
  variation: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
138
139
  };
139
- /** What the pre-warm query keeps of a long tail that is mostly seen once. */
140
+ /**
141
+ * What the pre-warm query keeps of a long tail that is mostly seen once.
142
+ *
143
+ * Every flag here shapes the list itself, so a command that builds that list
144
+ * takes all of them — `sk auto-prewarm` included, or a count could describe a
145
+ * list the pre-warmer would never produce.
146
+ */
147
+ export declare const CLI_QUERY_PREWARM_LIST: {
148
+ excludeNotFound: import("@oclif/core/interfaces").BooleanFlag<boolean>;
149
+ limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
150
+ match: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
151
+ minHits: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
152
+ device: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
153
+ variation: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
154
+ };
155
+ /**
156
+ * The pre-warm query flags in full: the list-shaping ones plus `--count`, which
157
+ * reports the list's size instead of returning it. Only a command that can
158
+ * answer with a count takes this one — `sk auto-prewarm` warms the list, so it
159
+ * takes {@link CLI_QUERY_PREWARM_LIST} instead.
160
+ */
140
161
  export declare const CLI_QUERY_PREWARM: {
141
162
  count: import("@oclif/core/interfaces").BooleanFlag<boolean>;
142
163
  excludeNotFound: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -146,6 +167,18 @@ export declare const CLI_QUERY_PREWARM: {
146
167
  device: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
147
168
  variation: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
148
169
  };
170
+ /**
171
+ * Where a query that is executed actually runs.
172
+ *
173
+ * Athena resolves the account's default workgroup when none is named, which is
174
+ * only right where the credentials are allowed to use it — a role scoped to one
175
+ * workgroup is refused on any other, and the result location is a workgroup
176
+ * setting too. `SK_ATHENA_WORKGROUP` lets a CI job set it once for every
177
+ * command in the job.
178
+ */
179
+ export declare const CLI_ATHENA: {
180
+ workgroup: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
181
+ };
149
182
  /** How the parameter query presents what it found. */
150
183
  export declare const CLI_QUERY_PARAMETER: {
151
184
  bySet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -45,6 +45,7 @@ export var CLIParameters;
45
45
  CLIParameters["Variation"] = "variation";
46
46
  CLIParameters["VariationPath"] = "variationPath";
47
47
  CLIParameters["Verbose"] = "verbose";
48
+ CLIParameters["Workgroup"] = "workgroup";
48
49
  CLIParameters["useTestConfig"] = "useTestConfig";
49
50
  })(CLIParameters || (CLIParameters = {}));
50
51
  /* eslint-disable @typescript-eslint/no-duplicate-enum-values */
@@ -197,14 +198,15 @@ export const CLI_QUERY_VARIATIONS = {
197
198
  required: false,
198
199
  }),
199
200
  };
200
- /** What the pre-warm query keeps of a long tail that is mostly seen once. */
201
- export const CLI_QUERY_PREWARM = {
201
+ /**
202
+ * What the pre-warm query keeps of a long tail that is mostly seen once.
203
+ *
204
+ * Every flag here shapes the list itself, so a command that builds that list
205
+ * takes all of them — `sk auto-prewarm` included, or a count could describe a
206
+ * list the pre-warmer would never produce.
207
+ */
208
+ export const CLI_QUERY_PREWARM_LIST = {
202
209
  ...CLI_QUERY_VARIATIONS,
203
- [CLIParameters.Count]: Flags.boolean({
204
- default: false,
205
- description: "Run the query and report how large the list is instead of what is in it: urls, the impressions they stand for, and a row per variation where the list carries variations. Every other flag still applies, so this counts the list the same command would produce",
206
- exclusive: [CLIParameters.Execute],
207
- }),
208
210
  [CLIParameters.ExcludeNotFound]: Flags.boolean({
209
211
  default: false,
210
212
  description: "Leave out urls the origin answers with a 404 more often than not",
@@ -234,6 +236,36 @@ export const CLI_QUERY_PREWARM = {
234
236
  required: false,
235
237
  }),
236
238
  };
239
+ /**
240
+ * The pre-warm query flags in full: the list-shaping ones plus `--count`, which
241
+ * reports the list's size instead of returning it. Only a command that can
242
+ * answer with a count takes this one — `sk auto-prewarm` warms the list, so it
243
+ * takes {@link CLI_QUERY_PREWARM_LIST} instead.
244
+ */
245
+ export const CLI_QUERY_PREWARM = {
246
+ ...CLI_QUERY_PREWARM_LIST,
247
+ [CLIParameters.Count]: Flags.boolean({
248
+ default: false,
249
+ description: "Run the query and report how large the list is instead of what is in it: urls, the impressions they stand for, and a row per variation where the list carries variations. Every other flag still applies, so this counts the list the same command would produce",
250
+ exclusive: [CLIParameters.Execute],
251
+ }),
252
+ };
253
+ /**
254
+ * Where a query that is executed actually runs.
255
+ *
256
+ * Athena resolves the account's default workgroup when none is named, which is
257
+ * only right where the credentials are allowed to use it — a role scoped to one
258
+ * workgroup is refused on any other, and the result location is a workgroup
259
+ * setting too. `SK_ATHENA_WORKGROUP` lets a CI job set it once for every
260
+ * command in the job.
261
+ */
262
+ export const CLI_ATHENA = {
263
+ [CLIParameters.Workgroup]: Flags.string({
264
+ description: "Athena workgroup to run the query in, e.g. 'prewarming'. Defaults to the account's default workgroup",
265
+ env: "SK_ATHENA_WORKGROUP",
266
+ required: false,
267
+ }),
268
+ };
237
269
  /** How the parameter query presents what it found. */
238
270
  export const CLI_QUERY_PARAMETER = {
239
271
  [CLIParameters.BySet]: Flags.boolean({
@@ -1,13 +1,16 @@
1
1
  import { AthenaService } from "./athena-query-service.js";
2
2
  export declare class AthenaServiceFactory {
3
3
  private app?;
4
+ private workgroup?;
4
5
  service?: AthenaService;
5
6
  /**
6
7
  * @param app - the app to query. Enables the Baqend native query path (app
7
8
  * token only) as a fallback when no AWS login is present. Without it, only
8
9
  * the AWS path is available.
10
+ * @param workgroup - Athena workgroup for the AWS path. The Baqend path has
11
+ * no such notion, so it is ignored there.
9
12
  */
10
- constructor(app?: string);
13
+ constructor(app?: string, workgroup?: string);
11
14
  getService(): Promise<AthenaService>;
12
15
  /**
13
16
  * Prefer direct AWS Athena whenever AWS credentials are present — they
@@ -8,14 +8,18 @@ import { BaqendAthenaService } from "./baqend-athena-service.js";
8
8
  import { EntityManagerFactory } from "../config-api/entity-manager-factory.js";
9
9
  export class AthenaServiceFactory {
10
10
  app;
11
+ workgroup;
11
12
  service;
12
13
  /**
13
14
  * @param app - the app to query. Enables the Baqend native query path (app
14
15
  * token only) as a fallback when no AWS login is present. Without it, only
15
16
  * the AWS path is available.
17
+ * @param workgroup - Athena workgroup for the AWS path. The Baqend path has
18
+ * no such notion, so it is ignored there.
16
19
  */
17
- constructor(app) {
20
+ constructor(app, workgroup) {
18
21
  this.app = app;
22
+ this.workgroup = workgroup;
19
23
  }
20
24
  async getService() {
21
25
  if (!this.service) {
@@ -33,8 +37,10 @@ export class AthenaServiceFactory {
33
37
  const cli = new CliServiceFactory().getService();
34
38
  const client = await this.tryGetAthenaClient();
35
39
  if (client) {
36
- cli.comment("Using AWS credentials for Athena queries.");
37
- return new AwsAthenaService(client, cli);
40
+ cli.comment(this.workgroup
41
+ ? `Using AWS credentials for Athena queries, workgroup ${this.workgroup}.`
42
+ : "Using AWS credentials for Athena queries.");
43
+ return new AwsAthenaService(client, cli, this.workgroup);
38
44
  }
39
45
  if (this.app) {
40
46
  return new BaqendAthenaService(this.app, new EntityManagerFactory(), cli);
@@ -10,7 +10,17 @@ import { CliServiceInterface } from "../cli/index.js";
10
10
  export declare class AwsAthenaService implements AthenaService {
11
11
  private client;
12
12
  private cli;
13
- constructor(client: AthenaClient, cli: CliServiceInterface);
13
+ /**
14
+ * Athena falls back to the account's default workgroup when this is unset,
15
+ * which is only right where the credentials are allowed to use it.
16
+ */
17
+ private workgroup?;
18
+ constructor(client: AthenaClient, cli: CliServiceInterface,
19
+ /**
20
+ * Athena falls back to the account's default workgroup when this is unset,
21
+ * which is only right where the credentials are allowed to use it.
22
+ */
23
+ workgroup?: string);
14
24
  getResult<T>(query: string, parameters?: string[], maxAgeInMinutes?: number): Promise<T[]>;
15
25
  /** The query, from sending it off to the rows it produced. */
16
26
  private runAndFetch;
@@ -11,9 +11,16 @@ import { safe } from "../../helpers/safe.js";
11
11
  export class AwsAthenaService {
12
12
  client;
13
13
  cli;
14
- constructor(client, cli) {
14
+ workgroup;
15
+ constructor(client, cli,
16
+ /**
17
+ * Athena falls back to the account's default workgroup when this is unset,
18
+ * which is only right where the credentials are allowed to use it.
19
+ */
20
+ workgroup) {
15
21
  this.client = client;
16
22
  this.cli = cli;
23
+ this.workgroup = workgroup;
17
24
  }
18
25
  async getResult(query, parameters = [], maxAgeInMinutes = DEFAULT_MAX_AGE_IN_MINUTES) {
19
26
  this.cli.startAction("ATHENA:QUERY", "execute athena query");
@@ -108,6 +115,10 @@ export class AwsAthenaService {
108
115
  MaxAgeInMinutes: maxAgeInMinutes,
109
116
  },
110
117
  },
118
+ // Omitted rather than sent empty: Athena reads an absent WorkGroup as
119
+ // "the default one", and an empty string as a workgroup that does not
120
+ // exist.
121
+ ...(this.workgroup ? { WorkGroup: this.workgroup } : {}),
111
122
  });
112
123
  const response = await this.client.send(command);
113
124
  await this.waitOnResponse(response.QueryExecutionId);
@@ -14,9 +14,10 @@ function recordingCli() {
14
14
  return { calls, cli };
15
15
  }
16
16
  /** An Athena that answers every execution with the given state. */
17
- function clientAnswering(state, reason) {
17
+ function clientAnswering(state, reason, sent = []) {
18
18
  return {
19
19
  send: async (command) => {
20
+ sent.push(command);
20
21
  if (command instanceof StartQueryExecutionCommand) {
21
22
  return { QueryExecutionId: "query-1" };
22
23
  }
@@ -62,6 +63,24 @@ describe("AwsAthenaService", () => {
62
63
  expect(result.message).to.contain("INVALID_ARGUMENTS: nope");
63
64
  expect(calls).to.deep.equal(["start:ATHENA:QUERY", "fail:ATHENA:QUERY"]);
64
65
  });
66
+ it("should run in the workgroup it was given", async () => {
67
+ const { cli } = recordingCli();
68
+ const sent = [];
69
+ const service = new AwsAthenaService(clientAnswering("SUCCEEDED", undefined, sent), cli, "prewarming");
70
+ await service.getResult("select 1", [], 0);
71
+ const start = sent.find((command) => command instanceof StartQueryExecutionCommand);
72
+ expect(start.input.WorkGroup).to.equal("prewarming");
73
+ });
74
+ it("should leave the workgroup out when none was given", async () => {
75
+ // Athena reads an absent WorkGroup as the account default; an empty string
76
+ // is a workgroup that does not exist, so the key has to be gone entirely.
77
+ const { cli } = recordingCli();
78
+ const sent = [];
79
+ const service = new AwsAthenaService(clientAnswering("SUCCEEDED", undefined, sent), cli);
80
+ await service.getResult("select 1", [], 0);
81
+ const start = sent.find((command) => command instanceof StartQueryExecutionCommand);
82
+ expect(start.input).to.not.have.property("WorkGroup");
83
+ });
65
84
  it("should not pass a failed query off as an empty result", async () => {
66
85
  const { cli } = recordingCli();
67
86
  const service = new AwsAthenaService(clientAnswering("CANCELLED"), cli);
@@ -6,8 +6,16 @@ export interface AutoPreWarmContext extends QueryFilterOptions {
6
6
  readonly configName: string;
7
7
  /** Device classes to warm each url in the variations it was requested in. */
8
8
  readonly device?: readonly string[];
9
+ /** Drop urls the origin mostly answers with a 404. */
10
+ readonly excludeNotFound?: boolean;
11
+ /** Keep only the most requested urls. */
12
+ readonly limit?: number;
9
13
  /** Regular expressions the pre-warmed urls have to match. */
10
14
  readonly match?: readonly string[];
15
+ /** Keep only urls requested at least this often in the window. */
16
+ readonly minHits?: number;
17
+ /** Athena workgroup the query runs in. */
18
+ readonly workgroup?: string;
11
19
  /** Variations to pair every url with, when no traffic can reveal them. */
12
20
  readonly variation?: readonly string[];
13
21
  readonly variationPath?: string;
@@ -34,13 +34,17 @@ export class AutoPreWarmFactory {
34
34
  days: this.context.days,
35
35
  devices: normalizeDevices(this.context.device),
36
36
  excludeNoindex: this.context.excludeNoindex,
37
+ excludeNotFound: this.context.excludeNotFound,
37
38
  excludeSuspicious: this.context.excludeSuspicious,
38
39
  execute: true,
39
40
  hardNavigationsOnly: this.context.hardNavigationsOnly,
40
41
  isWindows: this.context.isWindows,
42
+ limit: this.context.limit,
41
43
  match: this.context.match,
44
+ minHits: this.context.minHits,
42
45
  quiet: this.context.quiet,
43
46
  variations: this.context.variation,
47
+ workgroup: this.context.workgroup,
44
48
  }, this.userConfig).buildService(QueryType.prewarm);
45
49
  const app = queryService.app;
46
50
  const rows = await queryService.execute();
@@ -47,7 +47,7 @@ export class QueryBuilderFactory {
47
47
  // The Athena service is only needed when the query is executed directly —
48
48
  // which `--count` is, a count query being of no use as text.
49
49
  const athenaService = this.context.execute || this.context.count
50
- ? await new AthenaServiceFactory(app).getService()
50
+ ? await new AthenaServiceFactory(app, this.context.workgroup).getService()
51
51
  : undefined;
52
52
  return new QueryBuilderService(serviceContext, parseRuleSets(speedKitConfig), cli, athenaService);
53
53
  }
@@ -33,4 +33,6 @@ export interface QueryBuilderFactoryContext extends ParameterOptions, PrewarmOpt
33
33
  readonly explain?: boolean;
34
34
  readonly isWindows?: boolean;
35
35
  readonly quiet?: boolean;
36
+ /** Athena workgroup to execute in, when the query is executed at all. */
37
+ readonly workgroup?: string;
36
38
  }
@@ -14,6 +14,7 @@ export interface QueryCommandFlags extends ParameterOptions, Omit<PrewarmOptions
14
14
  readonly explain?: boolean;
15
15
  readonly quiet?: boolean;
16
16
  readonly variation?: readonly string[];
17
+ readonly workgroup?: string;
17
18
  }
18
19
  /**
19
20
  * Builds one of the config-derived queries and hands it over.
@@ -30,6 +30,7 @@ export async function runQuery(queryType, customerPath, flags, config) {
30
30
  minImpressions: flags.minImpressions,
31
31
  quiet: flags.quiet,
32
32
  variations: flags.variation,
33
+ workgroup: flags.workgroup,
33
34
  }, new CliConfig(config).load()).buildService(queryType);
34
35
  await service.run();
35
36
  }
@@ -14,9 +14,20 @@
14
14
  "$ sk auto-prewarm <customerPath> -c <configName>",
15
15
  "$ sk auto-prewarm customers/decathlon.de -c production",
16
16
  "$ sk auto-prewarm customers/decathlon.de --device desktop,mobile",
17
- "$ sk auto-prewarm customers/decathlon.de -v MOBILE,DESKTOP"
17
+ "$ sk auto-prewarm customers/decathlon.de -v MOBILE,DESKTOP",
18
+ "$ sk auto-prewarm customers/decathlon.de --limit 5000 --minHits 5",
19
+ "$ sk auto-prewarm customers/decathlon.de --workgroup prewarming"
18
20
  ],
19
21
  "flags": {
22
+ "workgroup": {
23
+ "description": "Athena workgroup to run the query in, e.g. 'prewarming'. Defaults to the account's default workgroup",
24
+ "env": "SK_ATHENA_WORKGROUP",
25
+ "name": "workgroup",
26
+ "required": false,
27
+ "hasDynamicHelp": false,
28
+ "multiple": false,
29
+ "type": "option"
30
+ },
20
31
  "configName": {
21
32
  "char": "c",
22
33
  "description": "The costumer config name",
@@ -60,14 +71,6 @@
60
71
  "allowNo": false,
61
72
  "type": "boolean"
62
73
  },
63
- "match": {
64
- "description": "Keep only urls whose path matches this regular expression, e.g. '^/p/'. The path is matched with its query string, the way a version 1 pathname rule matches it, so '[?&]size=' works too. Repeat the flag to keep the urls matching any of several patterns, and start a pattern with (?i) to match case-insensitively",
65
- "name": "match",
66
- "required": false,
67
- "hasDynamicHelp": false,
68
- "multiple": true,
69
- "type": "option"
70
- },
71
74
  "device": {
72
75
  "description": "Split the list by device class, so every url is warmed in the variations it was actually requested in. A class not named is left out",
73
76
  "exclusive": [
@@ -98,6 +101,36 @@
98
101
  "multiple": true,
99
102
  "type": "option"
100
103
  },
104
+ "excludeNotFound": {
105
+ "description": "Leave out urls the origin answers with a 404 more often than not",
106
+ "name": "excludeNotFound",
107
+ "allowNo": false,
108
+ "type": "boolean"
109
+ },
110
+ "limit": {
111
+ "description": "Keep only the most requested urls",
112
+ "name": "limit",
113
+ "required": false,
114
+ "hasDynamicHelp": false,
115
+ "multiple": false,
116
+ "type": "option"
117
+ },
118
+ "match": {
119
+ "description": "Keep only urls whose path matches this regular expression, e.g. '^/p/'. The path is matched with its query string, the way a version 1 pathname rule matches it, so '[?&]size=' works too. Repeat the flag to keep the urls matching any of several patterns, and start a pattern with (?i) to match case-insensitively",
120
+ "name": "match",
121
+ "required": false,
122
+ "hasDynamicHelp": false,
123
+ "multiple": true,
124
+ "type": "option"
125
+ },
126
+ "minHits": {
127
+ "description": "Keep only urls requested at least this often in the window",
128
+ "name": "minHits",
129
+ "required": false,
130
+ "hasDynamicHelp": false,
131
+ "multiple": false,
132
+ "type": "option"
133
+ },
101
134
  "variationPath": {
102
135
  "char": "p",
103
136
  "description": "path to variations.csv",
@@ -1309,6 +1342,15 @@
1309
1342
  "$ sk query parameter customers/decathlon.de --explain"
1310
1343
  ],
1311
1344
  "flags": {
1345
+ "workgroup": {
1346
+ "description": "Athena workgroup to run the query in, e.g. 'prewarming'. Defaults to the account's default workgroup",
1347
+ "env": "SK_ATHENA_WORKGROUP",
1348
+ "name": "workgroup",
1349
+ "required": false,
1350
+ "hasDynamicHelp": false,
1351
+ "multiple": false,
1352
+ "type": "option"
1353
+ },
1312
1354
  "configName": {
1313
1355
  "char": "c",
1314
1356
  "description": "The costumer config name",
@@ -1420,6 +1462,15 @@
1420
1462
  "$ sk query prewarm customers/decathlon.de --count"
1421
1463
  ],
1422
1464
  "flags": {
1465
+ "workgroup": {
1466
+ "description": "Athena workgroup to run the query in, e.g. 'prewarming'. Defaults to the account's default workgroup",
1467
+ "env": "SK_ATHENA_WORKGROUP",
1468
+ "name": "workgroup",
1469
+ "required": false,
1470
+ "hasDynamicHelp": false,
1471
+ "multiple": false,
1472
+ "type": "option"
1473
+ },
1423
1474
  "configName": {
1424
1475
  "char": "c",
1425
1476
  "description": "The costumer config name",
@@ -1507,15 +1558,6 @@
1507
1558
  "multiple": true,
1508
1559
  "type": "option"
1509
1560
  },
1510
- "count": {
1511
- "description": "Run the query and report how large the list is instead of what is in it: urls, the impressions they stand for, and a row per variation where the list carries variations. Every other flag still applies, so this counts the list the same command would produce",
1512
- "exclusive": [
1513
- "execute"
1514
- ],
1515
- "name": "count",
1516
- "allowNo": false,
1517
- "type": "boolean"
1518
- },
1519
1561
  "excludeNotFound": {
1520
1562
  "description": "Leave out urls the origin answers with a 404 more often than not",
1521
1563
  "name": "excludeNotFound",
@@ -1545,6 +1587,15 @@
1545
1587
  "hasDynamicHelp": false,
1546
1588
  "multiple": false,
1547
1589
  "type": "option"
1590
+ },
1591
+ "count": {
1592
+ "description": "Run the query and report how large the list is instead of what is in it: urls, the impressions they stand for, and a row per variation where the list carries variations. Every other flag still applies, so this counts the list the same command would produce",
1593
+ "exclusive": [
1594
+ "execute"
1595
+ ],
1596
+ "name": "count",
1597
+ "allowNo": false,
1598
+ "type": "boolean"
1548
1599
  }
1549
1600
  },
1550
1601
  "hasDynamicHelp": false,
@@ -1564,5 +1615,5 @@
1564
1615
  ]
1565
1616
  }
1566
1617
  },
1567
- "version": "4.27.0"
1618
+ "version": "4.27.1"
1568
1619
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@speedkit/cli",
3
3
  "description": "Speed Kit CLI",
4
- "version": "4.27.0",
4
+ "version": "4.27.1",
5
5
  "author": {
6
6
  "name": "Baqend.com",
7
7
  "email": "info@baqend.com"