// OAuth redirect landing (docs/connected-services.md). The broker relays the // provider's one-time ?code (+ ?state) here — same origin as the app. We hand it // back to the app to complete the exchange (the app holds the session/keys, the // bot does the exchange via the broker), then return to it. // // Same-tab flow (the one we use): merge the code into the pending sessionStorage // entry (verifying state), then navigate back to the app, which finishes on boot. // Popup flow (kept for a possible future/native path): postMessage to the opener. (function () { var q = new URLSearchParams(location.search); var code = q.get("code"); var state = q.get("state"); var error = q.get("error"); // Billing flow (paid access levels): the broker already exchanged the code // and hands back only the connected-account id — no code, no token. var billingAccount = q.get("billing_account"); if (window.opener) { try { window.opener.postMessage({ source: "lchat-oauth", code: code, state: state, error: error }, location.origin); } catch (e) {} window.close(); return; } try { var pend = JSON.parse(sessionStorage.getItem("lchat_oauth") || "null"); if (error || (!code && !billingAccount)) { // Keep the billing flag so the completion can word the failure right. sessionStorage.setItem("lchat_oauth", JSON.stringify({ service: pend && pend.service, billing: pend && pend.billing, error: error || "no code" })); } else if (pend && pend.state === state) { if (code) pend.code = code; if (billingAccount) pend.billingAccount = billingAccount; sessionStorage.setItem("lchat_oauth", JSON.stringify(pend)); } } catch (e) {} location.replace("/"); })();