@lightworkai.official/debug-capture 0.7.0 → 0.8.0
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 +16 -2
- package/dist/debug-capture.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +89 -8
- package/dist/portal.d.ts +23 -3
- package/dist/ui/handoff.d.ts +18 -0
- package/dist/ui/strings.d.ts +6 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/portal.ts +50 -12
- package/src/submit.ts +34 -1
- package/src/ui/handoff.ts +245 -0
- package/src/ui/strings.ts +16 -0
package/README.md
CHANGED
|
@@ -130,10 +130,24 @@ builds the URL if you would rather render your own anchor:
|
|
|
130
130
|
```ts
|
|
131
131
|
import { openSupportPortal, supportPortalUrl } from "@lightworkai.official/debug-capture";
|
|
132
132
|
|
|
133
|
-
await openSupportPortal();
|
|
134
|
-
await openSupportPortal({
|
|
133
|
+
await openSupportPortal(); // announces, then navigates
|
|
134
|
+
await openSupportPortal({ seconds: 5 }); // a longer countdown
|
|
135
|
+
await openSupportPortal({ announce: false }); // go on the spot, no dialog
|
|
136
|
+
await openSupportPortal({ target: "_blank" }); // new tab, noopener
|
|
135
137
|
```
|
|
136
138
|
|
|
139
|
+
**It announces itself first.** Leaving for another origin without warning,
|
|
140
|
+
mid-task, reads as a bug — so a small dialog says where they are going, that
|
|
141
|
+
they will be signed in when they arrive, and counts down with a way to go now or
|
|
142
|
+
not at all. The seconds are not an apology: the token is fetched underneath
|
|
143
|
+
them, so the click is answered by something on screen rather than by a pause of
|
|
144
|
+
unknown length.
|
|
145
|
+
|
|
146
|
+
The dialog lives in its own shadow root, so it needs no stylesheet and your CSS
|
|
147
|
+
cannot reach it. With it, a failure is reported *in* it and the call resolves;
|
|
148
|
+
with `announce: false` there is nowhere to put the message, so the error is
|
|
149
|
+
thrown for you to handle.
|
|
150
|
+
|
|
137
151
|
`supportPortalUrl(host, realmKey, token)` is pure and safe to call on a server.
|
|
138
152
|
|
|
139
153
|
|
package/dist/debug-capture.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(()=>{var c1={maxRequests:60,maxConsoleEntries:120,maxActions:80,maxBodyChars:20000},S=null;function T0($){S=$}function R(){if(!S)throw Error("[debug-capture] configureDebugCapture() has not been called");return S}function A0(){return S!==null}function h(){let $=R().app;return{name:$.name,version:$.version??"0.0.0",environment:$.environment??l1()}}function l1(){if(typeof window>"u")return"unknown";let $=window.location.hostname;if($==="localhost"||$==="127.0.0.1"||$.endsWith(".local"))return"development";return"production"}function A($){let j=S?.capture?.[$];return typeof j==="number"?j:c1[$]}function L0($){let j=S?.module;if(!j)return null;try{return j($)??null}catch{return null}}function e(){let $=S?.redact;return{headers:$?.headers??[],queryKeys:($?.queryKeys??[]).map((j)=>j.toLowerCase()),bodyKeys:($?.bodyKeys??[]).map((j)=>j.toLowerCase())}}function E0(){return S?.capture?.overlaySelectors??[]}function x0($){if(typeof window>"u")return!1;let j;try{j=new URL($,window.location.href)}catch{return!1}if(r1(j))return!1;if(j.origin===window.location.origin)return!0;return(S?.capture?.bodyOrigins??[]).some((J)=>{try{return new URL(J).origin===j.origin}catch{return!1}})}function r1($){if(!S?.host)return!1;try{if(new URL(S.host).origin!==$.origin)return!1}catch{return!1}return $.pathname.startsWith("/ingest/")}var v="‹redacted›",n1=/^(authorization|proxy-authorization|cookie|set-cookie|x-[a-z-]*token|x-csrf[a-z-]*|x-xsrf[a-z-]*)$/i,s1=new Set(["access_token","token","id_token","refresh_token","code","secret","client_secret","password","apikey","api_key","signature","x-amz-signature","x-amz-credential"]),a1=/(password|passwd|token|secret|authorization|refresh|client_secret|otp|pin)/i,t1=/[\w.+-]+@[\w-]+\.[\w.-]+/g,e1=/\d(?:[\d\s-]{7,})\d/g;function b($){return $.replace(t1,v).replace(e1,v)}function $2($){if(n1.test($))return!0;return e().headers.some((J)=>J.toLowerCase()===$.toLowerCase())}function u($){let j={};for(let[J,Q]of Object.entries($))j[J]=$2(J)?v:Q;return j}function i($){try{let j=/^https?:\/\//i.test($),J=new URL($,j?void 0:"http://local.invalid"),Q=!1;if(J.searchParams.forEach((z,W)=>{if(s1.has(W.toLowerCase())||e().queryKeys.includes(W.toLowerCase()))J.searchParams.set(W,v),Q=!0}),!Q)return $;return j?J.toString():`${J.pathname}${J.search}`}catch{return $}}function w0($,j){if(j>6||$===null||typeof $!=="object")return $;if(Array.isArray($))return $.map((Q)=>w0(Q,j+1));let J={};for(let[Q,z]of Object.entries($)){let W=a1.test(Q)||e().bodyKeys.some((V)=>Q.toLowerCase().includes(V));J[Q]=W?v:w0(z,j+1)}return J}function o($,j){if($==null)return null;let J=$,Q=$.trim();if(Q.startsWith("{")||Q.startsWith("["))try{let z=JSON.parse(Q);J=JSON.stringify(w0(z,0))}catch{}if(J.length>j)return`${J.slice(0,j)}… [truncated ${J.length-j} chars]`;return J}var X0=120,Y0=40,g=($,j)=>$.length>j?`${$.slice(0,j)}…`:$,F0=($)=>{try{return decodeURIComponent($)}catch{return $}},p=[],h0=0,p0=!1;function d($,j,J,Q){let z=g(j,X0),W=p[p.length-1];if($==="navigate"&&W?.kind==="click"){let X=z.replace(/^ไปที่\s*/,"");if(W.detail.includes(`→ ${X}`))return W.at=new Date().toISOString(),W;let F=X.split(/[?#]/)[0]??X,H=W.source?F0(W.source.replace(/^→\s*/,"")).split(/[?#]/)[0]:null;if(H&&(F===H||F.startsWith(H)))return W.detail=g(`${W.detail} → ${X}`,X0),W.source=void 0,W.at=new Date().toISOString(),W}if(W&&W.kind===$&&W.detail===z){if(W.at=new Date().toISOString(),$!=="navigate")W.count=(W.count??1)+1;return W}h0+=1;let V={id:`act_${h0}`,at:new Date().toISOString(),kind:$,detail:z,count:1,source:J,html:j0(Q)};p.push(V);while(p.length>A("maxActions"))J2(p.shift());return V}var j2=200000,c=0;function j0($){if(!$)return;if(c+$.length>j2)return;return c+=$.length,$}function J2($){if(!$)return;if(c-=($.html?.length??0)+($.afterHtml?.length??0),c<0)c=0}function $0($){return $ instanceof Element&&Boolean($.closest("[data-debug-reporter]"))}var Q2='button, a[href], [role="button"], [role="tab"], [role="menuitem"], [role="option"], [role="switch"], [role="checkbox"], [role="radio"], [role="link"], summary, input, select, textarea',z2={button:"ปุ่ม",a:"ลิงก์",input:"ช่อง",textarea:"ช่อง",select:"ตัวเลือก",summary:"ส่วนขยาย"},g0={button:"ปุ่ม",tab:"แท็บ",menuitem:"เมนู",option:"ตัวเลือก",switch:"สวิตช์",checkbox:"ช่องเลือก",radio:"ตัวเลือก",link:"ลิงก์"};function Z2($){let j=$.getAttribute("role");if(j&&g0[j])return g0[j];return z2[$.tagName.toLowerCase()]??"ปุ่ม"}function W2($,j){try{let J=$,Q=0;while(J&&Q<=j){let z=i0(J);if(z&&typeof z.memoizedProps?.onClick==="function")return J;J=J.parentElement,Q+=1}}catch{}return null}function K2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("title")?.trim();if(J)return J;if($ instanceof HTMLInputElement||$ instanceof HTMLTextAreaElement||$ instanceof HTMLSelectElement)return($.getAttribute("placeholder")||$.getAttribute("name")||"").trim();if($ instanceof HTMLImageElement)return($.getAttribute("alt")||"").trim();let Q=($.textContent??"").replace(/\s+/g," ").trim();if(Q)return Q;if($ instanceof HTMLAnchorElement){let z=$.getAttribute("href");if(z?.startsWith("/"))return F0(z)}return""}function V2($){if(!($ instanceof Element))return null;let j=$.closest(Q2)??W2($,4);if(!j)return null;let J=j.tagName.toLowerCase();if(J==="html"||J==="body")return null;return j}function G2($){let j=b(K2($));if(!j)return null;return`${Z2($)} “${g(j,Y0)}”`}var u0=6000,w2=4000,X2=/(?:^|\s)!?(?:fixed|absolute|sticky|inset-\S+|z-\S+|top-\S+|bottom-\S+|left-\S+|right-\S+|w-screen|h-screen|min-h-screen|max-h-screen|translate-\S+|scale-\S+)(?=\s|$)/g;function Y2($){$.querySelectorAll("script, style, link, iframe, object, embed, noscript, canvas, video, audio").forEach((z)=>z.remove());let j=[$,...Array.from($.querySelectorAll("*"))];for(let z of j){for(let V of Array.from(z.attributes)){let X=V.name.toLowerCase();if(X.startsWith("on")||X==="srcdoc"||X==="value"||X.startsWith("data-"))z.removeAttribute(V.name)}if(z instanceof HTMLAnchorElement)z.setAttribute("href","#");if(z instanceof HTMLImageElement)z.removeAttribute("src");let W=z.getAttribute("class");if(W){let V=W.replace(X2," ").replace(/\s+/g," ").trim();if(V)z.setAttribute("class",V);else z.removeAttribute("class")}}let J=document.createTreeWalker($,NodeFilter.SHOW_TEXT),Q=J.nextNode();while(Q){if(Q.nodeValue)Q.nodeValue=b(Q.nodeValue);Q=J.nextNode()}}function M0($,j,J){try{let Q=$.outerHTML;if(!Q||Q.length>j)return;let z=$.cloneNode(!0);Y2(z);let W=z.outerHTML;return W&&W.length<=J?W:void 0}catch{return}}var F2=($)=>M0($,u0,w2),M2=150000,H2=40000,m0=($)=>M0($,M2,H2);function I2($){if(!($ instanceof HTMLInputElement)&&!($ instanceof HTMLTextAreaElement)&&!($ instanceof HTMLSelectElement))return null;let j=$.name||$.id||$.getAttribute("aria-label")||$.getAttribute("placeholder")||$.tagName.toLowerCase();return`ช่อง “${b(j)}”`}var y0=80;function i0($){let j=Object.keys($).find((J)=>J.startsWith("__reactFiber$")||J.startsWith("__reactInternalInstance$"));return j?$[j]:null}function C2($){if(typeof $!=="function")return null;try{let j=Function.prototype.toString.call($);return(j.match(/\.(?:push|replace)\(\s*['"`]([^'"`]+)['"`]/)??j.match(/redirect\(\s*['"`]([^'"`]+)['"`]/))?.[1]??null}catch{return null}}function v0($){if(!$)return;return`→ ${$.length>y0?`${$.slice(0,y0)}…`:$}`}function U2($){try{let j=$.closest("a[href]")?.getAttribute("href");if(j&&j.startsWith("/"))return v0(j);let J=i0($),Q=0;while(J&&Q<30){if(typeof J.memoizedProps?.onClick==="function")return v0(C2(J.memoizedProps.onClick));J=J.return,Q+=1}return}catch{return}}var P2='[role="dialog"], [role="alertdialog"], [role="menu"], [role="listbox"], [role="status"], [role="alert"]';function N2(){let $=E0();return $.length?$.join(", "):P2}function B2($){let j=$.getAttribute("role");if(j==="status"||j==="alert")return"ข้อความแจ้งเตือน";if(j==="menu")return"เมนู";if(j==="listbox")return"รายการตัวเลือก";if(j==="alertdialog")return"กล่องยืนยัน";return"กล่องโต้ตอบ"}function q2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("aria-labelledby");if(J){let W=J.split(/\s+/).map((V)=>document.getElementById(V)?.textContent?.trim()??"").filter(Boolean).join(" ");if(W)return W}let z=$.querySelector('[data-slot="dialog-title"], h1, h2, h3, [role="heading"]')?.textContent?.replace(/\s+/g," ").trim();if(z)return z;return($.textContent??"").replace(/\s+/g," ").trim()}function o0($){let j=b(q2($)),J=B2($);return j?`เปิด ${J} “${g(j,Y0)}”`:`เปิด ${J}`}var D2='[aria-busy="true"], [role="progressbar"], [data-loading="true"], .animate-pulse, .animate-spin',f2=/กำลังโหลด|กำลังค้นหา|กำลังดำเนินการ|\bloading\b/i;function k2($){if($.querySelector(D2))return!0;return f2.test($.textContent??"")}var S2=400,R2=250,O2=8000;function _2($,j){if(typeof MutationObserver>"u"){j.html=j0(m0($));return}let J=Date.now(),Q=!1,z=()=>{Q=!0,V.disconnect(),window.clearInterval(X),window.clearTimeout(F)},W=()=>{if(Q)return;if(z(),!$.isConnected)return;j.detail=g(o0($),X0),j.html=j0(m0($))},V=new MutationObserver(()=>{J=Date.now()});V.observe($,{childList:!0,subtree:!0,attributes:!0,characterData:!0});let X=window.setInterval(()=>{if(Q)return;if(!$.isConnected){z();return}if(Date.now()-J>=S2&&!k2($))W()},R2),F=window.setTimeout(W,O2)}function T2($){if($0($))return;let j=d("ui",o0($));if(j)_2($,j)}function A2(){if(typeof MutationObserver>"u")return;let $=new WeakSet;new MutationObserver((J)=>{for(let Q of J)for(let z of Array.from(Q.addedNodes)){if(!(z instanceof Element))continue;let W=N2(),V=z.matches(W)?[z]:Array.from(z.querySelectorAll(W));for(let X of V){if($.has(X))continue;$.add(X),T2(X)}}}).observe(document.body,{childList:!0,subtree:!0})}var L2=1600,E2=2500;function b0($){return{disabled:$.hasAttribute("disabled")||$.getAttribute("aria-disabled")==="true",busy:$.getAttribute("aria-busy")==="true",text:g(($.textContent??"").replace(/\s+/g," ").trim(),Y0)}}function x2($,j){if(!$.disabled&&j.disabled)return"ปุ่มถูกปิดใช้งานหลังคลิก";if(!$.busy&&j.busy)return"ปุ่มเข้าสู่สถานะกำลังโหลด";if($.text!==j.text&&j.text)return`ข้อความเปลี่ยนเป็น “${j.text}”`;return null}function h2($,j){if(typeof MutationObserver>"u")return;let J=b0($),Q=!1,z=(X,F)=>{if(Q)return;if(Q=!0,W.disconnect(),window.clearTimeout(V),j.afterNote=X,F)j.afterHtml=j0(M0($,u0,E2))},W=new MutationObserver(()=>{if(!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}let X=x2(J,b0($));if(X)z(X,!0)});W.observe($,{attributes:!0,attributeFilter:["disabled","aria-disabled","aria-busy","class"],childList:!0,subtree:!0,characterData:!0});let V=window.setTimeout(()=>{if(!Q&&!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}Q=!0,W.disconnect()},L2)}function d0(){if(p0||typeof window>"u")return;p0=!0,document.addEventListener("click",(Q)=>{if($0(Q.target))return;let z=V2(Q.target);if(!z)return;let W=G2(z);if(!W)return;let V=d("click",`คลิก ${W}`,U2(z),F2(z));if(V)h2(z,V)},{capture:!0,passive:!0}),document.addEventListener("change",(Q)=>{if($0(Q.target))return;let z=I2(Q.target);if(z)d("input",`แก้ไข ${z}`)},{capture:!0,passive:!0}),document.addEventListener("submit",(Q)=>{if($0(Q.target))return;d("submit","ส่งฟอร์ม")},{capture:!0,passive:!0});let $=()=>d("navigate",`ไปที่ ${F0(i(location.pathname+location.search))}`),j=history.pushState.bind(history),J=history.replaceState.bind(history);history.pushState=(...Q)=>{let z=j(...Q);return $(),z},history.replaceState=(...Q)=>{let z=J(...Q);return $(),z},window.addEventListener("popstate",$),A2()}function c0(){return p.map(($)=>({...$}))}var l0=2000,J0=[],r0=0,n0=!1;function H0($,j){r0+=1,J0.push({id:`log_${r0}`,at:new Date().toISOString(),level:$,message:j.length>l0?`${j.slice(0,l0)}…`:j});while(J0.length>A("maxConsoleEntries"))J0.shift()}function p2(){let $=new WeakSet;return(j,J)=>{if(typeof J==="object"&&J!==null){if($.has(J))return"[Circular]";$.add(J)}if(typeof J==="bigint")return J.toString();return J}}function s0($){if(typeof $==="string")return $;if($ instanceof Error)return`${$.name}: ${$.message}`;try{return JSON.stringify($,p2())??String($)}catch{return String($)}}function a0(){if(n0||typeof window>"u")return;n0=!0;let $=["log","info","warn","error","debug"];for(let j of $){let J=console[j].bind(console);console[j]=(...Q)=>{H0(j,Q.map(s0).join(" ")),J(...Q)}}window.addEventListener("error",(j)=>{let J=j.filename?` (${j.filename}:${j.lineno}:${j.colno})`:"";H0("exception",`${j.message}${J}`)}),window.addEventListener("unhandledrejection",(j)=>{let J=j.reason instanceof Error?`${j.reason.name}: ${j.reason.message}`:s0(j.reason);H0("unhandledrejection",J)})}function t0(){return J0.map(($)=>({...$}))}var e0=new Set,$1=new Set;function j1($,j){return $.add(j),()=>$.delete(j)}function J1($,j){for(let J of[...$])J(j)}function Q1($){return j1(e0,$)}function Q0($={type:"manual"}){J1(e0,$)}function z1($){return j1($1,$)}function Z1($){J1($1,$)}var g2=15000,m2=["ResizeObserver loop","Script error.","Non-Error promise rejection captured"],W1=!1,K1=0;function y2($){return m2.some((j)=>$.includes(j))}function V1($){let j=$.message??"";if(!j||y2(j))return;let J=Date.now();if(J-K1<g2)return;K1=J,Z1({...$,message:j})}function G1(){if(W1||typeof window>"u")return;W1=!0,window.addEventListener("error",($)=>{if(!$.message&&!$.error)return;let j=$.error instanceof Error?$.error:null;V1({type:"runtime-error",message:$.message||(j?j.message:"Unknown error"),stack:j?.stack})}),window.addEventListener("unhandledrejection",($)=>{let j=$.reason;V1({type:"unhandledrejection",message:j instanceof Error?j.message:String(j),stack:j instanceof Error?j.stack:void 0})})}var F1=4000,v2=1e6,b2=1e7,z0=[],w1=0,X1=!1;function M1($){z0.push($);while(z0.length>A("maxRequests"))z0.shift()}function H1(){return w1+=1,`req_${w1}`}function Y1($){let j={};if(!$)return j;if($ instanceof Headers)$.forEach((J,Q)=>{j[Q]=J});else if(Array.isArray($))for(let[J,Q]of $)j[J]=Q;else Object.assign(j,$);return j}function u2($){let j={};return $.forEach((J,Q)=>{j[Q]=J}),j}function i2($){if($==null)return null;if(typeof $==="string")return $;if($ instanceof URLSearchParams)return $.toString();if(typeof FormData<"u"&&$ instanceof FormData)return`[FormData: ${Array.from($.keys()).join(", ")}]`;if(typeof Blob<"u"&&$ instanceof Blob)return`[Blob ${$.size} bytes]`;if($ instanceof ArrayBuffer)return`[ArrayBuffer ${$.byteLength} bytes]`;return"[binary]"}function o2($,j){let J="",Q="GET",z={},W=null;if(typeof $==="string")J=$;else if($ instanceof URL)J=$.toString();else J=$.url,Q=$.method||Q,z=Y1($.headers);if(j){if(j.method)Q=j.method;if(j.headers)z={...z,...Y1(j.headers)};if(j.body!==void 0)W=i2(j.body)}return{method:Q.toUpperCase(),url:J,headers:z,body:W}}function I1($){return!x0($)}function d2($,j){if(I1(j.url)){j.responseSnippet="[body not captured for this origin]";return}let J=$.headers.get("content-type")??"",Q=Number($.headers.get("content-length")??"0"),z=Q?`, ~${Q} bytes`:"";if(!/json|text|xml|html|javascript|urlencoded/i.test(J)){j.responseSnippet=`[binary ${J||"unknown"}${z}]`;return}if(Q>v2){j.responseSnippet=`[response ${J||"text"}${z} — omitted]`;return}try{$.clone().text().then((W)=>{j.responseSnippet=o(W,A("maxBodyChars"))}).catch(()=>{})}catch{}}function C1($,j){if(/[?&]_rsc=/.test($))return!0;for(let J of Object.keys(j)){let Q=J.toLowerCase();if(Q==="rsc"||Q==="next-router-prefetch"||Q==="next-router-state-tree")return!0}return!1}function c2(){if(typeof window>"u"||typeof window.fetch!=="function")return;let $=window.fetch.bind(window);window.fetch=Object.assign(async(j,J)=>{let Q=o2(j,J);if(C1(Q.url,Q.headers))return $(j,J);let z={id:H1(),startedAt:new Date().toISOString(),method:Q.method,url:i(Q.url),requestHeaders:u(Q.headers),requestBody:o(Q.body,F1),status:null,statusText:null,durationMs:null,via:"fetch"};M1(z);let W=performance.now();try{let V=await $(j,J);return z.status=V.status,z.statusText=V.statusText,z.durationMs=Math.round(performance.now()-W),z.responseHeaders=u(u2(V.headers)),d2(V,z),V}catch(V){throw z.durationMs=Math.round(performance.now()-W),z.error=V instanceof Error?`${V.name}: ${V.message}`:String(V),V}},$)}function l2(){if(typeof window>"u"||typeof window.XMLHttpRequest!=="function")return;let $=XMLHttpRequest.prototype,j=$.open,J=$.send,Q=function(W,V){let X=typeof V==="string"?V:V.toString();return this.__cibEntry=C1(X,{})?void 0:{id:H1(),startedAt:"",method:(W||"GET").toUpperCase(),url:i(X),requestHeaders:{},requestBody:null,status:null,statusText:null,durationMs:null,via:"xhr"},j.apply(this,arguments)},z=function(W){let V=this.__cibEntry;if(V){V.startedAt=new Date().toISOString(),V.requestBody=typeof W==="string"?o(W,F1):W==null?null:"[non-string body]";let X=performance.now();M1(V),this.addEventListener("loadend",()=>{if(V.status=this.status||null,V.statusText=this.statusText||null,V.durationMs=Math.round(performance.now()-X),I1(V.url))V.responseSnippet="[body not captured for this origin]";else if(this.responseType===""||this.responseType==="text")try{V.responseSnippet=o(this.responseText||"",A("maxBodyChars"))}catch{}else{let F=this.getResponseHeader("content-type")??this.responseType;V.responseSnippet=`[binary ${F}]`}})}return J.apply(this,arguments)};$.open=Q,$.send=z}function U1(){if(X1)return;X1=!0,c2(),l2()}function P1(){let $=z0.map((J)=>({...J})),j=0;for(let J=$.length-1;J>=0;J-=1){let Q=$[J],z=Q?.responseSnippet;if(!Q||typeof z!=="string"||z.length===0)continue;if(j+z.length>b2)Q.responseSnippet=`[response omitted — report size budget reached (${z.length.toLocaleString()} chars)]`;else j+=z.length}return $}var r2={title:"รายงานปัญหา",summaryLabel:"หัวข้อปัญหา",summaryRequired:"(ต้องกรอกก่อนแจ้งปัญหา)",summaryPlaceholder:"สรุปปัญหาสั้น ๆ เช่น กดบันทึกร่างแล้ว error",detailLabel:"อธิบายปัญหา (ไม่บังคับ)",detailPlaceholder:"เกิดอะไรขึ้น? กำลังทำอะไรอยู่ตอนที่พบปัญหา?",annotateTitle:"วาดบนรูป",annotateHint:"ทำเครื่องหมายจุดที่มีปัญหาก่อนแนบ — วงกรอบ ชี้ลูกศร ไฮไลต์ หรือพิมพ์ข้อความ",annotateApply:"ใช้รูปนี้",cancel:"ยกเลิก",toolRect:"กรอบ",toolArrow:"ลูกศร",toolHighlight:"ไฮไลต์",toolText:"ข้อความ",deleteSelected:"ลบที่เลือก",clearAll:"ล้างทั้งหมด",annotateHelp:"เลือกเครื่องมือแล้วลากบนรูป · ไม่ได้เลือกเครื่องมือ = ย้าย/ปรับขนาดสิ่งที่วาดไว้ · กดกากบาทมุมขวาบนของรูปทรงเพื่อลบ",capturing:"กำลังเก็บภาพหน้าจอ…",noScreenshot:"ไม่มีภาพหน้าจอ — ยังส่งรายงานได้",cancelled:"ยกเลิกการเก็บภาพหน้าจอแล้ว",close:"ปิด",submit:"แจ้งปัญหา",submitting:"กำลังส่ง…",submitted:"แจ้งปัญหาสำเร็จ",crashed:"เกิดข้อผิดพลาดในระบบ",crashAction:"แจ้งปัญหา",failed:"ส่งรายงานไม่สำเร็จ",captured:"เก็บข้อมูลแล้ว",reporter:"ผู้แจ้ง",page:"หน้า"},n2={title:"Report a problem",summaryLabel:"Summary",summaryRequired:"(required)",summaryPlaceholder:"One line, e.g. saving a draft returns an error",detailLabel:"Details (optional)",detailPlaceholder:"What happened? What were you doing at the time?",annotateTitle:"Draw on the image",annotateHint:"Mark what went wrong before attaching — box it, point at it, highlight it, or type on it",annotateApply:"Use this image",cancel:"Cancel",toolRect:"Box",toolArrow:"Arrow",toolHighlight:"Highlight",toolText:"Text",deleteSelected:"Delete selected",clearAll:"Clear all",annotateHelp:"Pick a tool and drag on the image · no tool selected = move/resize what you drew · press the ✕ on a shape to delete it",capturing:"Capturing the screen…",noScreenshot:"No screenshot — you can still send the report",cancelled:"Screen capture cancelled",close:"Close",submit:"Send report",submitting:"Sending…",submitted:"Report sent",crashed:"Something went wrong",crashAction:"Report it",failed:"Could not send the report",captured:"Captured",reporter:"Reporter",page:"Page"};function Z0($){return $==="en"?n2:r2}var I0=null;function s2(){if(typeof document>"u")return null;if(I0?.isConnected)return I0;let $=document.createElement("lw-debug-toasts");$.dataset.debugReporter="true";let j=$.attachShadow({mode:"open"}),J=document.createElement("style");J.textContent=`
|
|
1
|
+
(()=>{var c1={maxRequests:60,maxConsoleEntries:120,maxActions:80,maxBodyChars:20000},R=null;function T0($){R=$}function f(){if(!R)throw Error("[debug-capture] configureDebugCapture() has not been called");return R}function A0(){return R!==null}function h(){let $=f().app;return{name:$.name,version:$.version??"0.0.0",environment:$.environment??l1()}}function l1(){if(typeof window>"u")return"unknown";let $=window.location.hostname;if($==="localhost"||$==="127.0.0.1"||$.endsWith(".local"))return"development";return"production"}function A($){let j=R?.capture?.[$];return typeof j==="number"?j:c1[$]}function L0($){let j=R?.module;if(!j)return null;try{return j($)??null}catch{return null}}function e(){let $=R?.redact;return{headers:$?.headers??[],queryKeys:($?.queryKeys??[]).map((j)=>j.toLowerCase()),bodyKeys:($?.bodyKeys??[]).map((j)=>j.toLowerCase())}}function E0(){return R?.capture?.overlaySelectors??[]}function x0($){if(typeof window>"u")return!1;let j;try{j=new URL($,window.location.href)}catch{return!1}if(r1(j))return!1;if(j.origin===window.location.origin)return!0;return(R?.capture?.bodyOrigins??[]).some((J)=>{try{return new URL(J).origin===j.origin}catch{return!1}})}function r1($){if(!R?.host)return!1;try{if(new URL(R.host).origin!==$.origin)return!1}catch{return!1}return $.pathname.startsWith("/ingest/")}var v="‹redacted›",s1=/^(authorization|proxy-authorization|cookie|set-cookie|x-[a-z-]*token|x-csrf[a-z-]*|x-xsrf[a-z-]*)$/i,n1=new Set(["access_token","token","id_token","refresh_token","code","secret","client_secret","password","apikey","api_key","signature","x-amz-signature","x-amz-credential"]),a1=/(password|passwd|token|secret|authorization|refresh|client_secret|otp|pin)/i,t1=/[\w.+-]+@[\w-]+\.[\w.-]+/g,e1=/\d(?:[\d\s-]{7,})\d/g;function b($){return $.replace(t1,v).replace(e1,v)}function $2($){if(s1.test($))return!0;return e().headers.some((J)=>J.toLowerCase()===$.toLowerCase())}function u($){let j={};for(let[J,Q]of Object.entries($))j[J]=$2(J)?v:Q;return j}function i($){try{let j=/^https?:\/\//i.test($),J=new URL($,j?void 0:"http://local.invalid"),Q=!1;if(J.searchParams.forEach((z,W)=>{if(n1.has(W.toLowerCase())||e().queryKeys.includes(W.toLowerCase()))J.searchParams.set(W,v),Q=!0}),!Q)return $;return j?J.toString():`${J.pathname}${J.search}`}catch{return $}}function w0($,j){if(j>6||$===null||typeof $!=="object")return $;if(Array.isArray($))return $.map((Q)=>w0(Q,j+1));let J={};for(let[Q,z]of Object.entries($)){let W=a1.test(Q)||e().bodyKeys.some((V)=>Q.toLowerCase().includes(V));J[Q]=W?v:w0(z,j+1)}return J}function o($,j){if($==null)return null;let J=$,Q=$.trim();if(Q.startsWith("{")||Q.startsWith("["))try{let z=JSON.parse(Q);J=JSON.stringify(w0(z,0))}catch{}if(J.length>j)return`${J.slice(0,j)}… [truncated ${J.length-j} chars]`;return J}var X0=120,Y0=40,m=($,j)=>$.length>j?`${$.slice(0,j)}…`:$,F0=($)=>{try{return decodeURIComponent($)}catch{return $}},p=[],h0=0,p0=!1;function d($,j,J,Q){let z=m(j,X0),W=p[p.length-1];if($==="navigate"&&W?.kind==="click"){let X=z.replace(/^ไปที่\s*/,"");if(W.detail.includes(`→ ${X}`))return W.at=new Date().toISOString(),W;let F=X.split(/[?#]/)[0]??X,H=W.source?F0(W.source.replace(/^→\s*/,"")).split(/[?#]/)[0]:null;if(H&&(F===H||F.startsWith(H)))return W.detail=m(`${W.detail} → ${X}`,X0),W.source=void 0,W.at=new Date().toISOString(),W}if(W&&W.kind===$&&W.detail===z){if(W.at=new Date().toISOString(),$!=="navigate")W.count=(W.count??1)+1;return W}h0+=1;let V={id:`act_${h0}`,at:new Date().toISOString(),kind:$,detail:z,count:1,source:J,html:j0(Q)};p.push(V);while(p.length>A("maxActions"))J2(p.shift());return V}var j2=200000,c=0;function j0($){if(!$)return;if(c+$.length>j2)return;return c+=$.length,$}function J2($){if(!$)return;if(c-=($.html?.length??0)+($.afterHtml?.length??0),c<0)c=0}function $0($){return $ instanceof Element&&Boolean($.closest("[data-debug-reporter]"))}var Q2='button, a[href], [role="button"], [role="tab"], [role="menuitem"], [role="option"], [role="switch"], [role="checkbox"], [role="radio"], [role="link"], summary, input, select, textarea',z2={button:"ปุ่ม",a:"ลิงก์",input:"ช่อง",textarea:"ช่อง",select:"ตัวเลือก",summary:"ส่วนขยาย"},m0={button:"ปุ่ม",tab:"แท็บ",menuitem:"เมนู",option:"ตัวเลือก",switch:"สวิตช์",checkbox:"ช่องเลือก",radio:"ตัวเลือก",link:"ลิงก์"};function Z2($){let j=$.getAttribute("role");if(j&&m0[j])return m0[j];return z2[$.tagName.toLowerCase()]??"ปุ่ม"}function W2($,j){try{let J=$,Q=0;while(J&&Q<=j){let z=i0(J);if(z&&typeof z.memoizedProps?.onClick==="function")return J;J=J.parentElement,Q+=1}}catch{}return null}function K2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("title")?.trim();if(J)return J;if($ instanceof HTMLInputElement||$ instanceof HTMLTextAreaElement||$ instanceof HTMLSelectElement)return($.getAttribute("placeholder")||$.getAttribute("name")||"").trim();if($ instanceof HTMLImageElement)return($.getAttribute("alt")||"").trim();let Q=($.textContent??"").replace(/\s+/g," ").trim();if(Q)return Q;if($ instanceof HTMLAnchorElement){let z=$.getAttribute("href");if(z?.startsWith("/"))return F0(z)}return""}function V2($){if(!($ instanceof Element))return null;let j=$.closest(Q2)??W2($,4);if(!j)return null;let J=j.tagName.toLowerCase();if(J==="html"||J==="body")return null;return j}function G2($){let j=b(K2($));if(!j)return null;return`${Z2($)} “${m(j,Y0)}”`}var u0=6000,w2=4000,X2=/(?:^|\s)!?(?:fixed|absolute|sticky|inset-\S+|z-\S+|top-\S+|bottom-\S+|left-\S+|right-\S+|w-screen|h-screen|min-h-screen|max-h-screen|translate-\S+|scale-\S+)(?=\s|$)/g;function Y2($){$.querySelectorAll("script, style, link, iframe, object, embed, noscript, canvas, video, audio").forEach((z)=>z.remove());let j=[$,...Array.from($.querySelectorAll("*"))];for(let z of j){for(let V of Array.from(z.attributes)){let X=V.name.toLowerCase();if(X.startsWith("on")||X==="srcdoc"||X==="value"||X.startsWith("data-"))z.removeAttribute(V.name)}if(z instanceof HTMLAnchorElement)z.setAttribute("href","#");if(z instanceof HTMLImageElement)z.removeAttribute("src");let W=z.getAttribute("class");if(W){let V=W.replace(X2," ").replace(/\s+/g," ").trim();if(V)z.setAttribute("class",V);else z.removeAttribute("class")}}let J=document.createTreeWalker($,NodeFilter.SHOW_TEXT),Q=J.nextNode();while(Q){if(Q.nodeValue)Q.nodeValue=b(Q.nodeValue);Q=J.nextNode()}}function M0($,j,J){try{let Q=$.outerHTML;if(!Q||Q.length>j)return;let z=$.cloneNode(!0);Y2(z);let W=z.outerHTML;return W&&W.length<=J?W:void 0}catch{return}}var F2=($)=>M0($,u0,w2),M2=150000,H2=40000,g0=($)=>M0($,M2,H2);function I2($){if(!($ instanceof HTMLInputElement)&&!($ instanceof HTMLTextAreaElement)&&!($ instanceof HTMLSelectElement))return null;let j=$.name||$.id||$.getAttribute("aria-label")||$.getAttribute("placeholder")||$.tagName.toLowerCase();return`ช่อง “${b(j)}”`}var y0=80;function i0($){let j=Object.keys($).find((J)=>J.startsWith("__reactFiber$")||J.startsWith("__reactInternalInstance$"));return j?$[j]:null}function U2($){if(typeof $!=="function")return null;try{let j=Function.prototype.toString.call($);return(j.match(/\.(?:push|replace)\(\s*['"`]([^'"`]+)['"`]/)??j.match(/redirect\(\s*['"`]([^'"`]+)['"`]/))?.[1]??null}catch{return null}}function v0($){if(!$)return;return`→ ${$.length>y0?`${$.slice(0,y0)}…`:$}`}function C2($){try{let j=$.closest("a[href]")?.getAttribute("href");if(j&&j.startsWith("/"))return v0(j);let J=i0($),Q=0;while(J&&Q<30){if(typeof J.memoizedProps?.onClick==="function")return v0(U2(J.memoizedProps.onClick));J=J.return,Q+=1}return}catch{return}}var P2='[role="dialog"], [role="alertdialog"], [role="menu"], [role="listbox"], [role="status"], [role="alert"]';function N2(){let $=E0();return $.length?$.join(", "):P2}function B2($){let j=$.getAttribute("role");if(j==="status"||j==="alert")return"ข้อความแจ้งเตือน";if(j==="menu")return"เมนู";if(j==="listbox")return"รายการตัวเลือก";if(j==="alertdialog")return"กล่องยืนยัน";return"กล่องโต้ตอบ"}function q2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("aria-labelledby");if(J){let W=J.split(/\s+/).map((V)=>document.getElementById(V)?.textContent?.trim()??"").filter(Boolean).join(" ");if(W)return W}let z=$.querySelector('[data-slot="dialog-title"], h1, h2, h3, [role="heading"]')?.textContent?.replace(/\s+/g," ").trim();if(z)return z;return($.textContent??"").replace(/\s+/g," ").trim()}function o0($){let j=b(q2($)),J=B2($);return j?`เปิด ${J} “${m(j,Y0)}”`:`เปิด ${J}`}var D2='[aria-busy="true"], [role="progressbar"], [data-loading="true"], .animate-pulse, .animate-spin',f2=/กำลังโหลด|กำลังค้นหา|กำลังดำเนินการ|\bloading\b/i;function S2($){if($.querySelector(D2))return!0;return f2.test($.textContent??"")}var k2=400,R2=250,O2=8000;function _2($,j){if(typeof MutationObserver>"u"){j.html=j0(g0($));return}let J=Date.now(),Q=!1,z=()=>{Q=!0,V.disconnect(),window.clearInterval(X),window.clearTimeout(F)},W=()=>{if(Q)return;if(z(),!$.isConnected)return;j.detail=m(o0($),X0),j.html=j0(g0($))},V=new MutationObserver(()=>{J=Date.now()});V.observe($,{childList:!0,subtree:!0,attributes:!0,characterData:!0});let X=window.setInterval(()=>{if(Q)return;if(!$.isConnected){z();return}if(Date.now()-J>=k2&&!S2($))W()},R2),F=window.setTimeout(W,O2)}function T2($){if($0($))return;let j=d("ui",o0($));if(j)_2($,j)}function A2(){if(typeof MutationObserver>"u")return;let $=new WeakSet;new MutationObserver((J)=>{for(let Q of J)for(let z of Array.from(Q.addedNodes)){if(!(z instanceof Element))continue;let W=N2(),V=z.matches(W)?[z]:Array.from(z.querySelectorAll(W));for(let X of V){if($.has(X))continue;$.add(X),T2(X)}}}).observe(document.body,{childList:!0,subtree:!0})}var L2=1600,E2=2500;function b0($){return{disabled:$.hasAttribute("disabled")||$.getAttribute("aria-disabled")==="true",busy:$.getAttribute("aria-busy")==="true",text:m(($.textContent??"").replace(/\s+/g," ").trim(),Y0)}}function x2($,j){if(!$.disabled&&j.disabled)return"ปุ่มถูกปิดใช้งานหลังคลิก";if(!$.busy&&j.busy)return"ปุ่มเข้าสู่สถานะกำลังโหลด";if($.text!==j.text&&j.text)return`ข้อความเปลี่ยนเป็น “${j.text}”`;return null}function h2($,j){if(typeof MutationObserver>"u")return;let J=b0($),Q=!1,z=(X,F)=>{if(Q)return;if(Q=!0,W.disconnect(),window.clearTimeout(V),j.afterNote=X,F)j.afterHtml=j0(M0($,u0,E2))},W=new MutationObserver(()=>{if(!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}let X=x2(J,b0($));if(X)z(X,!0)});W.observe($,{attributes:!0,attributeFilter:["disabled","aria-disabled","aria-busy","class"],childList:!0,subtree:!0,characterData:!0});let V=window.setTimeout(()=>{if(!Q&&!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}Q=!0,W.disconnect()},L2)}function d0(){if(p0||typeof window>"u")return;p0=!0,document.addEventListener("click",(Q)=>{if($0(Q.target))return;let z=V2(Q.target);if(!z)return;let W=G2(z);if(!W)return;let V=d("click",`คลิก ${W}`,C2(z),F2(z));if(V)h2(z,V)},{capture:!0,passive:!0}),document.addEventListener("change",(Q)=>{if($0(Q.target))return;let z=I2(Q.target);if(z)d("input",`แก้ไข ${z}`)},{capture:!0,passive:!0}),document.addEventListener("submit",(Q)=>{if($0(Q.target))return;d("submit","ส่งฟอร์ม")},{capture:!0,passive:!0});let $=()=>d("navigate",`ไปที่ ${F0(i(location.pathname+location.search))}`),j=history.pushState.bind(history),J=history.replaceState.bind(history);history.pushState=(...Q)=>{let z=j(...Q);return $(),z},history.replaceState=(...Q)=>{let z=J(...Q);return $(),z},window.addEventListener("popstate",$),A2()}function c0(){return p.map(($)=>({...$}))}var l0=2000,J0=[],r0=0,s0=!1;function H0($,j){r0+=1,J0.push({id:`log_${r0}`,at:new Date().toISOString(),level:$,message:j.length>l0?`${j.slice(0,l0)}…`:j});while(J0.length>A("maxConsoleEntries"))J0.shift()}function p2(){let $=new WeakSet;return(j,J)=>{if(typeof J==="object"&&J!==null){if($.has(J))return"[Circular]";$.add(J)}if(typeof J==="bigint")return J.toString();return J}}function n0($){if(typeof $==="string")return $;if($ instanceof Error)return`${$.name}: ${$.message}`;try{return JSON.stringify($,p2())??String($)}catch{return String($)}}function a0(){if(s0||typeof window>"u")return;s0=!0;let $=["log","info","warn","error","debug"];for(let j of $){let J=console[j].bind(console);console[j]=(...Q)=>{H0(j,Q.map(n0).join(" ")),J(...Q)}}window.addEventListener("error",(j)=>{let J=j.filename?` (${j.filename}:${j.lineno}:${j.colno})`:"";H0("exception",`${j.message}${J}`)}),window.addEventListener("unhandledrejection",(j)=>{let J=j.reason instanceof Error?`${j.reason.name}: ${j.reason.message}`:n0(j.reason);H0("unhandledrejection",J)})}function t0(){return J0.map(($)=>({...$}))}var e0=new Set,$1=new Set;function j1($,j){return $.add(j),()=>$.delete(j)}function J1($,j){for(let J of[...$])J(j)}function Q1($){return j1(e0,$)}function Q0($={type:"manual"}){J1(e0,$)}function z1($){return j1($1,$)}function Z1($){J1($1,$)}var m2=15000,g2=["ResizeObserver loop","Script error.","Non-Error promise rejection captured"],W1=!1,K1=0;function y2($){return g2.some((j)=>$.includes(j))}function V1($){let j=$.message??"";if(!j||y2(j))return;let J=Date.now();if(J-K1<m2)return;K1=J,Z1({...$,message:j})}function G1(){if(W1||typeof window>"u")return;W1=!0,window.addEventListener("error",($)=>{if(!$.message&&!$.error)return;let j=$.error instanceof Error?$.error:null;V1({type:"runtime-error",message:$.message||(j?j.message:"Unknown error"),stack:j?.stack})}),window.addEventListener("unhandledrejection",($)=>{let j=$.reason;V1({type:"unhandledrejection",message:j instanceof Error?j.message:String(j),stack:j instanceof Error?j.stack:void 0})})}var F1=4000,v2=1e6,b2=1e7,z0=[],w1=0,X1=!1;function M1($){z0.push($);while(z0.length>A("maxRequests"))z0.shift()}function H1(){return w1+=1,`req_${w1}`}function Y1($){let j={};if(!$)return j;if($ instanceof Headers)$.forEach((J,Q)=>{j[Q]=J});else if(Array.isArray($))for(let[J,Q]of $)j[J]=Q;else Object.assign(j,$);return j}function u2($){let j={};return $.forEach((J,Q)=>{j[Q]=J}),j}function i2($){if($==null)return null;if(typeof $==="string")return $;if($ instanceof URLSearchParams)return $.toString();if(typeof FormData<"u"&&$ instanceof FormData)return`[FormData: ${Array.from($.keys()).join(", ")}]`;if(typeof Blob<"u"&&$ instanceof Blob)return`[Blob ${$.size} bytes]`;if($ instanceof ArrayBuffer)return`[ArrayBuffer ${$.byteLength} bytes]`;return"[binary]"}function o2($,j){let J="",Q="GET",z={},W=null;if(typeof $==="string")J=$;else if($ instanceof URL)J=$.toString();else J=$.url,Q=$.method||Q,z=Y1($.headers);if(j){if(j.method)Q=j.method;if(j.headers)z={...z,...Y1(j.headers)};if(j.body!==void 0)W=i2(j.body)}return{method:Q.toUpperCase(),url:J,headers:z,body:W}}function I1($){return!x0($)}function d2($,j){if(I1(j.url)){j.responseSnippet="[body not captured for this origin]";return}let J=$.headers.get("content-type")??"",Q=Number($.headers.get("content-length")??"0"),z=Q?`, ~${Q} bytes`:"";if(!/json|text|xml|html|javascript|urlencoded/i.test(J)){j.responseSnippet=`[binary ${J||"unknown"}${z}]`;return}if(Q>v2){j.responseSnippet=`[response ${J||"text"}${z} — omitted]`;return}try{$.clone().text().then((W)=>{j.responseSnippet=o(W,A("maxBodyChars"))}).catch(()=>{})}catch{}}function U1($,j){if(/[?&]_rsc=/.test($))return!0;for(let J of Object.keys(j)){let Q=J.toLowerCase();if(Q==="rsc"||Q==="next-router-prefetch"||Q==="next-router-state-tree")return!0}return!1}function c2(){if(typeof window>"u"||typeof window.fetch!=="function")return;let $=window.fetch.bind(window);window.fetch=Object.assign(async(j,J)=>{let Q=o2(j,J);if(U1(Q.url,Q.headers))return $(j,J);let z={id:H1(),startedAt:new Date().toISOString(),method:Q.method,url:i(Q.url),requestHeaders:u(Q.headers),requestBody:o(Q.body,F1),status:null,statusText:null,durationMs:null,via:"fetch"};M1(z);let W=performance.now();try{let V=await $(j,J);return z.status=V.status,z.statusText=V.statusText,z.durationMs=Math.round(performance.now()-W),z.responseHeaders=u(u2(V.headers)),d2(V,z),V}catch(V){throw z.durationMs=Math.round(performance.now()-W),z.error=V instanceof Error?`${V.name}: ${V.message}`:String(V),V}},$)}function l2(){if(typeof window>"u"||typeof window.XMLHttpRequest!=="function")return;let $=XMLHttpRequest.prototype,j=$.open,J=$.send,Q=function(W,V){let X=typeof V==="string"?V:V.toString();return this.__cibEntry=U1(X,{})?void 0:{id:H1(),startedAt:"",method:(W||"GET").toUpperCase(),url:i(X),requestHeaders:{},requestBody:null,status:null,statusText:null,durationMs:null,via:"xhr"},j.apply(this,arguments)},z=function(W){let V=this.__cibEntry;if(V){V.startedAt=new Date().toISOString(),V.requestBody=typeof W==="string"?o(W,F1):W==null?null:"[non-string body]";let X=performance.now();M1(V),this.addEventListener("loadend",()=>{if(V.status=this.status||null,V.statusText=this.statusText||null,V.durationMs=Math.round(performance.now()-X),I1(V.url))V.responseSnippet="[body not captured for this origin]";else if(this.responseType===""||this.responseType==="text")try{V.responseSnippet=o(this.responseText||"",A("maxBodyChars"))}catch{}else{let F=this.getResponseHeader("content-type")??this.responseType;V.responseSnippet=`[binary ${F}]`}})}return J.apply(this,arguments)};$.open=Q,$.send=z}function C1(){if(X1)return;X1=!0,c2(),l2()}function P1(){let $=z0.map((J)=>({...J})),j=0;for(let J=$.length-1;J>=0;J-=1){let Q=$[J],z=Q?.responseSnippet;if(!Q||typeof z!=="string"||z.length===0)continue;if(j+z.length>b2)Q.responseSnippet=`[response omitted — report size budget reached (${z.length.toLocaleString()} chars)]`;else j+=z.length}return $}var r2={title:"รายงานปัญหา",summaryLabel:"หัวข้อปัญหา",summaryRequired:"(ต้องกรอกก่อนแจ้งปัญหา)",summaryPlaceholder:"สรุปปัญหาสั้น ๆ เช่น กดบันทึกร่างแล้ว error",detailLabel:"อธิบายปัญหา (ไม่บังคับ)",detailPlaceholder:"เกิดอะไรขึ้น? กำลังทำอะไรอยู่ตอนที่พบปัญหา?",annotateTitle:"วาดบนรูป",annotateHint:"ทำเครื่องหมายจุดที่มีปัญหาก่อนแนบ — วงกรอบ ชี้ลูกศร ไฮไลต์ หรือพิมพ์ข้อความ",annotateApply:"ใช้รูปนี้",cancel:"ยกเลิก",toolRect:"กรอบ",toolArrow:"ลูกศร",toolHighlight:"ไฮไลต์",toolText:"ข้อความ",deleteSelected:"ลบที่เลือก",clearAll:"ล้างทั้งหมด",annotateHelp:"เลือกเครื่องมือแล้วลากบนรูป · ไม่ได้เลือกเครื่องมือ = ย้าย/ปรับขนาดสิ่งที่วาดไว้ · กดกากบาทมุมขวาบนของรูปทรงเพื่อลบ",capturing:"กำลังเก็บภาพหน้าจอ…",noScreenshot:"ไม่มีภาพหน้าจอ — ยังส่งรายงานได้",cancelled:"ยกเลิกการเก็บภาพหน้าจอแล้ว",close:"ปิด",submit:"แจ้งปัญหา",submitting:"กำลังส่ง…",submitted:"แจ้งปัญหาสำเร็จ",crashed:"เกิดข้อผิดพลาดในระบบ",crashAction:"แจ้งปัญหา",failed:"ส่งรายงานไม่สำเร็จ",captured:"เก็บข้อมูลแล้ว",reporter:"ผู้แจ้ง",page:"หน้า",handoffTitle:"กำลังพาไปที่ระบบแจ้งปัญหา",handoffBody:"ระบบจะลงชื่อเข้าใช้ให้อัตโนมัติ เพื่อดูเรื่องที่คุณแจ้งไว้",handoffGo:"ไปเลย",handoffPreparing:"กำลังเตรียม…",handoffFailed:"เปิดรายการที่แจ้งไว้ไม่สำเร็จ"},s2={title:"Report a problem",summaryLabel:"Summary",summaryRequired:"(required)",summaryPlaceholder:"One line, e.g. saving a draft returns an error",detailLabel:"Details (optional)",detailPlaceholder:"What happened? What were you doing at the time?",annotateTitle:"Draw on the image",annotateHint:"Mark what went wrong before attaching — box it, point at it, highlight it, or type on it",annotateApply:"Use this image",cancel:"Cancel",toolRect:"Box",toolArrow:"Arrow",toolHighlight:"Highlight",toolText:"Text",deleteSelected:"Delete selected",clearAll:"Clear all",annotateHelp:"Pick a tool and drag on the image · no tool selected = move/resize what you drew · press the ✕ on a shape to delete it",capturing:"Capturing the screen…",noScreenshot:"No screenshot — you can still send the report",cancelled:"Screen capture cancelled",close:"Close",submit:"Send report",submitting:"Sending…",submitted:"Report sent",crashed:"Something went wrong",crashAction:"Report it",failed:"Could not send the report",captured:"Captured",reporter:"Reporter",page:"Page",handoffTitle:"Opening the support portal",handoffBody:"You will be signed in automatically to see what you reported",handoffGo:"Go now",handoffPreparing:"Preparing…",handoffFailed:"Could not open your reports"};function Z0($){return $==="en"?s2:r2}var I0=null;function n2(){if(typeof document>"u")return null;if(I0?.isConnected)return I0;let $=document.createElement("lw-debug-toasts");$.dataset.debugReporter="true";let j=$.attachShadow({mode:"open"}),J=document.createElement("style");J.textContent=`
|
|
2
2
|
:host { all: initial; }
|
|
3
3
|
.stack {
|
|
4
4
|
position: fixed; top: 16px; right: 16px; z-index: 2147483001;
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
}
|
|
31
31
|
@keyframes in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
|
|
32
32
|
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }
|
|
33
|
-
`;let Q=document.createElement("div");return Q.className="stack",Q.setAttribute("role","status"),Q.setAttribute("aria-live","polite"),j.append(J,Q),document.body.append($),I0=Q,Q}function l($,j="success",J){let Q=s2();if(!Q)return;let z=document.createElement("div");z.className="toast",z.dataset.tone=j;let W=document.createElement("span");W.className="dot";let V=document.createElement("span");V.textContent=$;let X=document.createElement("button");X.type="button",X.className="close",X.textContent="✕",X.setAttribute("aria-label","ปิด");let F=()=>{window.clearTimeout(H),z.remove()};X.addEventListener("click",F);let H=j==="error"||J?0:window.setTimeout(F,6000);if(z.append(W,V),J){let C=document.createElement("button");C.type="button",C.className="action",C.textContent=J.label,C.addEventListener("click",()=>{F(),J.onClick()}),z.append(C)}z.append(X),Q.append(z)}function N1($,j,J){let Q=$.filter((W)=>Boolean(W.error)||W.status!=null&&W.status>=400).slice(-20).map((W)=>({method:W.method,url:W.url,status:W.status,error:W.error,at:W.startedAt})),z=j.filter((W)=>W.level==="error"||W.level==="exception"||W.level==="unhandledrejection").slice(-20).map((W)=>W.message);return{failedRequests:Q,errors:z,erroredQueries:J.slice(0,20)}}function a2(){let $={memoryUsedMb:null,memoryLimitMb:null,domContentLoadedMs:null,loadEventMs:null};if(typeof performance>"u")return $;let j=performance.memory;if(j)$.memoryUsedMb=Math.round(j.usedJSHeapSize/1024/1024),$.memoryLimitMb=Math.round(j.jsHeapSizeLimit/1024/1024);let[J]=performance.getEntriesByType("navigation");if(J)$.domContentLoadedMs=Math.round(J.domContentLoadedEventEnd),$.loadEventMs=Math.round(J.loadEventEnd);return $}function C0($,j){if(!$)return j;try{return $()}catch{return j}}function B1(){let $=R(),{pathname:j,search:J,href:Q}=window.location;return{capturedAt:new Date().toISOString(),route:{href:Q,pathname:j,search:J},module:L0(j),user:C0($.user,{}),apiHeaders:u(C0($.headers,{})),app:{name:h().name,version:h().version,environment:h().environment},client:{userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,online:navigator.onLine,viewport:{width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio},screen:{width:window.screen.width,height:window.screen.height}},performance:a2(),extra:C0($.extra,{})}}var t2=2;function q1($){let j=P1(),J=t0();return{context:B1(),reason:$.reason,note:$.note,cause:N1(j,J,$.erroredQueries),actionTrail:c0(),network:j,console:J,screenshotDataUrl:$.screenshotDataUrl,screenshotMethod:$.screenshotMethod,meta:{generatedBy:"lightwork-debug-capture",schemaVersion:t2}}}async function D1(){if(typeof navigator<"u"&&Boolean(navigator.mediaDevices?.getDisplayMedia)){let J=await e2();if(J.status==="ok")return{dataUrl:J.dataUrl,method:"display-media"};if(J.status==="cancelled")return{dataUrl:null,method:"cancelled"}}let j=await J4();if(j)return{dataUrl:j,method:"html-to-image"};return{dataUrl:null,method:"none"}}async function e2(){let $=null;try{let j={video:{frameRate:30},audio:!1,preferCurrentTab:!0,selfBrowserSurface:"include",surfaceSwitching:"exclude"};$=await navigator.mediaDevices.getDisplayMedia(j);let J=await $4($);return J?{status:"ok",dataUrl:J}:{status:"error"}}catch(j){if(j instanceof DOMException&&(j.name==="NotAllowedError"||j.name==="AbortError"))return{status:"cancelled"};return{status:"error"}}finally{$?.getTracks().forEach((j)=>j.stop())}}async function $4($){let j=document.createElement("video");j.srcObject=$,j.muted=!0,j.playsInline=!0,await new Promise((V)=>{let X=!1,F=()=>{if(X)return;X=!0,V()};j.onloadedmetadata=()=>{j.play().then(F).catch(F)},window.setTimeout(F,1500)}),await j4(j);let{videoWidth:J,videoHeight:Q}=j;if(!J||!Q)return null;let z=document.createElement("canvas");z.width=J,z.height=Q;let W=z.getContext("2d");if(!W)return null;W.drawImage(j,0,0,J,Q),j.pause(),j.srcObject=null;try{return z.toDataURL("image/png")}catch{return null}}function j4($){return new Promise((j)=>{let J=!1,Q=()=>{if(J)return;J=!0,j()},z=$;if(typeof z.requestVideoFrameCallback==="function")z.requestVideoFrameCallback(()=>Q()),window.setTimeout(Q,1000);else window.setTimeout(Q,250)})}async function J4(){let $=R().screenshotFallback;if(!$)return null;let j=await $().catch(()=>null);if(!j)return null;try{return await j(document.body,{cacheBust:!0,pixelRatio:Math.min(window.devicePixelRatio||1,2),filter:(J)=>!(J instanceof HTMLElement&&J.dataset?.debugReporter==="true")})}catch{return null}}var Q4=2000,z4=0.82,Z4=3000000;function W4($){return new Promise((j,J)=>{let Q=new Image;Q.onload=()=>j(Q),Q.onerror=()=>J(Error("could not read the screenshot")),Q.src=$})}async function f1($){try{let j=await W4($),J=Math.max(j.naturalWidth,j.naturalHeight),Q=Math.min(1,Q4/J),z=document.createElement("canvas");z.width=Math.max(1,Math.round(j.naturalWidth*Q)),z.height=Math.max(1,Math.round(j.naturalHeight*Q));let W=z.getContext("2d");if(!W)return $;W.fillStyle="#fff",W.fillRect(0,0,z.width,z.height),W.drawImage(j,0,0,z.width,z.height);let V=z4,X=z.toDataURL("image/jpeg",V);while(X.length>Z4&&V>0.4)V-=0.15,X=z.toDataURL("image/jpeg",V);return X}catch{return $}}var K4=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,V4=/^\d+$/,G4=/^[0-9a-f]{16,}$/i;function k1($){if($.reason.type==="manual")return null;let j=$.cause?.failedRequests?.[0];if(!j?.url)return null;let J;try{J=new URL(j.url,"http://x").pathname}catch{J=j.url}let Q=J.split("/").map((W)=>K4.test(W)||V4.test(W)||G4.test(W)?":id":W).join("/"),z=j.status??(j.error?"ERR":"?");return`${j.method??"REQ"} ${Q} ${z}`}var S1=2000000;function W0($){let{screenshotDataUrl:j,...J}=$;return JSON.stringify(J).length}function R1($,j=2000000){if(W0($)<=j)return $;let J=$.network.map((z)=>({...z})),Q={...$,network:J};for(let z of J){if(W0(Q)<=j)return Q;if(typeof z.responseSnippet==="string"&&z.responseSnippet.length>35)z.responseSnippet="[body dropped — report size budget]";if(typeof z.requestBody==="string"&&z.requestBody.length>35)z.requestBody="[body dropped — report size budget]"}while(Q.network.length>1&&W0(Q)>j)Q.network=Q.network.slice(1);while(Q.console.length>1&&W0(Q)>j)Q.console=Q.console.slice(1);return Q}var O1=32768;function w4($){let j="";for(let J=0;J<$.length;J+=O1)j+=String.fromCharCode(...$.subarray(J,J+O1));return btoa(j)}function X4($){return{dataUri:`data:application/json;base64,${w4(new TextEncoder().encode(JSON.stringify($)))}`,filename:"debug-bundle.json"}}async function _1($,j){let J=R(),Q=R1(j,S1),{context:z,note:W}=Q,V=[];if(Q.screenshotDataUrl){let C=await f1(Q.screenshotDataUrl);V.push({dataUri:C,filename:"screenshot.jpg"})}V.push(X4(Q));let X=k1(Q),F={title:$,description:W.trim()||void 0,category:z.module?.label||h().name,routeUrl:z.route.href,priority:"MEDIUM",requesterEmail:z.user.email??void 0,requesterName:z.user.fullName??void 0,customFields:{unit:z.user.unit??"",appVersion:z.app.version,environment:z.app.environment,reasonType:Q.reason.type,appName:h().name,module:z.module?.label??""},context:{...X?{signature:X}:{},capturedAt:z.capturedAt,reason:Q.reason,cause:Q.cause,actionTrail:Q.actionTrail,client:z.client,performance:z.performance,apiHeaders:z.apiHeaders,extra:z.extra,counts:{network:Q.network.length,console:Q.console.length,actions:Q.actionTrail.length},screenshotMethod:Q.screenshotMethod},attachments:V},H=await fetch(`${J.host.replace(/\/$/,"")}/ingest/tickets`,{method:"POST",headers:{"content-type":"application/json","x-realm-key":J.realmKey},body:JSON.stringify(F)});if(!H.ok){let C=H.headers.get("retry-after"),P=await H.json().then((U)=>U.error).catch(()=>null);throw Error(H.status===429?`Too many reports — try again in ${C??"a moment"}s`:P??`Report failed (${H.status})`)}return await H.json()}var r=Math.PI/6;function T1($,j,J){let Q=j.x-$.x,z=j.y-$.y,W=Math.hypot(Q,z),V=Math.atan2(z,Q),X=[{x:j.x,y:j.y},{x:j.x-J*Math.cos(V-r),y:j.y-J*Math.sin(V-r)},{x:j.x-J*Math.cos(V+r),y:j.y-J*Math.sin(V+r)}],F=J*Math.cos(r)*0.92;if(W<=F)return{shaft:null,head:X};return{shaft:{from:$,to:{x:j.x-F*Math.cos(V),y:j.y-F*Math.sin(V)}},head:X}}var U0="#f44336",Y4="rgba(250, 204, 21, 0.4)",P0=22,A1="#2563eb",L1=9,E1=11,x1=18,h1=4,K0=8,F4=[{id:"nw",fx:0,fy:0,cursor:"nwse-resize"},{id:"n",fx:0.5,fy:0,cursor:"ns-resize"},{id:"ne",fx:1,fy:0,cursor:"nesw-resize"},{id:"e",fx:1,fy:0.5,cursor:"ew-resize"},{id:"se",fx:1,fy:1,cursor:"nwse-resize"},{id:"s",fx:0.5,fy:1,cursor:"ns-resize"},{id:"sw",fx:0,fy:1,cursor:"nesw-resize"},{id:"w",fx:0,fy:0.5,cursor:"ew-resize"}];function p1($,j,J){let Q=[],z=null,W=-1,V=null,X=null,F=$.getContext("2d");function H(){let Z=$.getBoundingClientRect().width;return Z>0?$.width/Z:1}function C(Z){let K=$.getBoundingClientRect();return{x:(Z.clientX-K.left)/K.width*$.width,y:(Z.clientY-K.top)/K.height*$.height}}function P(Z){let K=Z.size??P0;if(!F)return(Z.text?.length??0)*K*0.6;F.save(),F.font=`600 ${K}px system-ui, sans-serif`;let w=F.measureText(Z.text??"").width;return F.restore(),w}function U(Z){if(Z.tool==="text"){let K=Z.size??P0;return{left:Z.x1,top:Z.y1,right:Z.x1+P(Z),bottom:Z.y1+K*1.25}}return{left:Math.min(Z.x1,Z.x2),top:Math.min(Z.y1,Z.y2),right:Math.max(Z.x1,Z.x2),bottom:Math.max(Z.y1,Z.y2)}}function f(Z){if(Z.tool==="arrow")return[{id:"tail",x:Z.x1,y:Z.y1,cursor:"move"},{id:"head",x:Z.x2,y:Z.y2,cursor:"move"}];let K=U(Z);if(Z.tool==="text")return[{id:"size",x:K.right,y:K.bottom,cursor:"nwse-resize"}];return F4.map((w)=>({id:w.id,x:K.left+(K.right-K.left)*w.fx,y:K.top+(K.bottom-K.top)*w.fy,cursor:w.cursor}))}function q(Z){let K=U(Z);return{x:K.right+x1*H(),y:K.top-x1*H()}}function D(Z,K,w){let{shaft:G,head:Y}=T1({x:K.x1,y:K.y1},{x:K.x2,y:K.y2},Math.max(10,16*w));if(G)Z.lineCap="butt",Z.beginPath(),Z.moveTo(G.from.x,G.from.y),Z.lineTo(G.to.x,G.to.y),Z.stroke();Z.beginPath(),Z.moveTo(Y[0].x,Y[0].y),Z.lineTo(Y[1].x,Y[1].y),Z.lineTo(Y[2].x,Y[2].y),Z.closePath(),Z.fill()}function O(Z,K,w){Z.save(),Z.lineWidth=Math.max(2,3*w),Z.strokeStyle=U0,Z.fillStyle=U0;let G=U(K);if(K.tool==="rect")Z.strokeRect(G.left,G.top,G.right-G.left,G.bottom-G.top);else if(K.tool==="arrow")D(Z,K,w);else if(K.tool==="highlight")Z.fillStyle=Y4,Z.fillRect(G.left,G.top,G.right-G.left,G.bottom-G.top);else if(K.tool==="text"&&K.text){let Y=K.size??P0;Z.font=`600 ${Y}px system-ui, sans-serif`,Z.textBaseline="top";let M=Y*0.22;Z.fillStyle="rgba(255,255,255,0.92)",Z.fillRect(G.left-M,G.top-M,G.right-G.left+M*2,G.bottom-G.top+M*2),Z.fillStyle=U0,Z.fillText(K.text,G.left,G.top)}Z.restore()}function s(Z,K,w){let G=U(K);Z.save(),Z.strokeStyle=A1,Z.lineWidth=Math.max(1,1.5*w),Z.setLineDash([6*w,4*w]),Z.strokeRect(G.left,G.top,G.right-G.left,G.bottom-G.top),Z.setLineDash([]);let Y=L1*w;for(let k of f(K))Z.fillStyle="#fff",Z.strokeStyle=A1,Z.lineWidth=Math.max(1,1.5*w),Z.beginPath(),Z.rect(k.x-Y/2,k.y-Y/2,Y,Y),Z.fill(),Z.stroke();let M=q(K),I=E1*w;Z.beginPath(),Z.arc(M.x,M.y,I,0,Math.PI*2),Z.fillStyle="#dc2626",Z.fill(),Z.strokeStyle="#fff",Z.lineWidth=Math.max(1.5,2*w),Z.beginPath(),Z.moveTo(M.x-I*0.4,M.y-I*0.4),Z.lineTo(M.x+I*0.4,M.y+I*0.4),Z.moveTo(M.x+I*0.4,M.y-I*0.4),Z.lineTo(M.x-I*0.4,M.y+I*0.4),Z.stroke(),Z.restore()}function N(){if(!F)return;let Z=H();if(F.clearRect(0,0,$.width,$.height),F.drawImage(j,0,0,$.width,$.height),Q.forEach((w,G)=>{if(G!==a)O(F,w,Z)}),V)O(F,V,Z);let K=Q[W];if(K&&!V)s(F,K,Z)}function B0(Z,K,w,G,Y){return Math.abs(Z-w)<=Y&&Math.abs(K-G)<=Y}function q0(Z,K){let w=Q[W];if(!w)return null;let G=L1*H()/2+3*H();for(let Y of f(w))if(B0(Z,K,Y.x,Y.y,G))return Y.id;return null}function D0(Z,K){let w=Q[W];if(!w)return!1;let G=q(w);return B0(Z,K,G.x,G.y,E1*H())}function V0(Z,K){let w=6*H();for(let G=Q.length-1;G>=0;G-=1){let Y=Q[G];if(Y.tool==="arrow"){let I=Y.x2-Y.x1,k=Y.y2-Y.y1,E=Math.hypot(I,k)||1,x=Math.max(0,Math.min(1,((Z-Y.x1)*I+(K-Y.y1)*k)/(E*E)));if(Math.hypot(Z-(Y.x1+x*I),K-(Y.y1+x*k))<=w+4*H())return G;continue}let M=U(Y);if(Z>=M.left-w&&Z<=M.right+w&&K>=M.top-w&&K<=M.bottom+w)return G}return-1}function b1(Z,K,w,G,Y){if(K==="tail"){Z.x1=w.x1+G,Z.y1=w.y1+Y;return}if(K==="head"){Z.x2=w.x2+G,Z.y2=w.y2+Y;return}if(K==="size"){let d1=(w.size??24)+Y;Z.size=Math.max(10,d1);return}let M=U(w),{left:I,top:k,right:E,bottom:x}=M;if(K.includes("w"))I=Math.min(E-K0,I+G);if(K.includes("e"))E=Math.max(I+K0,E+G);if(K.includes("n"))k=Math.min(x-K0,k+Y);if(K.includes("s"))x=Math.max(k+K0,x+Y);Z.x1=I,Z.y1=k,Z.x2=E,Z.y2=x}function u1(Z,K,w,G){Z.x1=K.x1+w,Z.y1=K.y1+G,Z.x2=K.x2+w,Z.y2=K.y2+G}let _=null,a=-1,T={x:0,y:0,size:24};function i1(){let Z=$.getBoundingClientRect().width;return Z>0?Z/$.width:1}function o1(Z,K){if(!F)return Z.length*K*0.6;F.save(),F.font=`600 ${K}px system-ui, sans-serif`;let w=F.measureText(Z||" ").width;return F.restore(),w}function f0(){if(!_)return;let Z=$.parentElement;if(!Z)return;let K=$.getBoundingClientRect(),w=Z.getBoundingClientRect(),G=i1(),Y=T.size*G;_.style.left=`${K.left-w.left+T.x*G}px`,_.style.top=`${K.top-w.top+T.y*G}px`,_.style.fontSize=`${Y}px`,_.style.width=`${Math.max(40,o1(_.value,Y)+Y)}px`}function y(Z){let K=_;if(!K)return;_=null;let w=K.value.trim(),G=a;if(a=-1,K.remove(),Z&&w){if(G>=0&&Q[G])Q[G].text=w,W=G;else Q.push({tool:"text",x1:T.x,y1:T.y,x2:T.x,y2:T.y,text:w,size:T.size}),W=Q.length-1;J()}else if(G>=0)W=G;$.focus(),N()}function k0(Z,K,w=-1){y(!0);let G=$.parentElement;if(!G)return;if(getComputedStyle(G).position==="static")G.style.position="relative";let Y=w>=0?Q[w]:void 0;a=w,T={x:Y?.x1??Z,y:Y?.y1??K,size:Y?.size??Math.round(24*H())};let M=document.createElement("input");M.type="text",M.className="text-edit",M.value=Y?.text??"",M.setAttribute("aria-label","ข้อความบนภาพ"),M.placeholder="ข้อความ",_=M,G.append(M),f0(),M.addEventListener("input",f0),M.addEventListener("keydown",(I)=>{if(I.stopPropagation(),I.key==="Enter")y(!0);else if(I.key==="Escape")y(!1)}),requestAnimationFrame(()=>{if(_!==M)return;M.focus(),M.select(),M.addEventListener("blur",()=>y(!0))}),N()}function S0(Z){let{x:K,y:w}=C(Z);if($.setPointerCapture(Z.pointerId),D0(K,w)){G0();return}let G=q0(K,w);if(G&&Q[W]){X={grip:G,x:K,y:w,start:{...Q[W]}};return}if(z==="text"){if(Z.preventDefault(),$.hasPointerCapture(Z.pointerId))$.releasePointerCapture(Z.pointerId);z=null,J(),k0(K,w);return}if(z){V={tool:z,x1:K,y1:w,x2:K,y2:w},W=-1;return}let Y=V0(K,w);W=Y,X=Y>=0?{grip:"body",x:K,y:w,start:{...Q[Y]}}:null,N()}function R0(Z){let{x:K,y:w}=C(Z);if(V){V.x2=K,V.y2=w,N();return}if(X){let Y=Q[W];if(!Y)return;let M=K-X.x,I=w-X.y;if(X.grip==="body")u1(Y,X.start,M,I);else b1(Y,X.grip,X.start,M,I);N();return}if(z){$.style.cursor="crosshair";return}if(D0(K,w)){$.style.cursor="pointer";return}let G=q0(K,w);if(G){let Y=Q[W]?f(Q[W]).find((M)=>M.id===G):null;$.style.cursor=Y?.cursor??"pointer";return}$.style.cursor=V0(K,w)>=0?"move":"default"}function t(){if(V){if(!(Math.abs(V.x2-V.x1)<h1&&Math.abs(V.y2-V.y1)<h1))Q.push(V),W=Q.length-1,z=null,J();V=null}if(X)X=null,J();N()}function O0(Z){let K=$.getBoundingClientRect(),w=(Z.clientX-K.left)/K.width*$.width,G=(Z.clientY-K.top)/K.height*$.height,Y=V0(w,G),M=Q[Y];if(!M||M.tool!=="text")return;Z.preventDefault(),k0(M.x1,M.y1,Y)}function _0(Z){if(W<0)return;if(Z.key==="Delete"||Z.key==="Backspace")Z.preventDefault(),G0();else if(Z.key==="Escape")W=-1,N()}function G0(){if(W<0)return;Q.splice(W,1),W=-1,J(),N()}return $.addEventListener("pointerdown",S0),$.addEventListener("pointermove",R0),$.addEventListener("pointerup",t),$.addEventListener("pointercancel",t),$.addEventListener("dblclick",O0),$.tabIndex=0,$.addEventListener("keydown",_0),N(),{setTool(Z){z=Z,W=-1,$.style.cursor=Z?"crosshair":"default",N()},deleteSelected:G0,clear(){Q.length=0,W=-1,J(),N()},hasShapes:()=>Q.length>0,hasSelection:()=>W>=0,toDataUrl(){let Z=document.createElement("canvas");Z.width=j.naturalWidth,Z.height=j.naturalHeight;let K=Z.getContext("2d");if(!K)return $.toDataURL("image/png");K.drawImage(j,0,0);let w=H();for(let G of Q)O(K,G,w);return Z.toDataURL("image/png")},destroy(){y(!1),$.removeEventListener("pointerdown",S0),$.removeEventListener("pointermove",R0),$.removeEventListener("pointerup",t),$.removeEventListener("pointercancel",t),$.removeEventListener("dblclick",O0),$.removeEventListener("keydown",_0)}}}var g1=`
|
|
33
|
+
`;let Q=document.createElement("div");return Q.className="stack",Q.setAttribute("role","status"),Q.setAttribute("aria-live","polite"),j.append(J,Q),document.body.append($),I0=Q,Q}function l($,j="success",J){let Q=n2();if(!Q)return;let z=document.createElement("div");z.className="toast",z.dataset.tone=j;let W=document.createElement("span");W.className="dot";let V=document.createElement("span");V.textContent=$;let X=document.createElement("button");X.type="button",X.className="close",X.textContent="✕",X.setAttribute("aria-label","ปิด");let F=()=>{window.clearTimeout(H),z.remove()};X.addEventListener("click",F);let H=j==="error"||J?0:window.setTimeout(F,6000);if(z.append(W,V),J){let U=document.createElement("button");U.type="button",U.className="action",U.textContent=J.label,U.addEventListener("click",()=>{F(),J.onClick()}),z.append(U)}z.append(X),Q.append(z)}function N1($,j,J){let Q=$.filter((W)=>Boolean(W.error)||W.status!=null&&W.status>=400).slice(-20).map((W)=>({method:W.method,url:W.url,status:W.status,error:W.error,at:W.startedAt})),z=j.filter((W)=>W.level==="error"||W.level==="exception"||W.level==="unhandledrejection").slice(-20).map((W)=>W.message);return{failedRequests:Q,errors:z,erroredQueries:J.slice(0,20)}}function a2(){let $={memoryUsedMb:null,memoryLimitMb:null,domContentLoadedMs:null,loadEventMs:null};if(typeof performance>"u")return $;let j=performance.memory;if(j)$.memoryUsedMb=Math.round(j.usedJSHeapSize/1024/1024),$.memoryLimitMb=Math.round(j.jsHeapSizeLimit/1024/1024);let[J]=performance.getEntriesByType("navigation");if(J)$.domContentLoadedMs=Math.round(J.domContentLoadedEventEnd),$.loadEventMs=Math.round(J.loadEventEnd);return $}function U0($,j){if(!$)return j;try{return $()}catch{return j}}function B1(){let $=f(),{pathname:j,search:J,href:Q}=window.location;return{capturedAt:new Date().toISOString(),route:{href:Q,pathname:j,search:J},module:L0(j),user:U0($.user,{}),apiHeaders:u(U0($.headers,{})),app:{name:h().name,version:h().version,environment:h().environment},client:{userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,online:navigator.onLine,viewport:{width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio},screen:{width:window.screen.width,height:window.screen.height}},performance:a2(),extra:U0($.extra,{})}}var t2=2;function q1($){let j=P1(),J=t0();return{context:B1(),reason:$.reason,note:$.note,cause:N1(j,J,$.erroredQueries),actionTrail:c0(),network:j,console:J,screenshotDataUrl:$.screenshotDataUrl,screenshotMethod:$.screenshotMethod,meta:{generatedBy:"lightwork-debug-capture",schemaVersion:t2}}}async function D1(){if(typeof navigator<"u"&&Boolean(navigator.mediaDevices?.getDisplayMedia)){let J=await e2();if(J.status==="ok")return{dataUrl:J.dataUrl,method:"display-media"};if(J.status==="cancelled")return{dataUrl:null,method:"cancelled"}}let j=await J4();if(j)return{dataUrl:j,method:"html-to-image"};return{dataUrl:null,method:"none"}}async function e2(){let $=null;try{let j={video:{frameRate:30},audio:!1,preferCurrentTab:!0,selfBrowserSurface:"include",surfaceSwitching:"exclude"};$=await navigator.mediaDevices.getDisplayMedia(j);let J=await $4($);return J?{status:"ok",dataUrl:J}:{status:"error"}}catch(j){if(j instanceof DOMException&&(j.name==="NotAllowedError"||j.name==="AbortError"))return{status:"cancelled"};return{status:"error"}}finally{$?.getTracks().forEach((j)=>j.stop())}}async function $4($){let j=document.createElement("video");j.srcObject=$,j.muted=!0,j.playsInline=!0,await new Promise((V)=>{let X=!1,F=()=>{if(X)return;X=!0,V()};j.onloadedmetadata=()=>{j.play().then(F).catch(F)},window.setTimeout(F,1500)}),await j4(j);let{videoWidth:J,videoHeight:Q}=j;if(!J||!Q)return null;let z=document.createElement("canvas");z.width=J,z.height=Q;let W=z.getContext("2d");if(!W)return null;W.drawImage(j,0,0,J,Q),j.pause(),j.srcObject=null;try{return z.toDataURL("image/png")}catch{return null}}function j4($){return new Promise((j)=>{let J=!1,Q=()=>{if(J)return;J=!0,j()},z=$;if(typeof z.requestVideoFrameCallback==="function")z.requestVideoFrameCallback(()=>Q()),window.setTimeout(Q,1000);else window.setTimeout(Q,250)})}async function J4(){let $=f().screenshotFallback;if(!$)return null;let j=await $().catch(()=>null);if(!j)return null;try{return await j(document.body,{cacheBust:!0,pixelRatio:Math.min(window.devicePixelRatio||1,2),filter:(J)=>!(J instanceof HTMLElement&&J.dataset?.debugReporter==="true")})}catch{return null}}var Q4=2000,z4=0.82,Z4=3000000;function W4($){return new Promise((j,J)=>{let Q=new Image;Q.onload=()=>j(Q),Q.onerror=()=>J(Error("could not read the screenshot")),Q.src=$})}async function f1($){try{let j=await W4($),J=Math.max(j.naturalWidth,j.naturalHeight),Q=Math.min(1,Q4/J),z=document.createElement("canvas");z.width=Math.max(1,Math.round(j.naturalWidth*Q)),z.height=Math.max(1,Math.round(j.naturalHeight*Q));let W=z.getContext("2d");if(!W)return $;W.fillStyle="#fff",W.fillRect(0,0,z.width,z.height),W.drawImage(j,0,0,z.width,z.height);let V=z4,X=z.toDataURL("image/jpeg",V);while(X.length>Z4&&V>0.4)V-=0.15,X=z.toDataURL("image/jpeg",V);return X}catch{return $}}var K4=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,V4=/^\d+$/,G4=/^[0-9a-f]{16,}$/i;function S1($){if($.reason.type==="manual")return null;let j=$.cause?.failedRequests?.[0];if(!j?.url)return null;let J;try{J=new URL(j.url,"http://x").pathname}catch{J=j.url}let Q=J.split("/").map((W)=>K4.test(W)||V4.test(W)||G4.test(W)?":id":W).join("/"),z=j.status??(j.error?"ERR":"?");return`${j.method??"REQ"} ${Q} ${z}`}var k1=2000000;function W0($){let{screenshotDataUrl:j,...J}=$;return JSON.stringify(J).length}function R1($,j=2000000){if(W0($)<=j)return $;let J=$.network.map((z)=>({...z})),Q={...$,network:J};for(let z of J){if(W0(Q)<=j)return Q;if(typeof z.responseSnippet==="string"&&z.responseSnippet.length>35)z.responseSnippet="[body dropped — report size budget]";if(typeof z.requestBody==="string"&&z.requestBody.length>35)z.requestBody="[body dropped — report size budget]"}while(Q.network.length>1&&W0(Q)>j)Q.network=Q.network.slice(1);while(Q.console.length>1&&W0(Q)>j)Q.console=Q.console.slice(1);return Q}var O1=32768;function w4($){let j="";for(let J=0;J<$.length;J+=O1)j+=String.fromCharCode(...$.subarray(J,J+O1));return btoa(j)}function X4($){return{dataUri:`data:application/json;base64,${w4(new TextEncoder().encode(JSON.stringify($)))}`,filename:"debug-bundle.json"}}async function Y4(){let $=f().identity;if(!$)return{};try{let j=await $();return j?{authorization:`Bearer ${j}`}:{}}catch{return{}}}async function _1($,j){let J=f(),Q=R1(j,k1),{context:z,note:W}=Q,V=[];if(Q.screenshotDataUrl){let U=await f1(Q.screenshotDataUrl);V.push({dataUri:U,filename:"screenshot.jpg"})}V.push(X4(Q));let X=S1(Q),F={title:$,description:W.trim()||void 0,category:z.module?.label||h().name,routeUrl:z.route.href,priority:"MEDIUM",requesterEmail:z.user.email??void 0,requesterName:z.user.fullName??void 0,customFields:{unit:z.user.unit??"",appVersion:z.app.version,environment:z.app.environment,reasonType:Q.reason.type,appName:h().name,module:z.module?.label??""},context:{...X?{signature:X}:{},capturedAt:z.capturedAt,reason:Q.reason,cause:Q.cause,actionTrail:Q.actionTrail,client:z.client,performance:z.performance,apiHeaders:z.apiHeaders,extra:z.extra,counts:{network:Q.network.length,console:Q.console.length,actions:Q.actionTrail.length},screenshotMethod:Q.screenshotMethod},attachments:V},H=await fetch(`${J.host.replace(/\/$/,"")}/ingest/tickets`,{method:"POST",headers:{"content-type":"application/json","x-realm-key":J.realmKey,...await Y4()},body:JSON.stringify(F)});if(!H.ok){let U=H.headers.get("retry-after"),P=await H.json().then((C)=>C.error).catch(()=>null);throw Error(H.status===429?`Too many reports — try again in ${U??"a moment"}s`:P??`Report failed (${H.status})`)}return await H.json()}var r=Math.PI/6;function T1($,j,J){let Q=j.x-$.x,z=j.y-$.y,W=Math.hypot(Q,z),V=Math.atan2(z,Q),X=[{x:j.x,y:j.y},{x:j.x-J*Math.cos(V-r),y:j.y-J*Math.sin(V-r)},{x:j.x-J*Math.cos(V+r),y:j.y-J*Math.sin(V+r)}],F=J*Math.cos(r)*0.92;if(W<=F)return{shaft:null,head:X};return{shaft:{from:$,to:{x:j.x-F*Math.cos(V),y:j.y-F*Math.sin(V)}},head:X}}var C0="#f44336",F4="rgba(250, 204, 21, 0.4)",P0=22,A1="#2563eb",L1=9,E1=11,x1=18,h1=4,K0=8,M4=[{id:"nw",fx:0,fy:0,cursor:"nwse-resize"},{id:"n",fx:0.5,fy:0,cursor:"ns-resize"},{id:"ne",fx:1,fy:0,cursor:"nesw-resize"},{id:"e",fx:1,fy:0.5,cursor:"ew-resize"},{id:"se",fx:1,fy:1,cursor:"nwse-resize"},{id:"s",fx:0.5,fy:1,cursor:"ns-resize"},{id:"sw",fx:0,fy:1,cursor:"nesw-resize"},{id:"w",fx:0,fy:0.5,cursor:"ew-resize"}];function p1($,j,J){let Q=[],z=null,W=-1,V=null,X=null,F=$.getContext("2d");function H(){let Z=$.getBoundingClientRect().width;return Z>0?$.width/Z:1}function U(Z){let K=$.getBoundingClientRect();return{x:(Z.clientX-K.left)/K.width*$.width,y:(Z.clientY-K.top)/K.height*$.height}}function P(Z){let K=Z.size??P0;if(!F)return(Z.text?.length??0)*K*0.6;F.save(),F.font=`600 ${K}px system-ui, sans-serif`;let w=F.measureText(Z.text??"").width;return F.restore(),w}function C(Z){if(Z.tool==="text"){let K=Z.size??P0;return{left:Z.x1,top:Z.y1,right:Z.x1+P(Z),bottom:Z.y1+K*1.25}}return{left:Math.min(Z.x1,Z.x2),top:Math.min(Z.y1,Z.y2),right:Math.max(Z.x1,Z.x2),bottom:Math.max(Z.y1,Z.y2)}}function S(Z){if(Z.tool==="arrow")return[{id:"tail",x:Z.x1,y:Z.y1,cursor:"move"},{id:"head",x:Z.x2,y:Z.y2,cursor:"move"}];let K=C(Z);if(Z.tool==="text")return[{id:"size",x:K.right,y:K.bottom,cursor:"nwse-resize"}];return M4.map((w)=>({id:w.id,x:K.left+(K.right-K.left)*w.fx,y:K.top+(K.bottom-K.top)*w.fy,cursor:w.cursor}))}function q(Z){let K=C(Z);return{x:K.right+x1*H(),y:K.top-x1*H()}}function D(Z,K,w){let{shaft:G,head:Y}=T1({x:K.x1,y:K.y1},{x:K.x2,y:K.y2},Math.max(10,16*w));if(G)Z.lineCap="butt",Z.beginPath(),Z.moveTo(G.from.x,G.from.y),Z.lineTo(G.to.x,G.to.y),Z.stroke();Z.beginPath(),Z.moveTo(Y[0].x,Y[0].y),Z.lineTo(Y[1].x,Y[1].y),Z.lineTo(Y[2].x,Y[2].y),Z.closePath(),Z.fill()}function O(Z,K,w){Z.save(),Z.lineWidth=Math.max(2,3*w),Z.strokeStyle=C0,Z.fillStyle=C0;let G=C(K);if(K.tool==="rect")Z.strokeRect(G.left,G.top,G.right-G.left,G.bottom-G.top);else if(K.tool==="arrow")D(Z,K,w);else if(K.tool==="highlight")Z.fillStyle=F4,Z.fillRect(G.left,G.top,G.right-G.left,G.bottom-G.top);else if(K.tool==="text"&&K.text){let Y=K.size??P0;Z.font=`600 ${Y}px system-ui, sans-serif`,Z.textBaseline="top";let M=Y*0.22;Z.fillStyle="rgba(255,255,255,0.92)",Z.fillRect(G.left-M,G.top-M,G.right-G.left+M*2,G.bottom-G.top+M*2),Z.fillStyle=C0,Z.fillText(K.text,G.left,G.top)}Z.restore()}function n(Z,K,w){let G=C(K);Z.save(),Z.strokeStyle=A1,Z.lineWidth=Math.max(1,1.5*w),Z.setLineDash([6*w,4*w]),Z.strokeRect(G.left,G.top,G.right-G.left,G.bottom-G.top),Z.setLineDash([]);let Y=L1*w;for(let k of S(K))Z.fillStyle="#fff",Z.strokeStyle=A1,Z.lineWidth=Math.max(1,1.5*w),Z.beginPath(),Z.rect(k.x-Y/2,k.y-Y/2,Y,Y),Z.fill(),Z.stroke();let M=q(K),I=E1*w;Z.beginPath(),Z.arc(M.x,M.y,I,0,Math.PI*2),Z.fillStyle="#dc2626",Z.fill(),Z.strokeStyle="#fff",Z.lineWidth=Math.max(1.5,2*w),Z.beginPath(),Z.moveTo(M.x-I*0.4,M.y-I*0.4),Z.lineTo(M.x+I*0.4,M.y+I*0.4),Z.moveTo(M.x+I*0.4,M.y-I*0.4),Z.lineTo(M.x-I*0.4,M.y+I*0.4),Z.stroke(),Z.restore()}function N(){if(!F)return;let Z=H();if(F.clearRect(0,0,$.width,$.height),F.drawImage(j,0,0,$.width,$.height),Q.forEach((w,G)=>{if(G!==a)O(F,w,Z)}),V)O(F,V,Z);let K=Q[W];if(K&&!V)n(F,K,Z)}function B0(Z,K,w,G,Y){return Math.abs(Z-w)<=Y&&Math.abs(K-G)<=Y}function q0(Z,K){let w=Q[W];if(!w)return null;let G=L1*H()/2+3*H();for(let Y of S(w))if(B0(Z,K,Y.x,Y.y,G))return Y.id;return null}function D0(Z,K){let w=Q[W];if(!w)return!1;let G=q(w);return B0(Z,K,G.x,G.y,E1*H())}function V0(Z,K){let w=6*H();for(let G=Q.length-1;G>=0;G-=1){let Y=Q[G];if(Y.tool==="arrow"){let I=Y.x2-Y.x1,k=Y.y2-Y.y1,E=Math.hypot(I,k)||1,x=Math.max(0,Math.min(1,((Z-Y.x1)*I+(K-Y.y1)*k)/(E*E)));if(Math.hypot(Z-(Y.x1+x*I),K-(Y.y1+x*k))<=w+4*H())return G;continue}let M=C(Y);if(Z>=M.left-w&&Z<=M.right+w&&K>=M.top-w&&K<=M.bottom+w)return G}return-1}function b1(Z,K,w,G,Y){if(K==="tail"){Z.x1=w.x1+G,Z.y1=w.y1+Y;return}if(K==="head"){Z.x2=w.x2+G,Z.y2=w.y2+Y;return}if(K==="size"){let d1=(w.size??24)+Y;Z.size=Math.max(10,d1);return}let M=C(w),{left:I,top:k,right:E,bottom:x}=M;if(K.includes("w"))I=Math.min(E-K0,I+G);if(K.includes("e"))E=Math.max(I+K0,E+G);if(K.includes("n"))k=Math.min(x-K0,k+Y);if(K.includes("s"))x=Math.max(k+K0,x+Y);Z.x1=I,Z.y1=k,Z.x2=E,Z.y2=x}function u1(Z,K,w,G){Z.x1=K.x1+w,Z.y1=K.y1+G,Z.x2=K.x2+w,Z.y2=K.y2+G}let _=null,a=-1,T={x:0,y:0,size:24};function i1(){let Z=$.getBoundingClientRect().width;return Z>0?Z/$.width:1}function o1(Z,K){if(!F)return Z.length*K*0.6;F.save(),F.font=`600 ${K}px system-ui, sans-serif`;let w=F.measureText(Z||" ").width;return F.restore(),w}function f0(){if(!_)return;let Z=$.parentElement;if(!Z)return;let K=$.getBoundingClientRect(),w=Z.getBoundingClientRect(),G=i1(),Y=T.size*G;_.style.left=`${K.left-w.left+T.x*G}px`,_.style.top=`${K.top-w.top+T.y*G}px`,_.style.fontSize=`${Y}px`,_.style.width=`${Math.max(40,o1(_.value,Y)+Y)}px`}function y(Z){let K=_;if(!K)return;_=null;let w=K.value.trim(),G=a;if(a=-1,K.remove(),Z&&w){if(G>=0&&Q[G])Q[G].text=w,W=G;else Q.push({tool:"text",x1:T.x,y1:T.y,x2:T.x,y2:T.y,text:w,size:T.size}),W=Q.length-1;J()}else if(G>=0)W=G;$.focus(),N()}function S0(Z,K,w=-1){y(!0);let G=$.parentElement;if(!G)return;if(getComputedStyle(G).position==="static")G.style.position="relative";let Y=w>=0?Q[w]:void 0;a=w,T={x:Y?.x1??Z,y:Y?.y1??K,size:Y?.size??Math.round(24*H())};let M=document.createElement("input");M.type="text",M.className="text-edit",M.value=Y?.text??"",M.setAttribute("aria-label","ข้อความบนภาพ"),M.placeholder="ข้อความ",_=M,G.append(M),f0(),M.addEventListener("input",f0),M.addEventListener("keydown",(I)=>{if(I.stopPropagation(),I.key==="Enter")y(!0);else if(I.key==="Escape")y(!1)}),requestAnimationFrame(()=>{if(_!==M)return;M.focus(),M.select(),M.addEventListener("blur",()=>y(!0))}),N()}function k0(Z){let{x:K,y:w}=U(Z);if($.setPointerCapture(Z.pointerId),D0(K,w)){G0();return}let G=q0(K,w);if(G&&Q[W]){X={grip:G,x:K,y:w,start:{...Q[W]}};return}if(z==="text"){if(Z.preventDefault(),$.hasPointerCapture(Z.pointerId))$.releasePointerCapture(Z.pointerId);z=null,J(),S0(K,w);return}if(z){V={tool:z,x1:K,y1:w,x2:K,y2:w},W=-1;return}let Y=V0(K,w);W=Y,X=Y>=0?{grip:"body",x:K,y:w,start:{...Q[Y]}}:null,N()}function R0(Z){let{x:K,y:w}=U(Z);if(V){V.x2=K,V.y2=w,N();return}if(X){let Y=Q[W];if(!Y)return;let M=K-X.x,I=w-X.y;if(X.grip==="body")u1(Y,X.start,M,I);else b1(Y,X.grip,X.start,M,I);N();return}if(z){$.style.cursor="crosshair";return}if(D0(K,w)){$.style.cursor="pointer";return}let G=q0(K,w);if(G){let Y=Q[W]?S(Q[W]).find((M)=>M.id===G):null;$.style.cursor=Y?.cursor??"pointer";return}$.style.cursor=V0(K,w)>=0?"move":"default"}function t(){if(V){if(!(Math.abs(V.x2-V.x1)<h1&&Math.abs(V.y2-V.y1)<h1))Q.push(V),W=Q.length-1,z=null,J();V=null}if(X)X=null,J();N()}function O0(Z){let K=$.getBoundingClientRect(),w=(Z.clientX-K.left)/K.width*$.width,G=(Z.clientY-K.top)/K.height*$.height,Y=V0(w,G),M=Q[Y];if(!M||M.tool!=="text")return;Z.preventDefault(),S0(M.x1,M.y1,Y)}function _0(Z){if(W<0)return;if(Z.key==="Delete"||Z.key==="Backspace")Z.preventDefault(),G0();else if(Z.key==="Escape")W=-1,N()}function G0(){if(W<0)return;Q.splice(W,1),W=-1,J(),N()}return $.addEventListener("pointerdown",k0),$.addEventListener("pointermove",R0),$.addEventListener("pointerup",t),$.addEventListener("pointercancel",t),$.addEventListener("dblclick",O0),$.tabIndex=0,$.addEventListener("keydown",_0),N(),{setTool(Z){z=Z,W=-1,$.style.cursor=Z?"crosshair":"default",N()},deleteSelected:G0,clear(){Q.length=0,W=-1,J(),N()},hasShapes:()=>Q.length>0,hasSelection:()=>W>=0,toDataUrl(){let Z=document.createElement("canvas");Z.width=j.naturalWidth,Z.height=j.naturalHeight;let K=Z.getContext("2d");if(!K)return $.toDataURL("image/png");K.drawImage(j,0,0);let w=H();for(let G of Q)O(K,G,w);return Z.toDataURL("image/png")},destroy(){y(!1),$.removeEventListener("pointerdown",k0),$.removeEventListener("pointermove",R0),$.removeEventListener("pointerup",t),$.removeEventListener("pointercancel",t),$.removeEventListener("dblclick",O0),$.removeEventListener("keydown",_0)}}}var m1=`
|
|
34
34
|
:host { all: initial; }
|
|
35
35
|
* { box-sizing: border-box; }
|
|
36
36
|
|
|
@@ -113,4 +113,4 @@ canvas { width: 100%; height: auto; display: block; border: 1px solid #e2e8f0; b
|
|
|
113
113
|
border-radius: 0 0 16px 16px;
|
|
114
114
|
}
|
|
115
115
|
.foot .grow { flex: 1; }
|
|
116
|
-
`;var
|
|
116
|
+
`;var s="lw-debug-reporter",H4=()=>[];var I4=[{tool:"rect",key:"toolRect"},{tool:"arrow",key:"toolArrow"},{tool:"highlight",key:"toolHighlight"},{tool:"text",key:"toolText"}];function U4(){return class extends HTMLElement{root;stop=null;annotator=null;bundle=null;busy=!1;constructor(){super();this.root=this.attachShadow({mode:"open"})}connectedCallback(){this.dataset.debugReporter="true",this.stop=Q1((j)=>void this.open(j))}disconnectedCallback(){this.stop?.(),this.stop=null,this.close()}async open(j){if(this.busy)return;this.busy=!0;let J=Z0(f().locale),Q=await D1();if(Q.method==="cancelled"){this.close();return}this.bundle=q1({reason:j,note:"",screenshotDataUrl:Q.dataUrl,screenshotMethod:Q.method,erroredQueries:C4()}),this.renderForm(J)}close(){this.annotator?.destroy(),this.annotator=null,this.bundle=null,this.busy=!1,this.root.replaceChildren()}shell(j){let J=document.createElement("style");J.textContent=m1;let Q=document.createElement("div");Q.className="backdrop";let z=document.createElement("div");return z.className="panel",z.setAttribute("role","dialog"),z.setAttribute("aria-modal","true"),z.setAttribute("aria-label",j.title),Q.append(z),this.root.replaceChildren(J,Q),z}renderShell(j,J){let Q=this.shell(j),z=B("div","head");z.append(B("h2","",j.title)),Q.append(z,B("p","status",J))}renderForm(j){let J=this.bundle;if(!J)return;let Q=this.shell(j),z=B("div","head"),W=g("✕","icon");W.setAttribute("aria-label",j.close),W.addEventListener("click",()=>this.close()),z.append(B("h2","",j.title),W);let V=document.createElement("input");V.type="text",V.placeholder=j.summaryPlaceholder;let X=N0(j.summaryLabel,j.summaryRequired,!0),F=document.createElement("textarea");F.placeholder=j.detailPlaceholder;let H=B("div","meta");H.innerHTML="";let{context:U}=J;for(let[D,O]of[[j.reporter,`${U.user.fullName??"—"} (${U.user.email??"—"})`],[j.page,U.route.href],[j.captured,`${J.network.length} network · ${J.console.length} console · ${J.actionTrail.length} actions`]]){let n=document.createElement("div"),N=document.createElement("b");N.textContent=`${D}: `,n.append(N,document.createTextNode(O)),H.append(n)}let P=B("p","status",""),C=g(j.submit,"primary");if(C.disabled=!0,V.addEventListener("input",()=>{C.disabled=V.value.trim().length===0}),Q.append(z,X,V,N0(j.detailLabel),F,H),J.screenshotDataUrl)Q.append(...this.screenshotSection(j,J.screenshotDataUrl));else Q.append(B("p","status",j.noScreenshot));let S=B("div","foot"),q=g(j.close);q.addEventListener("click",()=>this.close()),S.append(q,P,B("span","grow"),C),Q.append(S),C.addEventListener("click",async()=>{C.disabled=!0,P.dataset.tone="",P.textContent=j.submitting;try{let D=await _1(V.value.trim(),{...J,note:F.value,screenshotDataUrl:this.annotator?.hasShapes()?this.annotator.toDataUrl():J.screenshotDataUrl}),O=this.dispatchEvent(new CustomEvent("lw-report-submitted",{detail:D,bubbles:!0,composed:!0,cancelable:!0}));if(this.close(),O)l(`${j.submitted} — #${D.number}`,"success")}catch(D){let O=D instanceof Error?D.message:j.failed;P.dataset.tone="error",P.textContent=O,l(`${j.failed} — ${O}`,"error"),C.disabled=!1}}),V.focus()}screenshotSection(j,J){let Q=N0(j.annotateHint),z=B("div","tools"),W=document.createElement("canvas"),V=B("div","shot");V.append(W);let X=[],F=(C)=>{for(let S of X)S.setAttribute("aria-pressed",String(S===C))};for(let{tool:C,key:S}of I4){let q=g(j[S]);q.setAttribute("aria-pressed","false"),q.addEventListener("click",()=>{let D=q.getAttribute("aria-pressed")==="true";F(D?null:q),this.annotator?.setTool(D?null:C)}),X.push(q),z.append(q)}z.append(B("span","sep"));let H=g(j.deleteSelected);H.addEventListener("click",()=>this.annotator?.deleteSelected());let U=g(j.clearAll);U.addEventListener("click",()=>{this.annotator?.clear(),F(null)}),z.append(H,U);let P=new Image;return P.onload=()=>{W.width=P.naturalWidth,W.height=P.naturalHeight,this.annotator=p1(W,P,()=>{F(null),H.disabled=!this.annotator?.hasSelection()})},P.src=J,[Q,z,B("p","status",j.annotateHelp),V]}}}function C4(){try{return H4()}catch{return[]}}function B($,j="",J=""){let Q=document.createElement($);if(j)Q.className=j;if(J)Q.textContent=J;return Q}function g($,j=""){let J=document.createElement("button");if(J.type="button",J.textContent=$,j)J.className=j;return J}function N0($,j="",J=!1){let Q=document.createElement("label");if(Q.append(document.createTextNode($)),J){let z=document.createElement("span");z.className="req",z.textContent=" *",Q.append(z)}if(j){let z=document.createElement("span");z.className="hint",z.textContent=` ${j}`,Q.append(z)}return Q}function g1(){if(typeof window>"u"||customElements.get(s))return;customElements.define(s,U4())}var y1=!1;function v1($={}){if(y1||typeof window>"u")return;if(!A0()){console.error("[debug-capture] configureDebugCapture() must be called before install");return}if(y1=!0,C1(),a0(),d0(),G1(),$.ui===!1)return;let j=Z0(f().locale);if(z1((J)=>{l(J.message??j.crashed,"error",{label:j.crashAction,onClick:()=>Q0(J)})}),g1(),!document.querySelector(s))document.body.append(document.createElement(s))}var P4=document.currentScript,L=P4?.dataset??{};if(L.host&&L.realmKey)T0({host:L.host,realmKey:L.realmKey,app:{name:L.appName??document.title??"app",version:L.appVersion??"0.0.0",environment:L.environment??"production"},locale:L.locale==="en"?"en":"th"}),v1();window.lwReportProblem=Q0;})();
|
package/dist/index.d.ts
CHANGED
|
@@ -33,4 +33,5 @@ export type { Annotator, AnnotatorTool } from "./ui/annotator";
|
|
|
33
33
|
export { strings as reporterStrings } from "./ui/strings";
|
|
34
34
|
export type { Strings as ReporterStrings } from "./ui/strings";
|
|
35
35
|
export { openSupportPortal, supportPortalUrl, NoIdentityError } from "./portal";
|
|
36
|
+
export type { OpenPortalOptions } from "./portal";
|
|
36
37
|
export type * from "./types";
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var t1={maxRequests:60,maxConsoleEntries:120,maxActions:80,maxBodyChars:20000},_=null;function e1($){_=$}function f(){if(!_)throw Error("[debug-capture] configureDebugCapture() has not been called");return _}function V0(){return _!==null}function T(){let $=f().app;return{name:$.name,version:$.version??"0.0.0",environment:$.environment??$2()}}function $2(){if(typeof window>"u")return"unknown";let $=window.location.hostname;if($==="localhost"||$==="127.0.0.1"||$.endsWith(".local"))return"development";return"production"}function E($){let j=_?.capture?.[$];return typeof j==="number"?j:t1[$]}function l0($){let j=_?.module;if(!j)return null;try{return j($)??null}catch{return null}}function e(){let $=_?.redact;return{headers:$?.headers??[],queryKeys:($?.queryKeys??[]).map((j)=>j.toLowerCase()),bodyKeys:($?.bodyKeys??[]).map((j)=>j.toLowerCase())}}function r0(){return _?.capture?.overlaySelectors??[]}function n0($){if(typeof window>"u")return!1;let j;try{j=new URL($,window.location.href)}catch{return!1}if(j2(j))return!1;if(j.origin===window.location.origin)return!0;return(_?.capture?.bodyOrigins??[]).some((J)=>{try{return new URL(J).origin===j.origin}catch{return!1}})}function j2($){if(!_?.host)return!1;try{if(new URL(_.host).origin!==$.origin)return!1}catch{return!1}return $.pathname.startsWith("/ingest/")}var p="‹redacted›",J2=/^(authorization|proxy-authorization|cookie|set-cookie|x-[a-z-]*token|x-csrf[a-z-]*|x-xsrf[a-z-]*)$/i,Q2=new Set(["access_token","token","id_token","refresh_token","code","secret","client_secret","password","apikey","api_key","signature","x-amz-signature","x-amz-credential"]),z2=/(password|passwd|token|secret|authorization|refresh|client_secret|otp|pin)/i,Z2=/[\w.+-]+@[\w-]+\.[\w.-]+/g,W2=/\d(?:[\d\s-]{7,})\d/g;function g($){return $.replace(Z2,p).replace(W2,p)}function K2($){if(J2.test($))return!0;return e().headers.some((J)=>J.toLowerCase()===$.toLowerCase())}function m($){let j={};for(let[J,Q]of Object.entries($))j[J]=K2(J)?p:Q;return j}function v($){try{let j=/^https?:\/\//i.test($),J=new URL($,j?void 0:"http://local.invalid"),Q=!1;if(J.searchParams.forEach((z,W)=>{if(Q2.has(W.toLowerCase())||e().queryKeys.includes(W.toLowerCase()))J.searchParams.set(W,p),Q=!0}),!Q)return $;return j?J.toString():`${J.pathname}${J.search}`}catch{return $}}function X0($,j){if(j>6||$===null||typeof $!=="object")return $;if(Array.isArray($))return $.map((Q)=>X0(Q,j+1));let J={};for(let[Q,z]of Object.entries($)){let W=z2.test(Q)||e().bodyKeys.some((K)=>Q.toLowerCase().includes(K));J[Q]=W?p:X0(z,j+1)}return J}function y($,j){if($==null)return null;let J=$,Q=$.trim();if(Q.startsWith("{")||Q.startsWith("["))try{let z=JSON.parse(Q);J=JSON.stringify(X0(z,0))}catch{}if(J.length>j)return`${J.slice(0,j)}… [truncated ${J.length-j} chars]`;return J}var Y0=120,F0=40,u=($,j)=>$.length>j?`${$.slice(0,j)}…`:$,w0=($)=>{try{return decodeURIComponent($)}catch{return $}},b=[],s0=0,a0=!1;function l($,j,J,Q){let z=u(j,Y0),W=b[b.length-1];if($==="navigate"&&W?.kind==="click"){let Y=z.replace(/^ไปที่\s*/,"");if(W.detail.includes(`→ ${Y}`))return W.at=new Date().toISOString(),W;let w=Y.split(/[?#]/)[0]??Y,C=W.source?w0(W.source.replace(/^→\s*/,"")).split(/[?#]/)[0]:null;if(C&&(w===C||w.startsWith(C)))return W.detail=u(`${W.detail} → ${Y}`,Y0),W.source=void 0,W.at=new Date().toISOString(),W}if(W&&W.kind===$&&W.detail===z){if(W.at=new Date().toISOString(),$!=="navigate")W.count=(W.count??1)+1;return W}s0+=1;let K={id:`act_${s0}`,at:new Date().toISOString(),kind:$,detail:z,count:1,source:J,html:j0(Q)};b.push(K);while(b.length>E("maxActions"))V2(b.shift());return K}var G2=200000,r=0;function j0($){if(!$)return;if(r+$.length>G2)return;return r+=$.length,$}function V2($){if(!$)return;if(r-=($.html?.length??0)+($.afterHtml?.length??0),r<0)r=0}function H0($){return $&&$>1?` (×${$})`:""}function $0($){return $ instanceof Element&&Boolean($.closest("[data-debug-reporter]"))}var X2='button, a[href], [role="button"], [role="tab"], [role="menuitem"], [role="option"], [role="switch"], [role="checkbox"], [role="radio"], [role="link"], summary, input, select, textarea',Y2={button:"ปุ่ม",a:"ลิงก์",input:"ช่อง",textarea:"ช่อง",select:"ตัวเลือก",summary:"ส่วนขยาย"},t0={button:"ปุ่ม",tab:"แท็บ",menuitem:"เมนู",option:"ตัวเลือก",switch:"สวิตช์",checkbox:"ช่องเลือก",radio:"ตัวเลือก",link:"ลิงก์"};function F2($){let j=$.getAttribute("role");if(j&&t0[j])return t0[j];return Y2[$.tagName.toLowerCase()]??"ปุ่ม"}function w2($,j){try{let J=$,Q=0;while(J&&Q<=j){let z=z1(J);if(z&&typeof z.memoizedProps?.onClick==="function")return J;J=J.parentElement,Q+=1}}catch{}return null}function H2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("title")?.trim();if(J)return J;if($ instanceof HTMLInputElement||$ instanceof HTMLTextAreaElement||$ instanceof HTMLSelectElement)return($.getAttribute("placeholder")||$.getAttribute("name")||"").trim();if($ instanceof HTMLImageElement)return($.getAttribute("alt")||"").trim();let Q=($.textContent??"").replace(/\s+/g," ").trim();if(Q)return Q;if($ instanceof HTMLAnchorElement){let z=$.getAttribute("href");if(z?.startsWith("/"))return w0(z)}return""}function C2($){if(!($ instanceof Element))return null;let j=$.closest(X2)??w2($,4);if(!j)return null;let J=j.tagName.toLowerCase();if(J==="html"||J==="body")return null;return j}function M2($){let j=g(H2($));if(!j)return null;return`${F2($)} “${u(j,F0)}”`}var Q1=6000,U2=4000,I2=/(?:^|\s)!?(?:fixed|absolute|sticky|inset-\S+|z-\S+|top-\S+|bottom-\S+|left-\S+|right-\S+|w-screen|h-screen|min-h-screen|max-h-screen|translate-\S+|scale-\S+)(?=\s|$)/g;function P2($){$.querySelectorAll("script, style, link, iframe, object, embed, noscript, canvas, video, audio").forEach((z)=>z.remove());let j=[$,...Array.from($.querySelectorAll("*"))];for(let z of j){for(let K of Array.from(z.attributes)){let Y=K.name.toLowerCase();if(Y.startsWith("on")||Y==="srcdoc"||Y==="value"||Y.startsWith("data-"))z.removeAttribute(K.name)}if(z instanceof HTMLAnchorElement)z.setAttribute("href","#");if(z instanceof HTMLImageElement)z.removeAttribute("src");let W=z.getAttribute("class");if(W){let K=W.replace(I2," ").replace(/\s+/g," ").trim();if(K)z.setAttribute("class",K);else z.removeAttribute("class")}}let J=document.createTreeWalker($,NodeFilter.SHOW_TEXT),Q=J.nextNode();while(Q){if(Q.nodeValue)Q.nodeValue=g(Q.nodeValue);Q=J.nextNode()}}function C0($,j,J){try{let Q=$.outerHTML;if(!Q||Q.length>j)return;let z=$.cloneNode(!0);P2(z);let W=z.outerHTML;return W&&W.length<=J?W:void 0}catch{return}}var D2=($)=>C0($,Q1,U2),N2=150000,B2=40000,e0=($)=>C0($,N2,B2);function S2($){if(!($ instanceof HTMLInputElement)&&!($ instanceof HTMLTextAreaElement)&&!($ instanceof HTMLSelectElement))return null;let j=$.name||$.id||$.getAttribute("aria-label")||$.getAttribute("placeholder")||$.tagName.toLowerCase();return`ช่อง “${g(j)}”`}var $1=80;function z1($){let j=Object.keys($).find((J)=>J.startsWith("__reactFiber$")||J.startsWith("__reactInternalInstance$"));return j?$[j]:null}function q2($){if(typeof $!=="function")return null;try{let j=Function.prototype.toString.call($);return(j.match(/\.(?:push|replace)\(\s*['"`]([^'"`]+)['"`]/)??j.match(/redirect\(\s*['"`]([^'"`]+)['"`]/))?.[1]??null}catch{return null}}function j1($){if(!$)return;return`→ ${$.length>$1?`${$.slice(0,$1)}…`:$}`}function f2($){try{let j=$.closest("a[href]")?.getAttribute("href");if(j&&j.startsWith("/"))return j1(j);let J=z1($),Q=0;while(J&&Q<30){if(typeof J.memoizedProps?.onClick==="function")return j1(q2(J.memoizedProps.onClick));J=J.return,Q+=1}return}catch{return}}var R2='[role="dialog"], [role="alertdialog"], [role="menu"], [role="listbox"], [role="status"], [role="alert"]';function k2(){let $=r0();return $.length?$.join(", "):R2}function O2($){let j=$.getAttribute("role");if(j==="status"||j==="alert")return"ข้อความแจ้งเตือน";if(j==="menu")return"เมนู";if(j==="listbox")return"รายการตัวเลือก";if(j==="alertdialog")return"กล่องยืนยัน";return"กล่องโต้ตอบ"}function _2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("aria-labelledby");if(J){let W=J.split(/\s+/).map((K)=>document.getElementById(K)?.textContent?.trim()??"").filter(Boolean).join(" ");if(W)return W}let z=$.querySelector('[data-slot="dialog-title"], h1, h2, h3, [role="heading"]')?.textContent?.replace(/\s+/g," ").trim();if(z)return z;return($.textContent??"").replace(/\s+/g," ").trim()}function Z1($){let j=g(_2($)),J=O2($);return j?`เปิด ${J} “${u(j,F0)}”`:`เปิด ${J}`}var L2='[aria-busy="true"], [role="progressbar"], [data-loading="true"], .animate-pulse, .animate-spin',A2=/กำลังโหลด|กำลังค้นหา|กำลังดำเนินการ|\bloading\b/i;function T2($){if($.querySelector(L2))return!0;return A2.test($.textContent??"")}var E2=400,x2=250,h2=8000;function p2($,j){if(typeof MutationObserver>"u"){j.html=j0(e0($));return}let J=Date.now(),Q=!1,z=()=>{Q=!0,K.disconnect(),window.clearInterval(Y),window.clearTimeout(w)},W=()=>{if(Q)return;if(z(),!$.isConnected)return;j.detail=u(Z1($),Y0),j.html=j0(e0($))},K=new MutationObserver(()=>{J=Date.now()});K.observe($,{childList:!0,subtree:!0,attributes:!0,characterData:!0});let Y=window.setInterval(()=>{if(Q)return;if(!$.isConnected){z();return}if(Date.now()-J>=E2&&!T2($))W()},x2),w=window.setTimeout(W,h2)}function g2($){if($0($))return;let j=l("ui",Z1($));if(j)p2($,j)}function m2(){if(typeof MutationObserver>"u")return;let $=new WeakSet;new MutationObserver((J)=>{for(let Q of J)for(let z of Array.from(Q.addedNodes)){if(!(z instanceof Element))continue;let W=k2(),K=z.matches(W)?[z]:Array.from(z.querySelectorAll(W));for(let Y of K){if($.has(Y))continue;$.add(Y),g2(Y)}}}).observe(document.body,{childList:!0,subtree:!0})}var v2=1600,y2=2500;function J1($){return{disabled:$.hasAttribute("disabled")||$.getAttribute("aria-disabled")==="true",busy:$.getAttribute("aria-busy")==="true",text:u(($.textContent??"").replace(/\s+/g," ").trim(),F0)}}function b2($,j){if(!$.disabled&&j.disabled)return"ปุ่มถูกปิดใช้งานหลังคลิก";if(!$.busy&&j.busy)return"ปุ่มเข้าสู่สถานะกำลังโหลด";if($.text!==j.text&&j.text)return`ข้อความเปลี่ยนเป็น “${j.text}”`;return null}function u2($,j){if(typeof MutationObserver>"u")return;let J=J1($),Q=!1,z=(Y,w)=>{if(Q)return;if(Q=!0,W.disconnect(),window.clearTimeout(K),j.afterNote=Y,w)j.afterHtml=j0(C0($,Q1,y2))},W=new MutationObserver(()=>{if(!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}let Y=b2(J,J1($));if(Y)z(Y,!0)});W.observe($,{attributes:!0,attributeFilter:["disabled","aria-disabled","aria-busy","class"],childList:!0,subtree:!0,characterData:!0});let K=window.setTimeout(()=>{if(!Q&&!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}Q=!0,W.disconnect()},v2)}function W1(){if(a0||typeof window>"u")return;a0=!0,document.addEventListener("click",(Q)=>{if($0(Q.target))return;let z=C2(Q.target);if(!z)return;let W=M2(z);if(!W)return;let K=l("click",`คลิก ${W}`,f2(z),D2(z));if(K)u2(z,K)},{capture:!0,passive:!0}),document.addEventListener("change",(Q)=>{if($0(Q.target))return;let z=S2(Q.target);if(z)l("input",`แก้ไข ${z}`)},{capture:!0,passive:!0}),document.addEventListener("submit",(Q)=>{if($0(Q.target))return;l("submit","ส่งฟอร์ม")},{capture:!0,passive:!0});let $=()=>l("navigate",`ไปที่ ${w0(v(location.pathname+location.search))}`),j=history.pushState.bind(history),J=history.replaceState.bind(history);history.pushState=(...Q)=>{let z=j(...Q);return $(),z},history.replaceState=(...Q)=>{let z=J(...Q);return $(),z},window.addEventListener("popstate",$),m2()}function M0(){return b.map(($)=>({...$}))}var K1=2000,J0=[],G1=0,V1=!1;function U0($,j){G1+=1,J0.push({id:`log_${G1}`,at:new Date().toISOString(),level:$,message:j.length>K1?`${j.slice(0,K1)}…`:j});while(J0.length>E("maxConsoleEntries"))J0.shift()}function d2(){let $=new WeakSet;return(j,J)=>{if(typeof J==="object"&&J!==null){if($.has(J))return"[Circular]";$.add(J)}if(typeof J==="bigint")return J.toString();return J}}function X1($){if(typeof $==="string")return $;if($ instanceof Error)return`${$.name}: ${$.message}`;try{return JSON.stringify($,d2())??String($)}catch{return String($)}}function Y1(){if(V1||typeof window>"u")return;V1=!0;let $=["log","info","warn","error","debug"];for(let j of $){let J=console[j].bind(console);console[j]=(...Q)=>{U0(j,Q.map(X1).join(" ")),J(...Q)}}window.addEventListener("error",(j)=>{let J=j.filename?` (${j.filename}:${j.lineno}:${j.colno})`:"";U0("exception",`${j.message}${J}`)}),window.addEventListener("unhandledrejection",(j)=>{let J=j.reason instanceof Error?`${j.reason.name}: ${j.reason.message}`:X1(j.reason);U0("unhandledrejection",J)})}function I0(){return J0.map(($)=>({...$}))}var F1=new Set,w1=new Set;function H1($,j){return $.add(j),()=>$.delete(j)}function C1($,j){for(let J of[...$])J(j)}function P0($){return H1(F1,$)}function D0($={type:"manual"}){C1(F1,$)}function N0($){return H1(w1,$)}function B0($){C1(w1,$)}var i2=15000,o2=["ResizeObserver loop","Script error.","Non-Error promise rejection captured"],M1=!1,U1=0;function c2($){return o2.some((j)=>$.includes(j))}function I1($){let j=$.message??"";if(!j||c2(j))return;let J=Date.now();if(J-U1<i2)return;U1=J,B0({...$,message:j})}function P1(){if(M1||typeof window>"u")return;M1=!0,window.addEventListener("error",($)=>{if(!$.message&&!$.error)return;let j=$.error instanceof Error?$.error:null;I1({type:"runtime-error",message:$.message||(j?j.message:"Unknown error"),stack:j?.stack})}),window.addEventListener("unhandledrejection",($)=>{let j=$.reason;I1({type:"unhandledrejection",message:j instanceof Error?j.message:String(j),stack:j instanceof Error?j.stack:void 0})})}var S1=4000,l2=1e6,r2=1e7,Q0=[],D1=0,N1=!1;function q1($){Q0.push($);while(Q0.length>E("maxRequests"))Q0.shift()}function f1(){return D1+=1,`req_${D1}`}function B1($){let j={};if(!$)return j;if($ instanceof Headers)$.forEach((J,Q)=>{j[Q]=J});else if(Array.isArray($))for(let[J,Q]of $)j[J]=Q;else Object.assign(j,$);return j}function n2($){let j={};return $.forEach((J,Q)=>{j[Q]=J}),j}function s2($){if($==null)return null;if(typeof $==="string")return $;if($ instanceof URLSearchParams)return $.toString();if(typeof FormData<"u"&&$ instanceof FormData)return`[FormData: ${Array.from($.keys()).join(", ")}]`;if(typeof Blob<"u"&&$ instanceof Blob)return`[Blob ${$.size} bytes]`;if($ instanceof ArrayBuffer)return`[ArrayBuffer ${$.byteLength} bytes]`;return"[binary]"}function a2($,j){let J="",Q="GET",z={},W=null;if(typeof $==="string")J=$;else if($ instanceof URL)J=$.toString();else J=$.url,Q=$.method||Q,z=B1($.headers);if(j){if(j.method)Q=j.method;if(j.headers)z={...z,...B1(j.headers)};if(j.body!==void 0)W=s2(j.body)}return{method:Q.toUpperCase(),url:J,headers:z,body:W}}function R1($){return!n0($)}function t2($,j){if(R1(j.url)){j.responseSnippet="[body not captured for this origin]";return}let J=$.headers.get("content-type")??"",Q=Number($.headers.get("content-length")??"0"),z=Q?`, ~${Q} bytes`:"";if(!/json|text|xml|html|javascript|urlencoded/i.test(J)){j.responseSnippet=`[binary ${J||"unknown"}${z}]`;return}if(Q>l2){j.responseSnippet=`[response ${J||"text"}${z} — omitted]`;return}try{$.clone().text().then((W)=>{j.responseSnippet=y(W,E("maxBodyChars"))}).catch(()=>{})}catch{}}function k1($,j){if(/[?&]_rsc=/.test($))return!0;for(let J of Object.keys(j)){let Q=J.toLowerCase();if(Q==="rsc"||Q==="next-router-prefetch"||Q==="next-router-state-tree")return!0}return!1}function e2(){if(typeof window>"u"||typeof window.fetch!=="function")return;let $=window.fetch.bind(window);window.fetch=Object.assign(async(j,J)=>{let Q=a2(j,J);if(k1(Q.url,Q.headers))return $(j,J);let z={id:f1(),startedAt:new Date().toISOString(),method:Q.method,url:v(Q.url),requestHeaders:m(Q.headers),requestBody:y(Q.body,S1),status:null,statusText:null,durationMs:null,via:"fetch"};q1(z);let W=performance.now();try{let K=await $(j,J);return z.status=K.status,z.statusText=K.statusText,z.durationMs=Math.round(performance.now()-W),z.responseHeaders=m(n2(K.headers)),t2(K,z),K}catch(K){throw z.durationMs=Math.round(performance.now()-W),z.error=K instanceof Error?`${K.name}: ${K.message}`:String(K),K}},$)}function $4(){if(typeof window>"u"||typeof window.XMLHttpRequest!=="function")return;let $=XMLHttpRequest.prototype,j=$.open,J=$.send,Q=function(W,K){let Y=typeof K==="string"?K:K.toString();return this.__cibEntry=k1(Y,{})?void 0:{id:f1(),startedAt:"",method:(W||"GET").toUpperCase(),url:v(Y),requestHeaders:{},requestBody:null,status:null,statusText:null,durationMs:null,via:"xhr"},j.apply(this,arguments)},z=function(W){let K=this.__cibEntry;if(K){K.startedAt=new Date().toISOString(),K.requestBody=typeof W==="string"?y(W,S1):W==null?null:"[non-string body]";let Y=performance.now();q1(K),this.addEventListener("loadend",()=>{if(K.status=this.status||null,K.statusText=this.statusText||null,K.durationMs=Math.round(performance.now()-Y),R1(K.url))K.responseSnippet="[body not captured for this origin]";else if(this.responseType===""||this.responseType==="text")try{K.responseSnippet=y(this.responseText||"",E("maxBodyChars"))}catch{}else{let w=this.getResponseHeader("content-type")??this.responseType;K.responseSnippet=`[binary ${w}]`}})}return J.apply(this,arguments)};$.open=Q,$.send=z}function O1(){if(N1)return;N1=!0,e2(),$4()}function S0(){let $=Q0.map((J)=>({...J})),j=0;for(let J=$.length-1;J>=0;J-=1){let Q=$[J],z=Q?.responseSnippet;if(!Q||typeof z!=="string"||z.length===0)continue;if(j+z.length>r2)Q.responseSnippet=`[response omitted — report size budget reached (${z.length.toLocaleString()} chars)]`;else j+=z.length}return $}var j4={title:"รายงานปัญหา",summaryLabel:"หัวข้อปัญหา",summaryRequired:"(ต้องกรอกก่อนแจ้งปัญหา)",summaryPlaceholder:"สรุปปัญหาสั้น ๆ เช่น กดบันทึกร่างแล้ว error",detailLabel:"อธิบายปัญหา (ไม่บังคับ)",detailPlaceholder:"เกิดอะไรขึ้น? กำลังทำอะไรอยู่ตอนที่พบปัญหา?",annotateTitle:"วาดบนรูป",annotateHint:"ทำเครื่องหมายจุดที่มีปัญหาก่อนแนบ — วงกรอบ ชี้ลูกศร ไฮไลต์ หรือพิมพ์ข้อความ",annotateApply:"ใช้รูปนี้",cancel:"ยกเลิก",toolRect:"กรอบ",toolArrow:"ลูกศร",toolHighlight:"ไฮไลต์",toolText:"ข้อความ",deleteSelected:"ลบที่เลือก",clearAll:"ล้างทั้งหมด",annotateHelp:"เลือกเครื่องมือแล้วลากบนรูป · ไม่ได้เลือกเครื่องมือ = ย้าย/ปรับขนาดสิ่งที่วาดไว้ · กดกากบาทมุมขวาบนของรูปทรงเพื่อลบ",capturing:"กำลังเก็บภาพหน้าจอ…",noScreenshot:"ไม่มีภาพหน้าจอ — ยังส่งรายงานได้",cancelled:"ยกเลิกการเก็บภาพหน้าจอแล้ว",close:"ปิด",submit:"แจ้งปัญหา",submitting:"กำลังส่ง…",submitted:"แจ้งปัญหาสำเร็จ",crashed:"เกิดข้อผิดพลาดในระบบ",crashAction:"แจ้งปัญหา",failed:"ส่งรายงานไม่สำเร็จ",captured:"เก็บข้อมูลแล้ว",reporter:"ผู้แจ้ง",page:"หน้า"},J4={title:"Report a problem",summaryLabel:"Summary",summaryRequired:"(required)",summaryPlaceholder:"One line, e.g. saving a draft returns an error",detailLabel:"Details (optional)",detailPlaceholder:"What happened? What were you doing at the time?",annotateTitle:"Draw on the image",annotateHint:"Mark what went wrong before attaching — box it, point at it, highlight it, or type on it",annotateApply:"Use this image",cancel:"Cancel",toolRect:"Box",toolArrow:"Arrow",toolHighlight:"Highlight",toolText:"Text",deleteSelected:"Delete selected",clearAll:"Clear all",annotateHelp:"Pick a tool and drag on the image · no tool selected = move/resize what you drew · press the ✕ on a shape to delete it",capturing:"Capturing the screen…",noScreenshot:"No screenshot — you can still send the report",cancelled:"Screen capture cancelled",close:"Close",submit:"Send report",submitting:"Sending…",submitted:"Report sent",crashed:"Something went wrong",crashAction:"Report it",failed:"Could not send the report",captured:"Captured",reporter:"Reporter",page:"Page"};function n($){return $==="en"?J4:j4}var q0=null;function Q4(){if(typeof document>"u")return null;if(q0?.isConnected)return q0;let $=document.createElement("lw-debug-toasts");$.dataset.debugReporter="true";let j=$.attachShadow({mode:"open"}),J=document.createElement("style");J.textContent=`
|
|
1
|
+
var J2={maxRequests:60,maxConsoleEntries:120,maxActions:80,maxBodyChars:20000},A=null;function Q2($){A=$}function S(){if(!A)throw Error("[debug-capture] configureDebugCapture() has not been called");return A}function H0(){return A!==null}function E(){let $=S().app;return{name:$.name,version:$.version??"0.0.0",environment:$.environment??z2()}}function z2(){if(typeof window>"u")return"unknown";let $=window.location.hostname;if($==="localhost"||$==="127.0.0.1"||$.endsWith(".local"))return"development";return"production"}function x($){let j=A?.capture?.[$];return typeof j==="number"?j:J2[$]}function n0($){let j=A?.module;if(!j)return null;try{return j($)??null}catch{return null}}function Z0(){let $=A?.redact;return{headers:$?.headers??[],queryKeys:($?.queryKeys??[]).map((j)=>j.toLowerCase()),bodyKeys:($?.bodyKeys??[]).map((j)=>j.toLowerCase())}}function s0(){return A?.capture?.overlaySelectors??[]}function a0($){if(typeof window>"u")return!1;let j;try{j=new URL($,window.location.href)}catch{return!1}if(Z2(j))return!1;if(j.origin===window.location.origin)return!0;return(A?.capture?.bodyOrigins??[]).some((J)=>{try{return new URL(J).origin===j.origin}catch{return!1}})}function Z2($){if(!A?.host)return!1;try{if(new URL(A.host).origin!==$.origin)return!1}catch{return!1}return $.pathname.startsWith("/ingest/")}var u="‹redacted›",W2=/^(authorization|proxy-authorization|cookie|set-cookie|x-[a-z-]*token|x-csrf[a-z-]*|x-xsrf[a-z-]*)$/i,K2=new Set(["access_token","token","id_token","refresh_token","code","secret","client_secret","password","apikey","api_key","signature","x-amz-signature","x-amz-credential"]),V2=/(password|passwd|token|secret|authorization|refresh|client_secret|otp|pin)/i,X2=/[\w.+-]+@[\w-]+\.[\w.-]+/g,G2=/\d(?:[\d\s-]{7,})\d/g;function d($){return $.replace(X2,u).replace(G2,u)}function Y2($){if(W2.test($))return!0;return Z0().headers.some((J)=>J.toLowerCase()===$.toLowerCase())}function i($){let j={};for(let[J,Q]of Object.entries($))j[J]=Y2(J)?u:Q;return j}function c($){try{let j=/^https?:\/\//i.test($),J=new URL($,j?void 0:"http://local.invalid"),Q=!1;if(J.searchParams.forEach((z,W)=>{if(K2.has(W.toLowerCase())||Z0().queryKeys.includes(W.toLowerCase()))J.searchParams.set(W,u),Q=!0}),!Q)return $;return j?J.toString():`${J.pathname}${J.search}`}catch{return $}}function M0($,j){if(j>6||$===null||typeof $!=="object")return $;if(Array.isArray($))return $.map((Q)=>M0(Q,j+1));let J={};for(let[Q,z]of Object.entries($)){let W=V2.test(Q)||Z0().bodyKeys.some((K)=>Q.toLowerCase().includes(K));J[Q]=W?u:M0(z,j+1)}return J}function o($,j){if($==null)return null;let J=$,Q=$.trim();if(Q.startsWith("{")||Q.startsWith("["))try{let z=JSON.parse(Q);J=JSON.stringify(M0(z,0))}catch{}if(J.length>j)return`${J.slice(0,j)}… [truncated ${J.length-j} chars]`;return J}var U0=120,C0=40,r=($,j)=>$.length>j?`${$.slice(0,j)}…`:$,P0=($)=>{try{return decodeURIComponent($)}catch{return $}},l=[],t0=0,e0=!1;function $0($,j,J,Q){let z=r(j,U0),W=l[l.length-1];if($==="navigate"&&W?.kind==="click"){let G=z.replace(/^ไปที่\s*/,"");if(W.detail.includes(`→ ${G}`))return W.at=new Date().toISOString(),W;let w=G.split(/[?#]/)[0]??G,M=W.source?P0(W.source.replace(/^→\s*/,"")).split(/[?#]/)[0]:null;if(M&&(w===M||w.startsWith(M)))return W.detail=r(`${W.detail} → ${G}`,U0),W.source=void 0,W.at=new Date().toISOString(),W}if(W&&W.kind===$&&W.detail===z){if(W.at=new Date().toISOString(),$!=="navigate")W.count=(W.count??1)+1;return W}t0+=1;let K={id:`act_${t0}`,at:new Date().toISOString(),kind:$,detail:z,count:1,source:J,html:K0(Q)};l.push(K);while(l.length>x("maxActions"))w2(l.shift());return K}var F2=200000,j0=0;function K0($){if(!$)return;if(j0+$.length>F2)return;return j0+=$.length,$}function w2($){if(!$)return;if(j0-=($.html?.length??0)+($.afterHtml?.length??0),j0<0)j0=0}function I0($){return $&&$>1?` (×${$})`:""}function W0($){return $ instanceof Element&&Boolean($.closest("[data-debug-reporter]"))}var H2='button, a[href], [role="button"], [role="tab"], [role="menuitem"], [role="option"], [role="switch"], [role="checkbox"], [role="radio"], [role="link"], summary, input, select, textarea',M2={button:"ปุ่ม",a:"ลิงก์",input:"ช่อง",textarea:"ช่อง",select:"ตัวเลือก",summary:"ส่วนขยาย"},$1={button:"ปุ่ม",tab:"แท็บ",menuitem:"เมนู",option:"ตัวเลือก",switch:"สวิตช์",checkbox:"ช่องเลือก",radio:"ตัวเลือก",link:"ลิงก์"};function U2($){let j=$.getAttribute("role");if(j&&$1[j])return $1[j];return M2[$.tagName.toLowerCase()]??"ปุ่ม"}function C2($,j){try{let J=$,Q=0;while(J&&Q<=j){let z=W1(J);if(z&&typeof z.memoizedProps?.onClick==="function")return J;J=J.parentElement,Q+=1}}catch{}return null}function P2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("title")?.trim();if(J)return J;if($ instanceof HTMLInputElement||$ instanceof HTMLTextAreaElement||$ instanceof HTMLSelectElement)return($.getAttribute("placeholder")||$.getAttribute("name")||"").trim();if($ instanceof HTMLImageElement)return($.getAttribute("alt")||"").trim();let Q=($.textContent??"").replace(/\s+/g," ").trim();if(Q)return Q;if($ instanceof HTMLAnchorElement){let z=$.getAttribute("href");if(z?.startsWith("/"))return P0(z)}return""}function I2($){if(!($ instanceof Element))return null;let j=$.closest(H2)??C2($,4);if(!j)return null;let J=j.tagName.toLowerCase();if(J==="html"||J==="body")return null;return j}function D2($){let j=d(P2($));if(!j)return null;return`${U2($)} “${r(j,C0)}”`}var Z1=6000,N2=4000,B2=/(?:^|\s)!?(?:fixed|absolute|sticky|inset-\S+|z-\S+|top-\S+|bottom-\S+|left-\S+|right-\S+|w-screen|h-screen|min-h-screen|max-h-screen|translate-\S+|scale-\S+)(?=\s|$)/g;function q2($){$.querySelectorAll("script, style, link, iframe, object, embed, noscript, canvas, video, audio").forEach((z)=>z.remove());let j=[$,...Array.from($.querySelectorAll("*"))];for(let z of j){for(let K of Array.from(z.attributes)){let G=K.name.toLowerCase();if(G.startsWith("on")||G==="srcdoc"||G==="value"||G.startsWith("data-"))z.removeAttribute(K.name)}if(z instanceof HTMLAnchorElement)z.setAttribute("href","#");if(z instanceof HTMLImageElement)z.removeAttribute("src");let W=z.getAttribute("class");if(W){let K=W.replace(B2," ").replace(/\s+/g," ").trim();if(K)z.setAttribute("class",K);else z.removeAttribute("class")}}let J=document.createTreeWalker($,NodeFilter.SHOW_TEXT),Q=J.nextNode();while(Q){if(Q.nodeValue)Q.nodeValue=d(Q.nodeValue);Q=J.nextNode()}}function D0($,j,J){try{let Q=$.outerHTML;if(!Q||Q.length>j)return;let z=$.cloneNode(!0);q2(z);let W=z.outerHTML;return W&&W.length<=J?W:void 0}catch{return}}var S2=($)=>D0($,Z1,N2),R2=150000,O2=40000,j1=($)=>D0($,R2,O2);function _2($){if(!($ instanceof HTMLInputElement)&&!($ instanceof HTMLTextAreaElement)&&!($ instanceof HTMLSelectElement))return null;let j=$.name||$.id||$.getAttribute("aria-label")||$.getAttribute("placeholder")||$.tagName.toLowerCase();return`ช่อง “${d(j)}”`}var J1=80;function W1($){let j=Object.keys($).find((J)=>J.startsWith("__reactFiber$")||J.startsWith("__reactInternalInstance$"));return j?$[j]:null}function f2($){if(typeof $!=="function")return null;try{let j=Function.prototype.toString.call($);return(j.match(/\.(?:push|replace)\(\s*['"`]([^'"`]+)['"`]/)??j.match(/redirect\(\s*['"`]([^'"`]+)['"`]/))?.[1]??null}catch{return null}}function Q1($){if(!$)return;return`→ ${$.length>J1?`${$.slice(0,J1)}…`:$}`}function k2($){try{let j=$.closest("a[href]")?.getAttribute("href");if(j&&j.startsWith("/"))return Q1(j);let J=W1($),Q=0;while(J&&Q<30){if(typeof J.memoizedProps?.onClick==="function")return Q1(f2(J.memoizedProps.onClick));J=J.return,Q+=1}return}catch{return}}var L2='[role="dialog"], [role="alertdialog"], [role="menu"], [role="listbox"], [role="status"], [role="alert"]';function A2(){let $=s0();return $.length?$.join(", "):L2}function T2($){let j=$.getAttribute("role");if(j==="status"||j==="alert")return"ข้อความแจ้งเตือน";if(j==="menu")return"เมนู";if(j==="listbox")return"รายการตัวเลือก";if(j==="alertdialog")return"กล่องยืนยัน";return"กล่องโต้ตอบ"}function E2($){let j=$.getAttribute("aria-label")?.trim();if(j)return j;let J=$.getAttribute("aria-labelledby");if(J){let W=J.split(/\s+/).map((K)=>document.getElementById(K)?.textContent?.trim()??"").filter(Boolean).join(" ");if(W)return W}let z=$.querySelector('[data-slot="dialog-title"], h1, h2, h3, [role="heading"]')?.textContent?.replace(/\s+/g," ").trim();if(z)return z;return($.textContent??"").replace(/\s+/g," ").trim()}function K1($){let j=d(E2($)),J=T2($);return j?`เปิด ${J} “${r(j,C0)}”`:`เปิด ${J}`}var x2='[aria-busy="true"], [role="progressbar"], [data-loading="true"], .animate-pulse, .animate-spin',h2=/กำลังโหลด|กำลังค้นหา|กำลังดำเนินการ|\bloading\b/i;function g2($){if($.querySelector(x2))return!0;return h2.test($.textContent??"")}var p2=400,m2=250,v2=8000;function y2($,j){if(typeof MutationObserver>"u"){j.html=K0(j1($));return}let J=Date.now(),Q=!1,z=()=>{Q=!0,K.disconnect(),window.clearInterval(G),window.clearTimeout(w)},W=()=>{if(Q)return;if(z(),!$.isConnected)return;j.detail=r(K1($),U0),j.html=K0(j1($))},K=new MutationObserver(()=>{J=Date.now()});K.observe($,{childList:!0,subtree:!0,attributes:!0,characterData:!0});let G=window.setInterval(()=>{if(Q)return;if(!$.isConnected){z();return}if(Date.now()-J>=p2&&!g2($))W()},m2),w=window.setTimeout(W,v2)}function b2($){if(W0($))return;let j=$0("ui",K1($));if(j)y2($,j)}function u2(){if(typeof MutationObserver>"u")return;let $=new WeakSet;new MutationObserver((J)=>{for(let Q of J)for(let z of Array.from(Q.addedNodes)){if(!(z instanceof Element))continue;let W=A2(),K=z.matches(W)?[z]:Array.from(z.querySelectorAll(W));for(let G of K){if($.has(G))continue;$.add(G),b2(G)}}}).observe(document.body,{childList:!0,subtree:!0})}var d2=1600,i2=2500;function z1($){return{disabled:$.hasAttribute("disabled")||$.getAttribute("aria-disabled")==="true",busy:$.getAttribute("aria-busy")==="true",text:r(($.textContent??"").replace(/\s+/g," ").trim(),C0)}}function c2($,j){if(!$.disabled&&j.disabled)return"ปุ่มถูกปิดใช้งานหลังคลิก";if(!$.busy&&j.busy)return"ปุ่มเข้าสู่สถานะกำลังโหลด";if($.text!==j.text&&j.text)return`ข้อความเปลี่ยนเป็น “${j.text}”`;return null}function o2($,j){if(typeof MutationObserver>"u")return;let J=z1($),Q=!1,z=(G,w)=>{if(Q)return;if(Q=!0,W.disconnect(),window.clearTimeout(K),j.afterNote=G,w)j.afterHtml=K0(D0($,Z1,i2))},W=new MutationObserver(()=>{if(!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}let G=c2(J,z1($));if(G)z(G,!0)});W.observe($,{attributes:!0,attributeFilter:["disabled","aria-disabled","aria-busy","class"],childList:!0,subtree:!0,characterData:!0});let K=window.setTimeout(()=>{if(!Q&&!$.isConnected){z("องค์ประกอบหายไปจากหน้าจอ",!1);return}Q=!0,W.disconnect()},d2)}function V1(){if(e0||typeof window>"u")return;e0=!0,document.addEventListener("click",(Q)=>{if(W0(Q.target))return;let z=I2(Q.target);if(!z)return;let W=D2(z);if(!W)return;let K=$0("click",`คลิก ${W}`,k2(z),S2(z));if(K)o2(z,K)},{capture:!0,passive:!0}),document.addEventListener("change",(Q)=>{if(W0(Q.target))return;let z=_2(Q.target);if(z)$0("input",`แก้ไข ${z}`)},{capture:!0,passive:!0}),document.addEventListener("submit",(Q)=>{if(W0(Q.target))return;$0("submit","ส่งฟอร์ม")},{capture:!0,passive:!0});let $=()=>$0("navigate",`ไปที่ ${P0(c(location.pathname+location.search))}`),j=history.pushState.bind(history),J=history.replaceState.bind(history);history.pushState=(...Q)=>{let z=j(...Q);return $(),z},history.replaceState=(...Q)=>{let z=J(...Q);return $(),z},window.addEventListener("popstate",$),u2()}function N0(){return l.map(($)=>({...$}))}var X1=2000,V0=[],G1=0,Y1=!1;function B0($,j){G1+=1,V0.push({id:`log_${G1}`,at:new Date().toISOString(),level:$,message:j.length>X1?`${j.slice(0,X1)}…`:j});while(V0.length>x("maxConsoleEntries"))V0.shift()}function l2(){let $=new WeakSet;return(j,J)=>{if(typeof J==="object"&&J!==null){if($.has(J))return"[Circular]";$.add(J)}if(typeof J==="bigint")return J.toString();return J}}function F1($){if(typeof $==="string")return $;if($ instanceof Error)return`${$.name}: ${$.message}`;try{return JSON.stringify($,l2())??String($)}catch{return String($)}}function w1(){if(Y1||typeof window>"u")return;Y1=!0;let $=["log","info","warn","error","debug"];for(let j of $){let J=console[j].bind(console);console[j]=(...Q)=>{B0(j,Q.map(F1).join(" ")),J(...Q)}}window.addEventListener("error",(j)=>{let J=j.filename?` (${j.filename}:${j.lineno}:${j.colno})`:"";B0("exception",`${j.message}${J}`)}),window.addEventListener("unhandledrejection",(j)=>{let J=j.reason instanceof Error?`${j.reason.name}: ${j.reason.message}`:F1(j.reason);B0("unhandledrejection",J)})}function q0(){return V0.map(($)=>({...$}))}var H1=new Set,M1=new Set;function U1($,j){return $.add(j),()=>$.delete(j)}function C1($,j){for(let J of[...$])J(j)}function S0($){return U1(H1,$)}function R0($={type:"manual"}){C1(H1,$)}function O0($){return U1(M1,$)}function _0($){C1(M1,$)}var r2=15000,n2=["ResizeObserver loop","Script error.","Non-Error promise rejection captured"],P1=!1,I1=0;function s2($){return n2.some((j)=>$.includes(j))}function D1($){let j=$.message??"";if(!j||s2(j))return;let J=Date.now();if(J-I1<r2)return;I1=J,_0({...$,message:j})}function N1(){if(P1||typeof window>"u")return;P1=!0,window.addEventListener("error",($)=>{if(!$.message&&!$.error)return;let j=$.error instanceof Error?$.error:null;D1({type:"runtime-error",message:$.message||(j?j.message:"Unknown error"),stack:j?.stack})}),window.addEventListener("unhandledrejection",($)=>{let j=$.reason;D1({type:"unhandledrejection",message:j instanceof Error?j.message:String(j),stack:j instanceof Error?j.stack:void 0})})}var R1=4000,a2=1e6,t2=1e7,X0=[],B1=0,q1=!1;function O1($){X0.push($);while(X0.length>x("maxRequests"))X0.shift()}function _1(){return B1+=1,`req_${B1}`}function S1($){let j={};if(!$)return j;if($ instanceof Headers)$.forEach((J,Q)=>{j[Q]=J});else if(Array.isArray($))for(let[J,Q]of $)j[J]=Q;else Object.assign(j,$);return j}function e2($){let j={};return $.forEach((J,Q)=>{j[Q]=J}),j}function $4($){if($==null)return null;if(typeof $==="string")return $;if($ instanceof URLSearchParams)return $.toString();if(typeof FormData<"u"&&$ instanceof FormData)return`[FormData: ${Array.from($.keys()).join(", ")}]`;if(typeof Blob<"u"&&$ instanceof Blob)return`[Blob ${$.size} bytes]`;if($ instanceof ArrayBuffer)return`[ArrayBuffer ${$.byteLength} bytes]`;return"[binary]"}function j4($,j){let J="",Q="GET",z={},W=null;if(typeof $==="string")J=$;else if($ instanceof URL)J=$.toString();else J=$.url,Q=$.method||Q,z=S1($.headers);if(j){if(j.method)Q=j.method;if(j.headers)z={...z,...S1(j.headers)};if(j.body!==void 0)W=$4(j.body)}return{method:Q.toUpperCase(),url:J,headers:z,body:W}}function f1($){return!a0($)}function J4($,j){if(f1(j.url)){j.responseSnippet="[body not captured for this origin]";return}let J=$.headers.get("content-type")??"",Q=Number($.headers.get("content-length")??"0"),z=Q?`, ~${Q} bytes`:"";if(!/json|text|xml|html|javascript|urlencoded/i.test(J)){j.responseSnippet=`[binary ${J||"unknown"}${z}]`;return}if(Q>a2){j.responseSnippet=`[response ${J||"text"}${z} — omitted]`;return}try{$.clone().text().then((W)=>{j.responseSnippet=o(W,x("maxBodyChars"))}).catch(()=>{})}catch{}}function k1($,j){if(/[?&]_rsc=/.test($))return!0;for(let J of Object.keys(j)){let Q=J.toLowerCase();if(Q==="rsc"||Q==="next-router-prefetch"||Q==="next-router-state-tree")return!0}return!1}function Q4(){if(typeof window>"u"||typeof window.fetch!=="function")return;let $=window.fetch.bind(window);window.fetch=Object.assign(async(j,J)=>{let Q=j4(j,J);if(k1(Q.url,Q.headers))return $(j,J);let z={id:_1(),startedAt:new Date().toISOString(),method:Q.method,url:c(Q.url),requestHeaders:i(Q.headers),requestBody:o(Q.body,R1),status:null,statusText:null,durationMs:null,via:"fetch"};O1(z);let W=performance.now();try{let K=await $(j,J);return z.status=K.status,z.statusText=K.statusText,z.durationMs=Math.round(performance.now()-W),z.responseHeaders=i(e2(K.headers)),J4(K,z),K}catch(K){throw z.durationMs=Math.round(performance.now()-W),z.error=K instanceof Error?`${K.name}: ${K.message}`:String(K),K}},$)}function z4(){if(typeof window>"u"||typeof window.XMLHttpRequest!=="function")return;let $=XMLHttpRequest.prototype,j=$.open,J=$.send,Q=function(W,K){let G=typeof K==="string"?K:K.toString();return this.__cibEntry=k1(G,{})?void 0:{id:_1(),startedAt:"",method:(W||"GET").toUpperCase(),url:c(G),requestHeaders:{},requestBody:null,status:null,statusText:null,durationMs:null,via:"xhr"},j.apply(this,arguments)},z=function(W){let K=this.__cibEntry;if(K){K.startedAt=new Date().toISOString(),K.requestBody=typeof W==="string"?o(W,R1):W==null?null:"[non-string body]";let G=performance.now();O1(K),this.addEventListener("loadend",()=>{if(K.status=this.status||null,K.statusText=this.statusText||null,K.durationMs=Math.round(performance.now()-G),f1(K.url))K.responseSnippet="[body not captured for this origin]";else if(this.responseType===""||this.responseType==="text")try{K.responseSnippet=o(this.responseText||"",x("maxBodyChars"))}catch{}else{let w=this.getResponseHeader("content-type")??this.responseType;K.responseSnippet=`[binary ${w}]`}})}return J.apply(this,arguments)};$.open=Q,$.send=z}function L1(){if(q1)return;q1=!0,Q4(),z4()}function f0(){let $=X0.map((J)=>({...J})),j=0;for(let J=$.length-1;J>=0;J-=1){let Q=$[J],z=Q?.responseSnippet;if(!Q||typeof z!=="string"||z.length===0)continue;if(j+z.length>t2)Q.responseSnippet=`[response omitted — report size budget reached (${z.length.toLocaleString()} chars)]`;else j+=z.length}return $}var Z4={title:"รายงานปัญหา",summaryLabel:"หัวข้อปัญหา",summaryRequired:"(ต้องกรอกก่อนแจ้งปัญหา)",summaryPlaceholder:"สรุปปัญหาสั้น ๆ เช่น กดบันทึกร่างแล้ว error",detailLabel:"อธิบายปัญหา (ไม่บังคับ)",detailPlaceholder:"เกิดอะไรขึ้น? กำลังทำอะไรอยู่ตอนที่พบปัญหา?",annotateTitle:"วาดบนรูป",annotateHint:"ทำเครื่องหมายจุดที่มีปัญหาก่อนแนบ — วงกรอบ ชี้ลูกศร ไฮไลต์ หรือพิมพ์ข้อความ",annotateApply:"ใช้รูปนี้",cancel:"ยกเลิก",toolRect:"กรอบ",toolArrow:"ลูกศร",toolHighlight:"ไฮไลต์",toolText:"ข้อความ",deleteSelected:"ลบที่เลือก",clearAll:"ล้างทั้งหมด",annotateHelp:"เลือกเครื่องมือแล้วลากบนรูป · ไม่ได้เลือกเครื่องมือ = ย้าย/ปรับขนาดสิ่งที่วาดไว้ · กดกากบาทมุมขวาบนของรูปทรงเพื่อลบ",capturing:"กำลังเก็บภาพหน้าจอ…",noScreenshot:"ไม่มีภาพหน้าจอ — ยังส่งรายงานได้",cancelled:"ยกเลิกการเก็บภาพหน้าจอแล้ว",close:"ปิด",submit:"แจ้งปัญหา",submitting:"กำลังส่ง…",submitted:"แจ้งปัญหาสำเร็จ",crashed:"เกิดข้อผิดพลาดในระบบ",crashAction:"แจ้งปัญหา",failed:"ส่งรายงานไม่สำเร็จ",captured:"เก็บข้อมูลแล้ว",reporter:"ผู้แจ้ง",page:"หน้า",handoffTitle:"กำลังพาไปที่ระบบแจ้งปัญหา",handoffBody:"ระบบจะลงชื่อเข้าใช้ให้อัตโนมัติ เพื่อดูเรื่องที่คุณแจ้งไว้",handoffGo:"ไปเลย",handoffPreparing:"กำลังเตรียม…",handoffFailed:"เปิดรายการที่แจ้งไว้ไม่สำเร็จ"},W4={title:"Report a problem",summaryLabel:"Summary",summaryRequired:"(required)",summaryPlaceholder:"One line, e.g. saving a draft returns an error",detailLabel:"Details (optional)",detailPlaceholder:"What happened? What were you doing at the time?",annotateTitle:"Draw on the image",annotateHint:"Mark what went wrong before attaching — box it, point at it, highlight it, or type on it",annotateApply:"Use this image",cancel:"Cancel",toolRect:"Box",toolArrow:"Arrow",toolHighlight:"Highlight",toolText:"Text",deleteSelected:"Delete selected",clearAll:"Clear all",annotateHelp:"Pick a tool and drag on the image · no tool selected = move/resize what you drew · press the ✕ on a shape to delete it",capturing:"Capturing the screen…",noScreenshot:"No screenshot — you can still send the report",cancelled:"Screen capture cancelled",close:"Close",submit:"Send report",submitting:"Sending…",submitted:"Report sent",crashed:"Something went wrong",crashAction:"Report it",failed:"Could not send the report",captured:"Captured",reporter:"Reporter",page:"Page",handoffTitle:"Opening the support portal",handoffBody:"You will be signed in automatically to see what you reported",handoffGo:"Go now",handoffPreparing:"Preparing…",handoffFailed:"Could not open your reports"};function v($){return $==="en"?W4:Z4}var k0=null;function K4(){if(typeof document>"u")return null;if(k0?.isConnected)return k0;let $=document.createElement("lw-debug-toasts");$.dataset.debugReporter="true";let j=$.attachShadow({mode:"open"}),J=document.createElement("style");J.textContent=`
|
|
2
2
|
:host { all: initial; }
|
|
3
3
|
.stack {
|
|
4
4
|
position: fixed; top: 16px; right: 16px; z-index: 2147483001;
|
|
@@ -30,15 +30,15 @@ var t1={maxRequests:60,maxConsoleEntries:120,maxActions:80,maxBodyChars:20000},_
|
|
|
30
30
|
}
|
|
31
31
|
@keyframes in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
|
|
32
32
|
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }
|
|
33
|
-
`;let Q=document.createElement("div");return Q.className="stack",Q.setAttribute("role","status"),Q.setAttribute("aria-live","polite"),j.append(J,Q),document.body.append($),
|
|
33
|
+
`;let Q=document.createElement("div");return Q.className="stack",Q.setAttribute("role","status"),Q.setAttribute("aria-live","polite"),j.append(J,Q),document.body.append($),k0=Q,Q}function n($,j="success",J){let Q=K4();if(!Q)return;let z=document.createElement("div");z.className="toast",z.dataset.tone=j;let W=document.createElement("span");W.className="dot";let K=document.createElement("span");K.textContent=$;let G=document.createElement("button");G.type="button",G.className="close",G.textContent="✕",G.setAttribute("aria-label","ปิด");let w=()=>{window.clearTimeout(M),z.remove()};G.addEventListener("click",w);let M=j==="error"||J?0:window.setTimeout(w,6000);if(z.append(W,K),J){let U=document.createElement("button");U.type="button",U.className="action",U.textContent=J.label,U.addEventListener("click",()=>{w(),J.onClick()}),z.append(U)}z.append(G),Q.append(z)}function A1($,j,J){let Q=$.filter((W)=>Boolean(W.error)||W.status!=null&&W.status>=400).slice(-20).map((W)=>({method:W.method,url:W.url,status:W.status,error:W.error,at:W.startedAt})),z=j.filter((W)=>W.level==="error"||W.level==="exception"||W.level==="unhandledrejection").slice(-20).map((W)=>W.message);return{failedRequests:Q,errors:z,erroredQueries:J.slice(0,20)}}function T1($){return $.failedRequests.length+$.errors.length+$.erroredQueries.length}function V4(){let $={memoryUsedMb:null,memoryLimitMb:null,domContentLoadedMs:null,loadEventMs:null};if(typeof performance>"u")return $;let j=performance.memory;if(j)$.memoryUsedMb=Math.round(j.usedJSHeapSize/1024/1024),$.memoryLimitMb=Math.round(j.jsHeapSizeLimit/1024/1024);let[J]=performance.getEntriesByType("navigation");if(J)$.domContentLoadedMs=Math.round(J.domContentLoadedEventEnd),$.loadEventMs=Math.round(J.loadEventEnd);return $}function L0($,j){if(!$)return j;try{return $()}catch{return j}}function E1(){let $=S(),{pathname:j,search:J,href:Q}=window.location;return{capturedAt:new Date().toISOString(),route:{href:Q,pathname:j,search:J},module:n0(j),user:L0($.user,{}),apiHeaders:i(L0($.headers,{})),app:{name:E().name,version:E().version,environment:E().environment},client:{userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,online:navigator.onLine,viewport:{width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio},screen:{width:window.screen.width,height:window.screen.height}},performance:V4(),extra:L0($.extra,{})}}var X4=2,G4={manual:"ผู้ใช้แจ้งเอง","runtime-error":"ข้อผิดพลาด runtime (auto)",unhandledrejection:"Promise rejection (auto)","framework-error":"หน้าจอค้าง/พัง (auto)"};function A0($){let j=f0(),J=q0();return{context:E1(),reason:$.reason,note:$.note,cause:A1(j,J,$.erroredQueries),actionTrail:N0(),network:j,console:J,screenshotDataUrl:$.screenshotDataUrl,screenshotMethod:$.screenshotMethod,meta:{generatedBy:"lightwork-debug-capture",schemaVersion:X4}}}function x1($){return $.replace(/'/g,"'\\''")}function h1($){let j=[`curl -X ${$.method} '${$.url}'`];for(let[J,Q]of Object.entries($.requestHeaders))j.push(` -H '${J}: ${x1(Q)}'`);if($.requestBody)j.push(` --data '${x1($.requestBody)}'`);return j.join(" \\\n")}function Y4($){if($.error)return`ERR ${$.error}`;return`${$.status??"—"} ${$.statusText??""}`.trim()}function F4($){if($.length===0)return"No network activity captured.";return $.map((j)=>{let J=j.durationMs!=null?`${j.durationMs}ms`:"—",Q=`# [${Y4(j)}] ${j.method} ${j.url} (${J}, ${j.startedAt})`,z=j.responseSnippet?`
|
|
34
34
|
# response: ${j.responseSnippet}`:"";return`${Q}
|
|
35
|
-
${
|
|
35
|
+
${h1(j)}${z}`}).join(`
|
|
36
36
|
|
|
37
|
-
`)}function
|
|
38
|
-
`)}function
|
|
37
|
+
`)}function w4($){if($.length===0)return"No console output captured.";return $.map((j)=>`[${j.at}] ${j.level.toUpperCase()}: ${j.message}`).join(`
|
|
38
|
+
`)}function H4($){if($.length===0)return"No user actions captured.";let j=0;return $.map((J)=>{let Q=J.source?` (${J.source})`:"",z=`${J.detail}${I0(J.count)}${Q}`;if(J.kind==="ui")return` ↳ [${J.at}] ${z}`;j+=1;let W=`${j}. [${J.at}] ${z}`;return J.afterNote?`${W}
|
|
39
39
|
↳ ${J.afterNote}`:W}).join(`
|
|
40
|
-
`)}function
|
|
41
|
-
`)}function H4($){return $.replace(/[:.]/g,"-").replace("T","_").slice(0,19)}function C4($,j){return`debug-report_${H4($.context.capturedAt)}.${j}`}function M4($){return L1($.cause)>0}async function k0(){if(typeof navigator<"u"&&Boolean(navigator.mediaDevices?.getDisplayMedia)){let J=await U4();if(J.status==="ok")return{dataUrl:J.dataUrl,method:"display-media"};if(J.status==="cancelled")return{dataUrl:null,method:"cancelled"}}let j=await D4();if(j)return{dataUrl:j,method:"html-to-image"};return{dataUrl:null,method:"none"}}async function U4(){let $=null;try{let j={video:{frameRate:30},audio:!1,preferCurrentTab:!0,selfBrowserSurface:"include",surfaceSwitching:"exclude"};$=await navigator.mediaDevices.getDisplayMedia(j);let J=await I4($);return J?{status:"ok",dataUrl:J}:{status:"error"}}catch(j){if(j instanceof DOMException&&(j.name==="NotAllowedError"||j.name==="AbortError"))return{status:"cancelled"};return{status:"error"}}finally{$?.getTracks().forEach((j)=>j.stop())}}async function I4($){let j=document.createElement("video");j.srcObject=$,j.muted=!0,j.playsInline=!0,await new Promise((K)=>{let Y=!1,w=()=>{if(Y)return;Y=!0,K()};j.onloadedmetadata=()=>{j.play().then(w).catch(w)},window.setTimeout(w,1500)}),await P4(j);let{videoWidth:J,videoHeight:Q}=j;if(!J||!Q)return null;let z=document.createElement("canvas");z.width=J,z.height=Q;let W=z.getContext("2d");if(!W)return null;W.drawImage(j,0,0,J,Q),j.pause(),j.srcObject=null;try{return z.toDataURL("image/png")}catch{return null}}function P4($){return new Promise((j)=>{let J=!1,Q=()=>{if(J)return;J=!0,j()},z=$;if(typeof z.requestVideoFrameCallback==="function")z.requestVideoFrameCallback(()=>Q()),window.setTimeout(Q,1000);else window.setTimeout(Q,250)})}async function D4(){let $=f().screenshotFallback;if(!$)return null;let j=await $().catch(()=>null);if(!j)return null;try{return await j(document.body,{cacheBust:!0,pixelRatio:Math.min(window.devicePixelRatio||1,2),filter:(J)=>!(J instanceof HTMLElement&&J.dataset?.debugReporter==="true")})}catch{return null}}var N4=2000,B4=0.82,S4=3000000;function q4($){return new Promise((j,J)=>{let Q=new Image;Q.onload=()=>j(Q),Q.onerror=()=>J(Error("could not read the screenshot")),Q.src=$})}async function x1($){try{let j=await q4($),J=Math.max(j.naturalWidth,j.naturalHeight),Q=Math.min(1,N4/J),z=document.createElement("canvas");z.width=Math.max(1,Math.round(j.naturalWidth*Q)),z.height=Math.max(1,Math.round(j.naturalHeight*Q));let W=z.getContext("2d");if(!W)return $;W.fillStyle="#fff",W.fillRect(0,0,z.width,z.height),W.drawImage(j,0,0,z.width,z.height);let K=B4,Y=z.toDataURL("image/jpeg",K);while(Y.length>S4&&K>0.4)K-=0.15,Y=z.toDataURL("image/jpeg",K);return Y}catch{return $}}var f4=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,R4=/^\d+$/,k4=/^[0-9a-f]{16,}$/i;function O0($){if($.reason.type==="manual")return null;let j=$.cause?.failedRequests?.[0];if(!j?.url)return null;let J;try{J=new URL(j.url,"http://x").pathname}catch{J=j.url}let Q=J.split("/").map((W)=>f4.test(W)||R4.test(W)||k4.test(W)?":id":W).join("/"),z=j.status??(j.error?"ERR":"?");return`${j.method??"REQ"} ${Q} ${z}`}var _0=2000000;function z0($){let{screenshotDataUrl:j,...J}=$;return JSON.stringify(J).length}function L0($,j=2000000){if(z0($)<=j)return $;let J=$.network.map((z)=>({...z})),Q={...$,network:J};for(let z of J){if(z0(Q)<=j)return Q;if(typeof z.responseSnippet==="string"&&z.responseSnippet.length>35)z.responseSnippet="[body dropped — report size budget]";if(typeof z.requestBody==="string"&&z.requestBody.length>35)z.requestBody="[body dropped — report size budget]"}while(Q.network.length>1&&z0(Q)>j)Q.network=Q.network.slice(1);while(Q.console.length>1&&z0(Q)>j)Q.console=Q.console.slice(1);return Q}var h1=32768;function O4($){let j="";for(let J=0;J<$.length;J+=h1)j+=String.fromCharCode(...$.subarray(J,J+h1));return btoa(j)}function _4($){return{dataUri:`data:application/json;base64,${O4(new TextEncoder().encode(JSON.stringify($)))}`,filename:"debug-bundle.json"}}async function A0($,j){let J=f(),Q=L0(j,_0),{context:z,note:W}=Q,K=[];if(Q.screenshotDataUrl){let U=await x1(Q.screenshotDataUrl);K.push({dataUri:U,filename:"screenshot.jpg"})}K.push(_4(Q));let Y=O0(Q),w={title:$,description:W.trim()||void 0,category:z.module?.label||T().name,routeUrl:z.route.href,priority:"MEDIUM",requesterEmail:z.user.email??void 0,requesterName:z.user.fullName??void 0,customFields:{unit:z.user.unit??"",appVersion:z.app.version,environment:z.app.environment,reasonType:Q.reason.type,appName:T().name,module:z.module?.label??""},context:{...Y?{signature:Y}:{},capturedAt:z.capturedAt,reason:Q.reason,cause:Q.cause,actionTrail:Q.actionTrail,client:z.client,performance:z.performance,apiHeaders:z.apiHeaders,extra:z.extra,counts:{network:Q.network.length,console:Q.console.length,actions:Q.actionTrail.length},screenshotMethod:Q.screenshotMethod},attachments:K},C=await fetch(`${J.host.replace(/\/$/,"")}/ingest/tickets`,{method:"POST",headers:{"content-type":"application/json","x-realm-key":J.realmKey},body:JSON.stringify(w)});if(!C.ok){let U=C.headers.get("retry-after"),P=await C.json().then((I)=>I.error).catch(()=>null);throw Error(C.status===429?`Too many reports — try again in ${U??"a moment"}s`:P??`Report failed (${C.status})`)}return await C.json()}var s=Math.PI/6;function p1($,j,J){let Q=j.x-$.x,z=j.y-$.y,W=Math.hypot(Q,z),K=Math.atan2(z,Q),Y=[{x:j.x,y:j.y},{x:j.x-J*Math.cos(K-s),y:j.y-J*Math.sin(K-s)},{x:j.x-J*Math.cos(K+s),y:j.y-J*Math.sin(K+s)}],w=J*Math.cos(s)*0.92;if(W<=w)return{shaft:null,head:Y};return{shaft:{from:$,to:{x:j.x-w*Math.cos(K),y:j.y-w*Math.sin(K)}},head:Y}}var T0="#f44336",L4="rgba(250, 204, 21, 0.4)",E0=22,g1="#2563eb",m1=9,v1=11,y1=18,b1=4,Z0=8,A4=[{id:"nw",fx:0,fy:0,cursor:"nwse-resize"},{id:"n",fx:0.5,fy:0,cursor:"ns-resize"},{id:"ne",fx:1,fy:0,cursor:"nesw-resize"},{id:"e",fx:1,fy:0.5,cursor:"ew-resize"},{id:"se",fx:1,fy:1,cursor:"nwse-resize"},{id:"s",fx:0.5,fy:1,cursor:"ns-resize"},{id:"sw",fx:0,fy:1,cursor:"nesw-resize"},{id:"w",fx:0,fy:0.5,cursor:"ew-resize"}];function x0($,j,J){let Q=[],z=null,W=-1,K=null,Y=null,w=$.getContext("2d");function C(){let Z=$.getBoundingClientRect().width;return Z>0?$.width/Z:1}function U(Z){let G=$.getBoundingClientRect();return{x:(Z.clientX-G.left)/G.width*$.width,y:(Z.clientY-G.top)/G.height*$.height}}function P(Z){let G=Z.size??E0;if(!w)return(Z.text?.length??0)*G*0.6;w.save(),w.font=`600 ${G}px system-ui, sans-serif`;let X=w.measureText(Z.text??"").width;return w.restore(),X}function I(Z){if(Z.tool==="text"){let G=Z.size??E0;return{left:Z.x1,top:Z.y1,right:Z.x1+P(Z),bottom:Z.y1+G*1.25}}return{left:Math.min(Z.x1,Z.x2),top:Math.min(Z.y1,Z.y2),right:Math.max(Z.x1,Z.x2),bottom:Math.max(Z.y1,Z.y2)}}function B(Z){if(Z.tool==="arrow")return[{id:"tail",x:Z.x1,y:Z.y1,cursor:"move"},{id:"head",x:Z.x2,y:Z.y2,cursor:"move"}];let G=I(Z);if(Z.tool==="text")return[{id:"size",x:G.right,y:G.bottom,cursor:"nwse-resize"}];return A4.map((X)=>({id:X.id,x:G.left+(G.right-G.left)*X.fx,y:G.top+(G.bottom-G.top)*X.fy,cursor:X.cursor}))}function N(Z){let G=I(Z);return{x:G.right+y1*C(),y:G.top-y1*C()}}function S(Z,G,X){let{shaft:V,head:F}=p1({x:G.x1,y:G.y1},{x:G.x2,y:G.y2},Math.max(10,16*X));if(V)Z.lineCap="butt",Z.beginPath(),Z.moveTo(V.from.x,V.from.y),Z.lineTo(V.to.x,V.to.y),Z.stroke();Z.beginPath(),Z.moveTo(F[0].x,F[0].y),Z.lineTo(F[1].x,F[1].y),Z.lineTo(F[2].x,F[2].y),Z.closePath(),Z.fill()}function k(Z,G,X){Z.save(),Z.lineWidth=Math.max(2,3*X),Z.strokeStyle=T0,Z.fillStyle=T0;let V=I(G);if(G.tool==="rect")Z.strokeRect(V.left,V.top,V.right-V.left,V.bottom-V.top);else if(G.tool==="arrow")S(Z,G,X);else if(G.tool==="highlight")Z.fillStyle=L4,Z.fillRect(V.left,V.top,V.right-V.left,V.bottom-V.top);else if(G.tool==="text"&&G.text){let F=G.size??E0;Z.font=`600 ${F}px system-ui, sans-serif`,Z.textBaseline="top";let H=F*0.22;Z.fillStyle="rgba(255,255,255,0.92)",Z.fillRect(V.left-H,V.top-H,V.right-V.left+H*2,V.bottom-V.top+H*2),Z.fillStyle=T0,Z.fillText(G.text,V.left,V.top)}Z.restore()}function D(Z,G,X){let V=I(G);Z.save(),Z.strokeStyle=g1,Z.lineWidth=Math.max(1,1.5*X),Z.setLineDash([6*X,4*X]),Z.strokeRect(V.left,V.top,V.right-V.left,V.bottom-V.top),Z.setLineDash([]);let F=m1*X;for(let O of B(G))Z.fillStyle="#fff",Z.strokeStyle=g1,Z.lineWidth=Math.max(1,1.5*X),Z.beginPath(),Z.rect(O.x-F/2,O.y-F/2,F,F),Z.fill(),Z.stroke();let H=N(G),M=v1*X;Z.beginPath(),Z.arc(H.x,H.y,M,0,Math.PI*2),Z.fillStyle="#dc2626",Z.fill(),Z.strokeStyle="#fff",Z.lineWidth=Math.max(1.5,2*X),Z.beginPath(),Z.moveTo(H.x-M*0.4,H.y-M*0.4),Z.lineTo(H.x+M*0.4,H.y+M*0.4),Z.moveTo(H.x+M*0.4,H.y-M*0.4),Z.lineTo(H.x-M*0.4,H.y+M*0.4),Z.stroke(),Z.restore()}function q(){if(!w)return;let Z=C();if(w.clearRect(0,0,$.width,$.height),w.drawImage(j,0,0,$.width,$.height),Q.forEach((X,V)=>{if(V!==a)k(w,X,Z)}),K)k(w,K,Z);let G=Q[W];if(G&&!K)D(w,G,Z)}function m0(Z,G,X,V,F){return Math.abs(Z-X)<=F&&Math.abs(G-V)<=F}function v0(Z,G){let X=Q[W];if(!X)return null;let V=m1*C()/2+3*C();for(let F of B(X))if(m0(Z,G,F.x,F.y,V))return F.id;return null}function y0(Z,G){let X=Q[W];if(!X)return!1;let V=N(X);return m0(Z,G,V.x,V.y,v1*C())}function K0(Z,G){let X=6*C();for(let V=Q.length-1;V>=0;V-=1){let F=Q[V];if(F.tool==="arrow"){let M=F.x2-F.x1,O=F.y2-F.y1,x=Math.hypot(M,O)||1,h=Math.max(0,Math.min(1,((Z-F.x1)*M+(G-F.y1)*O)/(x*x)));if(Math.hypot(Z-(F.x1+h*M),G-(F.y1+h*O))<=X+4*C())return V;continue}let H=I(F);if(Z>=H.left-X&&Z<=H.right+X&&G>=H.top-X&&G<=H.bottom+X)return V}return-1}function l1(Z,G,X,V,F){if(G==="tail"){Z.x1=X.x1+V,Z.y1=X.y1+F;return}if(G==="head"){Z.x2=X.x2+V,Z.y2=X.y2+F;return}if(G==="size"){let a1=(X.size??24)+F;Z.size=Math.max(10,a1);return}let H=I(X),{left:M,top:O,right:x,bottom:h}=H;if(G.includes("w"))M=Math.min(x-Z0,M+V);if(G.includes("e"))x=Math.max(M+Z0,x+V);if(G.includes("n"))O=Math.min(h-Z0,O+F);if(G.includes("s"))h=Math.max(O+Z0,h+F);Z.x1=M,Z.y1=O,Z.x2=x,Z.y2=h}function r1(Z,G,X,V){Z.x1=G.x1+X,Z.y1=G.y1+V,Z.x2=G.x2+X,Z.y2=G.y2+V}let L=null,a=-1,A={x:0,y:0,size:24};function n1(){let Z=$.getBoundingClientRect().width;return Z>0?Z/$.width:1}function s1(Z,G){if(!w)return Z.length*G*0.6;w.save(),w.font=`600 ${G}px system-ui, sans-serif`;let X=w.measureText(Z||" ").width;return w.restore(),X}function b0(){if(!L)return;let Z=$.parentElement;if(!Z)return;let G=$.getBoundingClientRect(),X=Z.getBoundingClientRect(),V=n1(),F=A.size*V;L.style.left=`${G.left-X.left+A.x*V}px`,L.style.top=`${G.top-X.top+A.y*V}px`,L.style.fontSize=`${F}px`,L.style.width=`${Math.max(40,s1(L.value,F)+F)}px`}function c(Z){let G=L;if(!G)return;L=null;let X=G.value.trim(),V=a;if(a=-1,G.remove(),Z&&X){if(V>=0&&Q[V])Q[V].text=X,W=V;else Q.push({tool:"text",x1:A.x,y1:A.y,x2:A.x,y2:A.y,text:X,size:A.size}),W=Q.length-1;J()}else if(V>=0)W=V;$.focus(),q()}function u0(Z,G,X=-1){c(!0);let V=$.parentElement;if(!V)return;if(getComputedStyle(V).position==="static")V.style.position="relative";let F=X>=0?Q[X]:void 0;a=X,A={x:F?.x1??Z,y:F?.y1??G,size:F?.size??Math.round(24*C())};let H=document.createElement("input");H.type="text",H.className="text-edit",H.value=F?.text??"",H.setAttribute("aria-label","ข้อความบนภาพ"),H.placeholder="ข้อความ",L=H,V.append(H),b0(),H.addEventListener("input",b0),H.addEventListener("keydown",(M)=>{if(M.stopPropagation(),M.key==="Enter")c(!0);else if(M.key==="Escape")c(!1)}),requestAnimationFrame(()=>{if(L!==H)return;H.focus(),H.select(),H.addEventListener("blur",()=>c(!0))}),q()}function d0(Z){let{x:G,y:X}=U(Z);if($.setPointerCapture(Z.pointerId),y0(G,X)){G0();return}let V=v0(G,X);if(V&&Q[W]){Y={grip:V,x:G,y:X,start:{...Q[W]}};return}if(z==="text"){if(Z.preventDefault(),$.hasPointerCapture(Z.pointerId))$.releasePointerCapture(Z.pointerId);z=null,J(),u0(G,X);return}if(z){K={tool:z,x1:G,y1:X,x2:G,y2:X},W=-1;return}let F=K0(G,X);W=F,Y=F>=0?{grip:"body",x:G,y:X,start:{...Q[F]}}:null,q()}function i0(Z){let{x:G,y:X}=U(Z);if(K){K.x2=G,K.y2=X,q();return}if(Y){let F=Q[W];if(!F)return;let H=G-Y.x,M=X-Y.y;if(Y.grip==="body")r1(F,Y.start,H,M);else l1(F,Y.grip,Y.start,H,M);q();return}if(z){$.style.cursor="crosshair";return}if(y0(G,X)){$.style.cursor="pointer";return}let V=v0(G,X);if(V){let F=Q[W]?B(Q[W]).find((H)=>H.id===V):null;$.style.cursor=F?.cursor??"pointer";return}$.style.cursor=K0(G,X)>=0?"move":"default"}function t(){if(K){if(!(Math.abs(K.x2-K.x1)<b1&&Math.abs(K.y2-K.y1)<b1))Q.push(K),W=Q.length-1,z=null,J();K=null}if(Y)Y=null,J();q()}function o0(Z){let G=$.getBoundingClientRect(),X=(Z.clientX-G.left)/G.width*$.width,V=(Z.clientY-G.top)/G.height*$.height,F=K0(X,V),H=Q[F];if(!H||H.tool!=="text")return;Z.preventDefault(),u0(H.x1,H.y1,F)}function c0(Z){if(W<0)return;if(Z.key==="Delete"||Z.key==="Backspace")Z.preventDefault(),G0();else if(Z.key==="Escape")W=-1,q()}function G0(){if(W<0)return;Q.splice(W,1),W=-1,J(),q()}return $.addEventListener("pointerdown",d0),$.addEventListener("pointermove",i0),$.addEventListener("pointerup",t),$.addEventListener("pointercancel",t),$.addEventListener("dblclick",o0),$.tabIndex=0,$.addEventListener("keydown",c0),q(),{setTool(Z){z=Z,W=-1,$.style.cursor=Z?"crosshair":"default",q()},deleteSelected:G0,clear(){Q.length=0,W=-1,J(),q()},hasShapes:()=>Q.length>0,hasSelection:()=>W>=0,toDataUrl(){let Z=document.createElement("canvas");Z.width=j.naturalWidth,Z.height=j.naturalHeight;let G=Z.getContext("2d");if(!G)return $.toDataURL("image/png");G.drawImage(j,0,0);let X=C();for(let V of Q)k(G,V,X);return Z.toDataURL("image/png")},destroy(){c(!1),$.removeEventListener("pointerdown",d0),$.removeEventListener("pointermove",i0),$.removeEventListener("pointerup",t),$.removeEventListener("pointercancel",t),$.removeEventListener("dblclick",o0),$.removeEventListener("keydown",c0)}}}var u1=`
|
|
40
|
+
`)}function M4($){let j=[];for(let J of $.failedRequests)j.push(`✗ ${J.status??J.error??"ERR"} ${J.method} ${J.url}`);for(let J of $.errors)j.push(`⚠ ${J}`);for(let J of $.erroredQueries)j.push(`⚠ React Query error: ${J.key} — ${J.error}`);return j}function U4($){let{context:j}=$;return[`User : ${j.user.fullName??"—"} (${j.user.email??"—"})`,`Unit : ${j.user.unit??"—"}`,`Roles : ${j.user.roles?.join(", ")||"—"}`,`Route : ${j.route.href}`,`Module : ${j.module?`${j.module.label} (${j.module.key})`:"—"}`,`App : ${j.app.name} v${j.app.version} · ${j.app.environment}`,`Memory : ${j.performance.memoryUsedMb??"—"}/${j.performance.memoryLimitMb??"—"} MB`,`Client : ${j.client.userAgent}`,`Viewport : ${j.client.viewport.width}×${j.client.viewport.height} @${j.client.viewport.dpr}x`,`Reason : ${G4[$.reason.type]}${$.reason.message?` — ${$.reason.message}`:""}`,`Captured : ${$.network.length} requests · ${$.console.length} console · ${$.actionTrail.length} actions · screenshot=${$.screenshotMethod}`]}function C4($){let j=M4($.cause),J=[`## \uD83D\uDC1E ${$.context.app.name} — Debug Report`,`**Generated:** ${$.context.capturedAt}`,"",...U4($).map((Q)=>`- ${Q.replace(/\s{2,}:/,":")}`),"",`**หมายเหตุจากผู้แจ้ง:** ${$.note.trim()||"(ไม่มี)"}`];if(j.length>0)J.push("","### ⚠ สาเหตุที่น่าจะเป็น","```",...j,"```");return J.push("",`<details><summary>ขั้นตอน (${$.actionTrail.length})</summary>`,"","```",H4($.actionTrail),"```","</details>","",`<details><summary>Network (${$.network.length})</summary>`,"","```",F4($.network),"```","</details>","",`<details><summary>Console (${$.console.length})</summary>`,"","```",w4($.console),"```","</details>","","_ข้อมูลลับ (token, cookie) ถูกปกปิดอัตโนมัติ · ภาพหน้าจออยู่ในไฟล์ .zip_"),J.join(`
|
|
41
|
+
`)}function P4($){return $.replace(/[:.]/g,"-").replace("T","_").slice(0,19)}function I4($,j){return`debug-report_${P4($.context.capturedAt)}.${j}`}function D4($){return T1($.cause)>0}async function T0(){if(typeof navigator<"u"&&Boolean(navigator.mediaDevices?.getDisplayMedia)){let J=await N4();if(J.status==="ok")return{dataUrl:J.dataUrl,method:"display-media"};if(J.status==="cancelled")return{dataUrl:null,method:"cancelled"}}let j=await S4();if(j)return{dataUrl:j,method:"html-to-image"};return{dataUrl:null,method:"none"}}async function N4(){let $=null;try{let j={video:{frameRate:30},audio:!1,preferCurrentTab:!0,selfBrowserSurface:"include",surfaceSwitching:"exclude"};$=await navigator.mediaDevices.getDisplayMedia(j);let J=await B4($);return J?{status:"ok",dataUrl:J}:{status:"error"}}catch(j){if(j instanceof DOMException&&(j.name==="NotAllowedError"||j.name==="AbortError"))return{status:"cancelled"};return{status:"error"}}finally{$?.getTracks().forEach((j)=>j.stop())}}async function B4($){let j=document.createElement("video");j.srcObject=$,j.muted=!0,j.playsInline=!0,await new Promise((K)=>{let G=!1,w=()=>{if(G)return;G=!0,K()};j.onloadedmetadata=()=>{j.play().then(w).catch(w)},window.setTimeout(w,1500)}),await q4(j);let{videoWidth:J,videoHeight:Q}=j;if(!J||!Q)return null;let z=document.createElement("canvas");z.width=J,z.height=Q;let W=z.getContext("2d");if(!W)return null;W.drawImage(j,0,0,J,Q),j.pause(),j.srcObject=null;try{return z.toDataURL("image/png")}catch{return null}}function q4($){return new Promise((j)=>{let J=!1,Q=()=>{if(J)return;J=!0,j()},z=$;if(typeof z.requestVideoFrameCallback==="function")z.requestVideoFrameCallback(()=>Q()),window.setTimeout(Q,1000);else window.setTimeout(Q,250)})}async function S4(){let $=S().screenshotFallback;if(!$)return null;let j=await $().catch(()=>null);if(!j)return null;try{return await j(document.body,{cacheBust:!0,pixelRatio:Math.min(window.devicePixelRatio||1,2),filter:(J)=>!(J instanceof HTMLElement&&J.dataset?.debugReporter==="true")})}catch{return null}}var R4=2000,O4=0.82,_4=3000000;function f4($){return new Promise((j,J)=>{let Q=new Image;Q.onload=()=>j(Q),Q.onerror=()=>J(Error("could not read the screenshot")),Q.src=$})}async function g1($){try{let j=await f4($),J=Math.max(j.naturalWidth,j.naturalHeight),Q=Math.min(1,R4/J),z=document.createElement("canvas");z.width=Math.max(1,Math.round(j.naturalWidth*Q)),z.height=Math.max(1,Math.round(j.naturalHeight*Q));let W=z.getContext("2d");if(!W)return $;W.fillStyle="#fff",W.fillRect(0,0,z.width,z.height),W.drawImage(j,0,0,z.width,z.height);let K=O4,G=z.toDataURL("image/jpeg",K);while(G.length>_4&&K>0.4)K-=0.15,G=z.toDataURL("image/jpeg",K);return G}catch{return $}}var k4=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,L4=/^\d+$/,A4=/^[0-9a-f]{16,}$/i;function E0($){if($.reason.type==="manual")return null;let j=$.cause?.failedRequests?.[0];if(!j?.url)return null;let J;try{J=new URL(j.url,"http://x").pathname}catch{J=j.url}let Q=J.split("/").map((W)=>k4.test(W)||L4.test(W)||A4.test(W)?":id":W).join("/"),z=j.status??(j.error?"ERR":"?");return`${j.method??"REQ"} ${Q} ${z}`}var x0=2000000;function G0($){let{screenshotDataUrl:j,...J}=$;return JSON.stringify(J).length}function h0($,j=2000000){if(G0($)<=j)return $;let J=$.network.map((z)=>({...z})),Q={...$,network:J};for(let z of J){if(G0(Q)<=j)return Q;if(typeof z.responseSnippet==="string"&&z.responseSnippet.length>35)z.responseSnippet="[body dropped — report size budget]";if(typeof z.requestBody==="string"&&z.requestBody.length>35)z.requestBody="[body dropped — report size budget]"}while(Q.network.length>1&&G0(Q)>j)Q.network=Q.network.slice(1);while(Q.console.length>1&&G0(Q)>j)Q.console=Q.console.slice(1);return Q}var p1=32768;function T4($){let j="";for(let J=0;J<$.length;J+=p1)j+=String.fromCharCode(...$.subarray(J,J+p1));return btoa(j)}function E4($){return{dataUri:`data:application/json;base64,${T4(new TextEncoder().encode(JSON.stringify($)))}`,filename:"debug-bundle.json"}}async function x4(){let $=S().identity;if(!$)return{};try{let j=await $();return j?{authorization:`Bearer ${j}`}:{}}catch{return{}}}async function g0($,j){let J=S(),Q=h0(j,x0),{context:z,note:W}=Q,K=[];if(Q.screenshotDataUrl){let U=await g1(Q.screenshotDataUrl);K.push({dataUri:U,filename:"screenshot.jpg"})}K.push(E4(Q));let G=E0(Q),w={title:$,description:W.trim()||void 0,category:z.module?.label||E().name,routeUrl:z.route.href,priority:"MEDIUM",requesterEmail:z.user.email??void 0,requesterName:z.user.fullName??void 0,customFields:{unit:z.user.unit??"",appVersion:z.app.version,environment:z.app.environment,reasonType:Q.reason.type,appName:E().name,module:z.module?.label??""},context:{...G?{signature:G}:{},capturedAt:z.capturedAt,reason:Q.reason,cause:Q.cause,actionTrail:Q.actionTrail,client:z.client,performance:z.performance,apiHeaders:z.apiHeaders,extra:z.extra,counts:{network:Q.network.length,console:Q.console.length,actions:Q.actionTrail.length},screenshotMethod:Q.screenshotMethod},attachments:K},M=await fetch(`${J.host.replace(/\/$/,"")}/ingest/tickets`,{method:"POST",headers:{"content-type":"application/json","x-realm-key":J.realmKey,...await x4()},body:JSON.stringify(w)});if(!M.ok){let U=M.headers.get("retry-after"),D=await M.json().then((C)=>C.error).catch(()=>null);throw Error(M.status===429?`Too many reports — try again in ${U??"a moment"}s`:D??`Report failed (${M.status})`)}return await M.json()}var J0=Math.PI/6;function m1($,j,J){let Q=j.x-$.x,z=j.y-$.y,W=Math.hypot(Q,z),K=Math.atan2(z,Q),G=[{x:j.x,y:j.y},{x:j.x-J*Math.cos(K-J0),y:j.y-J*Math.sin(K-J0)},{x:j.x-J*Math.cos(K+J0),y:j.y-J*Math.sin(K+J0)}],w=J*Math.cos(J0)*0.92;if(W<=w)return{shaft:null,head:G};return{shaft:{from:$,to:{x:j.x-w*Math.cos(K),y:j.y-w*Math.sin(K)}},head:G}}var p0="#f44336",h4="rgba(250, 204, 21, 0.4)",m0=22,v1="#2563eb",y1=9,b1=11,u1=18,d1=4,Y0=8,g4=[{id:"nw",fx:0,fy:0,cursor:"nwse-resize"},{id:"n",fx:0.5,fy:0,cursor:"ns-resize"},{id:"ne",fx:1,fy:0,cursor:"nesw-resize"},{id:"e",fx:1,fy:0.5,cursor:"ew-resize"},{id:"se",fx:1,fy:1,cursor:"nwse-resize"},{id:"s",fx:0.5,fy:1,cursor:"ns-resize"},{id:"sw",fx:0,fy:1,cursor:"nesw-resize"},{id:"w",fx:0,fy:0.5,cursor:"ew-resize"}];function v0($,j,J){let Q=[],z=null,W=-1,K=null,G=null,w=$.getContext("2d");function M(){let Z=$.getBoundingClientRect().width;return Z>0?$.width/Z:1}function U(Z){let V=$.getBoundingClientRect();return{x:(Z.clientX-V.left)/V.width*$.width,y:(Z.clientY-V.top)/V.height*$.height}}function D(Z){let V=Z.size??m0;if(!w)return(Z.text?.length??0)*V*0.6;w.save(),w.font=`600 ${V}px system-ui, sans-serif`;let Y=w.measureText(Z.text??"").width;return w.restore(),Y}function C(Z){if(Z.tool==="text"){let V=Z.size??m0;return{left:Z.x1,top:Z.y1,right:Z.x1+D(Z),bottom:Z.y1+V*1.25}}return{left:Math.min(Z.x1,Z.x2),top:Math.min(Z.y1,Z.y2),right:Math.max(Z.x1,Z.x2),bottom:Math.max(Z.y1,Z.y2)}}function R(Z){if(Z.tool==="arrow")return[{id:"tail",x:Z.x1,y:Z.y1,cursor:"move"},{id:"head",x:Z.x2,y:Z.y2,cursor:"move"}];let V=C(Z);if(Z.tool==="text")return[{id:"size",x:V.right,y:V.bottom,cursor:"nwse-resize"}];return g4.map((Y)=>({id:Y.id,x:V.left+(V.right-V.left)*Y.fx,y:V.top+(V.bottom-V.top)*Y.fy,cursor:Y.cursor}))}function N(Z){let V=C(Z);return{x:V.right+u1*M(),y:V.top-u1*M()}}function q(Z,V,Y){let{shaft:X,head:F}=m1({x:V.x1,y:V.y1},{x:V.x2,y:V.y2},Math.max(10,16*Y));if(X)Z.lineCap="butt",Z.beginPath(),Z.moveTo(X.from.x,X.from.y),Z.lineTo(X.to.x,X.to.y),Z.stroke();Z.beginPath(),Z.moveTo(F[0].x,F[0].y),Z.lineTo(F[1].x,F[1].y),Z.lineTo(F[2].x,F[2].y),Z.closePath(),Z.fill()}function _(Z,V,Y){Z.save(),Z.lineWidth=Math.max(2,3*Y),Z.strokeStyle=p0,Z.fillStyle=p0;let X=C(V);if(V.tool==="rect")Z.strokeRect(X.left,X.top,X.right-X.left,X.bottom-X.top);else if(V.tool==="arrow")q(Z,V,Y);else if(V.tool==="highlight")Z.fillStyle=h4,Z.fillRect(X.left,X.top,X.right-X.left,X.bottom-X.top);else if(V.tool==="text"&&V.text){let F=V.size??m0;Z.font=`600 ${F}px system-ui, sans-serif`,Z.textBaseline="top";let H=F*0.22;Z.fillStyle="rgba(255,255,255,0.92)",Z.fillRect(X.left-H,X.top-H,X.right-X.left+H*2,X.bottom-X.top+H*2),Z.fillStyle=p0,Z.fillText(V.text,X.left,X.top)}Z.restore()}function I(Z,V,Y){let X=C(V);Z.save(),Z.strokeStyle=v1,Z.lineWidth=Math.max(1,1.5*Y),Z.setLineDash([6*Y,4*Y]),Z.strokeRect(X.left,X.top,X.right-X.left,X.bottom-X.top),Z.setLineDash([]);let F=y1*Y;for(let L of R(V))Z.fillStyle="#fff",Z.strokeStyle=v1,Z.lineWidth=Math.max(1,1.5*Y),Z.beginPath(),Z.rect(L.x-F/2,L.y-F/2,F,F),Z.fill(),Z.stroke();let H=N(V),P=b1*Y;Z.beginPath(),Z.arc(H.x,H.y,P,0,Math.PI*2),Z.fillStyle="#dc2626",Z.fill(),Z.strokeStyle="#fff",Z.lineWidth=Math.max(1.5,2*Y),Z.beginPath(),Z.moveTo(H.x-P*0.4,H.y-P*0.4),Z.lineTo(H.x+P*0.4,H.y+P*0.4),Z.moveTo(H.x+P*0.4,H.y-P*0.4),Z.lineTo(H.x-P*0.4,H.y+P*0.4),Z.stroke(),Z.restore()}function B(){if(!w)return;let Z=M();if(w.clearRect(0,0,$.width,$.height),w.drawImage(j,0,0,$.width,$.height),Q.forEach((Y,X)=>{if(X!==O)_(w,Y,Z)}),K)_(w,K,Z);let V=Q[W];if(V&&!K)I(w,V,Z)}function y(Z,V,Y,X,F){return Math.abs(Z-Y)<=F&&Math.abs(V-X)<=F}function t(Z,V){let Y=Q[W];if(!Y)return null;let X=y1*M()/2+3*M();for(let F of R(Y))if(y(Z,V,F.x,F.y,X))return F.id;return null}function b(Z,V){let Y=Q[W];if(!Y)return!1;let X=N(Y);return y(Z,V,X.x,X.y,b1*M())}function h(Z,V){let Y=6*M();for(let X=Q.length-1;X>=0;X-=1){let F=Q[X];if(F.tool==="arrow"){let P=F.x2-F.x1,L=F.y2-F.y1,p=Math.hypot(P,L)||1,m=Math.max(0,Math.min(1,((Z-F.x1)*P+(V-F.y1)*L)/(p*p)));if(Math.hypot(Z-(F.x1+m*P),V-(F.y1+m*L))<=Y+4*M())return X;continue}let H=C(F);if(Z>=H.left-Y&&Z<=H.right+Y&&V>=H.top-Y&&V<=H.bottom+Y)return X}return-1}function g(Z,V,Y,X,F){if(V==="tail"){Z.x1=Y.x1+X,Z.y1=Y.y1+F;return}if(V==="head"){Z.x2=Y.x2+X,Z.y2=Y.y2+F;return}if(V==="size"){let j2=(Y.size??24)+F;Z.size=Math.max(10,j2);return}let H=C(Y),{left:P,top:L,right:p,bottom:m}=H;if(V.includes("w"))P=Math.min(p-Y0,P+X);if(V.includes("e"))p=Math.max(P+Y0,p+X);if(V.includes("n"))L=Math.min(m-Y0,L+F);if(V.includes("s"))m=Math.max(L+Y0,m+F);Z.x1=P,Z.y1=L,Z.x2=p,Z.y2=m}function Q0(Z,V,Y,X){Z.x1=V.x1+Y,Z.y1=V.y1+X,Z.x2=V.x2+Y,Z.y2=V.y2+X}let k=null,O=-1,T={x:0,y:0,size:24};function e1(){let Z=$.getBoundingClientRect().width;return Z>0?Z/$.width:1}function $2(Z,V){if(!w)return Z.length*V*0.6;w.save(),w.font=`600 ${V}px system-ui, sans-serif`;let Y=w.measureText(Z||" ").width;return w.restore(),Y}function d0(){if(!k)return;let Z=$.parentElement;if(!Z)return;let V=$.getBoundingClientRect(),Y=Z.getBoundingClientRect(),X=e1(),F=T.size*X;k.style.left=`${V.left-Y.left+T.x*X}px`,k.style.top=`${V.top-Y.top+T.y*X}px`,k.style.fontSize=`${F}px`,k.style.width=`${Math.max(40,$2(k.value,F)+F)}px`}function e(Z){let V=k;if(!V)return;k=null;let Y=V.value.trim(),X=O;if(O=-1,V.remove(),Z&&Y){if(X>=0&&Q[X])Q[X].text=Y,W=X;else Q.push({tool:"text",x1:T.x,y1:T.y,x2:T.x,y2:T.y,text:Y,size:T.size}),W=Q.length-1;J()}else if(X>=0)W=X;$.focus(),B()}function i0(Z,V,Y=-1){e(!0);let X=$.parentElement;if(!X)return;if(getComputedStyle(X).position==="static")X.style.position="relative";let F=Y>=0?Q[Y]:void 0;O=Y,T={x:F?.x1??Z,y:F?.y1??V,size:F?.size??Math.round(24*M())};let H=document.createElement("input");H.type="text",H.className="text-edit",H.value=F?.text??"",H.setAttribute("aria-label","ข้อความบนภาพ"),H.placeholder="ข้อความ",k=H,X.append(H),d0(),H.addEventListener("input",d0),H.addEventListener("keydown",(P)=>{if(P.stopPropagation(),P.key==="Enter")e(!0);else if(P.key==="Escape")e(!1)}),requestAnimationFrame(()=>{if(k!==H)return;H.focus(),H.select(),H.addEventListener("blur",()=>e(!0))}),B()}function c0(Z){let{x:V,y:Y}=U(Z);if($.setPointerCapture(Z.pointerId),b(V,Y)){w0();return}let X=t(V,Y);if(X&&Q[W]){G={grip:X,x:V,y:Y,start:{...Q[W]}};return}if(z==="text"){if(Z.preventDefault(),$.hasPointerCapture(Z.pointerId))$.releasePointerCapture(Z.pointerId);z=null,J(),i0(V,Y);return}if(z){K={tool:z,x1:V,y1:Y,x2:V,y2:Y},W=-1;return}let F=h(V,Y);W=F,G=F>=0?{grip:"body",x:V,y:Y,start:{...Q[F]}}:null,B()}function o0(Z){let{x:V,y:Y}=U(Z);if(K){K.x2=V,K.y2=Y,B();return}if(G){let F=Q[W];if(!F)return;let H=V-G.x,P=Y-G.y;if(G.grip==="body")Q0(F,G.start,H,P);else g(F,G.grip,G.start,H,P);B();return}if(z){$.style.cursor="crosshair";return}if(b(V,Y)){$.style.cursor="pointer";return}let X=t(V,Y);if(X){let F=Q[W]?R(Q[W]).find((H)=>H.id===X):null;$.style.cursor=F?.cursor??"pointer";return}$.style.cursor=h(V,Y)>=0?"move":"default"}function z0(){if(K){if(!(Math.abs(K.x2-K.x1)<d1&&Math.abs(K.y2-K.y1)<d1))Q.push(K),W=Q.length-1,z=null,J();K=null}if(G)G=null,J();B()}function l0(Z){let V=$.getBoundingClientRect(),Y=(Z.clientX-V.left)/V.width*$.width,X=(Z.clientY-V.top)/V.height*$.height,F=h(Y,X),H=Q[F];if(!H||H.tool!=="text")return;Z.preventDefault(),i0(H.x1,H.y1,F)}function r0(Z){if(W<0)return;if(Z.key==="Delete"||Z.key==="Backspace")Z.preventDefault(),w0();else if(Z.key==="Escape")W=-1,B()}function w0(){if(W<0)return;Q.splice(W,1),W=-1,J(),B()}return $.addEventListener("pointerdown",c0),$.addEventListener("pointermove",o0),$.addEventListener("pointerup",z0),$.addEventListener("pointercancel",z0),$.addEventListener("dblclick",l0),$.tabIndex=0,$.addEventListener("keydown",r0),B(),{setTool(Z){z=Z,W=-1,$.style.cursor=Z?"crosshair":"default",B()},deleteSelected:w0,clear(){Q.length=0,W=-1,J(),B()},hasShapes:()=>Q.length>0,hasSelection:()=>W>=0,toDataUrl(){let Z=document.createElement("canvas");Z.width=j.naturalWidth,Z.height=j.naturalHeight;let V=Z.getContext("2d");if(!V)return $.toDataURL("image/png");V.drawImage(j,0,0);let Y=M();for(let X of Q)_(V,X,Y);return Z.toDataURL("image/png")},destroy(){e(!1),$.removeEventListener("pointerdown",c0),$.removeEventListener("pointermove",o0),$.removeEventListener("pointerup",z0),$.removeEventListener("pointercancel",z0),$.removeEventListener("dblclick",l0),$.removeEventListener("keydown",r0)}}}var i1=`
|
|
42
42
|
:host { all: initial; }
|
|
43
43
|
* { box-sizing: border-box; }
|
|
44
44
|
|
|
@@ -121,4 +121,85 @@ canvas { width: 100%; height: auto; display: block; border: 1px solid #e2e8f0; b
|
|
|
121
121
|
border-radius: 0 0 16px 16px;
|
|
122
122
|
}
|
|
123
123
|
.foot .grow { flex: 1; }
|
|
124
|
-
`;var
|
|
124
|
+
`;var a="lw-debug-reporter",c1=()=>[];function p4($){c1=$}var m4=[{tool:"rect",key:"toolRect"},{tool:"arrow",key:"toolArrow"},{tool:"highlight",key:"toolHighlight"},{tool:"text",key:"toolText"}];function v4(){return class extends HTMLElement{root;stop=null;annotator=null;bundle=null;busy=!1;constructor(){super();this.root=this.attachShadow({mode:"open"})}connectedCallback(){this.dataset.debugReporter="true",this.stop=S0((j)=>void this.open(j))}disconnectedCallback(){this.stop?.(),this.stop=null,this.close()}async open(j){if(this.busy)return;this.busy=!0;let J=v(S().locale),Q=await T0();if(Q.method==="cancelled"){this.close();return}this.bundle=A0({reason:j,note:"",screenshotDataUrl:Q.dataUrl,screenshotMethod:Q.method,erroredQueries:y4()}),this.renderForm(J)}close(){this.annotator?.destroy(),this.annotator=null,this.bundle=null,this.busy=!1,this.root.replaceChildren()}shell(j){let J=document.createElement("style");J.textContent=i1;let Q=document.createElement("div");Q.className="backdrop";let z=document.createElement("div");return z.className="panel",z.setAttribute("role","dialog"),z.setAttribute("aria-modal","true"),z.setAttribute("aria-label",j.title),Q.append(z),this.root.replaceChildren(J,Q),z}renderShell(j,J){let Q=this.shell(j),z=f("div","head");z.append(f("h2","",j.title)),Q.append(z,f("p","status",J))}renderForm(j){let J=this.bundle;if(!J)return;let Q=this.shell(j),z=f("div","head"),W=s("✕","icon");W.setAttribute("aria-label",j.close),W.addEventListener("click",()=>this.close()),z.append(f("h2","",j.title),W);let K=document.createElement("input");K.type="text",K.placeholder=j.summaryPlaceholder;let G=y0(j.summaryLabel,j.summaryRequired,!0),w=document.createElement("textarea");w.placeholder=j.detailPlaceholder;let M=f("div","meta");M.innerHTML="";let{context:U}=J;for(let[q,_]of[[j.reporter,`${U.user.fullName??"—"} (${U.user.email??"—"})`],[j.page,U.route.href],[j.captured,`${J.network.length} network · ${J.console.length} console · ${J.actionTrail.length} actions`]]){let I=document.createElement("div"),B=document.createElement("b");B.textContent=`${q}: `,I.append(B,document.createTextNode(_)),M.append(I)}let D=f("p","status",""),C=s(j.submit,"primary");if(C.disabled=!0,K.addEventListener("input",()=>{C.disabled=K.value.trim().length===0}),Q.append(z,G,K,y0(j.detailLabel),w,M),J.screenshotDataUrl)Q.append(...this.screenshotSection(j,J.screenshotDataUrl));else Q.append(f("p","status",j.noScreenshot));let R=f("div","foot"),N=s(j.close);N.addEventListener("click",()=>this.close()),R.append(N,D,f("span","grow"),C),Q.append(R),C.addEventListener("click",async()=>{C.disabled=!0,D.dataset.tone="",D.textContent=j.submitting;try{let q=await g0(K.value.trim(),{...J,note:w.value,screenshotDataUrl:this.annotator?.hasShapes()?this.annotator.toDataUrl():J.screenshotDataUrl}),_=this.dispatchEvent(new CustomEvent("lw-report-submitted",{detail:q,bubbles:!0,composed:!0,cancelable:!0}));if(this.close(),_)n(`${j.submitted} — #${q.number}`,"success")}catch(q){let _=q instanceof Error?q.message:j.failed;D.dataset.tone="error",D.textContent=_,n(`${j.failed} — ${_}`,"error"),C.disabled=!1}}),K.focus()}screenshotSection(j,J){let Q=y0(j.annotateHint),z=f("div","tools"),W=document.createElement("canvas"),K=f("div","shot");K.append(W);let G=[],w=(C)=>{for(let R of G)R.setAttribute("aria-pressed",String(R===C))};for(let{tool:C,key:R}of m4){let N=s(j[R]);N.setAttribute("aria-pressed","false"),N.addEventListener("click",()=>{let q=N.getAttribute("aria-pressed")==="true";w(q?null:N),this.annotator?.setTool(q?null:C)}),G.push(N),z.append(N)}z.append(f("span","sep"));let M=s(j.deleteSelected);M.addEventListener("click",()=>this.annotator?.deleteSelected());let U=s(j.clearAll);U.addEventListener("click",()=>{this.annotator?.clear(),w(null)}),z.append(M,U);let D=new Image;return D.onload=()=>{W.width=D.naturalWidth,W.height=D.naturalHeight,this.annotator=v0(W,D,()=>{w(null),M.disabled=!this.annotator?.hasSelection()})},D.src=J,[Q,z,f("p","status",j.annotateHelp),K]}}}function y4(){try{return c1()}catch{return[]}}function f($,j="",J=""){let Q=document.createElement($);if(j)Q.className=j;if(J)Q.textContent=J;return Q}function s($,j=""){let J=document.createElement("button");if(J.type="button",J.textContent=$,j)J.className=j;return J}function y0($,j="",J=!1){let Q=document.createElement("label");if(Q.append(document.createTextNode($)),J){let z=document.createElement("span");z.className="req",z.textContent=" *",Q.append(z)}if(j){let z=document.createElement("span");z.className="hint",z.textContent=` ${j}`,Q.append(z)}return Q}function b0(){if(typeof window>"u"||customElements.get(a))return;customElements.define(a,v4())}var o1=!1;function b4($={}){if(o1||typeof window>"u")return;if(!H0()){console.error("[debug-capture] configureDebugCapture() must be called before install");return}if(o1=!0,L1(),w1(),V1(),N1(),$.ui===!1)return;let j=v(S().locale);if(O0((J)=>{n(J.message??j.crashed,"error",{label:j.crashAction,onClick:()=>R0(J)})}),b0(),!document.querySelector(a))document.body.append(document.createElement(a))}var u4=new Set(["error","exception","unhandledrejection"]);function l1($){if($.error)return!0;return $.status!==null&&$.status>=400}function u0($){if(!$)return null;let j=Date.parse($);return Number.isNaN(j)?null:j}function d4($){try{let{pathname:j}=new URL($,"http://x");try{return decodeURIComponent(j)}catch{return j}}catch{return $.split(/[?#]/)[0]??$}}function i4($,j,J){let Q=(K)=>({elapsedMs:K,requests:[],failedRequests:[],consoleErrors:[],slowestMs:null});if($.length===0)return[];let z=$.map((K)=>u0(K.at)),W=(K)=>{for(let G=K+1;G<z.length;G+=1){let w=z[G];if(w!=null)return w}return Number.POSITIVE_INFINITY};return $.map((K,G)=>{let w=z[G]??null,M=(G>0?z[G-1]:null)??null,U=w!==null&&M!==null?Math.max(0,w-M):null;if(w===null)return Q(U);let D=w,C=Math.max(D,W(G)),R=(I)=>I!==null&&I>=D&&(I<C||C===Number.POSITIVE_INFINITY),N=j.filter((I)=>R(u0(I.startedAt))),q=J.filter((I)=>u4.has(I.level)&&R(u0(I.at))),_=N.map((I)=>I.durationMs).filter((I)=>typeof I==="number");return{elapsedMs:U,requests:N,failedRequests:N.filter(l1),consoleErrors:q,slowestMs:_.length>0?Math.max(..._):null}})}function c4($,j){return $.requests.length===0&&$.consoleErrors.length===0&&($.elapsedMs===null||$.elapsedMs<j)}function o4($){if($<1000)return`${Math.round($)} มิลลิวินาที`;let j=$/1000;if(j<10)return`${j.toFixed(1)} วิ`;if(j<60)return`${Math.round(j)} วิ`;let J=Math.floor(j/60),Q=Math.round(j%60);return Q===0?`${J} นาที`:`${J} นาที ${Q} วิ`}var l4="lw-portal-handoff",r1=138.23,r4=`
|
|
125
|
+
:host { all: initial; }
|
|
126
|
+
.backdrop {
|
|
127
|
+
position: fixed; inset: 0; z-index: 2147483002;
|
|
128
|
+
display: grid; place-items: center; padding: 20px;
|
|
129
|
+
background: rgba(15, 23, 42, 0.45);
|
|
130
|
+
-webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
|
|
131
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Thai", sans-serif;
|
|
132
|
+
opacity: 0; transition: opacity 180ms ease;
|
|
133
|
+
}
|
|
134
|
+
.backdrop[data-open="1"] { opacity: 1; }
|
|
135
|
+
|
|
136
|
+
.card {
|
|
137
|
+
width: min(360px, 100%); box-sizing: border-box;
|
|
138
|
+
padding: 24px 24px 18px; text-align: center;
|
|
139
|
+
background: #fff; border-radius: 16px;
|
|
140
|
+
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
|
|
141
|
+
transform: translateY(8px) scale(0.97); opacity: 0;
|
|
142
|
+
transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1), opacity 160ms ease;
|
|
143
|
+
}
|
|
144
|
+
.backdrop[data-open="1"] .card { transform: none; opacity: 1; }
|
|
145
|
+
|
|
146
|
+
.ring { display: block; margin: 0 auto 14px; width: 56px; height: 56px; }
|
|
147
|
+
.ring circle { fill: none; stroke-width: 4; stroke-linecap: round; }
|
|
148
|
+
.ring .track { stroke: #e2e8f0; }
|
|
149
|
+
.ring .bar {
|
|
150
|
+
stroke: #0ea5e9; transform: rotate(-90deg); transform-origin: 50% 50%;
|
|
151
|
+
stroke-dasharray: ${r1}; stroke-dashoffset: 0;
|
|
152
|
+
animation: deplete var(--secs, 3s) linear forwards;
|
|
153
|
+
}
|
|
154
|
+
@keyframes deplete { to { stroke-dashoffset: ${r1}; } }
|
|
155
|
+
.count {
|
|
156
|
+
position: relative; margin-top: -42px; margin-bottom: 20px;
|
|
157
|
+
font-size: 18px; font-weight: 600; color: #0f172a; font-variant-numeric: tabular-nums;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* The spinner replaces the ring once the countdown is over but the token has
|
|
161
|
+
not arrived — rare, and better than a frozen 0. */
|
|
162
|
+
.spinner { animation: spin 900ms linear infinite; }
|
|
163
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
164
|
+
|
|
165
|
+
h2 { margin: 0 0 6px; font-size: 16px; font-weight: 600; color: #0f172a; }
|
|
166
|
+
p { margin: 0; font-size: 13px; line-height: 1.6; color: #475569; }
|
|
167
|
+
.host { margin-top: 8px; font-size: 12px; color: #94a3b8; word-break: break-all; }
|
|
168
|
+
|
|
169
|
+
.actions { display: flex; gap: 8px; margin-top: 20px; }
|
|
170
|
+
button {
|
|
171
|
+
flex: 1; padding: 9px 12px; border-radius: 9px; font: inherit; font-size: 14px;
|
|
172
|
+
cursor: pointer; transition: background 120ms ease, border-color 120ms ease;
|
|
173
|
+
}
|
|
174
|
+
.go { border: none; background: #0f172a; color: #fff; font-weight: 600; }
|
|
175
|
+
.go:hover { background: #1e293b; }
|
|
176
|
+
.cancel { border: 1px solid #e2e8f0; background: #fff; color: #334155; }
|
|
177
|
+
.cancel:hover { background: #f8fafc; }
|
|
178
|
+
button:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
179
|
+
|
|
180
|
+
.error h2 { color: #b91c1c; }
|
|
181
|
+
|
|
182
|
+
@media (prefers-reduced-motion: reduce) {
|
|
183
|
+
/* Movement goes; the countdown does not — it is information, not decoration,
|
|
184
|
+
and someone who has asked for less motion still needs to know they are
|
|
185
|
+
about to be sent somewhere. */
|
|
186
|
+
.backdrop, .card { transition: opacity 120ms ease; }
|
|
187
|
+
.card { transform: none; }
|
|
188
|
+
.ring .bar { animation: none; stroke-dashoffset: 0; }
|
|
189
|
+
.spinner { animation-duration: 2s; }
|
|
190
|
+
}
|
|
191
|
+
`;function n1($){if(typeof document>"u")return $.prepare().then((I)=>I,()=>null);let j=v(S().locale),J=Math.max(1,Math.floor($.seconds??3)),Q=document.createElement(l4),z=Q.attachShadow({mode:"open"}),W=document.createElement("style");W.textContent=r4,z.append(W);let K=document.createElement("div");K.className="backdrop",K.innerHTML=`
|
|
192
|
+
<div class="card" role="dialog" aria-modal="true" aria-labelledby="lw-ho-title">
|
|
193
|
+
<svg class="ring" viewBox="0 0 52 52" aria-hidden="true">
|
|
194
|
+
<circle class="track" cx="26" cy="26" r="22"></circle>
|
|
195
|
+
<circle class="bar" cx="26" cy="26" r="22"></circle>
|
|
196
|
+
</svg>
|
|
197
|
+
<div class="count" aria-hidden="true"></div>
|
|
198
|
+
<h2 id="lw-ho-title"></h2>
|
|
199
|
+
<p class="body"></p>
|
|
200
|
+
<p class="host"></p>
|
|
201
|
+
<div class="actions">
|
|
202
|
+
<button type="button" class="cancel"></button>
|
|
203
|
+
<button type="button" class="go"></button>
|
|
204
|
+
</div>
|
|
205
|
+
</div>`,z.append(K);let G=(I)=>K.querySelector(I),w=G(".card"),M=G(".bar"),U=G(".count"),D=G("h2"),C=G(".body"),R=G(".host"),N=G(".go"),q=G(".cancel");D.textContent=j.handoffTitle,C.textContent=j.handoffBody;try{R.textContent=new URL(S().host).host}catch{R.textContent=""}N.textContent=j.handoffGo,q.textContent=j.cancel,w.style.setProperty("--secs",`${J}s`),U.textContent=String(J),document.body.append(Q),requestAnimationFrame(()=>K.setAttribute("data-open","1"));let _=document.activeElement;return N.focus({preventScroll:!0}),new Promise((I)=>{let B=!1,y=null,t=!1,b=Date.now()+J*1000,h=window.setInterval(()=>{let O=Math.ceil((b-Date.now())/1000);if(U.textContent=String(Math.max(0,O)),Date.now()>=b)Q0()},100);function g(O){if(B)return;if(B=!0,window.clearInterval(h),document.removeEventListener("keydown",k,!0),K.removeAttribute("data-open"),window.setTimeout(()=>Q.remove(),200),!O)_?.focus?.({preventScroll:!0});I(O)}function Q0(){if(B||t)return;if(y)return g(y);window.clearInterval(h),U.textContent="",M.classList.add("spinner"),D.textContent=j.handoffPreparing}function k(O){if(O.key==="Escape")O.stopPropagation(),g(null)}document.addEventListener("keydown",k,!0),N.addEventListener("click",Q0),q.addEventListener("click",()=>g(null)),K.addEventListener("click",(O)=>{if(O.target===K)g(null)}),$.prepare().then((O)=>{if(y=O,!B&&Date.now()>=b)g(O)},()=>{t=!0,window.clearInterval(h),w.classList.add("error"),M.classList.remove("spinner"),M.style.animation="none",U.textContent="",D.textContent=j.handoffFailed,C.textContent=j.handoffBody,N.remove(),q.textContent=j.close})})}var n4="/sso";function t1($,j,J){let Q=new URL(n4,$.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 s1(){let $=S();if(!$.identity)throw new F0;let j=await $.identity();if(!j)throw new F0;return t1($.host,$.realmKey,j)}function a1($,j){if(j==="_blank")window.open($,"_blank","noopener,noreferrer");else window.location.assign($)}async function s4($={}){if($.announce===!1){a1(await s1(),$.target);return}let j=await n1({seconds:$.seconds,prepare:s1});if(j)a1(j,$.target)}export{h0 as trimToBudget,h1 as toCurl,t1 as supportPortalUrl,g0 as submitBundle,n as showToast,p4 as setErroredQueriesSource,d4 as requestPath,v as reporterStrings,c as redactUrl,d as redactLabel,i as redactHeaders,o as redactBody,s4 as openSupportPortal,S0 as onLaunch,O0 as onCrash,R0 as launch,c4 as isQuietStep,l1 as isFailedRequest,H0 as isConfigured,b4 as installDebugCapture,D4 as hasCause,f0 as getNetworkLog,q0 as getConsoleLog,S as getConfig,N0 as getActionTrail,o4 as formatDuration,E0 as errorSignature,_0 as emitCrash,b0 as defineReporterElement,v0 as createAnnotator,i4 as correlateActionTrail,Q2 as configureDebugCapture,T0 as captureScreen,C4 as bundleToMarkdown,I4 as bundleFileName,A0 as buildBundle,E as appInfo,I0 as actionCountSuffix,a as REPORTER_TAG,u as REDACTED,F0 as NoIdentityError,x0 as BUNDLE_BUDGET_BYTES};
|
package/dist/portal.d.ts
CHANGED
|
@@ -7,6 +7,19 @@ export declare function supportPortalUrl(host: string, realmKey: string, token:
|
|
|
7
7
|
export declare class NoIdentityError extends Error {
|
|
8
8
|
constructor(message?: string);
|
|
9
9
|
}
|
|
10
|
+
export interface OpenPortalOptions {
|
|
11
|
+
/** Where to open it. Same tab by default — see below. */
|
|
12
|
+
target?: "_self" | "_blank";
|
|
13
|
+
/**
|
|
14
|
+
* Show the hand-off dialog first. Default true.
|
|
15
|
+
*
|
|
16
|
+
* `false` navigates on the spot, which is what this used to do and what a
|
|
17
|
+
* host wants if it is announcing the departure itself.
|
|
18
|
+
*/
|
|
19
|
+
announce?: boolean;
|
|
20
|
+
/** How long the dialog counts down. Default 3. */
|
|
21
|
+
seconds?: number;
|
|
22
|
+
}
|
|
10
23
|
/**
|
|
11
24
|
* Open the portal, signed in as the current user.
|
|
12
25
|
*
|
|
@@ -14,11 +27,18 @@ export declare class NoIdentityError extends Error {
|
|
|
14
27
|
* two minutes and is spent on arrival, so one obtained at page load would
|
|
15
28
|
* usually be dead by the time anybody pressed anything.
|
|
16
29
|
*
|
|
30
|
+
* By default this announces itself first. Leaving for another origin without
|
|
31
|
+
* warning, mid-task, reads as a bug — and the seconds are not an apology, they
|
|
32
|
+
* are when the token is fetched, so the click is answered by something on
|
|
33
|
+
* screen instead of by a pause of unknown length.
|
|
34
|
+
*
|
|
17
35
|
* Same origin by default. A new tab is available but is not the default: the
|
|
18
36
|
* point of this is that the support system owns the whole ticket experience,
|
|
19
37
|
* and leaving the host app open behind it invites the two to disagree about
|
|
20
38
|
* what a ticket says.
|
|
39
|
+
*
|
|
40
|
+
* With the dialog, a failure is REPORTED IN IT and this resolves; without it,
|
|
41
|
+
* the error is thrown for the caller to handle. One of them has somewhere to
|
|
42
|
+
* put the message and the other does not.
|
|
21
43
|
*/
|
|
22
|
-
export declare function openSupportPortal(options?:
|
|
23
|
-
target?: "_self" | "_blank";
|
|
24
|
-
}): Promise<void>;
|
|
44
|
+
export declare function openSupportPortal(options?: OpenPortalOptions): Promise<void>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface HandoffResult {
|
|
2
|
+
/** True when the caller should navigate. */
|
|
3
|
+
go: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface HandoffOptions {
|
|
6
|
+
/** Seconds before it leaves on its own. */
|
|
7
|
+
seconds?: number;
|
|
8
|
+
/** Resolves to the URL to open, or rejects. Awaited under the countdown. */
|
|
9
|
+
prepare: () => Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Show the hand-off and resolve with the URL to open, or null if the person
|
|
13
|
+
* backed out or it failed.
|
|
14
|
+
*
|
|
15
|
+
* The work happens WHILE the countdown runs, so a click is answered instantly
|
|
16
|
+
* by something on screen rather than by a pause of unknown length.
|
|
17
|
+
*/
|
|
18
|
+
export declare function showHandoff(options: HandoffOptions): Promise<string | null>;
|
package/dist/ui/strings.d.ts
CHANGED
|
@@ -38,5 +38,11 @@ export interface Strings {
|
|
|
38
38
|
captured: string;
|
|
39
39
|
reporter: string;
|
|
40
40
|
page: string;
|
|
41
|
+
/** The hand-off dialog, shown before leaving for the support portal. */
|
|
42
|
+
handoffTitle: string;
|
|
43
|
+
handoffBody: string;
|
|
44
|
+
handoffGo: string;
|
|
45
|
+
handoffPreparing: string;
|
|
46
|
+
handoffFailed: string;
|
|
41
47
|
}
|
|
42
48
|
export declare function strings(locale: "th" | "en" | undefined): Strings;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightworkai.official/debug-capture",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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/index.ts
CHANGED
|
@@ -61,5 +61,6 @@ export type { Strings as ReporterStrings } from "./ui/strings";
|
|
|
61
61
|
* link, and the ticket UI maintained where it lives.
|
|
62
62
|
*/
|
|
63
63
|
export { openSupportPortal, supportPortalUrl, NoIdentityError } from "./portal";
|
|
64
|
+
export type { OpenPortalOptions } from "./portal";
|
|
64
65
|
|
|
65
66
|
export type * from "./types";
|
package/src/portal.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* leaves the app they were in.
|
|
13
13
|
*/
|
|
14
14
|
import { getConfig } from "./config";
|
|
15
|
+
import { showHandoff } from "./ui/handoff";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Where a signed-in hand-off lands. Stable on purpose — it goes in other
|
|
@@ -38,6 +39,38 @@ export class NoIdentityError extends Error {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
export interface OpenPortalOptions {
|
|
43
|
+
/** Where to open it. Same tab by default — see below. */
|
|
44
|
+
target?: "_self" | "_blank";
|
|
45
|
+
/**
|
|
46
|
+
* Show the hand-off dialog first. Default true.
|
|
47
|
+
*
|
|
48
|
+
* `false` navigates on the spot, which is what this used to do and what a
|
|
49
|
+
* host wants if it is announcing the departure itself.
|
|
50
|
+
*/
|
|
51
|
+
announce?: boolean;
|
|
52
|
+
/** How long the dialog counts down. Default 3. */
|
|
53
|
+
seconds?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Build the destination. Separated so it can run UNDER the countdown. */
|
|
57
|
+
async function prepareUrl(): Promise<string> {
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
if (!config.identity) throw new NoIdentityError();
|
|
60
|
+
|
|
61
|
+
const token = await config.identity();
|
|
62
|
+
// Null is "nobody is signed in", which the host answers, not us — it has a
|
|
63
|
+
// login screen and we do not know where it is.
|
|
64
|
+
if (!token) throw new NoIdentityError();
|
|
65
|
+
|
|
66
|
+
return supportPortalUrl(config.host, config.realmKey, token);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function navigate(url: string, target: OpenPortalOptions["target"]): void {
|
|
70
|
+
if (target === "_blank") window.open(url, "_blank", "noopener,noreferrer");
|
|
71
|
+
else window.location.assign(url);
|
|
72
|
+
}
|
|
73
|
+
|
|
41
74
|
/**
|
|
42
75
|
* Open the portal, signed in as the current user.
|
|
43
76
|
*
|
|
@@ -45,21 +78,26 @@ export class NoIdentityError extends Error {
|
|
|
45
78
|
* two minutes and is spent on arrival, so one obtained at page load would
|
|
46
79
|
* usually be dead by the time anybody pressed anything.
|
|
47
80
|
*
|
|
81
|
+
* By default this announces itself first. Leaving for another origin without
|
|
82
|
+
* warning, mid-task, reads as a bug — and the seconds are not an apology, they
|
|
83
|
+
* are when the token is fetched, so the click is answered by something on
|
|
84
|
+
* screen instead of by a pause of unknown length.
|
|
85
|
+
*
|
|
48
86
|
* Same origin by default. A new tab is available but is not the default: the
|
|
49
87
|
* point of this is that the support system owns the whole ticket experience,
|
|
50
88
|
* and leaving the host app open behind it invites the two to disagree about
|
|
51
89
|
* what a ticket says.
|
|
90
|
+
*
|
|
91
|
+
* With the dialog, a failure is REPORTED IN IT and this resolves; without it,
|
|
92
|
+
* the error is thrown for the caller to handle. One of them has somewhere to
|
|
93
|
+
* put the message and the other does not.
|
|
52
94
|
*/
|
|
53
|
-
export async function openSupportPortal(options:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
const url = supportPortalUrl(config.host, config.realmKey, token);
|
|
63
|
-
if (options.target === "_blank") window.open(url, "_blank", "noopener,noreferrer");
|
|
64
|
-
else window.location.assign(url);
|
|
95
|
+
export async function openSupportPortal(options: OpenPortalOptions = {}): Promise<void> {
|
|
96
|
+
if (options.announce === false) {
|
|
97
|
+
navigate(await prepareUrl(), options.target);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const url = await showHandoff({ seconds: options.seconds, prepare: prepareUrl });
|
|
101
|
+
// Null means they backed out, or it failed and the dialog said so.
|
|
102
|
+
if (url) navigate(url, options.target);
|
|
65
103
|
}
|
package/src/submit.ts
CHANGED
|
@@ -46,6 +46,25 @@ function bundleAttachment(bundle: DebugBundle): { dataUri: string; filename: str
|
|
|
46
46
|
return { dataUri: `data:application/json;base64,${base64}`, filename: "debug-bundle.json" };
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* The host's proof of who is filing, when it has any.
|
|
51
|
+
*
|
|
52
|
+
* Never throws. Filing a report has to keep working for an app that has not
|
|
53
|
+
* wired identity up, for one where nobody is signed in, and for one whose token
|
|
54
|
+
* endpoint is having a bad day — a bug report is the last thing that should
|
|
55
|
+
* fail because of a side quest.
|
|
56
|
+
*/
|
|
57
|
+
async function identityHeader(): Promise<Record<string, string>> {
|
|
58
|
+
const provider = getConfig().identity;
|
|
59
|
+
if (!provider) return {};
|
|
60
|
+
try {
|
|
61
|
+
const token = await provider();
|
|
62
|
+
return token ? { authorization: `Bearer ${token}` } : {};
|
|
63
|
+
} catch {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
49
68
|
export async function submitBundle(title: string, bundle: DebugBundle): Promise<FiledTicket> {
|
|
50
69
|
const config = getConfig();
|
|
51
70
|
const trimmed = trimToBudget(bundle, BUNDLE_BUDGET_BYTES);
|
|
@@ -118,9 +137,23 @@ export async function submitBundle(title: string, bundle: DebugBundle): Promise<
|
|
|
118
137
|
// authenticated /api routes rather than inside them, because it is the one
|
|
119
138
|
// surface a public key reaches. Assuming the prefix cost a 404 that no unit
|
|
120
139
|
// test could have caught — it only appears against a real server.
|
|
140
|
+
/*
|
|
141
|
+
* Present the identity token if the host has one.
|
|
142
|
+
*
|
|
143
|
+
* The realm key alone files an ANONYMOUS report: `requesterEmail` in the body
|
|
144
|
+
* is caller-supplied under a public key, so the server cannot believe it, and
|
|
145
|
+
* the ticket lands with no `requesterId` — which is the field that makes it
|
|
146
|
+
* appear in the reporter's own list. It would show up eventually, when their
|
|
147
|
+
* next sign-in claims earlier reports by email, and "eventually" is not what
|
|
148
|
+
* someone expects after pressing send and seeing it succeed.
|
|
149
|
+
*/
|
|
121
150
|
const res = await fetch(`${config.host.replace(/\/$/, "")}/ingest/tickets`, {
|
|
122
151
|
method: "POST",
|
|
123
|
-
headers: {
|
|
152
|
+
headers: {
|
|
153
|
+
"content-type": "application/json",
|
|
154
|
+
"x-realm-key": config.realmKey,
|
|
155
|
+
...(await identityHeader()),
|
|
156
|
+
},
|
|
124
157
|
body: JSON.stringify(body),
|
|
125
158
|
});
|
|
126
159
|
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The moment before someone leaves for the support portal.
|
|
3
|
+
*
|
|
4
|
+
* Pressing the button used to navigate on the spot. Cross-origin, mid-task,
|
|
5
|
+
* with no warning — the app they were in simply became a different app, and the
|
|
6
|
+
* only way to find out what happened was to read the address bar. A redirect
|
|
7
|
+
* nobody announced reads as a bug, or as something worse.
|
|
8
|
+
*
|
|
9
|
+
* So: say where they are going, say they will be signed in when they arrive,
|
|
10
|
+
* count down, and let them leave now or not at all. The countdown is not a
|
|
11
|
+
* delay dressed up as politeness — the token is being fetched from the host's
|
|
12
|
+
* server underneath it, so the three seconds are doing work that would
|
|
13
|
+
* otherwise be a blank pause after the click.
|
|
14
|
+
*
|
|
15
|
+
* Its own shadow root, its own styles, same reasoning as the reporter dialog
|
|
16
|
+
* and the toast: this drops into pages we do not control, and neither side's
|
|
17
|
+
* CSS should reach the other.
|
|
18
|
+
*/
|
|
19
|
+
import { getConfig } from "../config";
|
|
20
|
+
import { strings } from "./strings";
|
|
21
|
+
|
|
22
|
+
const HOST_TAG = "lw-portal-handoff";
|
|
23
|
+
|
|
24
|
+
/** r=22 → 2πr. Hard-coded because the CSS needs it as a literal too. */
|
|
25
|
+
const RING = 138.23;
|
|
26
|
+
|
|
27
|
+
const CSS = `
|
|
28
|
+
:host { all: initial; }
|
|
29
|
+
.backdrop {
|
|
30
|
+
position: fixed; inset: 0; z-index: 2147483002;
|
|
31
|
+
display: grid; place-items: center; padding: 20px;
|
|
32
|
+
background: rgba(15, 23, 42, 0.45);
|
|
33
|
+
-webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
|
|
34
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Thai", sans-serif;
|
|
35
|
+
opacity: 0; transition: opacity 180ms ease;
|
|
36
|
+
}
|
|
37
|
+
.backdrop[data-open="1"] { opacity: 1; }
|
|
38
|
+
|
|
39
|
+
.card {
|
|
40
|
+
width: min(360px, 100%); box-sizing: border-box;
|
|
41
|
+
padding: 24px 24px 18px; text-align: center;
|
|
42
|
+
background: #fff; border-radius: 16px;
|
|
43
|
+
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
|
|
44
|
+
transform: translateY(8px) scale(0.97); opacity: 0;
|
|
45
|
+
transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1), opacity 160ms ease;
|
|
46
|
+
}
|
|
47
|
+
.backdrop[data-open="1"] .card { transform: none; opacity: 1; }
|
|
48
|
+
|
|
49
|
+
.ring { display: block; margin: 0 auto 14px; width: 56px; height: 56px; }
|
|
50
|
+
.ring circle { fill: none; stroke-width: 4; stroke-linecap: round; }
|
|
51
|
+
.ring .track { stroke: #e2e8f0; }
|
|
52
|
+
.ring .bar {
|
|
53
|
+
stroke: #0ea5e9; transform: rotate(-90deg); transform-origin: 50% 50%;
|
|
54
|
+
stroke-dasharray: ${RING}; stroke-dashoffset: 0;
|
|
55
|
+
animation: deplete var(--secs, 3s) linear forwards;
|
|
56
|
+
}
|
|
57
|
+
@keyframes deplete { to { stroke-dashoffset: ${RING}; } }
|
|
58
|
+
.count {
|
|
59
|
+
position: relative; margin-top: -42px; margin-bottom: 20px;
|
|
60
|
+
font-size: 18px; font-weight: 600; color: #0f172a; font-variant-numeric: tabular-nums;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* The spinner replaces the ring once the countdown is over but the token has
|
|
64
|
+
not arrived — rare, and better than a frozen 0. */
|
|
65
|
+
.spinner { animation: spin 900ms linear infinite; }
|
|
66
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
67
|
+
|
|
68
|
+
h2 { margin: 0 0 6px; font-size: 16px; font-weight: 600; color: #0f172a; }
|
|
69
|
+
p { margin: 0; font-size: 13px; line-height: 1.6; color: #475569; }
|
|
70
|
+
.host { margin-top: 8px; font-size: 12px; color: #94a3b8; word-break: break-all; }
|
|
71
|
+
|
|
72
|
+
.actions { display: flex; gap: 8px; margin-top: 20px; }
|
|
73
|
+
button {
|
|
74
|
+
flex: 1; padding: 9px 12px; border-radius: 9px; font: inherit; font-size: 14px;
|
|
75
|
+
cursor: pointer; transition: background 120ms ease, border-color 120ms ease;
|
|
76
|
+
}
|
|
77
|
+
.go { border: none; background: #0f172a; color: #fff; font-weight: 600; }
|
|
78
|
+
.go:hover { background: #1e293b; }
|
|
79
|
+
.cancel { border: 1px solid #e2e8f0; background: #fff; color: #334155; }
|
|
80
|
+
.cancel:hover { background: #f8fafc; }
|
|
81
|
+
button:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; }
|
|
82
|
+
|
|
83
|
+
.error h2 { color: #b91c1c; }
|
|
84
|
+
|
|
85
|
+
@media (prefers-reduced-motion: reduce) {
|
|
86
|
+
/* Movement goes; the countdown does not — it is information, not decoration,
|
|
87
|
+
and someone who has asked for less motion still needs to know they are
|
|
88
|
+
about to be sent somewhere. */
|
|
89
|
+
.backdrop, .card { transition: opacity 120ms ease; }
|
|
90
|
+
.card { transform: none; }
|
|
91
|
+
.ring .bar { animation: none; stroke-dashoffset: 0; }
|
|
92
|
+
.spinner { animation-duration: 2s; }
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
export interface HandoffResult {
|
|
97
|
+
/** True when the caller should navigate. */
|
|
98
|
+
go: boolean;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface HandoffOptions {
|
|
102
|
+
/** Seconds before it leaves on its own. */
|
|
103
|
+
seconds?: number;
|
|
104
|
+
/** Resolves to the URL to open, or rejects. Awaited under the countdown. */
|
|
105
|
+
prepare: () => Promise<string>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Show the hand-off and resolve with the URL to open, or null if the person
|
|
110
|
+
* backed out or it failed.
|
|
111
|
+
*
|
|
112
|
+
* The work happens WHILE the countdown runs, so a click is answered instantly
|
|
113
|
+
* by something on screen rather than by a pause of unknown length.
|
|
114
|
+
*/
|
|
115
|
+
export function showHandoff(options: HandoffOptions): Promise<string | null> {
|
|
116
|
+
if (typeof document === "undefined") return options.prepare().then((u) => u, () => null);
|
|
117
|
+
|
|
118
|
+
const t = strings(getConfig().locale);
|
|
119
|
+
const seconds = Math.max(1, Math.floor(options.seconds ?? 3));
|
|
120
|
+
|
|
121
|
+
const host = document.createElement(HOST_TAG);
|
|
122
|
+
const root = host.attachShadow({ mode: "open" });
|
|
123
|
+
const style = document.createElement("style");
|
|
124
|
+
style.textContent = CSS;
|
|
125
|
+
root.append(style);
|
|
126
|
+
|
|
127
|
+
const backdrop = document.createElement("div");
|
|
128
|
+
backdrop.className = "backdrop";
|
|
129
|
+
backdrop.innerHTML = `
|
|
130
|
+
<div class="card" role="dialog" aria-modal="true" aria-labelledby="lw-ho-title">
|
|
131
|
+
<svg class="ring" viewBox="0 0 52 52" aria-hidden="true">
|
|
132
|
+
<circle class="track" cx="26" cy="26" r="22"></circle>
|
|
133
|
+
<circle class="bar" cx="26" cy="26" r="22"></circle>
|
|
134
|
+
</svg>
|
|
135
|
+
<div class="count" aria-hidden="true"></div>
|
|
136
|
+
<h2 id="lw-ho-title"></h2>
|
|
137
|
+
<p class="body"></p>
|
|
138
|
+
<p class="host"></p>
|
|
139
|
+
<div class="actions">
|
|
140
|
+
<button type="button" class="cancel"></button>
|
|
141
|
+
<button type="button" class="go"></button>
|
|
142
|
+
</div>
|
|
143
|
+
</div>`;
|
|
144
|
+
root.append(backdrop);
|
|
145
|
+
|
|
146
|
+
const $ = <T extends Element>(sel: string) => backdrop.querySelector(sel) as T;
|
|
147
|
+
const card = $<HTMLElement>(".card");
|
|
148
|
+
const bar = $<SVGCircleElement>(".bar");
|
|
149
|
+
const count = $<HTMLElement>(".count");
|
|
150
|
+
const title = $<HTMLElement>("h2");
|
|
151
|
+
const body = $<HTMLElement>(".body");
|
|
152
|
+
const hostLine = $<HTMLElement>(".host");
|
|
153
|
+
const goBtn = $<HTMLButtonElement>(".go");
|
|
154
|
+
const cancelBtn = $<HTMLButtonElement>(".cancel");
|
|
155
|
+
|
|
156
|
+
title.textContent = t.handoffTitle;
|
|
157
|
+
body.textContent = t.handoffBody;
|
|
158
|
+
try {
|
|
159
|
+
hostLine.textContent = new URL(getConfig().host).host;
|
|
160
|
+
} catch {
|
|
161
|
+
hostLine.textContent = "";
|
|
162
|
+
}
|
|
163
|
+
goBtn.textContent = t.handoffGo;
|
|
164
|
+
cancelBtn.textContent = t.cancel;
|
|
165
|
+
card.style.setProperty("--secs", `${seconds}s`);
|
|
166
|
+
count.textContent = String(seconds);
|
|
167
|
+
|
|
168
|
+
document.body.append(host);
|
|
169
|
+
// Next frame, so the transition has a state to move away from.
|
|
170
|
+
requestAnimationFrame(() => backdrop.setAttribute("data-open", "1"));
|
|
171
|
+
|
|
172
|
+
const restoreFocus = document.activeElement as HTMLElement | null;
|
|
173
|
+
goBtn.focus({ preventScroll: true });
|
|
174
|
+
|
|
175
|
+
return new Promise<string | null>((resolve) => {
|
|
176
|
+
let settled = false;
|
|
177
|
+
let url: string | null = null;
|
|
178
|
+
let failed = false;
|
|
179
|
+
const endsAt = Date.now() + seconds * 1000;
|
|
180
|
+
|
|
181
|
+
const tick = window.setInterval(() => {
|
|
182
|
+
const left = Math.ceil((endsAt - Date.now()) / 1000);
|
|
183
|
+
count.textContent = String(Math.max(0, left));
|
|
184
|
+
if (Date.now() >= endsAt) leave();
|
|
185
|
+
}, 100);
|
|
186
|
+
|
|
187
|
+
function close(result: string | null) {
|
|
188
|
+
if (settled) return;
|
|
189
|
+
settled = true;
|
|
190
|
+
window.clearInterval(tick);
|
|
191
|
+
document.removeEventListener("keydown", onKey, true);
|
|
192
|
+
backdrop.removeAttribute("data-open");
|
|
193
|
+
// Let the fade finish before the node goes, or cancelling snaps.
|
|
194
|
+
window.setTimeout(() => host.remove(), 200);
|
|
195
|
+
if (!result) restoreFocus?.focus?.({ preventScroll: true });
|
|
196
|
+
resolve(result);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Go, or wait for the token if it is not here yet. */
|
|
200
|
+
function leave() {
|
|
201
|
+
if (settled || failed) return;
|
|
202
|
+
if (url) return close(url);
|
|
203
|
+
window.clearInterval(tick);
|
|
204
|
+
count.textContent = "";
|
|
205
|
+
bar.classList.add("spinner");
|
|
206
|
+
title.textContent = t.handoffPreparing;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function onKey(e: KeyboardEvent) {
|
|
210
|
+
if (e.key === "Escape") {
|
|
211
|
+
e.stopPropagation();
|
|
212
|
+
close(null);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
document.addEventListener("keydown", onKey, true);
|
|
216
|
+
|
|
217
|
+
goBtn.addEventListener("click", leave);
|
|
218
|
+
cancelBtn.addEventListener("click", () => close(null));
|
|
219
|
+
// The backdrop, but not the card — a click that lands on the dialog itself
|
|
220
|
+
// is not a click outside it.
|
|
221
|
+
backdrop.addEventListener("click", (e) => {
|
|
222
|
+
if (e.target === backdrop) close(null);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
options.prepare().then(
|
|
226
|
+
(ready) => {
|
|
227
|
+
url = ready;
|
|
228
|
+
// The countdown already ran out and is waiting on exactly this.
|
|
229
|
+
if (!settled && Date.now() >= endsAt) close(ready);
|
|
230
|
+
},
|
|
231
|
+
() => {
|
|
232
|
+
failed = true;
|
|
233
|
+
window.clearInterval(tick);
|
|
234
|
+
card.classList.add("error");
|
|
235
|
+
bar.classList.remove("spinner");
|
|
236
|
+
bar.style.animation = "none";
|
|
237
|
+
count.textContent = "";
|
|
238
|
+
title.textContent = t.handoffFailed;
|
|
239
|
+
body.textContent = t.handoffBody;
|
|
240
|
+
goBtn.remove();
|
|
241
|
+
cancelBtn.textContent = t.close;
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
}
|
package/src/ui/strings.ts
CHANGED
|
@@ -38,6 +38,12 @@ export interface Strings {
|
|
|
38
38
|
captured: string;
|
|
39
39
|
reporter: string;
|
|
40
40
|
page: string;
|
|
41
|
+
/** The hand-off dialog, shown before leaving for the support portal. */
|
|
42
|
+
handoffTitle: string;
|
|
43
|
+
handoffBody: string;
|
|
44
|
+
handoffGo: string;
|
|
45
|
+
handoffPreparing: string;
|
|
46
|
+
handoffFailed: string;
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
const th: Strings = {
|
|
@@ -72,6 +78,11 @@ const th: Strings = {
|
|
|
72
78
|
captured: "เก็บข้อมูลแล้ว",
|
|
73
79
|
reporter: "ผู้แจ้ง",
|
|
74
80
|
page: "หน้า",
|
|
81
|
+
handoffTitle: "กำลังพาไปที่ระบบแจ้งปัญหา",
|
|
82
|
+
handoffBody: "ระบบจะลงชื่อเข้าใช้ให้อัตโนมัติ เพื่อดูเรื่องที่คุณแจ้งไว้",
|
|
83
|
+
handoffGo: "ไปเลย",
|
|
84
|
+
handoffPreparing: "กำลังเตรียม…",
|
|
85
|
+
handoffFailed: "เปิดรายการที่แจ้งไว้ไม่สำเร็จ",
|
|
75
86
|
};
|
|
76
87
|
|
|
77
88
|
const en: Strings = {
|
|
@@ -106,6 +117,11 @@ const en: Strings = {
|
|
|
106
117
|
captured: "Captured",
|
|
107
118
|
reporter: "Reporter",
|
|
108
119
|
page: "Page",
|
|
120
|
+
handoffTitle: "Opening the support portal",
|
|
121
|
+
handoffBody: "You will be signed in automatically to see what you reported",
|
|
122
|
+
handoffGo: "Go now",
|
|
123
|
+
handoffPreparing: "Preparing…",
|
|
124
|
+
handoffFailed: "Could not open your reports",
|
|
109
125
|
};
|
|
110
126
|
|
|
111
127
|
export function strings(locale: "th" | "en" | undefined): Strings {
|