@adobe/spacecat-shared-utils 1.33.3 → 1.35.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 +14 -0
- package/package.json +1 -1
- package/src/functions.js +11 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +1 -0
- package/src/tracing-fetch.js +63 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-utils-v1.35.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.34.0...@adobe/spacecat-shared-utils-v1.35.0) (2025-03-06)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* tracing fetch timeout ([#657](https://github.com/adobe/spacecat-shared/issues/657)) ([67335e3](https://github.com/adobe/spacecat-shared/commit/67335e32b7cceeb500ca58dc05518876589a108a))
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-utils-v1.34.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.33.3...@adobe/spacecat-shared-utils-v1.34.0) (2025-03-05)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Brand client ([#640](https://github.com/adobe/spacecat-shared/issues/640)) ([8d82f45](https://github.com/adobe/spacecat-shared/commit/8d82f45349ea9be2b1359fe5ebebf5a350f52666))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-utils-v1.33.3](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.33.2...@adobe/spacecat-shared-utils-v1.33.3) (2025-03-04)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
package/src/functions.js
CHANGED
|
@@ -15,6 +15,7 @@ import { validate as uuidValidate } from 'uuid';
|
|
|
15
15
|
// Precompile regular expressions
|
|
16
16
|
const REGEX_ISO_DATE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
|
|
17
17
|
const REGEX_TIME_OFFSET_DATE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}(Z|[+-]\d{2}:\d{2})/;
|
|
18
|
+
const IMS_ORG_ID_REGEX = /[a-z0-9]{24}@AdobeOrg/i;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Determines if the given parameter is an array.
|
|
@@ -251,6 +252,15 @@ function dateAfterDays(days, dateString) {
|
|
|
251
252
|
return currentDate;
|
|
252
253
|
}
|
|
253
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Validates whether the given string is a valid IMS Org ID.
|
|
257
|
+
* @param {string} imsOrgId - The string to validate.
|
|
258
|
+
* @returns {boolean} True if the given string is a valid IMS Org ID, false otherwise.
|
|
259
|
+
*/
|
|
260
|
+
function isValidIMSOrgId(imsOrgId) {
|
|
261
|
+
return IMS_ORG_ID_REGEX.test(imsOrgId);
|
|
262
|
+
}
|
|
263
|
+
|
|
254
264
|
export {
|
|
255
265
|
arrayEquals,
|
|
256
266
|
dateAfterDays,
|
|
@@ -269,5 +279,6 @@ export {
|
|
|
269
279
|
isValidDate,
|
|
270
280
|
isValidUrl,
|
|
271
281
|
isValidUUID,
|
|
282
|
+
isValidIMSOrgId,
|
|
272
283
|
toBoolean,
|
|
273
284
|
};
|
package/src/index.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export function isValidUrl(urlString: string): boolean;
|
|
|
45
45
|
|
|
46
46
|
export function isValidUUID(uuid: string): boolean;
|
|
47
47
|
|
|
48
|
+
export function isValidIMSOrgId(imsOrgId: string): boolean;
|
|
49
|
+
|
|
48
50
|
export function dateAfterDays(days: number, dateString: string): Date;
|
|
49
51
|
|
|
50
52
|
export function deepEqual(a: unknown, b: unknown): boolean;
|
package/src/index.js
CHANGED
package/src/tracing-fetch.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 { Request } from '@adobe/fetch';
|
|
12
|
+
import { Request, timeoutSignal, AbortError } from '@adobe/fetch';
|
|
13
13
|
import AWSXRay from 'aws-xray-sdk';
|
|
14
14
|
|
|
15
15
|
import { fetch as adobeFetch } from './adobe-fetch.js';
|
|
@@ -107,17 +107,60 @@ const handleSubSegmentError = (subSegment, request, error) => {
|
|
|
107
107
|
subSegment.close(error);
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Creates a timeout error with a consistent format
|
|
112
|
+
* @param {number} timeout - The timeout value in milliseconds
|
|
113
|
+
* @returns {Error} A formatted timeout error
|
|
114
|
+
*/
|
|
115
|
+
const createTimeoutError = (timeout) => {
|
|
116
|
+
const timeoutError = new Error(`Request timeout after ${timeout}ms`);
|
|
117
|
+
timeoutError.code = 'ETIMEOUT';
|
|
118
|
+
return timeoutError;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Performs a fetch request with timeout handling
|
|
123
|
+
* @param {string|Request} resource - The resource to fetch
|
|
124
|
+
* @param {Object} options - Options for the fetch call
|
|
125
|
+
* @param {Object} signal - The timeout signal
|
|
126
|
+
* @returns {Promise<Response>} The fetch response
|
|
127
|
+
*/
|
|
128
|
+
const fetchWithTimeout = async (resource, options, signal) => {
|
|
129
|
+
try {
|
|
130
|
+
const fetchOptions = { ...options, signal };
|
|
131
|
+
return await adobeFetch(resource, fetchOptions);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error instanceof AbortError) {
|
|
134
|
+
// Extract timeout from signal (implementation detail, but necessary)
|
|
135
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
136
|
+
const timeout = signal._ms || 10000;
|
|
137
|
+
throw createTimeoutError(timeout);
|
|
138
|
+
}
|
|
139
|
+
throw error;
|
|
140
|
+
} finally {
|
|
141
|
+
signal.clear(); // Clean up the signal
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
110
145
|
/**
|
|
111
146
|
* Performs a fetch request and adds AWS X-Ray tracing, including request/response tracking.
|
|
112
147
|
* @param {string} url - The URL for the request.
|
|
113
|
-
* @param {Object} options -
|
|
148
|
+
* @param {Object} [options] - Optional options to be passed to the fetch call.
|
|
149
|
+
* @param {number} [options.timeout=10000] - Timeout in milliseconds (defaults to 10 seconds).
|
|
114
150
|
* @returns {Promise<Response>} The response from the fetch request.
|
|
115
151
|
*/
|
|
116
152
|
export async function tracingFetch(url, options) {
|
|
117
153
|
const parentSegment = AWSXRay.getSegment();
|
|
118
154
|
|
|
119
|
-
options = isObject(options) ? options : {};
|
|
120
|
-
options.headers = isObject(options.headers) ? options.headers :
|
|
155
|
+
options = isObject(options) ? { ...options } : {};
|
|
156
|
+
options.headers = isObject(options.headers) ? options.headers : { };
|
|
157
|
+
|
|
158
|
+
// Set default timeout of 10 seconds if not specified
|
|
159
|
+
const timeout = options.timeout || 10000;
|
|
160
|
+
delete options.timeout; // Remove from options as we'll handle it separately
|
|
161
|
+
|
|
162
|
+
// Create a timeout signal
|
|
163
|
+
const signal = timeoutSignal(timeout);
|
|
121
164
|
|
|
122
165
|
// find user-agent header in headers case insensitively
|
|
123
166
|
let hasUserAgent = false;
|
|
@@ -131,10 +174,12 @@ export async function tracingFetch(url, options) {
|
|
|
131
174
|
options.headers['User-Agent'] = SPACECAT_USER_AGENT;
|
|
132
175
|
}
|
|
133
176
|
|
|
177
|
+
// If no parent segment, perform fetch without tracing
|
|
134
178
|
if (!parentSegment) {
|
|
135
|
-
return
|
|
179
|
+
return fetchWithTimeout(url, options, signal);
|
|
136
180
|
}
|
|
137
181
|
|
|
182
|
+
// With parent segment, create subsegment and add tracing
|
|
138
183
|
const request = new Request(url, options);
|
|
139
184
|
const { hostname } = new URL(request.url);
|
|
140
185
|
const subSegment = createSubsegment(parentSegment, hostname);
|
|
@@ -145,21 +190,22 @@ export async function tracingFetch(url, options) {
|
|
|
145
190
|
setTraceHeaders(request, parentSegment, subSegment);
|
|
146
191
|
}
|
|
147
192
|
|
|
148
|
-
|
|
149
|
-
let response = null;
|
|
150
|
-
try {
|
|
151
|
-
response = await adobeFetch(request);
|
|
152
|
-
} catch (e) {
|
|
153
|
-
handleSubSegmentError(subSegment, request, e);
|
|
154
|
-
throw e;
|
|
155
|
-
}
|
|
193
|
+
subSegment.addAnnotation('timeout_ms', timeout);
|
|
156
194
|
|
|
157
|
-
|
|
195
|
+
try {
|
|
196
|
+
// Create a new request with the signal
|
|
197
|
+
const requestWithSignal = new Request(request, { signal });
|
|
198
|
+
|
|
199
|
+
// Use the same fetchWithTimeout function but catch errors to handle subsegment
|
|
200
|
+
const response = await fetchWithTimeout(requestWithSignal, { }, signal);
|
|
158
201
|
|
|
202
|
+
setSubSegmentFlagsByStatusCode(subSegment, response.status);
|
|
159
203
|
addFetchRequestDataToSegment(subSegment, request, response);
|
|
160
204
|
subSegment.close();
|
|
161
|
-
return response;
|
|
162
|
-
};
|
|
163
205
|
|
|
164
|
-
|
|
206
|
+
return response;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
handleSubSegmentError(subSegment, request, error);
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
165
211
|
}
|