@speedkit/cli 4.11.0 → 4.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 +9 -0
- package/README.md +1 -1
- package/dist/commands/generate-pop-config.js +1 -1
- package/dist/services/athena/athena-query-service.d.ts +30 -0
- package/dist/services/athena/athena-query-service.js +13 -0
- package/dist/services/athena/athena-service-factory.d.ts +18 -4
- package/dist/services/athena/athena-service-factory.js +35 -15
- package/dist/services/athena/athena-service.d.ts +8 -1
- package/dist/services/athena/athena-service.js +7 -1
- package/dist/services/athena/baqend-athena-service.d.ts +30 -0
- package/dist/services/athena/baqend-athena-service.js +92 -0
- package/dist/services/athena/index.d.ts +2 -0
- package/dist/services/athena/index.js +2 -0
- package/dist/services/onboarding/dashboard/index.js +2 -1
- package/dist/services/onboarding/onboarding-service-factory.js +3 -3
- package/dist/services/pop-config/pop-config-factory.d.ts +1 -1
- package/dist/services/pop-config/pop-config-factory.js +2 -2
- package/dist/services/pop-config/pop-config-service.js +2 -1
- package/dist/services/query-builder/query/parameter.js +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
# [4.12.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.11.0...v4.12.0) (2026-06-19)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* adapt queryBuilderParam ([7cca445](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/7cca445b200a96ee2fb4d1241dd803fefab0a1e4))
|
|
7
|
+
* prefer direct AWS over baqend Athena api ([b388456](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/b388456e4a0a073bac1c54e5e33b3178f375b7d7))
|
|
8
|
+
* prefere baqendAthenaApi ofer native awsLogin ([4ce13eb](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/4ce13eb5fc9332fa140d474d256418ed8866910c))
|
|
9
|
+
|
|
1
10
|
# [4.11.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.10.0...v4.11.0) (2026-06-19)
|
|
2
11
|
|
|
3
12
|
|
package/README.md
CHANGED
|
@@ -152,7 +152,7 @@ export default class GeneratePopConfig extends Command {
|
|
|
152
152
|
async run() {
|
|
153
153
|
const { args: { app }, flags: { coverage, deploy, "pop-limit": popLimit, "traffic-share": minimalShare, "use-rum": useRum, "force-shield": forceShield, }, } = await this.parse(GeneratePopConfig);
|
|
154
154
|
// @todo refactor businessCode from this command to src/pop-config/pop-config-service
|
|
155
|
-
const popConfigService = await new PopConfigFactory().getService();
|
|
155
|
+
const popConfigService = await new PopConfigFactory().getService(app);
|
|
156
156
|
const result = await popConfigService.getUsedPopsPerOrigin(app, useRum);
|
|
157
157
|
const originStats = this.generateOriginStats(result)
|
|
158
158
|
.filter((stats) => {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics buckets that exist in every app and map 1:1 to the Athena
|
|
3
|
+
* databases. Passed to {@link AthenaService.getResult} so the Baqend native
|
|
4
|
+
* query path knows which `/db/:bucket/query` endpoint to hit. The database is
|
|
5
|
+
* derived server-side from the part before the dot (e.g. `fastly.Logs` -> the
|
|
6
|
+
* `fastly` database).
|
|
7
|
+
*/
|
|
8
|
+
export declare enum AthenaBucket {
|
|
9
|
+
FastlyLogs = "fastly.Logs",
|
|
10
|
+
RumPi = "rum.Pi",
|
|
11
|
+
RumPiAgg = "rum.PiAgg"
|
|
12
|
+
}
|
|
13
|
+
export type AthenaParameter = boolean | number | string;
|
|
14
|
+
/**
|
|
15
|
+
* Contract shared by every Athena query implementation (AWS SDK, Baqend native
|
|
16
|
+
* query, and the fallback that combines them). Consumers depend on this
|
|
17
|
+
* interface, never on a concrete class.
|
|
18
|
+
*/
|
|
19
|
+
export interface AthenaService {
|
|
20
|
+
/**
|
|
21
|
+
* Run a query and return the rows as objects keyed by column name.
|
|
22
|
+
*
|
|
23
|
+
* @param query - the SQL to execute
|
|
24
|
+
* @param parameters - values substituted for the `?` placeholders, in order
|
|
25
|
+
* @param maxAgeInMinutes - result-reuse cache window
|
|
26
|
+
* @param bucket - the analytics bucket the query targets. Required for the
|
|
27
|
+
* Baqend native query path; when omitted the AWS path is used.
|
|
28
|
+
*/
|
|
29
|
+
getResult<T>(query: string, parameters?: AthenaParameter[], maxAgeInMinutes?: number, bucket?: AthenaBucket): Promise<T[]>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics buckets that exist in every app and map 1:1 to the Athena
|
|
3
|
+
* databases. Passed to {@link AthenaService.getResult} so the Baqend native
|
|
4
|
+
* query path knows which `/db/:bucket/query` endpoint to hit. The database is
|
|
5
|
+
* derived server-side from the part before the dot (e.g. `fastly.Logs` -> the
|
|
6
|
+
* `fastly` database).
|
|
7
|
+
*/
|
|
8
|
+
export var AthenaBucket;
|
|
9
|
+
(function (AthenaBucket) {
|
|
10
|
+
AthenaBucket["FastlyLogs"] = "fastly.Logs";
|
|
11
|
+
AthenaBucket["RumPi"] = "rum.Pi";
|
|
12
|
+
AthenaBucket["RumPiAgg"] = "rum.PiAgg";
|
|
13
|
+
})(AthenaBucket || (AthenaBucket = {}));
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
import { AthenaService } from "./athena-service.js";
|
|
1
|
+
import { AthenaService } from "./athena-query-service.js";
|
|
2
2
|
export declare class AthenaServiceFactory {
|
|
3
|
+
private app?;
|
|
3
4
|
service?: AthenaService;
|
|
5
|
+
/**
|
|
6
|
+
* @param app - the app to query. Enables the Baqend native query path (app
|
|
7
|
+
* token only) as a fallback when no AWS login is present. Without it, only
|
|
8
|
+
* the AWS path is available.
|
|
9
|
+
*/
|
|
10
|
+
constructor(app?: string);
|
|
4
11
|
getService(): Promise<AthenaService>;
|
|
12
|
+
/**
|
|
13
|
+
* Prefer direct AWS Athena whenever AWS credentials are present — they
|
|
14
|
+
* usually carry higher access rights than the Baqend app-token path. Only
|
|
15
|
+
* when no AWS login is available do we fall back to the Baqend native query
|
|
16
|
+
* path (which needs an `app`).
|
|
17
|
+
*/
|
|
5
18
|
private createService;
|
|
6
19
|
/**
|
|
7
|
-
*
|
|
20
|
+
* Resolve the AWS credential chain (env, SSO cache, ...) without prompting.
|
|
21
|
+
* Returns a ready client when credentials exist, otherwise `undefined` so the
|
|
22
|
+
* caller can fall back to the Baqend path.
|
|
8
23
|
*
|
|
9
|
-
* @param cli
|
|
10
24
|
* @private
|
|
11
25
|
*/
|
|
12
|
-
private
|
|
26
|
+
private tryGetAthenaClient;
|
|
13
27
|
}
|
|
@@ -1,36 +1,56 @@
|
|
|
1
1
|
import { AthenaClient } from "@aws-sdk/client-athena";
|
|
2
2
|
import { safe } from "../../helpers/safe.js";
|
|
3
3
|
import { CliServiceFactory } from "../cli/index.js";
|
|
4
|
-
import { ATHENA_CONFIG
|
|
5
|
-
import {
|
|
4
|
+
import { ATHENA_CONFIG } from "./athena-service-model.js";
|
|
5
|
+
import { FetchCredentialsError } from "./error/fetch-credentials-error.js";
|
|
6
|
+
import { AwsAthenaService } from "./athena-service.js";
|
|
7
|
+
import { BaqendAthenaService } from "./baqend-athena-service.js";
|
|
8
|
+
import { EntityManagerFactory } from "../config-api/entity-manager-factory.js";
|
|
6
9
|
export class AthenaServiceFactory {
|
|
10
|
+
app;
|
|
7
11
|
service;
|
|
12
|
+
/**
|
|
13
|
+
* @param app - the app to query. Enables the Baqend native query path (app
|
|
14
|
+
* token only) as a fallback when no AWS login is present. Without it, only
|
|
15
|
+
* the AWS path is available.
|
|
16
|
+
*/
|
|
17
|
+
constructor(app) {
|
|
18
|
+
this.app = app;
|
|
19
|
+
}
|
|
8
20
|
async getService() {
|
|
9
|
-
if (!
|
|
21
|
+
if (!this.service) {
|
|
10
22
|
this.service = await this.createService();
|
|
11
23
|
}
|
|
12
24
|
return this.service;
|
|
13
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Prefer direct AWS Athena whenever AWS credentials are present — they
|
|
28
|
+
* usually carry higher access rights than the Baqend app-token path. Only
|
|
29
|
+
* when no AWS login is available do we fall back to the Baqend native query
|
|
30
|
+
* path (which needs an `app`).
|
|
31
|
+
*/
|
|
14
32
|
async createService() {
|
|
15
33
|
const cli = new CliServiceFactory().getService();
|
|
16
|
-
const client = await this.
|
|
17
|
-
|
|
34
|
+
const client = await this.tryGetAthenaClient();
|
|
35
|
+
if (client) {
|
|
36
|
+
cli.comment("Using AWS credentials for Athena queries.");
|
|
37
|
+
return new AwsAthenaService(client, cli);
|
|
38
|
+
}
|
|
39
|
+
if (this.app) {
|
|
40
|
+
return new BaqendAthenaService(this.app, new EntityManagerFactory(), cli);
|
|
41
|
+
}
|
|
42
|
+
throw new FetchCredentialsError("Cannot send Athena queries: no AWS credentials found and no app given for the Baqend API.");
|
|
18
43
|
}
|
|
19
44
|
/**
|
|
20
|
-
*
|
|
45
|
+
* Resolve the AWS credential chain (env, SSO cache, ...) without prompting.
|
|
46
|
+
* Returns a ready client when credentials exist, otherwise `undefined` so the
|
|
47
|
+
* caller can fall back to the Baqend path.
|
|
21
48
|
*
|
|
22
|
-
* @param cli
|
|
23
49
|
* @private
|
|
24
50
|
*/
|
|
25
|
-
async
|
|
51
|
+
async tryGetAthenaClient() {
|
|
26
52
|
const client = new AthenaClient(ATHENA_CONFIG);
|
|
27
|
-
cli.startAction("ATHENA", "check for aws credentials");
|
|
28
53
|
const credentialsResult = await safe(client.config.credentials());
|
|
29
|
-
|
|
30
|
-
cli.successAction("ATHENA");
|
|
31
|
-
return client;
|
|
32
|
-
}
|
|
33
|
-
cli.failAction("ATHENA");
|
|
34
|
-
throw new FetchCredentialsError(credentialsResult.error);
|
|
54
|
+
return credentialsResult.success === true ? client : undefined;
|
|
35
55
|
}
|
|
36
56
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { AthenaClient } from "@aws-sdk/client-athena";
|
|
2
|
+
import { AthenaService } from "./athena-query-service.js";
|
|
2
3
|
import { CliServiceInterface } from "../cli/index.js";
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Athena query implementation backed by the AWS SDK. Requires a valid AWS
|
|
6
|
+
* login (SSO). Preferred whenever AWS credentials are present, as they usually
|
|
7
|
+
* grant higher access than the Baqend app-token path; see
|
|
8
|
+
* {@link AthenaServiceFactory}.
|
|
9
|
+
*/
|
|
10
|
+
export declare class AwsAthenaService implements AthenaService {
|
|
4
11
|
private client;
|
|
5
12
|
private cli;
|
|
6
13
|
constructor(client: AthenaClient, cli: CliServiceInterface);
|
|
@@ -2,7 +2,13 @@ import { GetQueryExecutionCommand, GetQueryResultsCommand, QueryExecutionState,
|
|
|
2
2
|
import { DEFAULT_MAX_AGE_IN_MINUTES } from "./athena-service-model.js";
|
|
3
3
|
import { AthenaQueryError } from "./error/athena-query-error.js";
|
|
4
4
|
import { safe } from "../../helpers/safe.js";
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Athena query implementation backed by the AWS SDK. Requires a valid AWS
|
|
7
|
+
* login (SSO). Preferred whenever AWS credentials are present, as they usually
|
|
8
|
+
* grant higher access than the Baqend app-token path; see
|
|
9
|
+
* {@link AthenaServiceFactory}.
|
|
10
|
+
*/
|
|
11
|
+
export class AwsAthenaService {
|
|
6
12
|
client;
|
|
7
13
|
cli;
|
|
8
14
|
constructor(client, cli) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AthenaBucket, AthenaParameter, AthenaService } from "./athena-query-service.js";
|
|
2
|
+
import { EntityManagerFactory } from "../config-api/entity-manager-factory.js";
|
|
3
|
+
import { CliServiceInterface } from "../cli/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Runs Athena SQL through the Baqend API, authenticated by the app token only
|
|
6
|
+
* (no AWS login). Hits the native query path via
|
|
7
|
+
* `db["<bucket>"].executeQuery(sql, triggeredBy, ttl)`.
|
|
8
|
+
*
|
|
9
|
+
* Two normalizations vs the AWS path:
|
|
10
|
+
* - `?` placeholders are inlined (the native path has no parameter binding).
|
|
11
|
+
* - the `live.` catalog prefix is stripped — the server derives catalog and
|
|
12
|
+
* database itself, and a 3-part `live.<db>.<table>` reference fails there
|
|
13
|
+
* (verified against a live app), whereas 2-part `<db>.<table>` works.
|
|
14
|
+
*/
|
|
15
|
+
export declare class BaqendAthenaService implements AthenaService {
|
|
16
|
+
private app;
|
|
17
|
+
private entityManagerFactory;
|
|
18
|
+
private cli;
|
|
19
|
+
private static readonly TRIGGERED_BY;
|
|
20
|
+
private static readonly CATALOG_PREFIX;
|
|
21
|
+
constructor(app: string, entityManagerFactory: EntityManagerFactory, cli: CliServiceInterface);
|
|
22
|
+
getResult<T>(query: string, parameters?: AthenaParameter[], maxAgeInMinutes?: number, bucket?: AthenaBucket): Promise<T[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Inline the `?` placeholders with the given parameters (same quoting as the
|
|
25
|
+
* AWS path) and strip any `live.` catalog prefix. Done in a single
|
|
26
|
+
* string-literal-aware pass so `?` and `live.` occurring inside single-quoted
|
|
27
|
+
* literals (e.g. `split(url, '?')`, `'https://live.foo.com'`) are left intact.
|
|
28
|
+
*/
|
|
29
|
+
private prepareQuery;
|
|
30
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { DEFAULT_MAX_AGE_IN_MINUTES } from "./athena-service-model.js";
|
|
2
|
+
import { safe } from "../../helpers/safe.js";
|
|
3
|
+
/**
|
|
4
|
+
* Runs Athena SQL through the Baqend API, authenticated by the app token only
|
|
5
|
+
* (no AWS login). Hits the native query path via
|
|
6
|
+
* `db["<bucket>"].executeQuery(sql, triggeredBy, ttl)`.
|
|
7
|
+
*
|
|
8
|
+
* Two normalizations vs the AWS path:
|
|
9
|
+
* - `?` placeholders are inlined (the native path has no parameter binding).
|
|
10
|
+
* - the `live.` catalog prefix is stripped — the server derives catalog and
|
|
11
|
+
* database itself, and a 3-part `live.<db>.<table>` reference fails there
|
|
12
|
+
* (verified against a live app), whereas 2-part `<db>.<table>` works.
|
|
13
|
+
*/
|
|
14
|
+
export class BaqendAthenaService {
|
|
15
|
+
app;
|
|
16
|
+
entityManagerFactory;
|
|
17
|
+
cli;
|
|
18
|
+
static TRIGGERED_BY = "speed-kit-cli";
|
|
19
|
+
// a `live.` catalog qualifier in front of a `<db>.<table>` reference
|
|
20
|
+
static CATALOG_PREFIX = /^live\.[a-z_]\w*\.[a-z_]/i;
|
|
21
|
+
constructor(app, entityManagerFactory, cli) {
|
|
22
|
+
this.app = app;
|
|
23
|
+
this.entityManagerFactory = entityManagerFactory;
|
|
24
|
+
this.cli = cli;
|
|
25
|
+
}
|
|
26
|
+
async getResult(query, parameters = [], maxAgeInMinutes = DEFAULT_MAX_AGE_IN_MINUTES, bucket) {
|
|
27
|
+
if (!bucket) {
|
|
28
|
+
throw new Error("BaqendAthenaService.getResult requires a bucket to target");
|
|
29
|
+
}
|
|
30
|
+
this.cli.startAction("ATHENA:QUERY", "execute athena query via baqend");
|
|
31
|
+
const db = await this.entityManagerFactory.getEntityManager(this.app);
|
|
32
|
+
const sql = this.prepareQuery(query, parameters);
|
|
33
|
+
const ttl = `${maxAgeInMinutes}m`;
|
|
34
|
+
const result = await safe(db[bucket].executeQuery(sql, BaqendAthenaService.TRIGGERED_BY, ttl));
|
|
35
|
+
if (result.success === true) {
|
|
36
|
+
this.cli.successAction("ATHENA:QUERY");
|
|
37
|
+
return result.data;
|
|
38
|
+
}
|
|
39
|
+
this.cli.failAction("ATHENA:QUERY");
|
|
40
|
+
this.cli.writeError("Cannot send Athena queries via the Baqend API for this app.");
|
|
41
|
+
throw result.errorObj ?? new Error(result.error);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Inline the `?` placeholders with the given parameters (same quoting as the
|
|
45
|
+
* AWS path) and strip any `live.` catalog prefix. Done in a single
|
|
46
|
+
* string-literal-aware pass so `?` and `live.` occurring inside single-quoted
|
|
47
|
+
* literals (e.g. `split(url, '?')`, `'https://live.foo.com'`) are left intact.
|
|
48
|
+
*/
|
|
49
|
+
prepareQuery(query, parameters) {
|
|
50
|
+
let out = "";
|
|
51
|
+
let inString = false;
|
|
52
|
+
let paramIndex = 0;
|
|
53
|
+
for (let index = 0; index < query.length; index++) {
|
|
54
|
+
const char = query[index];
|
|
55
|
+
if (inString) {
|
|
56
|
+
out += char;
|
|
57
|
+
// a doubled '' is an escaped quote that stays inside the string
|
|
58
|
+
if (char === "'") {
|
|
59
|
+
if (query[index + 1] === "'") {
|
|
60
|
+
out += query[++index];
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
inString = false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (char === "'") {
|
|
69
|
+
inString = true;
|
|
70
|
+
out += char;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (char === "?") {
|
|
74
|
+
if (paramIndex >= parameters.length) {
|
|
75
|
+
throw new Error("Not enough parameters provided for the query");
|
|
76
|
+
}
|
|
77
|
+
const value = parameters[paramIndex++];
|
|
78
|
+
out += typeof value === "string" ? `'${value}'` : String(value);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// strip a `live.` catalog qualifier at a word boundary
|
|
82
|
+
if ((char === "l" || char === "L") &&
|
|
83
|
+
(index === 0 || !/\w/.test(query[index - 1])) &&
|
|
84
|
+
BaqendAthenaService.CATALOG_PREFIX.test(query.slice(index))) {
|
|
85
|
+
index += 4; // skip "live." (the loop's index++ skips the dot)
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
out += char;
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
export * from "./athena-query-service.js";
|
|
1
2
|
export * from "./athena-service.js";
|
|
3
|
+
export * from "./baqend-athena-service.js";
|
|
2
4
|
export * from "./athena-service-factory.js";
|
|
3
5
|
export * from "./athena-service-model.js";
|
|
4
6
|
export * from "./error/fetch-credentials-error.js";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
export * from "./athena-query-service.js";
|
|
1
2
|
export * from "./athena-service.js";
|
|
3
|
+
export * from "./baqend-athena-service.js";
|
|
2
4
|
export * from "./athena-service-factory.js";
|
|
3
5
|
export * from "./athena-service-model.js";
|
|
4
6
|
export * from "./error/fetch-credentials-error.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaqendResponse } from "../browser/baqend-response.js";
|
|
2
2
|
import { safe } from "../../../helpers/safe.js";
|
|
3
3
|
import json2Csv from "json2csv";
|
|
4
|
+
import { AthenaBucket } from "../../athena/index.js";
|
|
4
5
|
export class Dashboard {
|
|
5
6
|
customerConfig;
|
|
6
7
|
parameterQueryBuilder;
|
|
@@ -32,7 +33,7 @@ export class Dashboard {
|
|
|
32
33
|
if (url.pathname.startsWith("/query/execute")) {
|
|
33
34
|
const postData = request.postData;
|
|
34
35
|
const data = JSON.parse(postData);
|
|
35
|
-
const response = await safe(this.athenaClient.getResult(data.query, []));
|
|
36
|
+
const response = await safe(this.athenaClient.getResult(data.query, [], undefined, AthenaBucket.RumPi));
|
|
36
37
|
if (response.success === true) {
|
|
37
38
|
return this.createBaqendResponse(requestOrigin, JSON.stringify(response.data), "application/json; charset=UTF-8");
|
|
38
39
|
}
|
|
@@ -81,7 +81,7 @@ export class OnboardingServiceFactory {
|
|
|
81
81
|
cli.writeWarning("Running in headless mode.");
|
|
82
82
|
}
|
|
83
83
|
const fileWatcher = new FileWatcher(cli, customerConfig, files, documentHandler, browserContext, cache);
|
|
84
|
-
const athenaClient = (await this.getAthenaClient()) || null;
|
|
84
|
+
const athenaClient = (await this.getAthenaClient(customerConfig.app)) || null;
|
|
85
85
|
const messageHandler = await this.prepareMessagehandler(athenaClient, files, customerConfig);
|
|
86
86
|
const fetchHandler = await this.getFetchEventHandler(files, customerConfig, documentHandler, cache, cli, browserContext, athenaClient, messageHandler);
|
|
87
87
|
const extensionBridge = new ExtensionBridge(cli);
|
|
@@ -134,8 +134,8 @@ export class OnboardingServiceFactory {
|
|
|
134
134
|
}
|
|
135
135
|
cli.failAction("ONBOARDING:BUILD:INSTALL_RESOURCE", result.error);
|
|
136
136
|
}
|
|
137
|
-
async getAthenaClient() {
|
|
138
|
-
const athenaFactory = new AthenaServiceFactory();
|
|
137
|
+
async getAthenaClient(app) {
|
|
138
|
+
const athenaFactory = new AthenaServiceFactory(app);
|
|
139
139
|
const result = await safe(athenaFactory.getService());
|
|
140
140
|
if (result.success === true) {
|
|
141
141
|
return result.data;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { PopConfigService } from "./pop-config-service.js";
|
|
2
2
|
import { AthenaServiceFactory } from "../athena/index.js";
|
|
3
3
|
export class PopConfigFactory {
|
|
4
|
-
async getService() {
|
|
5
|
-
const athenaService = await new AthenaServiceFactory().getService();
|
|
4
|
+
async getService(app) {
|
|
5
|
+
const athenaService = await new AthenaServiceFactory(app).getService();
|
|
6
6
|
return new PopConfigService(athenaService);
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AthenaBucket } from "../athena/index.js";
|
|
1
2
|
export class PopConfigService {
|
|
2
3
|
athenaService;
|
|
3
4
|
constructor(athenaService) {
|
|
@@ -30,6 +31,6 @@ export class PopConfigService {
|
|
|
30
31
|
const startDate = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate() - 7);
|
|
31
32
|
const start = startDate.toISOString().slice(0, 10);
|
|
32
33
|
const end = endDate.toISOString().slice(0, 10);
|
|
33
|
-
return await this.athenaService.getResult(query, [start, end, app], 12 * 60);
|
|
34
|
+
return await this.athenaService.getResult(query, [start, end, app], 12 * 60, AthenaBucket.FastlyLogs);
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -37,7 +37,7 @@ from urlWithParams
|
|
|
37
37
|
group by paramKeys
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
-
select paramKeys, cachedUrls - uniqueWithoutParam as potentialGain, cachedUrls, PIs, example1, example2, example3
|
|
40
|
+
select '[' || array_join(paramKeys, ', ') || ']' as paramKeys, cachedUrls - uniqueWithoutParam as potentialGain, cachedUrls, PIs, example1, example2, example3
|
|
41
41
|
from prepared
|
|
42
42
|
where cardinality(paramKeys) > 0
|
|
43
43
|
order by potentialGain desc, cachedUrls desc, PIs desc`;
|
package/oclif.manifest.json
CHANGED