Files
remnawave-minishop/frontend/src/lib/webapp/telegramSdk.js
T

170 lines
4.6 KiB
JavaScript

export function readTelegramMiniAppInitDataFromLocation() {
if (typeof window === "undefined") return "";
const queryText = window.location.search.replace(/^\?/, "");
const hashText = window.location.hash.replace(/^#/, "");
for (const text of [queryText, hashText]) {
if (!text) continue;
const params = new URLSearchParams(text);
const initData = params.get("tgWebAppData");
if (initData) return initData;
}
return "";
}
export function createTelegramSdk({
scriptUrl,
bootTimeoutMs,
actionTimeoutMs,
miniAppAuthTimeoutMs,
onStatusChange = () => {},
onInitDataChange = () => {},
} = {}) {
let tg = resolve();
let sdkPromise = null;
let launchParamsDetected = false;
let initData = tg?.initData || readTelegramMiniAppInitDataFromLocation();
if (initData) launchParamsDetected = true;
function resolve() {
return window.Telegram?.WebApp || null;
}
function setStatus(status) {
onStatusChange(status);
}
function refresh() {
tg = resolve();
if (tg) setStatus("ready");
initData = tg?.initData || readTelegramMiniAppInitDataFromLocation();
onInitDataChange(initData);
if (initData) launchParamsDetected = true;
return tg;
}
function hasLaunchParams() {
refresh();
if (launchParamsDetected || initData) {
launchParamsDetected = true;
return true;
}
const queryText = window.location.search.replace(/^\?/, "");
const hashText = window.location.hash.replace(/^#/, "");
const detected = [queryText, hashText].some((text) => {
if (!text) return false;
const params = new URLSearchParams(text);
return ["tgWebAppData", "tgWebAppVersion", "tgWebAppPlatform", "tgWebAppThemeParams"].some(
(key) => params.has(key)
);
});
if (detected) launchParamsDetected = true;
return detected;
}
function load(timeoutMs = bootTimeoutMs) {
if (refresh()) return Promise.resolve(tg);
if (sdkPromise) return sdkPromise;
if (typeof document === "undefined") return Promise.resolve(null);
setStatus("loading");
sdkPromise = new Promise((resolvePromise) => {
const existingScript = document.querySelector("script[data-rw-telegram-web-app-sdk]");
const script = existingScript || document.createElement("script");
let resolved = false;
let timeoutId = null;
const resolveOnce = (value) => {
if (resolved) return;
resolved = true;
if (timeoutId) window.clearTimeout(timeoutId);
resolvePromise(value);
};
const refreshFromScript = () => {
tg = resolve();
setStatus(tg ? "ready" : "unavailable");
return tg;
};
script.addEventListener("load", () => resolveOnce(refreshFromScript()), { once: true });
script.addEventListener(
"error",
() => {
setStatus("unavailable");
resolveOnce(null);
},
{ once: true }
);
if (!existingScript) {
script.src = scriptUrl;
script.async = true;
script.defer = true;
script.dataset.rwTelegramWebAppSdk = "1";
document.head.appendChild(script);
}
timeoutId = window.setTimeout(() => {
if (!tg) setStatus("unavailable");
resolveOnce(tg);
}, timeoutMs);
}).finally(() => {
sdkPromise = null;
});
return sdkPromise;
}
async function ensureForAction() {
if (refresh()) return tg;
return await load(actionTimeoutMs);
}
function createMiniAppAuthTimeout() {
const controller = typeof AbortController === "undefined" ? null : new AbortController();
let timedOut = false;
let timeoutId = null;
let timeoutPromise = new Promise(() => {});
if (typeof window !== "undefined") {
timeoutPromise = new Promise((_, reject) => {
timeoutId = window.setTimeout(() => {
timedOut = true;
controller?.abort();
const error = new Error("telegram_mini_app_auth_timeout");
error.name = "AbortError";
reject(error);
}, miniAppAuthTimeoutMs);
});
}
return {
promise: timeoutPromise,
get signal() {
return controller?.signal;
},
get timedOut() {
return timedOut;
},
clear() {
if (timeoutId) window.clearTimeout(timeoutId);
timeoutId = null;
},
};
}
return {
get tg() {
return tg;
},
get initData() {
return initData;
},
refresh,
hasLaunchParams,
load,
ensureForAction,
createMiniAppAuthTimeout,
readInitDataFromLocation: readTelegramMiniAppInitDataFromLocation,
};
}