@adobe/spacecat-shared-rum-api-client 2.20.2 → 2.21.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 +14 -0
- package/README.md +31 -14
- package/package.json +2 -2
- package/src/index.d.ts +56 -23
- package/src/index.js +61 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-rum-api-client-v2.21.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.21.0...@adobe/spacecat-shared-rum-api-client-v2.21.1) (2025-02-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** update external fixes ([#603](https://github.com/adobe/spacecat-shared/issues/603)) ([b58d4c7](https://github.com/adobe/spacecat-shared/commit/b58d4c7237fb2522bba9b722e9eed7b0ae9e5f70))
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-rum-api-client-v2.21.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.20.2...@adobe/spacecat-shared-rum-api-client-v2.21.0) (2025-02-11)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **rum-api-client:** admin key support ([#590](https://github.com/adobe/spacecat-shared/issues/590)) ([0213fa3](https://github.com/adobe/spacecat-shared/commit/0213fa3697cfc006c9edb5038a10ecc896cb6b6e))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-rum-api-client-v2.20.2](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.20.1...@adobe/spacecat-shared-rum-api-client-v2.20.2) (2025-02-08)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -12,18 +12,22 @@ npm install @adobe/spacecat-shared-rum-api-client
|
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
|
-
#### Creating
|
|
15
|
+
#### Creating an instance from Helix UniversalContext
|
|
16
16
|
|
|
17
17
|
```js
|
|
18
|
-
|
|
18
|
+
// The context must include an 'env' property so that the client can use RUM_ADMIN_KEY if needed.
|
|
19
|
+
const context = { env: process.env };
|
|
19
20
|
const rumApiClient = RUMAPIClient.createFrom(context);
|
|
20
|
-
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
####
|
|
23
|
+
#### Using the constructor
|
|
24
24
|
|
|
25
25
|
```js
|
|
26
|
-
|
|
26
|
+
// Optionally, pass a configuration and a logger objects to the constructor.
|
|
27
|
+
// If you want the client to automatically fetch the domainkey for a domain,
|
|
28
|
+
// provide the admin key as 'rumAdminKey'. If omitted, you must provide the domainkey
|
|
29
|
+
// in the query options.
|
|
30
|
+
const rumApiClient = new RUMAPIClient({ rumAdminKey: '<admin-key>' }, logger);
|
|
27
31
|
```
|
|
28
32
|
|
|
29
33
|
### Running a query
|
|
@@ -31,25 +35,38 @@ const rumApiClient = new RUMAPIClient();
|
|
|
31
35
|
```js
|
|
32
36
|
const opts = {
|
|
33
37
|
domain: 'www.aem.live',
|
|
38
|
+
// Either provide the domainkey directly...
|
|
34
39
|
domainkey: '<domain-key>',
|
|
40
|
+
// ...or omit it to let the client auto-fetch it if an admin key is configured.
|
|
35
41
|
granularity: 'hourly',
|
|
36
42
|
interval: 10
|
|
37
|
-
}
|
|
43
|
+
};
|
|
38
44
|
|
|
39
45
|
const result = await rumApiClient.query('cwv', opts);
|
|
40
|
-
console.log(`Query result: ${result}`)
|
|
46
|
+
console.log(`Query result: ${result}`);
|
|
41
47
|
```
|
|
42
48
|
|
|
43
|
-
**Note**:
|
|
49
|
+
**Note**: All query names must be lowercase.
|
|
44
50
|
|
|
45
51
|
### Query Options: the 'opts' object
|
|
46
52
|
|
|
47
|
-
|
|
|
48
|
-
|
|
49
|
-
| domain | yes | |
|
|
50
|
-
| domainkey |
|
|
51
|
-
| interval | no | 7 |
|
|
52
|
-
| granularity | no | daily | 'daily' or 'hourly'
|
|
53
|
+
| Option | Required | Default | Remarks |
|
|
54
|
+
|-------------|----------|---------|----------------------------------------------------------|
|
|
55
|
+
| domain | yes | | The domain for which to fetch data. |
|
|
56
|
+
| domainkey | no | | Provide directly or omit to auto-fetch using `RUM_ADMIN_KEY`. |
|
|
57
|
+
| interval | no | 7 | Interval in days (integer). |
|
|
58
|
+
| granularity | no | daily | 'daily' or 'hourly'. |
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
### Retrieving and Caching the Domainkey
|
|
62
|
+
|
|
63
|
+
You can also retrieve the domainkey for a given domain directly using the new `retrieveDomainkey` method.
|
|
64
|
+
This method will fetch the domainkey using the admin key (if necessary) and cache it for subsequent calls.
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
const domainKey = await rumApiClient.retrieveDomainkey('www.example.com');
|
|
68
|
+
console.log(`Domain key: ${domainKey}`);
|
|
69
|
+
```
|
|
53
70
|
|
|
54
71
|
## Available queries
|
|
55
72
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/spacecat-shared-rum-api-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"description": "Shared modules of the Spacecat Services - Rum API client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"urijs": "1.19.11"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"chai": "5.
|
|
47
|
+
"chai": "5.2.0",
|
|
48
48
|
"chai-as-promised": "8.0.1",
|
|
49
49
|
"nock": "14.0.1",
|
|
50
50
|
"sinon": "19.0.2",
|
package/src/index.d.ts
CHANGED
|
@@ -13,52 +13,85 @@
|
|
|
13
13
|
import { UniversalContext } from '@adobe/helix-universal';
|
|
14
14
|
|
|
15
15
|
export interface RUMAPIOptions {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
/** The domain for which to fetch data. */
|
|
17
|
+
domain: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The domain key. If not provided, the client will attempt to auto-fetch the domainkey
|
|
21
|
+
* using the admin key (if configured). Fetched domainkeys are cached for subsequent calls.
|
|
22
|
+
*/
|
|
23
|
+
domainkey?: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Interval in days.
|
|
27
|
+
* @default 7
|
|
28
|
+
*/
|
|
29
|
+
interval?: number;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Granularity can be 'hourly' or 'daily'.
|
|
33
|
+
* @default 'daily'
|
|
34
|
+
*/
|
|
35
|
+
granularity?: 'hourly' | 'daily';
|
|
36
|
+
|
|
37
|
+
groupedURLs?: Array<{
|
|
38
|
+
name: string;
|
|
39
|
+
pattern: string;
|
|
40
|
+
}>;
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
export default class RUMAPIClient {
|
|
27
44
|
/**
|
|
28
45
|
* Static factory method to create an instance of RUMAPIClient.
|
|
29
|
-
*
|
|
46
|
+
*
|
|
47
|
+
* @param {UniversalContext} context - An object containing the HelixUniversal context.
|
|
48
|
+
* The context must include an `env` property that can optionally include a `RUM_ADMIN_KEY`.
|
|
30
49
|
* @returns An instance of RUMAPIClient.
|
|
31
|
-
* @remarks This method
|
|
32
|
-
*
|
|
33
|
-
* this method will return the singleton instance if previously created.
|
|
50
|
+
* @remarks This method creates a new instance from a HelixUniversal context and
|
|
51
|
+
* caches it on the context.
|
|
34
52
|
*/
|
|
35
53
|
static createFrom(context: UniversalContext): RUMAPIClient;
|
|
36
54
|
|
|
37
55
|
/**
|
|
38
56
|
* Constructor for creating an instance of RUMAPIClient.
|
|
57
|
+
*
|
|
58
|
+
* @param options Optional configuration. If you want the client to auto-fetch the domainkey,
|
|
59
|
+
* provide the admin key as `rumAdminKey`.
|
|
60
|
+
* @param log Optional logger, defaults to `console`.
|
|
39
61
|
*/
|
|
40
|
-
constructor();
|
|
62
|
+
constructor(options?: { rumAdminKey?: string }, log?: Console);
|
|
41
63
|
|
|
42
64
|
/**
|
|
43
|
-
* Asynchronous method to run
|
|
44
|
-
*
|
|
45
|
-
* @param
|
|
65
|
+
* Asynchronous method to run a query against the RUM Bundler API.
|
|
66
|
+
*
|
|
67
|
+
* @param query - Name of the query to run.
|
|
68
|
+
* @param opts - A object containing options for the query. Either provide a `domainkey`
|
|
69
|
+
* here or configure an admin key so that the client can fetch it automatically.
|
|
46
70
|
* @returns A Promise resolving to an object with the query results.
|
|
47
71
|
* @remarks See the README.md for the available queries.
|
|
48
72
|
*/
|
|
49
|
-
query(query: string, opts
|
|
73
|
+
query(query: string, opts: RUMAPIOptions): Promise<object>;
|
|
50
74
|
|
|
51
75
|
/**
|
|
52
|
-
* Asynchronous method to run multiple queries against the data fetched from RUM Bundler API.
|
|
76
|
+
* Asynchronous method to run multiple queries against the data fetched from the RUM Bundler API.
|
|
53
77
|
*
|
|
54
78
|
* This method makes a single call to the RUM Bundler API to fetch the raw data, then applies
|
|
55
79
|
* all the requested queries to this raw data. The results are returned in an object where each
|
|
56
80
|
* key corresponds to a query name and each value contains the result of that query.
|
|
57
81
|
*
|
|
58
|
-
* @param
|
|
59
|
-
* @param
|
|
60
|
-
* @returns
|
|
61
|
-
*
|
|
82
|
+
* @param queries - An array of query names to execute.
|
|
83
|
+
* @param opts - Optional object containing options for the queries.
|
|
84
|
+
* @returns A Promise that resolves to an object where each key is the name
|
|
85
|
+
* of a query, and each value is the result of that query.
|
|
86
|
+
*/
|
|
87
|
+
queryMulti(queries: string[], opts: RUMAPIOptions): Promise<object>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Retrieves the domainkey for the given domain. If the domainkey was already fetched,
|
|
91
|
+
* the cached value is returned.
|
|
92
|
+
*
|
|
93
|
+
* @param domain - The domain for which to retrieve the domainkey.
|
|
94
|
+
* @returns A Promise resolving to the domainkey string.
|
|
62
95
|
*/
|
|
63
|
-
|
|
96
|
+
retrieveDomainkey(domain: string): Promise<string>;
|
|
64
97
|
}
|
package/src/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import { hasText } from '@adobe/spacecat-shared-utils';
|
|
12
|
+
import { hasText, fetch } from '@adobe/spacecat-shared-utils';
|
|
13
13
|
import { fetchBundles } from './common/rum-bundler-client.js';
|
|
14
14
|
import notfound from './functions/404.js';
|
|
15
15
|
import notfoundInternalLinks from './functions/404-internal-links.js';
|
|
@@ -23,6 +23,9 @@ import rageclick from './functions/opportunities/rageclick.js';
|
|
|
23
23
|
import highInorganicHighBounceRate from './functions/opportunities/high-inorganic-high-bounce-rate.js';
|
|
24
24
|
import highOrganicLowCtr from './functions/opportunities/high-organic-low-ctr.js';
|
|
25
25
|
|
|
26
|
+
// exported for tests
|
|
27
|
+
export const RUM_BUNDLER_API_HOST = 'https://bundles.aem.page';
|
|
28
|
+
|
|
26
29
|
const HANDLERS = {
|
|
27
30
|
404: notfound,
|
|
28
31
|
'404-internal-links': notfoundInternalLinks,
|
|
@@ -47,17 +50,65 @@ function sanitize(opts) {
|
|
|
47
50
|
|
|
48
51
|
export default class RUMAPIClient {
|
|
49
52
|
static createFrom(context) {
|
|
50
|
-
const { log = console } = context;
|
|
53
|
+
const { env, log = console } = context;
|
|
54
|
+
const { RUM_ADMIN_KEY: rumAdminKey } = env;
|
|
51
55
|
|
|
52
56
|
if (context.rumApiClient) return context.rumApiClient;
|
|
53
57
|
|
|
54
|
-
const client = new RUMAPIClient(log);
|
|
58
|
+
const client = new RUMAPIClient({ rumAdminKey }, log);
|
|
55
59
|
context.rumApiClient = client;
|
|
56
60
|
return client;
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
constructor(log) {
|
|
63
|
+
constructor({ rumAdminKey }, log) {
|
|
60
64
|
this.log = log;
|
|
65
|
+
this.rumAdminKey = rumAdminKey;
|
|
66
|
+
this.domainkeyCache = {};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async _exchangeDomainkey(domain) {
|
|
70
|
+
if (hasText(this.domainkeyCache[domain])) {
|
|
71
|
+
return this.domainkeyCache[domain];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const resp = await fetch(`${RUM_BUNDLER_API_HOST}/domainkey/${domain}`, {
|
|
75
|
+
headers: {
|
|
76
|
+
Authorization: `Bearer ${this.rumAdminKey}`,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (!resp.ok) {
|
|
81
|
+
throw new Error(`Error during fetching domainkey for domain '${domain} using admin key. Status: ${resp.status}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const json = await resp.json();
|
|
86
|
+
if (!hasText(json.domainkey)) {
|
|
87
|
+
throw new Error(`Unexpected response: ${JSON.stringify(json)}`);
|
|
88
|
+
}
|
|
89
|
+
this.domainkeyCache[domain] = json.domainkey;
|
|
90
|
+
return json.domainkey;
|
|
91
|
+
} catch (e) {
|
|
92
|
+
throw new Error(`Error during fetching domainkey for domain '${domain} using admin key. Error: ${e.message}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async _getDomainkey(opts) {
|
|
97
|
+
const { domain, domainkey } = opts;
|
|
98
|
+
|
|
99
|
+
if (!hasText(domainkey) && !hasText(this.rumAdminKey)) {
|
|
100
|
+
throw new Error('You need to provide a \'domainkey\' or set RUM_ADMIN_KEY env variable');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (hasText(domainkey)) {
|
|
104
|
+
return domainkey;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return this._exchangeDomainkey(domain);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async retrieveDomainkey(domain) {
|
|
111
|
+
return this._exchangeDomainkey(domain);
|
|
61
112
|
}
|
|
62
113
|
|
|
63
114
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -66,8 +117,11 @@ export default class RUMAPIClient {
|
|
|
66
117
|
if (!handler) throw new Error(`Unknown query ${query}`);
|
|
67
118
|
|
|
68
119
|
try {
|
|
120
|
+
const domainkey = await this._getDomainkey(opts);
|
|
121
|
+
|
|
69
122
|
const bundles = await fetchBundles({
|
|
70
123
|
...opts,
|
|
124
|
+
domainkey,
|
|
71
125
|
checkpoints,
|
|
72
126
|
}, this.log);
|
|
73
127
|
|
|
@@ -96,9 +150,12 @@ export default class RUMAPIClient {
|
|
|
96
150
|
}
|
|
97
151
|
|
|
98
152
|
try {
|
|
153
|
+
const domainkey = await this._getDomainkey(opts);
|
|
154
|
+
|
|
99
155
|
// Fetch bundles with deduplicated checkpoints
|
|
100
156
|
const bundles = await fetchBundles({
|
|
101
157
|
...opts,
|
|
158
|
+
domainkey,
|
|
102
159
|
checkpoints: [...allCheckpoints],
|
|
103
160
|
}, this.log);
|
|
104
161
|
|