feat: update tg integration
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m35s
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m35s
This commit is contained in:
126
src/tg/index.ts
126
src/tg/index.ts
@@ -1,22 +1,87 @@
|
||||
import * as tg from "@telegram-apps/sdk-react";
|
||||
import * as tg from "@tma.js/sdk-react";
|
||||
|
||||
export const STORAGE_KEYS = {
|
||||
authToken: "authToken",
|
||||
} as const;
|
||||
export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];
|
||||
|
||||
const MOCKED_START_PARAM = `debug+${Math.random().toString(36).substring(2, 15)}`;
|
||||
|
||||
tg.mockTelegramEnv({
|
||||
launchParams: {
|
||||
tgWebAppData: new URLSearchParams({
|
||||
user: JSON.stringify({
|
||||
id: 1,
|
||||
first_name: "Pavel",
|
||||
is_bot: false,
|
||||
last_name: "Durov",
|
||||
username: "durov",
|
||||
language_code: "en",
|
||||
is_premium: true,
|
||||
photo_url:
|
||||
"https://media4.giphy.com/media/v1.Y2lkPTZjMDliOTUyeXF1MzYyY2pwMjR2YWFhNDhqdXBsc216MWo2aW9pczNnNXM2ZmZmbCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xUPGcHc4I3wICqp8bu/giphy.gif",
|
||||
added_to_attachment_menu: false,
|
||||
allows_write_to_pm: true,
|
||||
} satisfies tg.User),
|
||||
hash: "",
|
||||
signature: "",
|
||||
auth_date: Date.now().toString(),
|
||||
}),
|
||||
tgWebAppStartParam: MOCKED_START_PARAM,
|
||||
tgWebAppThemeParams: {},
|
||||
tgWebAppVersion: "8",
|
||||
tgWebAppPlatform: "android",
|
||||
},
|
||||
});
|
||||
|
||||
type WithChecks<Result> = {
|
||||
ifAvailable: (...args: any[]) => { ok: true; data: Result } | { ok: false };
|
||||
};
|
||||
|
||||
const isPromise = <T>(value: T | Promise<T>): value is Promise<T> =>
|
||||
value && typeof value === "object" && "then" in value && typeof value.then === "function";
|
||||
|
||||
const promisify = <T>(value: T | Promise<T>): Promise<T> =>
|
||||
isPromise(value) ? value : Promise.resolve(value);
|
||||
|
||||
const isTMA = () => tg.retrieveLaunchParams().tgWebAppStartParam !== MOCKED_START_PARAM;
|
||||
|
||||
const fallbackImplementation = <
|
||||
T extends ((...args: any) => any) & WithChecks<any>,
|
||||
Async extends boolean,
|
||||
Params extends Parameters<T>,
|
||||
Result extends T extends WithChecks<infer Result> ? Result : never,
|
||||
F extends (...args: Params) => Async extends true ? Result | Awaited<Result> : Result,
|
||||
>(
|
||||
async: Async,
|
||||
args: Params,
|
||||
cb: T,
|
||||
onErr: F,
|
||||
): Async extends true ? Promise<Result> : Awaited<Result> => {
|
||||
if (isTMA()) {
|
||||
const res = cb.ifAvailable.apply(null, args);
|
||||
const returnValue = (res.ok ? res.data : onErr.apply(null, args)) as Result;
|
||||
if (!async) return returnValue as Async extends true ? Promise<Result> : Awaited<Result>;
|
||||
return promisify(returnValue).catch(() => onErr.apply(null, args)) as Async extends true
|
||||
? Promise<Result>
|
||||
: Awaited<Result>;
|
||||
} else {
|
||||
const result = onErr.apply(null, args);
|
||||
return (async ? promisify(result) : result) as Async extends true
|
||||
? Promise<Result>
|
||||
: Awaited<Result>;
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
init: () => {
|
||||
try {
|
||||
tg.setDebug(import.meta.env.DEV);
|
||||
tg.init({ acceptCustomStyles: true });
|
||||
tg.requestFullscreen();
|
||||
tg.disableVerticalSwipes();
|
||||
tg.expandViewport();
|
||||
tg.setMiniAppHeaderColor("#000000");
|
||||
} catch {
|
||||
console.warn("Telegram SDK not available in browser.");
|
||||
}
|
||||
tg.setDebug(import.meta.env.DEV);
|
||||
tg.init({ acceptCustomStyles: true });
|
||||
tg.viewport.requestFullscreen.ifAvailable();
|
||||
tg.swipeBehavior.disableVertical.ifAvailable();
|
||||
tg.viewport.expand.ifAvailable();
|
||||
tg.miniApp.setHeaderColor.ifAvailable("#000000");
|
||||
console.log(isTMA() ? "Telegram Mini App initialized" : "TMA Debug mode in Web initialized");
|
||||
},
|
||||
openLink(url: string | URL, options?: tg.OpenLinkOptions) {
|
||||
tg.openLink.ifAvailable(url, options);
|
||||
@@ -28,25 +93,32 @@ export default {
|
||||
},
|
||||
initData: tg.initData,
|
||||
storage: {
|
||||
clear() {
|
||||
localStorage.clear();
|
||||
tg.cloudStorage.clear.ifAvailable();
|
||||
async clear() {
|
||||
return fallbackImplementation(true, [], tg.cloudStorage.clear, localStorage.clear);
|
||||
},
|
||||
getItem(key: StorageKey, options?: tg.InvokeCustomMethodOptions) {
|
||||
return tg.cloudStorage
|
||||
.getItem(key, options)
|
||||
.catch(
|
||||
() =>
|
||||
localStorage.getItem(key) ?? tg.AbortablePromise.reject(new Error("Item not found")),
|
||||
);
|
||||
async getItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) {
|
||||
return fallbackImplementation(
|
||||
true,
|
||||
[key, options],
|
||||
tg.cloudStorage.getItem,
|
||||
(key) => localStorage.getItem(key) ?? "",
|
||||
);
|
||||
},
|
||||
setItem(key: StorageKey, value: string, options?: tg.InvokeCustomMethodOptions) {
|
||||
localStorage.setItem(key, value);
|
||||
tg.cloudStorage.setItem.ifAvailable(key, value, options);
|
||||
async setItem(key: StorageKey, value: string, options?: tg.InvokeCustomMethodFpOptions) {
|
||||
return fallbackImplementation(
|
||||
true,
|
||||
[key, value, options],
|
||||
tg.cloudStorage.setItem,
|
||||
localStorage.setItem,
|
||||
);
|
||||
},
|
||||
deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodOptions) {
|
||||
tg.cloudStorage.deleteItem.ifAvailable(key, options);
|
||||
localStorage.removeItem(key);
|
||||
async deleteItem(key: StorageKey, options?: tg.InvokeCustomMethodFpOptions) {
|
||||
return fallbackImplementation(
|
||||
true,
|
||||
[key, options],
|
||||
tg.cloudStorage.deleteItem,
|
||||
localStorage.removeItem as typeof tg.cloudStorage.deleteItem,
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user