@lightworkai.official/debug-capture 0.8.1 → 0.8.2
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/README.md +5 -0
- package/dist/index.mjs +11 -5
- package/package.json +1 -1
- package/src/portal.ts +23 -4
- package/src/ui/handoff.ts +10 -4
package/README.md
CHANGED
|
@@ -142,6 +142,11 @@ takes ten seconds. A tab opened after a countdown can be refused — the click's
|
|
|
142
142
|
activation may have expired — so the dialog offers a real link in that case,
|
|
143
143
|
which is a fresh gesture and cannot be blocked.
|
|
144
144
|
|
|
145
|
+
The tab is opened without the `noopener` window feature and its `opener` is
|
|
146
|
+
nulled afterwards instead. `window.open(…, "noopener")` returns `null` on
|
|
147
|
+
*success*, by specification, so asking for it destroys the only signal that says
|
|
148
|
+
whether the tab opened at all.
|
|
149
|
+
|
|
145
150
|
**It announces itself first.** Leaving for another origin without warning,
|
|
146
151
|
mid-task, reads as a bug — so a small dialog says where they are going, that
|
|
147
152
|
they will be signed in when they arrive, and counts down with a way to go now or
|
package/dist/index.mjs
CHANGED
|
@@ -171,15 +171,21 @@ p { margin: 0; font-size: 13px; line-height: 1.6; color: #475569; }
|
|
|
171
171
|
.host { margin-top: 8px; font-size: 12px; color: #94a3b8; word-break: break-all; }
|
|
172
172
|
|
|
173
173
|
.actions { display: flex; gap: 8px; margin-top: 20px; }
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
/* The anchor too: when a blocked tab turns the primary action into a link, it
|
|
175
|
+
has to be the same object it was a moment ago. Styling only the button left it
|
|
176
|
+
with the dark fill and none of the shape: an underlined black smear. */
|
|
177
|
+
.actions button, .actions a {
|
|
178
|
+
flex: 1; box-sizing: border-box;
|
|
179
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
180
|
+
padding: 9px 12px; border-radius: 9px; font: inherit; font-size: 14px;
|
|
181
|
+
text-decoration: none; cursor: pointer;
|
|
182
|
+
transition: background 120ms ease, border-color 120ms ease;
|
|
177
183
|
}
|
|
178
184
|
.go { border: none; background: #0f172a; color: #fff; font-weight: 600; }
|
|
179
185
|
.go:hover { background: #1e293b; }
|
|
180
186
|
.cancel { border: 1px solid #e2e8f0; background: #fff; color: #334155; }
|
|
181
187
|
.cancel:hover { background: #f8fafc; }
|
|
182
|
-
button:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
188
|
+
.actions button:focus-visible, .actions a:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
183
189
|
|
|
184
190
|
.error h2 { color: #b91c1c; }
|
|
185
191
|
|
|
@@ -208,4 +214,4 @@ button:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
|
208
214
|
<button type="button" class="cancel"></button>
|
|
209
215
|
<button type="button" class="go"></button>
|
|
210
216
|
</div>
|
|
211
|
-
</div>`,z.append(K);let G=(D)=>K.querySelector(D),H=G(".card"),U=G(".bar"),C=G(".count"),w=G("h2"),P=G(".body"),O=G(".host"),N=G(".go"),S=G(".cancel");w.textContent=j.handoffTitle,P.textContent=j.handoffBody;try{O.textContent=new URL(R().host).host}catch{O.textContent=""}N.textContent=j.handoffGo,S.textContent=j.cancel,H.style.setProperty("--secs",`${J}s`),C.textContent=String(J),document.body.append(Q),requestAnimationFrame(()=>K.setAttribute("data-open","1"));let _=document.activeElement;return N.focus({preventScroll:!0}),new Promise((D)=>{let q=!1,g=null,e=!1,u=Date.now()+J*1000,E=window.setInterval(()=>{let B=Math.ceil((u-Date.now())/1000);if(C.textContent=String(Math.max(0,B)),Date.now()>=u)L()},100);function p(B){if(q)return;if(q=!0,window.clearInterval(E),document.removeEventListener("keydown",m,!0),K.removeAttribute("data-open"),window.setTimeout(()=>Q.remove(),200),!B)_?.focus?.({preventScroll:!0});D()}function H0(B){window.clearInterval(E),U.classList.remove("spinner"),U.style.animation="none",C.textContent="",w.textContent=j.handoffBlocked,P.textContent=j.handoffBody;let k=document.createElement("a");k.className="go",k.href=B,k.target="_blank",k.rel="noopener noreferrer",k.textContent=j.handoffOpen,k.addEventListener("click",()=>p(!0)),N.replaceWith(k),k.focus({preventScroll:!0})}function L(){if(q||e)return;if(g)return $.go(g)?p(!0):H0(g);window.clearInterval(E),C.textContent="",U.classList.add("spinner"),w.textContent=j.handoffPreparing}function m(B){if(B.key==="Escape")B.stopPropagation(),p(!1)}document.addEventListener("keydown",m,!0),N.addEventListener("click",L),S.addEventListener("click",()=>p(!1)),K.addEventListener("click",(B)=>{if(B.target===K)p(!1)}),$.prepare().then((B)=>{if(g=B,!q&&Date.now()>=u)L()},()=>{e=!0,window.clearInterval(E),H.classList.add("error"),U.classList.remove("spinner"),U.style.animation="none",C.textContent="",w.textContent=j.handoffFailed,P.textContent=j.handoffBody,N.remove(),S.textContent=j.close})})}var s4="/sso";function e1($,j,J){let Q=new URL(s4,$.endsWith("/")?$:`${$}/`);return Q.searchParams.set("realm",j),Q.searchParams.set("token",J),Q.toString()}class F0 extends Error{constructor($="No identity provider is configured, or nobody is signed in"){super($);this.name="NoIdentityError"}}async function a1(){let $=R();if(!$.identity)throw new F0;let j=await $.identity();if(!j)throw new F0;return e1($.host,$.realmKey,j)}function t1($,j){if(j==="_self")return window.location.assign($),!0;
|
|
217
|
+
</div>`,z.append(K);let G=(D)=>K.querySelector(D),H=G(".card"),U=G(".bar"),C=G(".count"),w=G("h2"),P=G(".body"),O=G(".host"),N=G(".go"),S=G(".cancel");w.textContent=j.handoffTitle,P.textContent=j.handoffBody;try{O.textContent=new URL(R().host).host}catch{O.textContent=""}N.textContent=j.handoffGo,S.textContent=j.cancel,H.style.setProperty("--secs",`${J}s`),C.textContent=String(J),document.body.append(Q),requestAnimationFrame(()=>K.setAttribute("data-open","1"));let _=document.activeElement;return N.focus({preventScroll:!0}),new Promise((D)=>{let q=!1,g=null,e=!1,u=Date.now()+J*1000,E=window.setInterval(()=>{let B=Math.ceil((u-Date.now())/1000);if(C.textContent=String(Math.max(0,B)),Date.now()>=u)L()},100);function p(B){if(q)return;if(q=!0,window.clearInterval(E),document.removeEventListener("keydown",m,!0),K.removeAttribute("data-open"),window.setTimeout(()=>Q.remove(),200),!B)_?.focus?.({preventScroll:!0});D()}function H0(B){window.clearInterval(E),U.classList.remove("spinner"),U.style.animation="none",C.textContent="",w.textContent=j.handoffBlocked,P.textContent=j.handoffBody;let k=document.createElement("a");k.className="go",k.href=B,k.target="_blank",k.rel="noopener noreferrer",k.textContent=j.handoffOpen,k.addEventListener("click",()=>p(!0)),N.replaceWith(k),k.focus({preventScroll:!0})}function L(){if(q||e)return;if(g)return $.go(g)?p(!0):H0(g);window.clearInterval(E),C.textContent="",U.classList.add("spinner"),w.textContent=j.handoffPreparing}function m(B){if(B.key==="Escape")B.stopPropagation(),p(!1)}document.addEventListener("keydown",m,!0),N.addEventListener("click",L),S.addEventListener("click",()=>p(!1)),K.addEventListener("click",(B)=>{if(B.target===K)p(!1)}),$.prepare().then((B)=>{if(g=B,!q&&Date.now()>=u)L()},()=>{e=!0,window.clearInterval(E),H.classList.add("error"),U.classList.remove("spinner"),U.style.animation="none",C.textContent="",w.textContent=j.handoffFailed,P.textContent=j.handoffBody,N.remove(),S.textContent=j.close})})}var s4="/sso";function e1($,j,J){let Q=new URL(s4,$.endsWith("/")?$:`${$}/`);return Q.searchParams.set("realm",j),Q.searchParams.set("token",J),Q.toString()}class F0 extends Error{constructor($="No identity provider is configured, or nobody is signed in"){super($);this.name="NoIdentityError"}}async function a1(){let $=R();if(!$.identity)throw new F0;let j=await $.identity();if(!j)throw new F0;return e1($.host,$.realmKey,j)}function t1($,j){if(j==="_self")return window.location.assign($),!0;let J=window.open($,"_blank");if(!J)return!1;try{J.opener=null}catch{}return!0}async function n4($={}){if($.announce===!1){t1(await a1(),$.target);return}await n1({seconds:$.seconds,prepare:a1,go:(j)=>t1(j,$.target)})}export{g0 as trimToBudget,g1 as toCurl,e1 as supportPortalUrl,p0 as submitBundle,n as showToast,p4 as setErroredQueriesSource,d4 as requestPath,b as reporterStrings,o as redactUrl,c as redactLabel,i as redactHeaders,l as redactBody,n4 as openSupportPortal,R0 as onLaunch,_0 as onCrash,O0 as launch,i4 as isQuietStep,r1 as isFailedRequest,U0 as isConfigured,b4 as installDebugCapture,D4 as hasCause,A0 as getNetworkLog,S0 as getConsoleLog,R as getConfig,B0 as getActionTrail,o4 as formatDuration,x0 as errorSignature,L0 as emitCrash,u0 as defineReporterElement,y0 as createAnnotator,c4 as correlateActionTrail,Q2 as configureDebugCapture,E0 as captureScreen,P4 as bundleToMarkdown,w4 as bundleFileName,k0 as buildBundle,x as appInfo,D0 as actionCountSuffix,t as REPORTER_TAG,d as REDACTED,F0 as NoIdentityError,h0 as BUNDLE_BUDGET_BYTES};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightworkai.official/debug-capture",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Report-a-problem widget: rolling network/console/action capture, annotated screenshot, and submission to a Lightwork Support host",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.mjs",
|
package/src/portal.ts
CHANGED
|
@@ -72,10 +72,29 @@ function navigate(url: string, target: OpenPortalOptions["target"]): boolean {
|
|
|
72
72
|
window.location.assign(url);
|
|
73
73
|
return true;
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* Opened WITHOUT the `noopener` feature, then severed by hand.
|
|
78
|
+
*
|
|
79
|
+
* `window.open(…, "noopener")` returns null on success — by specification,
|
|
80
|
+
* because handing back a reference is the very thing noopener exists to
|
|
81
|
+
* prevent. So "did it open?" and "give it no opener" cannot both be answered
|
|
82
|
+
* by the same call: asking for one destroys the answer to the other. Reading
|
|
83
|
+
* that null as "blocked" made every successful hand-off report a popup
|
|
84
|
+
* blocker while the tab it had just opened sat there.
|
|
85
|
+
*
|
|
86
|
+
* Nulling `opener` afterwards is the long-standing equivalent. In a try
|
|
87
|
+
* because a cross-origin window may refuse the assignment — and if it does,
|
|
88
|
+
* the tab is open, which is what the return value is about.
|
|
89
|
+
*/
|
|
90
|
+
const opened = window.open(url, "_blank");
|
|
91
|
+
if (!opened) return false;
|
|
92
|
+
try {
|
|
93
|
+
opened.opener = null;
|
|
94
|
+
} catch {
|
|
95
|
+
/* the tab is open either way */
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
79
98
|
}
|
|
80
99
|
|
|
81
100
|
/**
|
package/src/ui/handoff.ts
CHANGED
|
@@ -74,15 +74,21 @@ p { margin: 0; font-size: 13px; line-height: 1.6; color: #475569; }
|
|
|
74
74
|
.host { margin-top: 8px; font-size: 12px; color: #94a3b8; word-break: break-all; }
|
|
75
75
|
|
|
76
76
|
.actions { display: flex; gap: 8px; margin-top: 20px; }
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
/* The anchor too: when a blocked tab turns the primary action into a link, it
|
|
78
|
+
has to be the same object it was a moment ago. Styling only the button left it
|
|
79
|
+
with the dark fill and none of the shape: an underlined black smear. */
|
|
80
|
+
.actions button, .actions a {
|
|
81
|
+
flex: 1; box-sizing: border-box;
|
|
82
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
83
|
+
padding: 9px 12px; border-radius: 9px; font: inherit; font-size: 14px;
|
|
84
|
+
text-decoration: none; cursor: pointer;
|
|
85
|
+
transition: background 120ms ease, border-color 120ms ease;
|
|
80
86
|
}
|
|
81
87
|
.go { border: none; background: #0f172a; color: #fff; font-weight: 600; }
|
|
82
88
|
.go:hover { background: #1e293b; }
|
|
83
89
|
.cancel { border: 1px solid #e2e8f0; background: #fff; color: #334155; }
|
|
84
90
|
.cancel:hover { background: #f8fafc; }
|
|
85
|
-
button:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
91
|
+
.actions button:focus-visible, .actions a:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
86
92
|
|
|
87
93
|
.error h2 { color: #b91c1c; }
|
|
88
94
|
|