@newrelic/video-core 3.1.1 → 3.2.0-beta-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/src/utils.js ADDED
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Makes an API call with retry logic and fallback to sendBeacon for final harvests
3
+ * @param {Object} params - Request parameters
4
+ * @param {string} params.url - The URL to send the request to
5
+ * @param {Object} params.payload - The payload object containing body data
6
+ * @param {Object} params.options - Request options
7
+ * @param {boolean} params.options.isFinalHarvest - Whether this is a final harvest on page unload
8
+ * @param {Function} callback - Callback function to handle the response
9
+ */
10
+ export function callApi({ url, payload, options = {} }, callback) {
11
+ // Input validation
12
+ if (!url || !payload || !callback) {
13
+ console.error("callApi: Missing required parameters");
14
+ if (callback) callback({ retry: false, status: 0 });
15
+ return;
16
+ }
17
+
18
+ // The Browser Agent sends the 'body' part of the payload object as the actual request body.
19
+ let body;
20
+ try {
21
+ body = JSON.stringify(payload.body);
22
+ } catch (error) {
23
+ console.error("callApi: Error serializing payload", error);
24
+ callback({ retry: false, status: 0 });
25
+ return;
26
+ }
27
+
28
+ // For final harvests on page unload, use sendBeacon for reliability.
29
+ if (options.isFinalHarvest && navigator.sendBeacon) {
30
+ try {
31
+ const success = navigator.sendBeacon(url, body);
32
+ // sendBeacon returns true if the request was successfully queued
33
+ callback({ retry: !success, status: success ? 200 : 0 });
34
+ } catch (e) {
35
+ // sendBeacon can fail if the payload is too large.
36
+ callback({ retry: true, status: 0 });
37
+ }
38
+ return;
39
+ }
40
+
41
+ fetch(url, {
42
+ method: "POST",
43
+ body: body,
44
+ headers: {
45
+ "Content-Type": "application/json", // More accurate content type
46
+ },
47
+ keepalive: options.isFinalHarvest, // Important for final harvest fallback
48
+ })
49
+ .then((response) => {
50
+ // Check for statuses that indicate a retry is needed.
51
+ const isRetry = shouldRetry(response.status);
52
+ callback({
53
+ retry: isRetry,
54
+ status: response.status,
55
+ ok: response.ok,
56
+ });
57
+ })
58
+ .catch(() => {
59
+ // Any network failure (e.g., no internet) should also trigger a retry.
60
+ callback({ retry: true, status: 0 });
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Determines if a request should be retried based on HTTP status code
66
+ * @param {number} status - HTTP status code
67
+ * @returns {boolean} - True if request should be retried
68
+ */
69
+ function shouldRetry(status) {
70
+ switch (status) {
71
+ case 408: // Request Timeout
72
+ case 429: // Too Many Requests
73
+ case 500: // Internal Server Error
74
+ return true;
75
+ case 401: // Unauthorized - don't retry
76
+ case 403: // Forbidden - don't retry
77
+ case 404: // Not Found - don't retry
78
+ return false;
79
+ }
80
+ // Retry for 5xx server errors and specific ranges
81
+ return (status >= 502 && status <= 504) || (status >= 512 && status <= 530);
82
+ }
83
+
84
+ /**
85
+ * Calculates the size of a payload object in megabytes
86
+ * @param {Object} obj - The object to calculate size for
87
+ * @returns {number} - Size in megabytes, or 0 if calculation fails
88
+ */
89
+ export function getPayloadSize(obj) {
90
+ if (!obj || typeof obj !== "object") {
91
+ return 0;
92
+ }
93
+
94
+ try {
95
+ const json = JSON.stringify(obj);
96
+ return new TextEncoder().encode(json).length / (1024 * 1024);
97
+ } catch (error) {
98
+ console.error("getPayloadSize: Error calculating payload size", error);
99
+ return 0;
100
+ }
101
+ }