@telegram-apps/bridge
Version:
TypeScript package to provide communication layer between Mini App and Telegram application.
551 lines (550 loc) • 15.2 kB
JavaScript
import { is as y, looseObject as u, function as $, boolean as x, nullish as d, number as A, string as w, optional as C, unknown as Z, parse as v, pipe as j, any as O } from "valibot";
import { AbortablePromise as N } from "better-promises";
import { AbortablePromise as Xe, CancelledError as Ze, ManualPromise as Oe, TimeoutError as Ve, isCancelledError as et, isTimeoutError as tt } from "better-promises";
import { createLogger as V, createCbCollector as ee, getStorageValue as te, setStorageValue as z, deepSnakeToCamelObjKeys as re } from "@telegram-apps/toolkit";
import { createLogger as ot } from "@telegram-apps/toolkit";
import { themeParams as oe, jsonParse as D, MiniAppsMessageSchema as G, isLaunchParamsQuery as J, parseLaunchParamsQuery as E, serializeLaunchParamsQuery as ne } from "@telegram-apps/transformers";
import ae from "mitt";
import { signal as P } from "@telegram-apps/signals";
import { errorClass as b, errorClassWithData as se } from "error-kid";
function B(e) {
return btoa(
encodeURIComponent(e).replace(/%([0-9A-F]{2})/g, (t, r) => String.fromCharCode(parseInt(`0x${r}`)))
).replace(/\+/g, "-").replace(/\//g, "_");
}
function ce(e) {
return decodeURIComponent(
atob(e).replace(/-/g, "+").replace(/_/g, "/").split("").map((t) => "%" + ("00" + t.charCodeAt(0).toString(16)).slice(-2)).join("")
);
}
function Q(e) {
return y(
u({ TelegramWebviewProxy: u({ postEvent: $() }) }),
e
);
}
function K() {
try {
return window.self !== window.top;
} catch {
return !0;
}
}
function ie(e, t) {
const r = ae(), o = /* @__PURE__ */ new Map(), s = (n, a, c) => {
c || (c = !1);
const i = o.get(n) || /* @__PURE__ */ new Map();
o.set(n, i);
const _ = i.get(a) || [];
i.set(a, _);
const l = _.findIndex((m) => m[1] === c);
l >= 0 && (r.off(n, _[l][0]), _.splice(l, 1), !_.length && i.delete(a), i.size || (o.delete(n), !o.size && t()));
};
return [
function(a, c, i) {
!o.size && e();
function _() {
s(a, c, i);
}
function l(...M) {
i && _(), a === "*" ? c(M) : c(...M);
}
r.on(a, l);
const m = o.get(a) || /* @__PURE__ */ new Map();
o.set(a, m);
const S = m.get(c) || [];
return m.set(c, S), S.push([l, i || !1]), _;
},
s,
// eslint-disable-next-line @typescript-eslint/unbound-method
r.emit,
function() {
const a = r.all.size;
r.all.clear(), o.clear(), a && t();
}
];
}
function T(e, t) {
window.dispatchEvent(new MessageEvent("message", {
data: JSON.stringify({ eventType: e, eventData: t }),
// We specify window.parent to imitate the case, the parent iframe sent us this event.
source: window.parent
}));
}
let h = !1;
const q = (e) => {
f().log("Event received:", e);
};
function pe(e) {
e !== h && (h = e, h ? F("*", q) : ue("*", q));
}
const f = P(V("Bridge", {
bgColor: "#9147ff",
textColor: "white",
shouldLog() {
return h;
}
})), _e = {
clipboard_text_received: u({
req_id: w(),
data: d(w())
}),
custom_method_invoked: u({
req_id: w(),
result: C(Z()),
error: C(w())
}),
popup_closed: d(
u({ button_id: d(w(), () => {
}) }),
{}
),
viewport_changed: u({
height: A(),
width: d(A(), () => window.innerWidth),
is_state_stable: x(),
is_expanded: x()
}),
theme_changed: u({
theme_params: oe()
})
};
function L(e) {
if (e.source !== window.parent)
return;
let t;
try {
t = v(j(w(), D(), G), e.data);
} catch {
return;
}
const { eventType: r, eventData: o } = t, s = _e[r];
let n;
try {
n = s ? v(s, o) : o;
} catch (a) {
return f().forceError(
[
`An error occurred processing the "${r}" event from the Telegram application.`,
"Please, file an issue here:",
"https://github.com/Telegram-Mini-Apps/telegram-apps/issues/new/choose"
].join(`
`),
t,
a
);
}
le(r, n);
}
const [
F,
ue,
le,
fe
] = ie(
() => {
const e = window, t = { receiveEvent: T };
e.TelegramGameProxy_receiveEvent = T, e.TelegramGameProxy = t, e.Telegram = { WebView: t }, window.addEventListener("message", L);
},
() => {
["TelegramGameProxy_receiveEvent", "TelegramGameProxy", "Telegram"].forEach((e) => {
delete window[e];
}), window.removeEventListener("message", L);
}
), [
we,
qe
] = b(
"MethodUnsupportedError",
(e, t) => [
`Method "${e}" is unsupported in Mini Apps version ${t}`
]
), [
me,
Le
] = b(
"MethodParameterUnsupportedError",
(e, t, r) => [
`Parameter "${t}" of "${e}" method is unsupported in Mini Apps version ${r}`
]
), [
ge,
Ue
] = se(
"LaunchParamsRetrieveError",
(e) => ({ errors: e }),
(e) => [
[
"Unable to retrieve launch parameters from any known source. Perhaps, you have opened your app outside Telegram?",
"📖 Refer to docs for more information:",
"https://docs.telegram-mini-apps.com/packages/telegram-apps-bridge/environment",
"",
"Collected errors:",
...e.map(([t, r]) => `Source: ${t} / ${r instanceof Error ? r.message : String(r)}`)
].join(`
`)
]
), [
be,
Ie
] = b(
"InvalidLaunchParamsError",
(e, t) => [
`Invalid value for launch params: ${e}`,
{ cause: t }
]
), [de, Re] = b("UnknownEnvError"), [
he,
We
] = b(
"InvokeCustomMethodError",
(e) => [`Server returned error: ${e}`]
), g = P((...e) => {
try {
window.parent.postMessage(...e);
} catch (t) {
t instanceof SyntaxError ? f().forceError(
"Unable to call window.parent.postMessage due to incorrectly configured target origin. Use the setTargetOrigin method to allow this origin to receive events",
t
) : f().forceError(t);
}
}), ye = (...e) => g()(...e), k = P("https://web.telegram.org");
function $e(e) {
k.set(e), f().log("New target origin set", e);
}
function Y(e, t) {
f().log("Posting event:", t ? { eventType: e, eventData: t } : { eventType: e });
const r = window, o = JSON.stringify({ eventType: e, eventData: t });
if (K())
return ye(o, k());
if (Q(r)) {
r.TelegramWebviewProxy.postEvent(e, JSON.stringify(t));
return;
}
if (y(u({ external: u({ notify: $() }) }), r)) {
r.external.notify(o);
return;
}
throw new de();
}
function H(e, t, r) {
r || (r = {});
const { capture: o } = r, [s, n] = ee();
return new N((a) => {
(Array.isArray(t) ? t : [t]).forEach((c) => {
s(
F(c, (i) => {
(!o || (Array.isArray(t) ? o({
event: c,
payload: i
}) : o(i))) && a(i);
})
);
}), (r.postEvent || Y)(e, r.params);
}, r).finally(n);
}
const U = "launchParams";
function I(e) {
return e.replace(/^[^?#]*[?#]/, "").replace(/[?#]/g, "&");
}
function X() {
const e = [];
for (const [t, r] of [
// Try to retrieve launch parameters from the current location. This method can return
// nothing in case, location was changed, and then the page was reloaded.
[() => I(window.location.href), "window.location.href"],
// Then, try using the lower level API - window.performance.
[() => {
const o = performance.getEntriesByType("navigation")[0];
return o && I(o.name);
}, "performance navigation entries"],
[() => te(U), "local storage"]
]) {
const o = t();
if (!o) {
e.push([r, new Error("Source is empty")]);
continue;
}
if (J(o))
return z(U, o), o;
try {
E(o);
} catch (s) {
e.push([r, s]);
}
}
throw new ge(e);
}
function ve(e) {
const t = E(X());
return e ? re(t) : t;
}
function je(e, t) {
if (!e)
try {
return ve(), !0;
} catch {
return !1;
}
return N.fn(async (r) => {
if (Q(window))
return !0;
try {
return await H("web_app_request_theme", "theme_changed", r), !0;
} catch {
return !1;
}
}, t || { timeout: 100 });
}
function Ne({ launchParams: e, onEvent: t, resetPostMessage: r } = {}) {
if (e) {
const n = typeof e == "string" || e instanceof URLSearchParams ? e.toString() : (
// Here we have to trick serializeLaunchParamsQuery into thinking, it serializes a valid
// value. We are doing it because we are working with tgWebAppData presented as a
// string, not an object as serializeLaunchParamsQuery requires.
ne({ ...e, tgWebAppData: void 0 }) + (e.tgWebAppData ? `&tgWebAppData=${encodeURIComponent(e.tgWebAppData.toString())}` : "")
);
if (!J(n))
try {
E(n);
} catch (a) {
throw new be(n, a);
}
z("launchParams", n);
}
if (K()) {
if (!t)
return;
const n = j(
w(),
D(),
G
);
r && g.reset();
const a = g();
g.set((...c) => {
const [i] = c, _ = () => {
a(...c);
};
if (y(n, i)) {
const l = v(n, i);
t([l.eventType, l.eventData], _);
} else
_();
});
return;
}
const o = window.TelegramWebviewProxy || {}, s = o.postEvent || (() => {
});
window.TelegramWebviewProxy = {
...o,
postEvent(n, a) {
const c = () => {
s(n, a);
};
t ? t([n, a ? JSON.parse(a) : void 0], c) : c();
}
}, f().log("Environment was mocked by the mockTelegramEnv function");
}
function ze() {
return new URLSearchParams(X()).get("tgWebAppData") || void 0;
}
function Ee(e) {
return ({ req_id: t }) => t === e;
}
function R(e) {
return e.split(".").map(Number);
}
function Pe(e, t) {
const r = R(e), o = R(t), s = Math.max(r.length, o.length);
for (let n = 0; n < s; n += 1) {
const a = r[n] || 0, c = o[n] || 0;
if (a !== c)
return a > c ? 1 : -1;
}
return 0;
}
function p(e, t) {
return Pe(e, t) <= 0;
}
function W(e, t, r) {
if (typeof r == "string") {
if (e === "web_app_open_link") {
if (t === "try_instant_view")
return p("6.4", r);
if (t === "try_browser")
return p("7.6", r);
}
if (e === "web_app_set_header_color" && t === "color")
return p("6.9", r);
if (e === "web_app_close" && t === "return_back")
return p("7.6", r);
if (e === "web_app_setup_main_button" && t === "has_shine_effect")
return p("7.10", r);
}
switch (e) {
case "web_app_open_tg_link":
case "web_app_open_invoice":
case "web_app_setup_back_button":
case "web_app_set_background_color":
case "web_app_set_header_color":
case "web_app_trigger_haptic_feedback":
return p("6.1", t);
case "web_app_open_popup":
return p("6.2", t);
case "web_app_close_scan_qr_popup":
case "web_app_open_scan_qr_popup":
case "web_app_read_text_from_clipboard":
return p("6.4", t);
case "web_app_switch_inline_query":
return p("6.7", t);
case "web_app_invoke_custom_method":
case "web_app_request_write_access":
case "web_app_request_phone":
return p("6.9", t);
case "web_app_setup_settings_button":
return p("6.10", t);
case "web_app_biometry_get_info":
case "web_app_biometry_open_settings":
case "web_app_biometry_request_access":
case "web_app_biometry_request_auth":
case "web_app_biometry_update_token":
return p("7.2", t);
case "web_app_setup_swipe_behavior":
return p("7.7", t);
case "web_app_share_to_story":
return p("7.8", t);
case "web_app_setup_secondary_button":
case "web_app_set_bottom_bar_color":
return p("7.10", t);
case "web_app_request_safe_area":
case "web_app_request_content_safe_area":
case "web_app_request_fullscreen":
case "web_app_exit_fullscreen":
case "web_app_set_emoji_status":
case "web_app_add_to_home_screen":
case "web_app_check_home_screen":
case "web_app_request_emoji_status_access":
case "web_app_check_location":
case "web_app_open_location_settings":
case "web_app_request_file_download":
case "web_app_request_location":
case "web_app_send_prepared_message":
case "web_app_start_accelerometer":
case "web_app_start_device_orientation":
case "web_app_start_gyroscope":
case "web_app_stop_accelerometer":
case "web_app_stop_device_orientation":
case "web_app_stop_gyroscope":
case "web_app_toggle_orientation_lock":
return p("8.0", t);
default:
return [
"iframe_ready",
"iframe_will_reload",
"web_app_close",
"web_app_data_send",
"web_app_expand",
"web_app_open_link",
"web_app_ready",
"web_app_request_theme",
"web_app_request_viewport",
"web_app_setup_main_button",
"web_app_setup_closing_behavior"
].includes(e);
}
}
function De(e, t) {
t || (t = "strict");
const r = typeof t == "function" ? t : (o) => {
const { method: s, version: n } = o, a = "param" in o ? new me(s, o.param, n) : new we(s, n);
if (t === "strict")
throw a;
return f().forceWarn(a.message);
};
return (o, s) => W(o, e) ? o === "web_app_set_header_color" && y(u({ color: O() }), s) && !W(o, "color", e) ? r({ version: e, method: o, param: "color" }) : Y(o, s) : r({ version: e, method: o });
}
function Ge(e) {
const t = B(e);
if (t.length > 512)
throw new Error("Value is too long for start parameter");
return t;
}
const Je = ce;
function Be(e) {
return B(e).length <= 512;
}
function Qe(e, t, r, o) {
return H("web_app_invoke_custom_method", "custom_method_invoked", {
...o || {},
params: { method: e, params: t, req_id: r },
capture: Ee(r)
}).then(({ result: s, error: n }) => {
if (n)
throw new he(n);
return s;
});
}
function Ke() {
Object.hasOwn || (Object.hasOwn = function(e, t) {
return Object.prototype.hasOwnProperty.call(e, t);
});
}
function Fe() {
fe(), pe(!1), [g, k].forEach((e) => {
e.unsubAll(), e.reset();
});
}
export {
Xe as AbortablePromise,
Ze as CancelledError,
be as InvalidLaunchParamsError,
he as InvokeCustomMethodError,
ge as LaunchParamsRetrieveError,
Oe as ManualPromise,
me as MethodParameterUnsupportedError,
we as MethodUnsupportedError,
Ve as TimeoutError,
de as UnknownEnvError,
Ke as applyPolyfills,
Ee as captureSameReq,
Pe as compareVersions,
ot as createLogger,
De as createPostEvent,
Ge as createStartParam,
ce as decodeBase64Url,
Je as decodeStartParam,
T as emitEvent,
B as encodeBase64Url,
Q as hasWebviewProxy,
Qe as invokeCustomMethod,
et as isCancelledError,
K as isIframe,
Ie as isInvalidLaunchParamsError,
We as isInvokeCustomMethodError,
Ue as isLaunchParamsRetrieveError,
Le as isMethodMethodParameterUnsupportedError,
qe as isMethodUnsupportedError,
Be as isSafeToCreateStartParam,
je as isTMA,
tt as isTimeoutError,
Re as isUnknownEnvError,
f as logger,
Ne as mockTelegramEnv,
ue as off,
fe as offAll,
F as on,
Y as postEvent,
ye as postMessage,
g as postMessageImplementation,
H as request,
Fe as resetPackageState,
ve as retrieveLaunchParams,
ze as retrieveRawInitData,
X as retrieveRawLaunchParams,
pe as setDebug,
$e as setTargetOrigin,
W as supports,
k as targetOrigin
};
//# sourceMappingURL=index.js.map