Skip to content

Instantly share code, notes, and snippets.

@gulitsky
Last active March 11, 2026 14:01
Show Gist options
  • Select an option

  • Save gulitsky/e7784a94d934ac0be1ca6c17af591718 to your computer and use it in GitHub Desktop.

Select an option

Save gulitsky/e7784a94d934ac0be1ca6c17af591718 to your computer and use it in GitHub Desktop.
import {
backButton,
emitEvent,
init as initSDK,
initData,
isTMA,
miniApp,
mockTelegramEnv,
retrieveLaunchParams,
setDebug,
themeParams,
type ThemeParams,
viewport,
settingsButton,
swipeBehavior,
} from "@tma.js/sdk";
const noInsets = { left: 0, top: 0, bottom: 0, right: 0 } as const;
export async function init(): Promise<void> {
const {
tgWebAppStartParam: start,
tgWebAppPlatform: platform,
tgWebAppVersion: version,
tgWebAppData: data,
tgWebAppThemeParams,
} = retrieveLaunchParams();
const debug = start === "debug" || import.meta.env.DEV;
const mobile = ["android", "ios"].includes(platform);
setDebug(debug);
initSDK();
if (mobile && debug) {
const { default: eruda } = await import("eruda");
eruda.init({
tool: ["console", "elements", "network", "resources", "info"],
});
eruda.position({ x: window.innerWidth - 50, y: 0 });
const info = eruda.get("info");
info.remove("Location");
info.remove("System");
info.remove("Sponsor this Project");
info.remove("About");
let html = `
<table>
<tbody>
<tr>
<th class="eruda-system-key">platform</th>
<td>${platform}</td>
</tr>
<tr>
<th>version</th>
<td>${version}</td>
</tr>
<tr>
<th>auth date</th>
<td>${data?.auth_date.toLocaleString()}</td>
</tr>
<tr>
<th>hash</th>
<td>${data?.hash}</td>
</tr>
<tr>
<th>signature</th>
<td>${data?.signature}</td>
</tr>
<tr>
<th>start param</th>
<td>${data?.start_param}</td>
</tr>
<tr>
<th>chat type</th>
<td>${data?.chat_type}</td>
</tr>
<tr>
<th>chat instance</th>
<td>${data?.chat_instance}</td>
</tr>
</tbody>
</table>
`;
info.add("Init Data", html);
html = `
<table>
<tbody>
<tr>
<th class="eruda-system-key">id</th>
<td>${data?.user?.id}</td>
</tr>
<tr>
<th>username</th>
<td>${data?.user?.username}</td>
</tr>
<tr>
<th>first name</th>
<td>${data?.user?.first_name}</td>
</tr>
<tr>
<th>last name</th>
<td>${data?.user?.last_name}</td>
</tr>
<tr>
<th>language code</th>
<td>${data?.user?.language_code}</td>
</tr>
<tr>
<th>is premium?</th>
<td>${data?.user?.is_premium}</td>
</tr>
<tr>
<th>allows write to pm?</th>
<td>${data?.user?.allows_write_to_pm}</td>
</tr>
<tr>
<th>photo</th>
<td><a href="${data?.user?.photo_url}">url</a></td>
</tr>
</tbody>
</table>
`;
info.add("User", html);
}
if (platform === "macos") {
let firstThemeSent = false;
mockTelegramEnv({
onEvent(event, next) {
if (event.name === "web_app_request_theme") {
let tp: ThemeParams = {};
if (firstThemeSent) {
tp = themeParams.state();
} else {
firstThemeSent = true;
tp ||= tgWebAppThemeParams;
}
return emitEvent("theme_changed", { theme_params: tp });
}
if (event.name === "web_app_request_safe_area") {
return emitEvent("safe_area_changed", noInsets);
}
next();
},
});
}
backButton.mount.ifAvailable();
initData.restore();
themeParams.mount.ifAvailable();
miniApp.mount.ifAvailable();
themeParams.bindCssVars.ifAvailable();
if (viewport.mount.isAvailable()) {
await viewport.mount();
viewport.bindCssVars.ifAvailable();
}
if (mobile && viewport.requestFullscreen.isAvailable()) {
await viewport.requestFullscreen();
}
swipeBehavior.mount.ifAvailable();
swipeBehavior.disableVertical.ifAvailable();
settingsButton.mount.ifAvailable();
settingsButton.show.ifAvailable();
}
if (import.meta.env.DEV) {
if (!(await isTMA("complete"))) {
const themeParams = {
accent_text_color: "#6ab2f2",
bg_color: "#17212b",
button_color: "#5288c1",
button_text_color: "#ffffff",
destructive_text_color: "#ec3942",
header_bg_color: "#17212b",
hint_color: "#708499",
link_color: "#6ab3f3",
secondary_bg_color: "#232e3c",
section_bg_color: "#17212b",
section_header_text_color: "#6ab3f3",
subtitle_text_color: "#708499",
text_color: "#f5f5f5",
} as const;
mockTelegramEnv({
onEvent(event) {
if (event.name === "web_app_request_theme") {
return emitEvent("theme_changed", { theme_params: themeParams });
}
if (event.name === "web_app_request_viewport") {
return emitEvent("viewport_changed", {
height: window.innerHeight,
width: window.innerWidth,
is_expanded: true,
is_state_stable: true,
});
}
if (event.name === "web_app_request_content_safe_area") {
return emitEvent("content_safe_area_changed", noInsets);
}
if (event.name === "web_app_request_safe_area") {
return emitEvent("safe_area_changed", noInsets);
}
},
launchParams: new URLSearchParams([
["tgWebAppThemeParams", JSON.stringify(themeParams)],
[
"tgWebAppData",
new URLSearchParams([
["auth_date", ((new Date().getTime() / 1000) | 0).toString()],
["hash", "some-hash"],
["signature", "some-signature"],
["user", JSON.stringify({ id: 1, first_name: "Vladislav" })],
]).toString(),
],
["tgWebAppVersion", "9.1"],
["tgWebAppPlatform", "tdesktop"],
]),
});
console.warn(
"As long as the current environment was not recognized as Telegram-based, it was mocked. Please note that you should not do this in production, and the current behavior is specific to the development process. Environment mocking is applied only in development mode. After building the application, this behavior and the related warning will not appear, so the application will not crash outside Telegram.",
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment