@adobe/spacecat-shared-rum-api-client 2.29.0 → 2.30.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
@@ -1,3 +1,10 @@
1
+ # [@adobe/spacecat-shared-rum-api-client-v2.30.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.29.0...@adobe/spacecat-shared-rum-api-client-v2.30.0) (2025-06-25)
2
+
3
+
4
+ ### Features
5
+
6
+ * SITES-32914 implement `startDate` and `endDate` in RUM client ([#819](https://github.com/adobe/spacecat-shared/issues/819)) ([1520465](https://github.com/adobe/spacecat-shared/commit/15204653ca7a1c3f04b1df30afc1a72f74d2b254))
7
+
1
8
  # [@adobe/spacecat-shared-rum-api-client-v2.29.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-rum-api-client-v2.28.1...@adobe/spacecat-shared-rum-api-client-v2.29.0) (2025-06-20)
2
9
 
3
10
 
package/README.md CHANGED
@@ -46,6 +46,21 @@ const result = await rumApiClient.query('cwv', opts);
46
46
  console.log(`Query result: ${result}`);
47
47
  ```
48
48
 
49
+ **Using startTime and endTime for precise date ranges:**
50
+
51
+ ```js
52
+ const opts = {
53
+ domain: 'www.aem.live',
54
+ domainkey: '<domain-key>',
55
+ granularity: 'daily',
56
+ startTime: '2024-01-01T00:00:00Z',
57
+ endTime: '2024-01-31T23:59:59Z'
58
+ };
59
+
60
+ const result = await rumApiClient.query('cwv', opts);
61
+ console.log(`Query result: ${result}`);
62
+ ```
63
+
49
64
  **Note**: All query names must be lowercase.
50
65
 
51
66
  ### Query Options: the 'opts' object
@@ -54,8 +69,10 @@ console.log(`Query result: ${result}`);
54
69
  |-------------|----------|---------|----------------------------------------------------------|
55
70
  | domain | yes | | The domain for which to fetch data. |
56
71
  | domainkey | no | | Provide directly or omit to auto-fetch using `RUM_ADMIN_KEY`. |
57
- | interval | no | 7 | Interval in days (integer). |
72
+ | interval | no | 7 | Interval in days (integer). Ignored when startTime/endTime are provided. |
58
73
  | granularity | no | daily | 'daily' or 'hourly'. |
74
+ | startTime | no | | Start time in ISO 8601 format (e.g., "2024-01-01T00:00:00Z"). Must be before endTime. Format `YYYY-MM-DD` or `YYYY-MM-DDTHH:MM:SSZ` |
75
+ | endTime | no | | End time in ISO 8601 format (e.g., "2024-01-31T23:59:59Z"). Must be after startTime. Format `YYYY-MM-DD` or `YYYY-MM-DDTHH:MM:SSZ` |
59
76
 
60
77
 
61
78
  ### Retrieving and Caching the Domainkey
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-rum-api-client",
3
- "version": "2.29.0",
3
+ "version": "2.30.0",
4
4
  "description": "Shared modules of the Spacecat Services - Rum API client",
5
5
  "type": "module",
6
6
  "engines": {
@@ -22,6 +22,24 @@ const ONE_DAY = ONE_HOUR * HOURS_IN_DAY;
22
22
 
23
23
  const CHUNK_SIZE = 31;
24
24
 
25
+ /**
26
+ * Parses a date string and returns a Date object.
27
+ * Supports both ISO 8601 format (e.g., "2024-01-01T00:00:00Z")
28
+ * and simple date format (e.g., "2024-01-01").
29
+ * For simple date strings, assumes UTC timezone.
30
+ * @param {string} dateString - The date string to parse
31
+ * @returns {Date} The parsed Date object
32
+ */
33
+ function parseDate(dateString) {
34
+ // If it's a simple date string (YYYY-MM-DD), convert to ISO format
35
+ if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
36
+ return new Date(`${dateString}T00:00:00.000Z`);
37
+ }
38
+
39
+ // Otherwise, let the Date constructor handle it (ISO 8601, etc.)
40
+ return new Date(dateString);
41
+ }
42
+
25
43
  function isBotTraffic(bundle) {
26
44
  return bundle?.userAgent?.includes('bot');
27
45
  }
@@ -54,6 +72,24 @@ function getUrlChunks(urls, chunkSize) {
54
72
  .map((_, index) => urls.slice(index * chunkSize, (index + 1) * chunkSize));
55
73
  }
56
74
 
75
+ function generateUrlsForDateRange(startDate, endDate, domain, granularity, domainkey) {
76
+ const urls = [];
77
+ const currentDate = parseDate(startDate);
78
+ const endDateTime = parseDate(endDate);
79
+
80
+ while (currentDate < endDateTime) {
81
+ urls.push(constructUrl(domain, currentDate, granularity, domainkey));
82
+
83
+ if (granularity.toUpperCase() === GRANULARITY.HOURLY) {
84
+ currentDate.setUTCHours(currentDate.getUTCHours() + 1);
85
+ } else {
86
+ currentDate.setUTCDate(currentDate.getUTCDate() + 1);
87
+ }
88
+ }
89
+
90
+ return urls;
91
+ }
92
+
57
93
  /* c8 ignore start */
58
94
  /*
59
95
  * throw-away code for a single customer who customized the experimentation engine
@@ -165,23 +201,46 @@ async function fetchBundles(opts, log) {
165
201
  granularity = GRANULARITY.DAILY,
166
202
  checkpoints = [],
167
203
  filterBotTraffic = true,
204
+ startTime,
205
+ endTime,
168
206
  } = opts;
169
207
 
170
208
  if (!hasText(domain) || !hasText(domainkey)) {
171
209
  throw new Error('Missing required parameters');
172
210
  }
173
211
 
174
- const multiplier = granularity.toUpperCase() === GRANULARITY.HOURLY ? ONE_HOUR : ONE_DAY;
175
- const range = granularity.toUpperCase() === GRANULARITY.HOURLY
176
- ? interval * HOURS_IN_DAY
177
- : interval + 1;
212
+ // Validate startTime and endTime if provided
213
+ if (startTime && endTime) {
214
+ const start = parseDate(startTime);
215
+ const end = parseDate(endTime);
178
216
 
179
- const urls = [];
180
- const currentDate = new Date();
217
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
218
+ throw new Error('Invalid startTime or endTime format. Use ISO 8601 format (e.g., "2024-01-01T00:00:00Z") or simple date format (e.g., "2024-01-01")');
219
+ }
181
220
 
182
- for (let i = 0; i < range; i += 1) {
183
- const date = new Date(currentDate.getTime() - i * multiplier);
184
- urls.push(constructUrl(domain, date, granularity, domainkey));
221
+ if (start >= end) {
222
+ throw new Error('startTime must be before endTime');
223
+ }
224
+ }
225
+
226
+ let urls = [];
227
+
228
+ if (startTime && endTime) {
229
+ // Use custom date range
230
+ urls = generateUrlsForDateRange(startTime, endTime, domain, granularity, domainkey);
231
+ } else {
232
+ // Use existing interval-based logic
233
+ const multiplier = granularity.toUpperCase() === GRANULARITY.HOURLY ? ONE_HOUR : ONE_DAY;
234
+ const range = granularity.toUpperCase() === GRANULARITY.HOURLY
235
+ ? interval * HOURS_IN_DAY
236
+ : interval + 1;
237
+
238
+ const currentDate = new Date();
239
+
240
+ for (let i = 0; i < range; i += 1) {
241
+ const date = new Date(currentDate.getTime() - i * multiplier);
242
+ urls.push(constructUrl(domain, date, granularity, domainkey));
243
+ }
185
244
  }
186
245
 
187
246
  const chunks = getUrlChunks(urls, CHUNK_SIZE);
@@ -197,7 +256,6 @@ async function fetchBundles(opts, log) {
197
256
  return response;
198
257
  }));
199
258
  const bundles = await Promise.all(responses.map((response) => response.json()));
200
-
201
259
  bundles.forEach((b) => {
202
260
  b.rumBundles
203
261
  .filter((bundle) => !filterBotTraffic || !isBotTraffic(bundle))
package/src/index.d.ts CHANGED
@@ -28,6 +28,16 @@ export interface RUMAPIOptions {
28
28
  */
29
29
  interval?: number;
30
30
 
31
+ /**
32
+ * Start Date
33
+ */
34
+ startDate?: string;
35
+
36
+ /**
37
+ * End Date
38
+ */
39
+ endDate?: string;
40
+
31
41
  /**
32
42
  * Granularity can be 'hourly' or 'daily'.
33
43
  * @default 'daily'