PageSourceSearch

https://newcastlegateshead.com/cpresources/232e6323/ga-availability-interceptor.js

js newcastlegateshead.com collected 2026-10-02 04:03:12 UTC 4,342 bytes, 143 lines download raw bytes

1/**
2 * Availability Search Engine Request Interceptor (early-load)
3 *
4 * This script MUST load before the Booking Engine API client initialises.
5 * It patches both fetch and XMLHttpRequest to capture availability search
6 * requests and buffer them for the GA event tracking registry to
7 * process once it loads.
8 *
9 * The host to intercept is read from the <meta name="availabilitySearchUrl">
10 * tag so it works across environments without hardcoding.
11 *
12 * Buffered responses are stored in window.__gaAvailabilityBuffer and
13 * consumed by registerAvailabilitySearchTracking() in ga-event-tracking-registry.js.
14 */
15(function () {
16  window.__gaAvailabilityBuffer = [];
17
18  /**
19   * Resolve the availability search engine host from the meta tag.
20   * Returns the origin (e.g. "https://availability-search-engine.staging.destinationcore.io")
21   * or null if the meta tag is absent.
22   */
23  function getAvailabilityHost() {
24    if (window.__gaAvailabilityHost !== undefined) {
25      return window.__gaAvailabilityHost;
26    }
27
28    var meta = document.querySelector('meta[name="availabilitySearchUrl"]');
29    if (!meta || !meta.content) {
30      window.__gaAvailabilityHost = null;
31      return null;
32    }
33
34    // Normalise: ensure scheme, strip trailing slash
35    var host = meta.content.trim().replace(/\/+$/, "");
36    if (host.indexOf("://") === -1) {
37      host = "https://" + host;
38    }
39
40    try {
41      window.__gaAvailabilityHost = new URL(host).origin;
42    } catch (e) {
43      window.__gaAvailabilityHost = null;
44    }
45
46    return window.__gaAvailabilityHost;
47  }
48
49  function isAvailabilityRequest(url) {
50    var host = getAvailabilityHost();
51    if (!host) {
52      return false;
53    }
54    return typeof url === "string" && url.indexOf(host) !== -1;
55  }
56
57  /**
58   * Determine the request type from the URL path.
59   *   - "search_create"  → POST /api/v1/search/create
60   *   - "search_results"  → GET  /api/v1/search/{uuid}/results
61   *   - "booking_intent"  → POST /api/v1/booking-intent/create
62   *   - null              → not an availability request we care about
63   */
64  function getRequestType(url) {
65    if (!isAvailabilityRequest(url)) {
66      return null;
67    }
68    if (url.indexOf("/api/v1/search/create") !== -1) {
69      return "search_create";
70    }
71    if (url.indexOf("/results") !== -1 && url.indexOf("/api/v1/search/") !== -1) {
72      return "search_results";
73    }
74    if (url.indexOf("/api/v1/booking-intent/create") !== -1) {
75      return "booking_intent";
76    }
77    return null;
78  }
79
80  // --- Patch fetch ---
81  var originalFetch = window.fetch;
82  window.fetch = function () {
83    var url = arguments[0];
84    var opts = arguments[1];
85    var urlStr = typeof url === "string" ? url : (url && url.url ? url.url : "");
86
87    var requestType = getRequestType(urlStr);
88    if (!requestType) {
89      return originalFetch.apply(this, arguments);
90    }
91
92    var fetchBody = opts && opts.body ? opts.body : null;
93
94    return originalFetch.apply(this, arguments).then(function (response) {
95      var clone = response.clone();
96      clone.json().then(function (data) {
97        window.__gaAvailabilityBuffer.push({
98          data: data,
99          body: fetchBody,
100          type: requestType,
101          url: urlStr,
102          status: response.status,
103        });
104      }).catch(function () {});
105      return response;
106    });
107  };
108
109  // --- Patch XMLHttpRequest ---
110  var originalXHROpen = XMLHttpRequest.prototype.open;
111  var originalXHRSend = XMLHttpRequest.prototype.send;
112
113  XMLHttpRequest.prototype.open = function () {
114    this._gaAvailUrl = arguments[1] || "";
115    this._gaAvailMethod = arguments[0] || "";
116    return originalXHROpen.apply(this, arguments);
117  };
118
119  XMLHttpRequest.prototype.send = function (body) {
120    var xhr = this;
121    var xhrBody = body;
122
123    var requestType = getRequestType(xhr._gaAvailUrl || "");
124    if (requestType) {
125      xhr.addEventListener("load", function () {
126        try {
127          var data = JSON.parse(xhr.responseText);
128          window.__gaAvailabilityBuffer.push({
129            data: data,
130            body: xhrBody,
131            type: requestType,
132            url: xhr._gaAvailUrl,
133            status: xhr.status,
134          });
135        } catch (e) {
136          // Silently ignore parse errors
137        }
138      });
139    }
140
141    return originalXHRSend.apply(this, arguments);
142  };
143})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.