1(function (root, factory) { 2 if (typeof module === "object" && module.exports) { 3 module.exports = factory(root); 4 } else if (typeof define === "function" && define.amd) { 5 define([], function () { 6 return factory(root); 7 }); 8 } else { 9 var api = factory(root); 10 root.CommuterCookies = api; 11 root.callCommuterCookiesAPI = api.callCommuterCookiesAPI; 12 } 13})(typeof self !== "undefined" ? self : this, function (root) { 14 "use strict"; 15 16 17 function getAllUrlParams() { 18 var search = window.location.search || ""; 19 if (search.length > 1) { 20 return encodeURI(search.substring(1)); 21 } 22 return ""; 23 } 24 25 26 function getCookie(name) { 27 var value = "; " + document.cookie; 28 var parts = value.split("; " + name + "="); 29 if (parts.length === 2) { 30 return decodeURIComponent(parts.pop().split(";").shift()); 31 } 32 return null; 33 } 34 35 36 // ---- retry helpers (NEW) ---- 37 function sleep(ms) { 38 return new Promise(function (r) { 39 setTimeout(r, ms); 40 }); 41 } 42 43 44 async function retryAsync(fn, opts) { 45 var retries = (opts && opts.retries) != null ? opts.retries : 2; // total extra retries 46 var baseDelayMs = 47 (opts && opts.baseDelayMs) != null ? opts.baseDelayMs : 600; 48 var jitterMs = (opts && opts.jitterMs) != null ? opts.jitterMs : 200; 49 50 51 var lastErr = null; 52 53 54 for (var attempt = 0; attempt <= retries; attempt++) { 55 try { 56 return await fn(attempt); 57 } catch (e) { 58 lastErr = e; 59 if (attempt === retries) break; 60 61 62 var backoff = baseDelayMs * Math.pow(2, attempt); 63 var jitter = Math.floor(Math.random() * jitterMs); 64 await sleep(backoff + jitter); 65 } 66 } 67 throw lastErr; 68 } 69 70 71 function generateUUIDv4() { 72 if (typeof crypto !== "undefined" && crypto.randomUUID) { 73 return crypto.randomUUID(); 74 } 75 76 77 let buf; 78 if (typeof crypto !== "undefined" && crypto.getRandomValues) { 79 buf = new Uint8Array(16); 80 crypto.getRandomValues(buf); 81 } else { 82 // Fallback if crypto is not available 83 buf = new Array(16); 84 for (let i = 0; i < 16; i++) { 85 buf[i] = (Math.random() * 256) | 0; 86 } 87 } 88 89 90 // RFC4122 version 4 91 buf[6] = (buf[6] & 0x0f) | 0x40; // version 92 buf[8] = (buf[8] & 0x3f) | 0x80; // variant 93 94 95 const hex = Array.from(buf).map((b) => b.toString(16).padStart(2, "0")); 96 97 98 return ( 99 hex.slice(0, 4).join("") + 100 "-" + 101 hex.slice(4, 6).join("") + 102 "-" + 103 hex.slice(6, 8).join("") + 104 "-" + 105 hex.slice(8, 10).join("") + 106 "-" + 107 hex.slice(10, 16).join("") 108 ); 109 } 110 111 112 function isTripConfirmationPage() { 113 const path = window.location.pathname || ""; 114 console.log(path); 115 // matches: /tripconfirmation and /tripconfirmation/anything 116 return ( 117 path === "/tripconfirmation" || path.startsWith("/tripconfirmation/") 118 ); 119 } 120 121 122 var SYNC_COOKIE = "commuterCookiesAPISuccess"; 123 var COOKIE_LONG_ID = "commuterCookieID"; 124 125 126 function readCookieId() { 127 var v = getCookie(COOKIE_LONG_ID); 128 if (v == null || v === "") return null; 129 var n = Number(v); 130 return Number.isFinite(n) ? n : null; 131 } 132 133 134 function writeCookieId(cookieId) { 135 if (cookieId == null) return; 136 setCookie(COOKIE_LONG_ID, String(cookieId)); 137 } 138 139 140 function clearCookieId() { 141 deleteCookie(COOKIE_LONG_ID); 142 } 143 144 145 function readCommuterSyncState() { 146 try { 147 var raw = getCookie(SYNC_COOKIE); 148 if (!raw) return null; 149 return JSON.parse(raw); 150 } catch (e) { 151 return null; 152 } 153 } 154 155 156 function writeCommuterSyncState(userId, cookie) { 157 try { 158 // session-only cookie (no days) 159 setCookie( 160 SYNC_COOKIE, 161 JSON.stringify({ userId: userId, cookie: cookie }), 162 ); 163 } catch (e) { 164 // ignore 165 } 166 } 167 168 169 function clearCommuterSyncState() { 170 deleteCookie(SYNC_COOKIE); 171 } 172 173 174 function callCommuterCookiesAPI(baseUrl, direct = false) { 175 if(direct) { 176 return syncCommuterCookies(baseUrl, null); 177 } 178 179 var stored = readCommuterSyncState(); 180 181 182 var currentUserId = getCookie("_ourbususersessid") ?? ""; 183 var currentCookie = getCookie("_ourbussessid"); 184 185 186 var alreadySent = 187 isTripConfirmationPage() || 188 (stored && 189 typeof stored === "object" && 190 stored.userId === currentUserId && 191 stored.cookie === currentCookie); 192 193
194 if (alreadySent) { 195 const profileCookie = getCookie("profile"); 196 const txnDone = getCookie("txnDone") === "true"; 197 const onTripConfirmation = isTripConfirmationPage(); 198 199 200 // NOTE: if profile cookie is JSON string, parse; if it's plain, adapt accordingly 201 let isGuestLogin = false; 202 if (profileCookie) { 203 try { 204 const profileObj = JSON.parse(profileCookie); 205 isGuestLogin = profileObj.isGuestLogin === 1; 206 } catch (e) { 207 // if it's not JSON, you can replace this logic with your actual format 208 // isGuestLogin = profileCookie === "1"; // example fallback 209 } 210 } 211 212 213 if (onTripConfirmation) { 214 setCookie("txnDone", "true"); 215 clearCookieId(); 216 } else if (isGuestLogin && txnDone && !onTripConfirmation) { 217 // guest user, txn already done, and we are NOT on tripconfirmation anymore 218 // -> clear txn-related cookie 219 clearCookieId(); 220 logout(); 221 return syncCommuterCookies(baseUrl, readCookieId()); 222 } else if (!isGuestLogin && txnDone && !onTripConfirmation) { 223 setCookie("txnDone", "false"); 224 // sessionStorage.clear(); 225 clearCookieId(); 226 clearCommuterSyncState(); 227 return syncCommuterCookies(baseUrl, readCookieId()); 228 } 229 230 231 return Promise.resolve(null); 232 } 233 234 235 // first time: actually hit backend 236 var previousCookieId = readCookieId(); 237 return syncCommuterCookies(baseUrl, previousCookieId); 238 } 239 240 241 function getOrCreateDeviceId() { 242 // deviceId should always be saved in localStorage and fetched from it only. 243 try { 244 var existing = window.localStorage 245 ? window.localStorage.getItem("deviceId") 246 : null; 247 if (existing) { 248 return { deviceId: existing, isNew: false }; 249 } 250 var deviceId = generateUUIDv4(); 251 if (window.localStorage) { 252 window.localStorage.setItem("deviceId", deviceId); 253 } 254 return { deviceId: deviceId, isNew: true }; 255 } catch (e) { 256 // Fallback (should be rare): still generate, but cannot persist without localStorage 257 var deviceIdFallback = generateUUIDv4(); 258 return { deviceId: deviceIdFallback, isNew: true }; 259 } 260 } 261 262 263 function getOrCreateSessionCookie() { 264 var existing = getCookie("_ourbussessid"); 265 if (existing) return existing; 266 267 268 var newId = generateUUIDv4(); 269 270 271 setCookie("_ourbussessid", newId, 365); 272 return newId; 273 } 274 275 276 async function syncCommuterCookies(baseUrl, previousCookieId) { 277 if (!baseUrl) { 278 var host = window.location.hostname || ""; 279 280 281 if (host.includes("dev.ourbus.com")) { 282 baseUrl = "https://api.dev.ourbus.com"; 283 } else if (host.includes("www.ourbus.com")) { 284 baseUrl = "https://api.ourbus.com"; 285 } else { 286 baseUrl = "https://api.stg.ourbus.com"; // final fallback (UPDATED) 287 } 288 } 289 var params = getAllUrlParams(); 290 var cookie = getOrCreateSessionCookie(); 291 var userIdCookie = getCookie("auth") 292 ? getCookie("_ourbususersessid") 293 : null; 294 var url = baseUrl + "/wsapi/commuter/cookies"; 295 if (params) { 296 url += "?" + params; 297 } 298 if (userIdCookie) { 299 url += 300 (params ? "&" : "?") + "userid=" + encodeURIComponent(userIdCookie); 301 } 302 303 304 const { deviceId, isNew } = getOrCreateDeviceId(); 305 306 307 var body = { 308 all_param: params, 309 cookie: cookie, 310 referrer: document.referrer || "", 311 deviceId: deviceId, 312 }; 313 314 315 if (previousCookieId != null) { 316 body.cookieId = previousCookieId; 317 } 318 319 320 // Retry wrapper (NEW) - no storage updates unless status===200 321 return retryAsync( 322 async function () { 323 return fetch(url, { 324 method: "POST", 325 headers: { 326 "Content-Type": "application/json", 327 }, 328 body: JSON.stringify(body), 329 }).then(async function (response) { 330 if (response.status === 200) { 331 let data = null; 332 try { 333 data = await response.json(); 334 } catch (e) { 335 throw new Error(
336 "commuter/cookies sync failed: invalid JSON response", 337 ); 338 } 339 340 341 if (data?.statusCode === 201) { 342 const ourbusUserSessId = getCookie("_ourbususersessid") ?? ""; 343 writeCommuterSyncState(ourbusUserSessId, cookie); 344 345 346 writeCookieId(data.cookieId); 347 } 348 349 350 // deviceId is persisted in localStorage only; no cookie writes/removals 351 352 353 return true; 354 } 355 // Non-200 should be treated as failure to trigger retry 356 throw new Error( 357 "commuter/cookies sync failed with status " + response.status, 358 ); 359 }); 360 }, 361 { retries: 2, baseDelayMs: 600, jitterMs: 200 }, 362 )["catch"](function (error) { 363 if (typeof console !== "undefined" && console.error) { 364 console.error("API call error:", error); 365 } 366 return null; 367 }); 368 } 369 370 371 function logout() { 372 // Log the exact URL from where logout was triggered 373 console.log("LOGOUT REQUEST FROM URL =", window.location.href); 374 //sessionStorage.removeItem("commuterCookiesAPISuccess"); 375 // ---- Clear the full session (equivalent to session.invalidate()) ---- 376 // sessionStorage.clear(); 377 378 379 clearCommuterSyncState(); 380 381 382 // ---- Delete cookies: auth, profile, _socialTokenCheck ---- 383 deleteCookie("auth"); 384 deleteCookie("profile"); 385 deleteCookie("_socialTokenCheck"); 386 } 387 388 389 // Utility: delete cookies correctly 390 function deleteCookie(name) { 391 document.cookie = `${name}=; Max-Age=0; path=/; SameSite=Lax; Secure`; 392 } 393 394 395 function setCookie(name, value, days) { 396 let expires = ""; 397 398 399 // If expiry is provided (number of days) 400 if (typeof days === "number") { 401 const d = new Date(); 402 d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000); 403 expires = "; expires=" + d.toUTCString(); 404 } 405 406 407 document.cookie = 408 name + 409 "=" + 410 encodeURIComponent(value) + 411 expires + 412 "; path=/" + 413 "; SameSite=Lax" + 414 "; Secure"; 415 } 416 417 418 return { 419 callCommuterCookiesAPI: callCommuterCookiesAPI, 420 }; 421});
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.