/** * P0:Autocomplete 实例拓扑 + place_changed 监听器指纹 * P2:全局 fetch 劫持(axel/location/place) * 纯字符串 initScript,供 addInitScript 注入。 */ export const P0_PLACE_DIAG_INIT = `(() => { if (window.__rpaPlaceDiagP0) return; window.__rpaPlaceDiagP0 = true; window.__rpaPlaceDiag = window.__rpaPlaceDiag || { instances: [], listeners: [], events: [], fetchLog: [], mark: "init", nextInstanceId: 1, nextListenerId: 1, }; var diag = window.__rpaPlaceDiag; function inputMeta(el) { if (!el) return null; var gmKeys = Object.keys(el).filter(function(k) { return k.indexOf("gm_") === 0; }); return { tagName: el.tagName || "", id: el.id || "", className: (el.className || "").slice(0, 80), placeholder: el.placeholder || "", pacTarget: el.classList && el.classList.contains("pac-target-input"), valuePreview: ((el.value || el.textContent || "") + "").replace(/\\s+/g, " ").trim().slice(0, 100), gmKeyCount: gmKeys.length, gmKeys: gmKeys.slice(0, 6), }; } function resolveInstanceFromInput(el) { if (!el) return null; for (var i = 0; i < Object.keys(el).length; i += 1) { var key = Object.keys(el)[i]; if (key.indexOf("gm_") !== 0) continue; var val = el[key]; if (val && typeof val.getPlace === "function") return val; } for (var j = 0; j < diag.instances.length; j += 1) { if (diag.instances[j].inputEl === el) return diag.instances[j].instance; } return null; } function instanceIdFor(inst, inputEl) { for (var i = 0; i < diag.instances.length; i += 1) { if (diag.instances[i].instance === inst) return diag.instances[i].id; } var id = "ac-" + diag.nextInstanceId++; diag.instances.push({ id: id, instance: inst, inputEl: inputEl || inst.__rpaInputEl || null, input: inputMeta(inputEl || inst.__rpaInputEl || null), createdAt: Date.now(), listenerIds: [], }); return id; } function fingerprintHandler(handler, source) { var src = ""; try { src = Function.prototype.toString.call(handler); } catch (e) { src = String(handler); } var compact = src.replace(/\\s+/g, " ").trim(); return { source: source, length: compact.length, preview: compact.slice(0, 240), hasFetch: /\\bfetch\\s*\\(/.test(compact), hasAxelPlace: /axel\\/location\\/place/.test(compact), hasGetPlace: /getPlace\\s*\\(/.test(compact), hasXMLHttpRequest: /XMLHttpRequest|\\.open\\s*\\(/.test(compact), }; } function safeGetPlace(inst) { if (!inst || typeof inst.getPlace !== "function") { return { ok: false, reason: "no-getPlace" }; } try { var p = inst.getPlace(); if (!p) return { ok: true, empty: true }; var loc = p.geometry && p.geometry.location; var lat = null; var lng = null; if (loc) { lat = typeof loc.lat === "function" ? loc.lat() : loc.lat; lng = typeof loc.lng === "function" ? loc.lng() : loc.lng; } return { ok: true, place_id: p.place_id || null, formatted_address: (p.formatted_address || "").slice(0, 160), name: (p.name || "").slice(0, 80), hasGeometry: Boolean(loc), lat: lat, lng: lng, }; } catch (e2) { return { ok: false, reason: "getPlace-threw", error: String(e2) }; } } function wrapHandler(inst, handler, source, inputEl) { var instId = instanceIdFor(inst, inputEl); var fp = fingerprintHandler(handler, source); var lid = "lh-" + diag.nextListenerId++; diag.listeners.push({ id: lid, instanceId: instId, registeredAt: Date.now(), fingerprint: fp, }); for (var i = 0; i < diag.instances.length; i += 1) { if (diag.instances[i].id === instId) { diag.instances[i].listenerIds.push(lid); break; } } return function wrappedPlaceChangedHandler() { diag.events.push({ type: "place_changed_handler", mark: diag.mark, at: Date.now(), instanceId: instId, listenerId: lid, fingerprint: fp, getPlaceBefore: safeGetPlace(inst), }); return handler.apply(this, arguments); }; } function registerPlaceChanged(inst, handler, source, inputEl) { if (!inst || typeof handler !== "function") return handler; return wrapHandler(inst, handler, source, inputEl); } window.__rpaAutocompleteInstances = window.__rpaAutocompleteInstances || []; window.__rpaPlaceChangedHandlers = window.__rpaPlaceChangedHandlers || []; var waitForGoogle = function() { if (typeof google === "undefined" || !google.maps || !google.maps.places || !google.maps.places.Autocomplete) { setTimeout(waitForGoogle, 200); return; } if (window.__rpaAutocompletePatched) return; window.__rpaAutocompletePatched = true; var AutocompleteCtor = google.maps.places.Autocomplete; google.maps.places.Autocomplete = function() { var args = arguments; var instance = Reflect.construct(AutocompleteCtor, args); var inputEl = args[0] || null; instance.__rpaInputEl = inputEl; window.__rpaAutocompleteInstances.push(instance); instanceIdFor(instance, inputEl); if (typeof instance.addListener === "function") { var origInstAdd = instance.addListener.bind(instance); instance.addListener = function(eventName, handler) { var h = handler; if (eventName === "place_changed" && typeof handler === "function") { h = registerPlaceChanged(instance, handler, "instance.addListener", inputEl); window.__rpaPlaceChangedHandlers.push({ instance: instance, handler: h, inputEl: inputEl }); } return origInstAdd(eventName, h); }; } return instance; }; google.maps.places.Autocomplete.prototype = AutocompleteCtor.prototype; if (google.maps.event && typeof google.maps.event.addListener === "function") { var origMapsAdd = google.maps.event.addListener; google.maps.event.addListener = function(instance, eventName, handler) { var h = handler; if ( eventName === "place_changed" && instance && typeof instance.getPlace === "function" && typeof handler === "function" ) { h = registerPlaceChanged(instance, handler, "maps.event.addListener", instance.__rpaInputEl || null); window.__rpaPlaceChangedHandlers.push({ instance: instance, handler: h, inputEl: instance.__rpaInputEl || null, }); } return origMapsAdd(instance, eventName, h); }; } if (google.maps.event && typeof google.maps.event.trigger === "function") { var origTrigger = google.maps.event.trigger; google.maps.event.trigger = function(instance, eventName) { var instId = instance && typeof instance.getPlace === "function" ? instanceIdFor(instance, instance.__rpaInputEl || null) : null; if (eventName === "place_changed") { diag.events.push({ type: "maps_event_trigger", mark: diag.mark, at: Date.now(), instanceId: instId, getPlaceAtTrigger: instance ? safeGetPlace(instance) : null, }); } return origTrigger.apply(this, arguments); }; } diag.events.push({ type: "p0-ready", at: Date.now(), mark: diag.mark }); }; waitForGoogle(); })();`; export const P2_FETCH_HIJACK_INIT = `(() => { if (window.__rpaPlaceFetchP2) return; window.__rpaPlaceFetchP2 = true; window.__rpaPlaceDiag = window.__rpaPlaceDiag || { fetchLog: [], events: [], mark: "init" }; var diag = window.__rpaPlaceDiag; diag.fetchLog = diag.fetchLog || []; var origFetch = window.fetch; if (typeof origFetch === "function") { window.fetch = function() { var url = ""; try { var first = arguments[0]; url = typeof first === "string" ? first : (first && first.url) || ""; } catch (e) {} if (url && url.indexOf("axel/location/place") >= 0) { var stack = ""; try { stack = (new Error("place-fetch")).stack || ""; } catch (e2) {} diag.fetchLog.push({ mark: diag.mark, at: Date.now(), url: url.slice(0, 240), stackPreview: stack.split("\\n").slice(0, 8).join(" | "), }); diag.events.push({ type: "fetch_place", mark: diag.mark, at: Date.now(), url: url.slice(0, 240) }); } return origFetch.apply(this, arguments); }; } var XHR = window.XMLHttpRequest; if (XHR && XHR.prototype && XHR.prototype.open) { var origOpen = XHR.prototype.open; XHR.prototype.open = function(method, url) { this.__rpaUrl = url; return origOpen.apply(this, arguments); }; var origSend = XHR.prototype.send; XHR.prototype.send = function() { var url = this.__rpaUrl || ""; if (url && String(url).indexOf("axel/location/place") >= 0) { diag.fetchLog.push({ mark: diag.mark, at: Date.now(), url: String(url).slice(0, 240), transport: "xhr", }); diag.events.push({ type: "xhr_place", mark: diag.mark, at: Date.now(), url: String(url).slice(0, 240) }); } return origSend.apply(this, arguments); }; } })();`; /** 设置诊断阶段标记并清空本阶段事件 */ export const PLACE_DIAG_SET_MARK = `(mark) => { window.__rpaPlaceDiag = window.__rpaPlaceDiag || { events: [], mark: "init" }; window.__rpaPlaceDiag.mark = mark || "phase"; return { ok: true, mark: window.__rpaPlaceDiag.mark }; }`; /** 采集实例拓扑 + 监听器指纹 + 事件 + fetch 日志(可序列化) */ export const PLACE_DIAG_COLLECT_SNAPSHOT = `() => { try { var diag = window.__rpaPlaceDiag; if (!diag) return { ok: false, reason: "no-diag" }; function inputMeta(el) { if (!el) return null; var gmKeys = Object.keys(el).filter(function(k) { return k.indexOf("gm_") === 0; }); return { tagName: el.tagName || "", placeholder: el.placeholder || "", pacTarget: el.classList && el.classList.contains("pac-target-input"), valuePreview: ((el.value || "") + "").replace(/\\s+/g, " ").trim().slice(0, 100), gmKeyCount: gmKeys.length, }; } function resolveFromInput(el) { if (!el) return null; for (var i = 0; i < Object.keys(el).length; i += 1) { var key = Object.keys(el)[i]; if (key.indexOf("gm_") !== 0) continue; var val = el[key]; if (val && typeof val.getPlace === "function") return val; } return null; } var widget = document.querySelector("#react-quoter-landing-plugin"); var inputProbes = []; if (widget) { var inputs = widget.querySelectorAll("input[type='text'], input:not([type])"); for (var i = 0; i < inputs.length; i += 1) { var inp = inputs[i]; var inst = resolveFromInput(inp); inputProbes.push({ index: i, meta: inputMeta(inp), hasGmInstance: Boolean(inst), getPlace: inst && typeof inst.getPlace === "function" ? (function() { try { var p = inst.getPlace(); return { place_id: p && p.place_id, formatted_address: p && p.formatted_address, hasGeometry: Boolean(p && p.geometry && p.geometry.location), }; } catch (e) { return { error: String(e) }; } })() : null, }); } } var instances = (diag.instances || []).map(function(row) { var inst = row.instance; var getPlace = null; if (inst && typeof inst.getPlace === "function") { try { var p = inst.getPlace(); getPlace = { place_id: p && p.place_id, formatted_address: p && p.formatted_address, hasGeometry: Boolean(p && p.geometry && p.geometry.location), }; } catch (e2) { getPlace = { error: String(e2) }; } } var listenerRows = (diag.listeners || []).filter(function(l) { return l.instanceId === row.id; }); return { id: row.id, input: row.input, listenerCount: listenerRows.length, listenerFingerprints: listenerRows.map(function(l) { return l.fingerprint; }), getPlace: getPlace, }; }); var anyListenerHasFetch = (diag.listeners || []).some(function(l) { return l.fingerprint && l.fingerprint.hasFetch; }); var anyListenerHasAxel = (diag.listeners || []).some(function(l) { return l.fingerprint && l.fingerprint.hasAxelPlace; }); var handlerEvents = (diag.events || []).filter(function(e) { return e.type === "place_changed_handler" || e.type === "maps_event_trigger"; }); var fetchEvents = (diag.fetchLog || []).slice(-20); return { ok: true, mark: diag.mark, topology: { instanceCount: instances.length, instances: instances, inputProbes: inputProbes, monkeyPatchInstances: (window.__rpaAutocompleteInstances || []).length, capturedHandlers: (window.__rpaPlaceChangedHandlers || []).length, }, listeners: { total: (diag.listeners || []).length, anyHasFetch: anyListenerHasFetch, anyHasAxelPlace: anyListenerHasAxel, rows: (diag.listeners || []).map(function(l) { return { id: l.id, instanceId: l.instanceId, fingerprint: l.fingerprint }; }), }, events: (diag.events || []).slice(-40), handlerEvents: handlerEvents, fetchLog: fetchEvents, activeElement: (function() { var el = document.activeElement; if (!el) return null; return inputMeta(el); })(), }; } catch (err) { return { ok: false, reason: "snapshot-error", error: String(err) }; } }`;