1// applytop/app-1.6.19/src/helpers/native-bridge.js 2function nativePlugins() { 3 try { 4 const cap = window.Capacitor; 5 if (!cap || typeof cap.isNativePlatform !== "function" || !cap.isNativePlatform()) return null; 6 return cap.Plugins || {}; 7 } catch (_) { 8 return null; 9 } 10} 11function install(P) { 12 const App = P.App; 13 const Share = P.Share; 14 const Camera = P.Camera; 15 const PushNotifications = P.PushNotifications; 16 const Network = P.Network; 17 const Browser = P.Browser; 18 const SecureStorage = P.SecureStoragePlugin; 19 const BiometricAuth = P.BiometricAuthNative; 20 function getStore() { 21 return typeof window.CdvPurchase !== "undefined" ? window.CdvPurchase.store : null; 22 } 23 const GPB_PRODUCTS = [ 24 { id: "credits_small", type: "consumable" }, 25 { id: "credits_medium", type: "consumable" }, 26 { id: "credits_large", type: "consumable" }, 27 { id: "pro_lifetime", type: "non consumable" }, 28 { id: "pro_weekly", type: "paid subscription" }, 29 { id: "pro_monthly", type: "paid subscription" }, 30 { id: "pro_yearly", type: "paid subscription" }, 31 { id: "career_growth_weekly", type: "paid subscription" } 32 ]; 33 const _pendingPurchases = /* @__PURE__ */ new Map(); 34 let _storeInitialized = false; 35 function initStore() { 36 const store = getStore(); 37 if (!store || _storeInitialized) return; 38 _storeInitialized = true; 39 try { 40 const CdvPurchase = window.CdvPurchase; 41 const Platform = CdvPurchase.Platform; 42 const ProductType = CdvPurchase.ProductType; 43 const typeMap = { 44 "consumable": ProductType.CONSUMABLE, 45 "non consumable": ProductType.NON_CONSUMABLE, 46 "paid subscription": ProductType.PAID_SUBSCRIPTION 47 }; 48 store.register(GPB_PRODUCTS.map((p) => ({ 49 id: p.id, 50 type: typeMap[p.type] || ProductType.CONSUMABLE, 51 platform: Platform.GOOGLE_PLAY 52 }))); 53 store.when().approved((transaction) => { 54 for (const productId of (transaction.products || []).map((p) => p.id)) { 55 const waiter = _pendingPurchases.get(productId); 56 if (waiter) { 57 waiter.resolve({ 58 purchaseToken: transaction.purchaseId || transaction.transactionId, 59 productId, 60 orderId: transaction.transactionId || null 61 }); 62 _pendingPurchases.delete(productId); 63 } 64 } 65 transaction.finish(); 66 }).cancelled((transaction) => { 67 for (const productId of (transaction.products || []).map((p) => p.id)) { 68 const waiter = _pendingPurchases.get(productId); 69 if (waiter) { 70 waiter.resolve(null); 71 _pendingPurchases.delete(productId); 72 } 73 } 74 }); 75 store.error((err) => { 76 console.warn("[AT bridge] Store error:", err); 77 }); 78 store.initialize([Platform.GOOGLE_PLAY]).catch((err) => { 79 console.warn("[AT bridge] Store initialize failed:", err); 80 }); 81 } catch (err) { 82 console.warn("[AT bridge] initStore failed:", err); 83 } 84 } 85 async function startPurchase(productId) { 86 const store = getStore(); 87 if (!store) { 88 console.warn("[AT bridge] cordova-plugin-purchase not loaded"); 89 return null; 90 } 91 initStore(); 92 const offer = store.get(productId)?.getOffer(); 93 if (!offer) { 94 console.warn("[AT bridge] No Play offer for product:", productId); 95 return { error: true, message: "This purchase is not available on this build" }; 96 } 97 return new Promise((resolve, reject) => { 98 _pendingPurchases.set(productId, { resolve, reject }); 99 offer.order().catch((err) => { 100 console.warn("[AT bridge] order() failed:", err); 101 const waiter = _pendingPurchases.get(productId); 102 if (waiter) { 103 waiter.resolve(null); 104 _pendingPurchases.delete(productId); 105 } 106 }); 107 }); 108 } 109 const TOKEN_KEY = "at.token"; 110 const USER_ID_KEY = "at.userId"; 111 const USER_EMAIL_KEY = "at.email"; 112 async function saveToken({ token, userId, email }) { 113 if (!SecureStorage) return false; 114 try { 115 await SecureStorage.set({ key: TOKEN_KEY, value: token }); 116 if (userId) await SecureStorage.set({ key: USER_ID_KEY, value: userId }); 117 if (email) await SecureStorage.set({ key: USER_EMAIL_KEY, value: email }); 118 return true; 119 } catch (err) { 120 console.warn("[AT bridge] saveToken failed:", err); 121 return false;
122 } 123 } 124 async function getToken() { 125 if (!SecureStorage) return null; 126 try { 127 const tokenRes = await SecureStorage.get({ key: TOKEN_KEY }).catch(() => null); 128 const userIdRes = await SecureStorage.get({ key: USER_ID_KEY }).catch(() => null); 129 const emailRes = await SecureStorage.get({ key: USER_EMAIL_KEY }).catch(() => null); 130 if (!tokenRes?.value || !userIdRes?.value) return null; 131 return { token: tokenRes.value, userId: userIdRes.value, email: emailRes?.value || null }; 132 } catch (err) { 133 console.warn("[AT bridge] getToken failed:", err); 134 return null; 135 } 136 } 137 async function clearToken() { 138 if (!SecureStorage) return; 139 try { 140 await SecureStorage.remove({ key: TOKEN_KEY }).catch(() => { 141 }); 142 await SecureStorage.remove({ key: USER_ID_KEY }).catch(() => { 143 }); 144 await SecureStorage.remove({ key: USER_EMAIL_KEY }).catch(() => { 145 }); 146 } catch (_) { 147 } 148 } 149 let _cachedFcmToken = null; 150 let _fcmTokenWaiters = []; 151 function setFcmToken(token) { 152 _cachedFcmToken = token; 153 _fcmTokenWaiters.forEach((fn) => fn(token)); 154 _fcmTokenWaiters = []; 155 } 156 async function pushIsSafe() { 157 try { 158 const ATPush = P.ATPush; 159 if (!ATPush || typeof ATPush.isAvailable !== "function") return false; 160 const res = await ATPush.isAvailable(); 161 return !!(res && res.available); 162 } catch (_) { 163 return false; 164 } 165 } 166 async function getFcmToken() { 167 if (_cachedFcmToken) return _cachedFcmToken; 168 if (!PushNotifications) return null; 169 if (!await pushIsSafe()) { 170 console.warn("[AT bridge] Push unavailable (Firebase not initialised in this build); skipping registration"); 171 return null; 172 } 173 try { 174 const perm = await PushNotifications.requestPermissions(); 175 if (perm.receive !== "granted") return null; 176 await PushNotifications.register(); 177 return await new Promise((resolve) => { 178 const timeout = setTimeout(() => resolve(null), 1e4); 179 _fcmTokenWaiters.push((token) => { 180 clearTimeout(timeout); 181 resolve(token); 182 }); 183 }); 184 } catch (err) { 185 console.warn("[AT bridge] getFcmToken failed:", err); 186 return null; 187 } 188 } 189 async function share({ title, text, url }) { 190 if (!Share) return false; 191 try { 192 await Share.share({ title, text, url, dialogTitle: title }); 193 return true; 194 } catch (_) { 195 return false; 196 } 197 } 198 async function cameraCapture() { 199 if (!Camera) return null; 200 try { 201 const photo = await Camera.getPhoto({ 202 quality: 80, 203 allowEditing: false, 204 resultType: "base64", 205 source: "CAMERA" 206 }); 207 return { base64: photo.base64String, mimeType: "image/" + (photo.format || "jpeg") }; 208 } catch (_) { 209 return null; 210 } 211 } 212 async function enableBiometric() { 213 if (!BiometricAuth) return false; 214 try { 215 const info = await BiometricAuth.checkBiometry(); 216 return !!info?.isAvailable; 217 } catch (_) { 218 return false; 219 } 220 } 221 async function promptBiometric() { 222 if (!BiometricAuth) return true; 223 try { 224 const info = await BiometricAuth.checkBiometry(); 225 if (!info?.isAvailable) return true; 226 await BiometricAuth.authenticate({ 227 reason: "Unlock ApplyTop", 228 cancelTitle: "Use password", 229 allowDeviceCredential: true 230 }); 231 return true; 232 } catch (_) { 233 return false; 234 } 235 } 236 async function logout() { 237 await clearToken(); 238 return true; 239 } 240 async function openExternal({ url }) { 241 if (!Browser) { 242 window.open(url, "_blank"); 243 return true; 244 } 245 try { 246 await Browser.open({ url }); 247 return true; 248 } catch (err) { 249 console.warn("[AT bridge] openExternal failed:", err); 250 return false; 251 } 252 } 253 function wireLifecycleEvents() { 254 if (App) { 255 try { 256 App.addListener("appStateChange", ({ isActive }) => { 257 window.dispatchEvent(new CustomEvent(isActive ? "at:resume" : "at:pause")); 258 }); 259 App.addListener("backButton", ({ canGoBack }) => { 260 if (window.history.length > 1 || canGoBack) window.history.back(); 261 else App.exitApp(); 262 }); 263 App.addListener("appUrlOpen", ({ url }) => { 264 try { 265 const parsed = new URL(url); 266 if (parsed.protocol === "applytop:") { 267 window.location.href = "/" + parsed.host + parsed.pathname + (parsed.search || ""); 268 } else if (parsed.host && parsed.host.endsWith("applytop.com")) { 269 window.location.href = parsed.pathname + parsed.search + parsed.hash; 270 } 271 } catch (err) { 272 console.warn("[AT bridge] appUrlOpen parse failed:", err); 273 } 274 }); 275 } catch (err) { 276 console.warn("[AT bridge] App listener wiring failed:", err); 277 } 278 } 279 if (Network) {
280 try { 281 Network.addListener("networkStatusChange", (status) => { 282 window.dispatchEvent(new CustomEvent("at:networkchange", { 283 detail: { connected: status.connected, type: status.connectionType } 284 })); 285 }); 286 Network.getStatus().then((status) => { 287 window.dispatchEvent(new CustomEvent("at:networkchange", { 288 detail: { connected: status.connected, type: status.connectionType } 289 })); 290 }).catch(() => { 291 }); 292 } catch (err) { 293 console.warn("[AT bridge] Network listener wiring failed:", err); 294 } 295 } 296 if (PushNotifications) { 297 try { 298 PushNotifications.addListener("registration", ({ value }) => setFcmToken(value)); 299 PushNotifications.addListener("registrationError", (err) => { 300 console.warn("[AT bridge] FCM registration error:", err); 301 }); 302 PushNotifications.addListener("pushNotificationActionPerformed", ({ notification }) => { 303 const data = notification?.data || {}; 304 if (data.url) window.location.href = data.url; 305 else if (data.alertId) window.location.href = "/dashboard/matches?alert=" + encodeURIComponent(data.alertId); 306 else window.location.href = "/dashboard/matches"; 307 }); 308 } catch (err) { 309 console.warn("[AT bridge] Push listener wiring failed:", err); 310 } 311 } 312 } 313 window.AT = { 314 saveToken, 315 getToken, 316 clearToken, 317 purchase: ({ productId }) => startPurchase(productId), 318 purchaseSubscription: ({ productId }) => startPurchase(productId), 319 share, 320 cameraCapture, 321 getFcmToken, 322 enableBiometric, 323 promptBiometric, 324 logout, 325 openExternal 326 }; 327 wireLifecycleEvents(); 328 if (typeof window.CdvPurchase !== "undefined") initStore(); 329 else document.addEventListener("deviceready", initStore, { once: true }); 330} 331try { 332 const P = nativePlugins(); 333 if (P) install(P); 334} catch (err) { 335 console.warn("[AT bridge] install failed:", err); 336} 337
338// applytop/app-1.6.19/src/helpers/net.js 339function nativeHeaders() { 340 try { 341 if (window.Capacitor && window.Capacitor.isNativePlatform && window.Capacitor.isNativePlatform()) { 342 return { 343 "X-AT-Client": "android", 344 "X-AT-App-Version": window.constant && window.constant.appVersion || "" 345 }; 346 } 347 } catch (_) { 348 } 349 return {}; 350} 351function clearSession() { 352 localStorage.removeItem("token"); 353 localStorage.removeItem("user"); 354 try { 355 if (window.AT && window.AT.logout) window.AT.logout(); 356 } catch (_) { 357 } 358} 359async function call(path, method, data) { 360 const cleanPath = path.replace(/^\/+/, "").replace(/\/+$/, ""); 361 const apiUrl = (window.constant && window.constant.apiUrl || `https://${window.location.hostname}/api`).replace(/\/+$/, ""); 362 let fullUrl = `${apiUrl}/${cleanPath}`; 363 if (method === "POST") { 364 let response = await fetch(fullUrl, { 365 method: "POST", 366 headers: { 367 "Content-Type": "application/json;charset=utf-8", 368 ...nativeHeaders() 369 }, 370 body: JSON.stringify(data) 371 }); 372 let result = await response.json(); 373 if (result.error && result.errorMessage === "Auth Error") { 374 clearSession(); 375 window.location.href = "/login"; 376 return result; 377 } 378 return result; 379 } else if (method === "FORMDATA") { 380 let response = await fetch(fullUrl, { 381 method: "POST", 382 headers: { ...nativeHeaders() }, 383 body: data 384 }); 385 let result = await response.json(); 386 if (result.error && result.errorMessage === "Auth Error") { 387 clearSession(); 388 window.location.href = "/login"; 389 return result; 390 } 391 return result; 392 } else if (method === "GET") { 393 const authHeaders = {}; 394 if (data) { 395 const separator = fullUrl.includes("?") ? "&" : "?"; 396 const queryParams = []; 397 if (data.token) { 398 authHeaders["Authorization"] = `Bearer ${data.token}`; 399 delete data.token; 400 } 401 if (data.userId) { 402 queryParams.push(`userId=${encodeURIComponent(data.userId)}`); 403 delete data.userId; 404 } 405 for (const key in data) { 406 if (data[key] !== void 0 && data[key] !== null) { 407 queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`); 408 } 409 } 410 if (queryParams.length > 0) { 411 fullUrl += separator + queryParams.join("&"); 412 } 413 } 414 let response = await fetch(fullUrl, { 415 method: "GET", 416 headers: authHeaders 417 }); 418 if (response.ok) { 419 let result = await response.json(); 420 if (result.error && result.errorMessage === "Auth Error") { 421 clearSession(); 422 window.location.href = "/login"; 423 return result; 424 } 425 return result; 426 } else { 427 console.error("GET request failed:", response.status, response.statusText); 428 let result = await response.json(); 429 if (result.error && result.errorMessage === "Auth Error") { 430 clearSession(); 431 window.location.href = "/login"; 432 return result; 433 } 434 return { 435 success: false, 436 error: `Request failed with status ${response.status}` 437 }; 438 } 439 } 440} 441
442// applytop/app-1.6.19/src/helpers/attribution.js 443var STORAGE_KEY = "applytop.attribution"; 444var FIRST_TOUCH_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "gclid", "fbclid", "ttclid", "ref"]; 445var LAST_TOUCH_KEYS = ["click_id", "sub_id"]; 446function readStoredRaw() { 447 try { 448 return localStorage.getItem(STORAGE_KEY); 449 } catch (e) { 450 return null; 451 } 452} 453function isInternalReferrer(referrer) { 454 if (!referrer) return false; 455 try { 456 const ref = new URL(referrer); 457 const here = window.location.hostname || ""; 458 if (ref.hostname === here) return true; 459 const refApex = ref.hostname.replace(/^.*?([^.]+\.[^.]+)$/, "$1"); 460 const hereApex = here.replace(/^.*?([^.]+\.[^.]+)$/, "$1"); 461 return !!hereApex && refApex === hereApex; 462 } catch (e) { 463 return false; 464 } 465} 466function captureAttribution() { 467 if (typeof window === "undefined" || typeof localStorage === "undefined") return; 468 let params; 469 try { 470 params = new URLSearchParams(window.location.search || ""); 471 } catch (e) { 472 return; 473 } 474 let existing = {}; 475 const raw = readStoredRaw(); 476 if (raw) { 477 try { 478 const parsed = JSON.parse(raw); 479 if (parsed && typeof parsed === "object") existing = parsed; 480 } catch (e) { 481 } 482 } 483 let changed = false; 484 for (const key of LAST_TOUCH_KEYS) { 485 const v = params.get(key); 486 if (v !== null && v !== "" && existing[key] !== v) { 487 existing[key] = v.slice(0, 512); 488 changed = true; 489 } 490 } 491 for (const key of FIRST_TOUCH_KEYS) { 492 if (existing[key]) continue; 493 const v = params.get(key); 494 if (v !== null && v !== "") { 495 existing[key] = v.slice(0, 512); 496 changed = true; 497 } 498 } 499 if (!existing.referrer_url) { 500 const rawReferrer = (document.referrer || "").slice(0, 2048); 501 if (rawReferrer && !isInternalReferrer(rawReferrer)) { 502 existing.referrer_url = rawReferrer; 503 changed = true; 504 } 505 } 506 if (!existing.landing_page) { 507 existing.landing_page = (window.location.pathname || "/") + (window.location.search || ""); 508 existing.landing_page_at = (/* @__PURE__ */ new Date()).toISOString(); 509 changed = true; 510 } 511 if (!changed) return; 512 try { 513 localStorage.setItem(STORAGE_KEY, JSON.stringify(existing)); 514 } catch (e) { 515 } 516} 517function readAttribution() { 518 const raw = readStoredRaw(); 519 if (!raw) return {}; 520 try { 521 const obj = JSON.parse(raw); 522 return obj && typeof obj === "object" ? obj : {}; 523 } catch (e) { 524 return {}; 525 } 526} 527captureAttribution(); 528
529// applytop/app-1.6.19/src/helpers/track.js 530var SESSION_KEY = "applytop.anon_session"; 531function getOrCreateSessionId() { 532 try { 533 let id = localStorage.getItem(SESSION_KEY); 534 if (id) return id; 535 const rand = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).slice(2); 536 id = `anon_${rand}`.slice(0, 64); 537 localStorage.setItem(SESSION_KEY, id); 538 return id; 539 } catch (_) { 540 return null; 541 } 542} 543function abVariant() { 544 const key = getOrCreateSessionId(); 545 if (!key) return "A"; 546 let h = 5381; 547 const s = String(key); 548 for (let i = 0; i < s.length; i++) h = (h << 5) + h + s.charCodeAt(i) | 0; 549 return (h & 1) === 0 ? "A" : "B"; 550} 551function isLandingPath(pathname) { 552 const p = (pathname || "/").replace(/\/+$/, "") || "/"; 553 return p === "/" || p === "/index" || p === "/pl" || p === "/es" || p === "/hi"; 554} 555function track(eventType, opts = {}) { 556 if (!eventType) return; 557 try { 558 let user = null; 559 try { 560 user = JSON.parse(localStorage.getItem("user") || "null"); 561 } catch (_) { 562 } 563 const body = { 564 eventType, 565 metadata: { 566 ...readAttribution(), 567 ...opts.metadata || {} 568 } 569 }; 570 if (user && user.id && user.token) { 571 body.userId = user.id; 572 body.token = user.token; 573 } else { 574 body.sessionId = getOrCreateSessionId(); 575 } 576 if (opts.cvId) body.cvId = opts.cvId; 577 if (opts.jobId) body.jobId = opts.jobId; 578 if (opts.variant) body.variant = opts.variant; 579 if (opts.trigger) body.trigger = opts.trigger; 580 if (opts.path) body.path = opts.path; 581 if (opts.referrer) body.referrer = opts.referrer; 582 call("events/track", "POST", body).catch(() => { 583 }); 584 } catch (_) { 585 } 586} 587var bootstrapped = false; 588function bootstrapAutoTracking() { 589 if (typeof window === "undefined" || typeof document === "undefined") return; 590 if (bootstrapped) return; 591 bootstrapped = true; 592 if (typeof location !== "undefined" && location.pathname && location.pathname.startsWith("/roppongi")) { 593 return; 594 } 595 const firePageView = () => { 596 try { 597 const path = (location.pathname || "/") + (location.search || ""); 598 const referrer = document.referrer || null; 599 const screenStr = typeof screen !== "undefined" && screen.width && screen.height ? `${screen.width}x${screen.height}` : null; 600 track("page_view", { 601 path, 602 referrer, 603 metadata: screenStr ? { screen: screenStr } : {}, 604 // Stamp the hero A/B bucket on landing views so page_view is the 605 // denominator of the variant funnel. 606 variant: isLandingPath(location.pathname) ? abVariant() : void 0 607 }); 608 } catch (_) { 609 } 610 }; 611 if (document.readyState === "loading") { 612 document.addEventListener("DOMContentLoaded", firePageView, { once: true }); 613 } else { 614 firePageView(); 615 } 616 document.addEventListener("click", (e) => { 617 try { 618 const el = e.target && e.target.closest && e.target.closest("[data-track-cta]"); 619 if (!el) return; 620 const cta = el.getAttribute("data-track-cta"); 621 if (!cta) return; 622 const body = { 623 eventType: "landing_cta_clicked", 624 metadata: { ...readAttribution(), cta }, 625 path: (location.pathname || "/") + (location.search || "") 626 }; 627 if (isLandingPath(location.pathname)) body.variant = abVariant(); 628 let user = null; 629 try { 630 user = JSON.parse(localStorage.getItem("user") || "null"); 631 } catch (_) { 632 } 633 if (user && user.id && user.token) { 634 body.userId = user.id; 635 body.token = user.token; 636 } else { 637 body.sessionId = getOrCreateSessionId(); 638 } 639 const apiUrl = typeof window !== "undefined" && window.constant && window.constant.apiUrl ? window.constant.apiUrl.replace(/\/+$/, "") : `https://${location.hostname}/api`; 640 if (apiUrl && navigator.sendBeacon) { 641 navigator.sendBeacon(`${apiUrl}/events/track`, new Blob([JSON.stringify(body)], { type: "application/json" })); 642 } else { 643 track("landing_cta_clicked", { metadata: { cta }, variant: body.variant, path: body.path }); 644 } 645 } catch (_) { 646 } 647 }, true); 648 document.addEventListener("click", (e) => { 649 try { 650 const a = e.target && e.target.closest && e.target.closest("a[href]"); 651 if (!a) return; 652 const href = a.getAttribute("href") || ""; 653 if (!href || href.startsWith("#") || /^(mailto:|tel:|javascript:)/i.test(href)) return; 654 let url;
655 try { 656 url = new URL(href, location.href); 657 } catch (_) { 658 return; 659 } 660 if (!/^https?:$/i.test(url.protocol)) return; 661 if (url.hostname === location.hostname) return; 662 track("outbound_click", { 663 metadata: { 664 url: url.href.slice(0, 512), 665 text: (a.textContent || "").trim().slice(0, 80) || null 666 } 667 }); 668 } catch (_) { 669 } 670 }, true); 671} 672bootstrapAutoTracking();
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.