hypha-debugger 0.1.4 → 0.1.6
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/dist/debugger.d.ts +13 -0
- package/dist/hypha-debugger.js +347 -16
- package/dist/hypha-debugger.js.map +1 -1
- package/dist/hypha-debugger.min.js +4 -4
- package/dist/hypha-debugger.min.js.map +1 -1
- package/dist/hypha-debugger.mjs +346 -17
- package/dist/hypha-debugger.mjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/services/navigate.d.ts +25 -1
- package/package.json +1 -1
package/dist/debugger.d.ts
CHANGED
|
@@ -45,9 +45,22 @@ export declare class HyphaDebugger {
|
|
|
45
45
|
private cursor;
|
|
46
46
|
private server;
|
|
47
47
|
private serviceInfo;
|
|
48
|
+
private boundBeforeUnload;
|
|
49
|
+
private cleanupInterceptor;
|
|
48
50
|
constructor(config: DebuggerConfig);
|
|
49
51
|
start(): Promise<DebugSession>;
|
|
50
52
|
destroy(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Persist debugger config to sessionStorage so the debugger can
|
|
55
|
+
* auto-reconnect after a page reload (soft reload injects the script,
|
|
56
|
+
* autoStart() reads this config).
|
|
57
|
+
*/
|
|
58
|
+
private saveConfigToStorage;
|
|
59
|
+
/**
|
|
60
|
+
* Detect the URL of the currently loaded hypha-debugger script.
|
|
61
|
+
* Used by navigate.ts to inject the correct script after soft reload.
|
|
62
|
+
*/
|
|
63
|
+
private detectScriptUrl;
|
|
51
64
|
/**
|
|
52
65
|
* Generate token, build service URL, update overlay instructions, and
|
|
53
66
|
* return a DebugSession.
|
package/dist/hypha-debugger.js
CHANGED
|
@@ -10584,20 +10584,248 @@
|
|
|
10584
10584
|
};
|
|
10585
10585
|
|
|
10586
10586
|
/**
|
|
10587
|
-
* Navigation service.
|
|
10587
|
+
* Navigation service with auto-reconnect support.
|
|
10588
|
+
*
|
|
10589
|
+
* For agent-triggered reload() and same-origin navigate(), we use a "soft"
|
|
10590
|
+
* approach: fetch the target HTML, inject the debugger <script> tag, then
|
|
10591
|
+
* replace the document via document.write(). The injected script auto-starts
|
|
10592
|
+
* from sessionStorage config, so the debugger reconnects with the same
|
|
10593
|
+
* workspace and service ID. The agent's URL stays stable.
|
|
10594
|
+
*
|
|
10595
|
+
* For cross-origin navigate(), goBack(), and goForward(), we fall back to
|
|
10596
|
+
* normal navigation. The debugger config is saved to sessionStorage so
|
|
10597
|
+
* re-clicking the bookmarklet reconnects seamlessly.
|
|
10598
|
+
*/
|
|
10599
|
+
const STORAGE_KEY$1 = "__hypha_debugger_config__";
|
|
10600
|
+
/** Read the saved script URL from sessionStorage, or fall back to CDN. */
|
|
10601
|
+
function getScriptUrl() {
|
|
10602
|
+
try {
|
|
10603
|
+
const raw = sessionStorage.getItem(STORAGE_KEY$1);
|
|
10604
|
+
if (raw) {
|
|
10605
|
+
const config = JSON.parse(raw);
|
|
10606
|
+
if (config.script_url)
|
|
10607
|
+
return config.script_url;
|
|
10608
|
+
}
|
|
10609
|
+
}
|
|
10610
|
+
catch {
|
|
10611
|
+
// ignore
|
|
10612
|
+
}
|
|
10613
|
+
return "https://cdn.jsdelivr.net/npm/hypha-debugger/dist/hypha-debugger.min.js";
|
|
10614
|
+
}
|
|
10615
|
+
/**
|
|
10616
|
+
* Inject the debugger loader script into HTML before </body> (or append).
|
|
10617
|
+
*/
|
|
10618
|
+
function injectLoader(html, scriptUrl) {
|
|
10619
|
+
const loader = `<script src="${scriptUrl}"><\/script>`;
|
|
10620
|
+
if (html.includes("</body>")) {
|
|
10621
|
+
return html.replace("</body>", loader + "\n</body>");
|
|
10622
|
+
}
|
|
10623
|
+
if (html.includes("</html>")) {
|
|
10624
|
+
return html.replace("</html>", loader + "\n</html>");
|
|
10625
|
+
}
|
|
10626
|
+
return html + "\n" + loader;
|
|
10627
|
+
}
|
|
10628
|
+
/**
|
|
10629
|
+
* Perform a soft page replacement: fetch HTML, inject debugger script,
|
|
10630
|
+
* replace the document via document.write(). If the fetch or write fails,
|
|
10631
|
+
* falls back to hard navigation.
|
|
10632
|
+
*/
|
|
10633
|
+
function softReplace(url, pushState) {
|
|
10634
|
+
const scriptUrl = getScriptUrl();
|
|
10635
|
+
fetch(url, { credentials: "same-origin", cache: "reload" })
|
|
10636
|
+
.then((response) => {
|
|
10637
|
+
if (!response.ok)
|
|
10638
|
+
throw new Error(`HTTP ${response.status}`);
|
|
10639
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
10640
|
+
if (!contentType.includes("text/html")) {
|
|
10641
|
+
throw new Error("Not HTML");
|
|
10642
|
+
}
|
|
10643
|
+
return response.text();
|
|
10644
|
+
})
|
|
10645
|
+
.then((html) => {
|
|
10646
|
+
const modified = injectLoader(html, scriptUrl);
|
|
10647
|
+
document.open();
|
|
10648
|
+
document.write(modified);
|
|
10649
|
+
document.close();
|
|
10650
|
+
if (pushState) {
|
|
10651
|
+
try {
|
|
10652
|
+
history.pushState({}, "", pushState);
|
|
10653
|
+
}
|
|
10654
|
+
catch {
|
|
10655
|
+
// ignore — URL might already match
|
|
10656
|
+
}
|
|
10657
|
+
}
|
|
10658
|
+
})
|
|
10659
|
+
.catch(() => {
|
|
10660
|
+
// Soft replace failed — fall back to hard navigation
|
|
10661
|
+
if (pushState) {
|
|
10662
|
+
window.location.href = pushState;
|
|
10663
|
+
}
|
|
10664
|
+
else {
|
|
10665
|
+
window.location.reload();
|
|
10666
|
+
}
|
|
10667
|
+
});
|
|
10668
|
+
}
|
|
10669
|
+
/** Check if a URL is same-origin as the current page. */
|
|
10670
|
+
function isSameOrigin(url) {
|
|
10671
|
+
try {
|
|
10672
|
+
const target = new URL(url, location.href);
|
|
10673
|
+
return target.origin === location.origin;
|
|
10674
|
+
}
|
|
10675
|
+
catch {
|
|
10676
|
+
return false;
|
|
10677
|
+
}
|
|
10678
|
+
}
|
|
10679
|
+
// ── Global navigation interception ────────────────────────────────────
|
|
10680
|
+
let _interceptInstalled = false;
|
|
10681
|
+
/**
|
|
10682
|
+
* Install global listeners that intercept same-origin link clicks and
|
|
10683
|
+
* form submissions, routing them through soft navigation so the debugger
|
|
10684
|
+
* stays connected.
|
|
10685
|
+
*
|
|
10686
|
+
* Called once from HyphaDebugger.start().
|
|
10588
10687
|
*/
|
|
10688
|
+
function installNavigationInterceptor() {
|
|
10689
|
+
if (_interceptInstalled)
|
|
10690
|
+
return () => { };
|
|
10691
|
+
_interceptInstalled = true;
|
|
10692
|
+
/**
|
|
10693
|
+
* Click handler: intercept <a> clicks that would navigate to a
|
|
10694
|
+
* same-origin HTML page.
|
|
10695
|
+
*/
|
|
10696
|
+
const onClick = (e) => {
|
|
10697
|
+
// Skip if modifier keys (new tab, etc.) or not left-click
|
|
10698
|
+
if (e.defaultPrevented || e.button !== 0)
|
|
10699
|
+
return;
|
|
10700
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
|
|
10701
|
+
return;
|
|
10702
|
+
// Walk up from target to find the nearest <a>
|
|
10703
|
+
let anchor = null;
|
|
10704
|
+
let el = e.target;
|
|
10705
|
+
while (el) {
|
|
10706
|
+
if (el.tagName === "A") {
|
|
10707
|
+
anchor = el;
|
|
10708
|
+
break;
|
|
10709
|
+
}
|
|
10710
|
+
el = el.parentElement;
|
|
10711
|
+
}
|
|
10712
|
+
if (!anchor)
|
|
10713
|
+
return;
|
|
10714
|
+
const href = anchor.href;
|
|
10715
|
+
if (!href)
|
|
10716
|
+
return;
|
|
10717
|
+
// Skip non-http(s), download links, target=_blank, javascript:, #hash-only
|
|
10718
|
+
if (anchor.target && anchor.target !== "_self")
|
|
10719
|
+
return;
|
|
10720
|
+
if (anchor.hasAttribute("download"))
|
|
10721
|
+
return;
|
|
10722
|
+
if (href.startsWith("javascript:") || href.startsWith("mailto:") || href.startsWith("tel:"))
|
|
10723
|
+
return;
|
|
10724
|
+
// Skip hash-only links (same page anchor)
|
|
10725
|
+
try {
|
|
10726
|
+
const target = new URL(href, location.href);
|
|
10727
|
+
if (target.origin === location.origin &&
|
|
10728
|
+
target.pathname === location.pathname &&
|
|
10729
|
+
target.search === location.search &&
|
|
10730
|
+
target.hash !== location.hash) {
|
|
10731
|
+
return; // Just a hash change, let browser handle it
|
|
10732
|
+
}
|
|
10733
|
+
}
|
|
10734
|
+
catch {
|
|
10735
|
+
return;
|
|
10736
|
+
}
|
|
10737
|
+
// Skip cross-origin
|
|
10738
|
+
if (!isSameOrigin(href))
|
|
10739
|
+
return;
|
|
10740
|
+
// Intercept: prevent default navigation and do soft replace
|
|
10741
|
+
e.preventDefault();
|
|
10742
|
+
const targetUrl = new URL(href, location.href).href;
|
|
10743
|
+
softReplace(targetUrl, targetUrl);
|
|
10744
|
+
};
|
|
10745
|
+
/**
|
|
10746
|
+
* Submit handler: intercept form submissions to same-origin action URLs.
|
|
10747
|
+
* Only handles GET forms (POST forms need the request body which is harder
|
|
10748
|
+
* to replicate via fetch).
|
|
10749
|
+
*/
|
|
10750
|
+
const onSubmit = (e) => {
|
|
10751
|
+
if (e.defaultPrevented)
|
|
10752
|
+
return;
|
|
10753
|
+
const form = e.target;
|
|
10754
|
+
const method = (form.method || "GET").toUpperCase();
|
|
10755
|
+
// Only intercept GET forms — POST forms are too complex to replicate
|
|
10756
|
+
if (method !== "GET")
|
|
10757
|
+
return;
|
|
10758
|
+
const action = form.action || location.href;
|
|
10759
|
+
if (!isSameOrigin(action))
|
|
10760
|
+
return;
|
|
10761
|
+
// Build the URL with form data as query params
|
|
10762
|
+
const formData = new FormData(form);
|
|
10763
|
+
const url = new URL(action, location.href);
|
|
10764
|
+
for (const [key, value] of formData.entries()) {
|
|
10765
|
+
if (typeof value === "string") {
|
|
10766
|
+
url.searchParams.set(key, value);
|
|
10767
|
+
}
|
|
10768
|
+
}
|
|
10769
|
+
// Skip if target is _blank or similar
|
|
10770
|
+
if (form.target && form.target !== "_self")
|
|
10771
|
+
return;
|
|
10772
|
+
e.preventDefault();
|
|
10773
|
+
softReplace(url.href, url.href);
|
|
10774
|
+
};
|
|
10775
|
+
/**
|
|
10776
|
+
* Popstate handler: intercept browser back/forward (bfcache miss).
|
|
10777
|
+
* When the browser navigates via back/forward and there's no bfcache,
|
|
10778
|
+
* we can catch it via popstate and do a soft load of the target URL.
|
|
10779
|
+
*/
|
|
10780
|
+
const onPopState = () => {
|
|
10781
|
+
// The URL has already changed when popstate fires.
|
|
10782
|
+
// Do a soft load of the current URL (which is the target of back/forward).
|
|
10783
|
+
softReplace(location.href);
|
|
10784
|
+
};
|
|
10785
|
+
document.addEventListener("click", onClick, true); // capture phase
|
|
10786
|
+
document.addEventListener("submit", onSubmit, true);
|
|
10787
|
+
window.addEventListener("popstate", onPopState);
|
|
10788
|
+
// Return cleanup function
|
|
10789
|
+
return () => {
|
|
10790
|
+
document.removeEventListener("click", onClick, true);
|
|
10791
|
+
document.removeEventListener("submit", onSubmit, true);
|
|
10792
|
+
window.removeEventListener("popstate", onPopState);
|
|
10793
|
+
_interceptInstalled = false;
|
|
10794
|
+
};
|
|
10795
|
+
}
|
|
10796
|
+
// ── navigate ──────────────────────────────────────────────────────────
|
|
10589
10797
|
function navigate(url) {
|
|
10590
10798
|
try {
|
|
10591
|
-
|
|
10592
|
-
|
|
10799
|
+
const targetUrl = new URL(url, location.href);
|
|
10800
|
+
const sameOrigin = targetUrl.origin === location.origin;
|
|
10801
|
+
if (sameOrigin) {
|
|
10802
|
+
// Soft navigate: fetch + inject + document.write, then pushState
|
|
10803
|
+
// Schedule after RPC response is sent
|
|
10804
|
+
setTimeout(() => softReplace(targetUrl.href, targetUrl.href), 150);
|
|
10805
|
+
return {
|
|
10806
|
+
success: true,
|
|
10807
|
+
message: `Navigating to ${url} (debugger will auto-reconnect)`,
|
|
10808
|
+
};
|
|
10809
|
+
}
|
|
10810
|
+
else {
|
|
10811
|
+
// Cross-origin: can't soft navigate, fall back to hard
|
|
10812
|
+
window.location.href = url;
|
|
10813
|
+
return {
|
|
10814
|
+
success: true,
|
|
10815
|
+
message: `Navigating to ${url} (cross-origin, debugger will disconnect)`,
|
|
10816
|
+
};
|
|
10817
|
+
}
|
|
10593
10818
|
}
|
|
10594
10819
|
catch (err) {
|
|
10595
|
-
return {
|
|
10820
|
+
return {
|
|
10821
|
+
success: false,
|
|
10822
|
+
message: `Navigation failed: ${err.message ?? err}`,
|
|
10823
|
+
};
|
|
10596
10824
|
}
|
|
10597
10825
|
}
|
|
10598
10826
|
navigate.__schema__ = {
|
|
10599
10827
|
name: "navigate",
|
|
10600
|
-
description: "Navigate the browser to a new URL.",
|
|
10828
|
+
description: "Navigate the browser to a new URL. For same-origin URLs, the debugger auto-reconnects. Cross-origin navigation will disconnect the debugger.",
|
|
10601
10829
|
parameters: {
|
|
10602
10830
|
type: "object",
|
|
10603
10831
|
properties: {
|
|
@@ -10609,18 +10837,25 @@
|
|
|
10609
10837
|
required: ["url"],
|
|
10610
10838
|
},
|
|
10611
10839
|
};
|
|
10840
|
+
// ── goBack / goForward ───────────────────────────────────────────────
|
|
10612
10841
|
function goBack() {
|
|
10613
10842
|
try {
|
|
10614
10843
|
window.history.back();
|
|
10615
|
-
return {
|
|
10844
|
+
return {
|
|
10845
|
+
success: true,
|
|
10846
|
+
message: "Navigated back (debugger will auto-reconnect via popstate)",
|
|
10847
|
+
};
|
|
10616
10848
|
}
|
|
10617
10849
|
catch (err) {
|
|
10618
|
-
return {
|
|
10850
|
+
return {
|
|
10851
|
+
success: false,
|
|
10852
|
+
message: `Back navigation failed: ${err.message ?? err}`,
|
|
10853
|
+
};
|
|
10619
10854
|
}
|
|
10620
10855
|
}
|
|
10621
10856
|
goBack.__schema__ = {
|
|
10622
10857
|
name: "goBack",
|
|
10623
|
-
description: "Navigate back in browser history.",
|
|
10858
|
+
description: "Navigate back in browser history. The debugger auto-reconnects for same-origin pages.",
|
|
10624
10859
|
parameters: {
|
|
10625
10860
|
type: "object",
|
|
10626
10861
|
properties: {},
|
|
@@ -10629,7 +10864,10 @@
|
|
|
10629
10864
|
function goForward() {
|
|
10630
10865
|
try {
|
|
10631
10866
|
window.history.forward();
|
|
10632
|
-
return {
|
|
10867
|
+
return {
|
|
10868
|
+
success: true,
|
|
10869
|
+
message: "Navigated forward (debugger will auto-reconnect via popstate)",
|
|
10870
|
+
};
|
|
10633
10871
|
}
|
|
10634
10872
|
catch (err) {
|
|
10635
10873
|
return {
|
|
@@ -10640,16 +10878,21 @@
|
|
|
10640
10878
|
}
|
|
10641
10879
|
goForward.__schema__ = {
|
|
10642
10880
|
name: "goForward",
|
|
10643
|
-
description: "Navigate forward in browser history.",
|
|
10881
|
+
description: "Navigate forward in browser history. The debugger auto-reconnects for same-origin pages.",
|
|
10644
10882
|
parameters: {
|
|
10645
10883
|
type: "object",
|
|
10646
10884
|
properties: {},
|
|
10647
10885
|
},
|
|
10648
10886
|
};
|
|
10887
|
+
// ── reload ───────────────────────────────────────────────────────────
|
|
10649
10888
|
function reload() {
|
|
10650
10889
|
try {
|
|
10651
|
-
|
|
10652
|
-
|
|
10890
|
+
// Schedule soft reload after RPC response is sent
|
|
10891
|
+
setTimeout(() => softReplace(location.href), 150);
|
|
10892
|
+
return {
|
|
10893
|
+
success: true,
|
|
10894
|
+
message: "Reloading page (debugger will auto-reconnect)",
|
|
10895
|
+
};
|
|
10653
10896
|
}
|
|
10654
10897
|
catch (err) {
|
|
10655
10898
|
return { success: false, message: `Reload failed: ${err.message ?? err}` };
|
|
@@ -10657,7 +10900,7 @@
|
|
|
10657
10900
|
}
|
|
10658
10901
|
reload.__schema__ = {
|
|
10659
10902
|
name: "reload",
|
|
10660
|
-
description: "Reload the current page.",
|
|
10903
|
+
description: "Reload the current page. The debugger auto-reconnects after reload using soft page replacement.",
|
|
10661
10904
|
parameters: {
|
|
10662
10905
|
type: "object",
|
|
10663
10906
|
properties: {},
|
|
@@ -13768,12 +14011,16 @@
|
|
|
13768
14011
|
crypto.getRandomValues(arr);
|
|
13769
14012
|
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
13770
14013
|
}
|
|
14014
|
+
/** sessionStorage key for persisting debugger config across reloads. */
|
|
14015
|
+
const STORAGE_KEY = "__hypha_debugger_config__";
|
|
13771
14016
|
class HyphaDebugger {
|
|
13772
14017
|
constructor(config) {
|
|
13773
14018
|
this.overlay = null;
|
|
13774
14019
|
this.cursor = null;
|
|
13775
14020
|
this.server = null;
|
|
13776
14021
|
this.serviceInfo = null;
|
|
14022
|
+
this.boundBeforeUnload = null;
|
|
14023
|
+
this.cleanupInterceptor = null;
|
|
13777
14024
|
const requireToken = config.require_token ?? false;
|
|
13778
14025
|
// Always append random suffix unless user provided a custom id.
|
|
13779
14026
|
let serviceId = config.service_id ?? "web-debugger";
|
|
@@ -13833,6 +14080,13 @@
|
|
|
13833
14080
|
// Store globally
|
|
13834
14081
|
w.__HYPHA_DEBUGGER__ = w.__HYPHA_DEBUGGER__ ?? {};
|
|
13835
14082
|
w.__HYPHA_DEBUGGER__.instance = this;
|
|
14083
|
+
// Persist config to sessionStorage for auto-reconnect after reload
|
|
14084
|
+
this.saveConfigToStorage();
|
|
14085
|
+
this.boundBeforeUnload = () => this.saveConfigToStorage();
|
|
14086
|
+
window.addEventListener("beforeunload", this.boundBeforeUnload);
|
|
14087
|
+
// Intercept same-origin link clicks, form submits, and popstate
|
|
14088
|
+
// so the debugger survives user-initiated navigation
|
|
14089
|
+
this.cleanupInterceptor = installNavigationInterceptor();
|
|
13836
14090
|
return session;
|
|
13837
14091
|
}
|
|
13838
14092
|
catch (err) {
|
|
@@ -13848,6 +14102,15 @@
|
|
|
13848
14102
|
}
|
|
13849
14103
|
}
|
|
13850
14104
|
async destroy() {
|
|
14105
|
+
// Remove event listeners
|
|
14106
|
+
if (this.boundBeforeUnload) {
|
|
14107
|
+
window.removeEventListener("beforeunload", this.boundBeforeUnload);
|
|
14108
|
+
this.boundBeforeUnload = null;
|
|
14109
|
+
}
|
|
14110
|
+
if (this.cleanupInterceptor) {
|
|
14111
|
+
this.cleanupInterceptor();
|
|
14112
|
+
this.cleanupInterceptor = null;
|
|
14113
|
+
}
|
|
13851
14114
|
try {
|
|
13852
14115
|
if (this.serviceInfo && this.server) {
|
|
13853
14116
|
await this.server.unregisterService(this.serviceInfo.id);
|
|
@@ -13856,6 +14119,13 @@
|
|
|
13856
14119
|
catch {
|
|
13857
14120
|
// Ignore unregister errors on cleanup
|
|
13858
14121
|
}
|
|
14122
|
+
// Clear sessionStorage config (explicit destroy = user wants to stop)
|
|
14123
|
+
try {
|
|
14124
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
14125
|
+
}
|
|
14126
|
+
catch {
|
|
14127
|
+
// ignore
|
|
14128
|
+
}
|
|
13859
14129
|
disposeController();
|
|
13860
14130
|
this.cursor?.destroy();
|
|
13861
14131
|
this.cursor = null;
|
|
@@ -13867,6 +14137,48 @@
|
|
|
13867
14137
|
delete w.__HYPHA_DEBUGGER__.session;
|
|
13868
14138
|
}
|
|
13869
14139
|
}
|
|
14140
|
+
/**
|
|
14141
|
+
* Persist debugger config to sessionStorage so the debugger can
|
|
14142
|
+
* auto-reconnect after a page reload (soft reload injects the script,
|
|
14143
|
+
* autoStart() reads this config).
|
|
14144
|
+
*/
|
|
14145
|
+
saveConfigToStorage() {
|
|
14146
|
+
try {
|
|
14147
|
+
const data = {
|
|
14148
|
+
server_url: this.config.server_url,
|
|
14149
|
+
workspace: this.server?.config?.workspace ?? this.config.workspace,
|
|
14150
|
+
token: this.config.token,
|
|
14151
|
+
service_id: this.config.service_id,
|
|
14152
|
+
service_name: this.config.service_name,
|
|
14153
|
+
show_ui: this.config.show_ui,
|
|
14154
|
+
visibility: this.config.visibility,
|
|
14155
|
+
require_token: this.config.require_token,
|
|
14156
|
+
script_url: this.detectScriptUrl(),
|
|
14157
|
+
};
|
|
14158
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
14159
|
+
}
|
|
14160
|
+
catch {
|
|
14161
|
+
// sessionStorage might be unavailable (private browsing, full quota)
|
|
14162
|
+
}
|
|
14163
|
+
}
|
|
14164
|
+
/**
|
|
14165
|
+
* Detect the URL of the currently loaded hypha-debugger script.
|
|
14166
|
+
* Used by navigate.ts to inject the correct script after soft reload.
|
|
14167
|
+
*/
|
|
14168
|
+
detectScriptUrl() {
|
|
14169
|
+
try {
|
|
14170
|
+
const scripts = document.querySelectorAll("script[src]");
|
|
14171
|
+
for (const s of Array.from(scripts)) {
|
|
14172
|
+
if (s.src && s.src.includes("hypha-debugger")) {
|
|
14173
|
+
return s.src;
|
|
14174
|
+
}
|
|
14175
|
+
}
|
|
14176
|
+
}
|
|
14177
|
+
catch {
|
|
14178
|
+
// ignore
|
|
14179
|
+
}
|
|
14180
|
+
return "https://cdn.jsdelivr.net/npm/hypha-debugger/dist/hypha-debugger.min.js";
|
|
14181
|
+
}
|
|
13870
14182
|
/**
|
|
13871
14183
|
* Generate token, build service URL, update overlay instructions, and
|
|
13872
14184
|
* return a DebugSession.
|
|
@@ -14122,6 +14434,26 @@
|
|
|
14122
14434
|
function autoStart() {
|
|
14123
14435
|
if (typeof window === "undefined" || typeof document === "undefined")
|
|
14124
14436
|
return;
|
|
14437
|
+
// Skip if already started
|
|
14438
|
+
if (window.__HYPHA_DEBUGGER__?.instance)
|
|
14439
|
+
return;
|
|
14440
|
+
// Check sessionStorage for saved config (auto-reconnect after soft reload)
|
|
14441
|
+
try {
|
|
14442
|
+
const saved = sessionStorage.getItem("__hypha_debugger_config__");
|
|
14443
|
+
if (saved) {
|
|
14444
|
+
const savedConfig = JSON.parse(saved);
|
|
14445
|
+
if (savedConfig.server_url) {
|
|
14446
|
+
console.log("[hypha-debugger] Reconnecting from saved session...");
|
|
14447
|
+
startDebugger(savedConfig).catch((err) => {
|
|
14448
|
+
console.error("[hypha-debugger] Auto-reconnect failed:", err);
|
|
14449
|
+
});
|
|
14450
|
+
return;
|
|
14451
|
+
}
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
catch {
|
|
14455
|
+
// sessionStorage not available or parse error — continue to script tag detection
|
|
14456
|
+
}
|
|
14125
14457
|
// Find our own script tag
|
|
14126
14458
|
const scripts = document.querySelectorAll("script[src]");
|
|
14127
14459
|
let scriptEl = null;
|
|
@@ -14134,9 +14466,6 @@
|
|
|
14134
14466
|
// Skip if data-manual is set
|
|
14135
14467
|
if (scriptEl?.hasAttribute("data-manual"))
|
|
14136
14468
|
return;
|
|
14137
|
-
// Skip if already started
|
|
14138
|
-
if (window.__HYPHA_DEBUGGER__?.instance)
|
|
14139
|
-
return;
|
|
14140
14469
|
const serverUrl = scriptEl?.getAttribute("data-server-url") ?? "https://hypha.aicell.io";
|
|
14141
14470
|
const config = {
|
|
14142
14471
|
server_url: serverUrl,
|
|
@@ -14190,6 +14519,7 @@
|
|
|
14190
14519
|
exports.goForward = goForward;
|
|
14191
14520
|
exports.inputText = inputText;
|
|
14192
14521
|
exports.installConsoleCapture = installConsoleCapture;
|
|
14522
|
+
exports.installNavigationInterceptor = installNavigationInterceptor;
|
|
14193
14523
|
exports.navigate = navigate;
|
|
14194
14524
|
exports.queryDom = queryDom;
|
|
14195
14525
|
exports.reload = reload;
|
|
@@ -14197,6 +14527,7 @@
|
|
|
14197
14527
|
exports.scroll = scroll;
|
|
14198
14528
|
exports.scrollTo = scrollTo;
|
|
14199
14529
|
exports.selectOption = selectOption;
|
|
14530
|
+
exports.softReplace = softReplace;
|
|
14200
14531
|
exports.startDebugger = startDebugger;
|
|
14201
14532
|
exports.takeScreenshot = takeScreenshot;
|
|
14202
14533
|
exports.wrapFn = wrapFn;
|