@telegram-apps/sdk
Version:
TypeScript Source Development Kit for Telegram Mini Apps client application.
1 lines • 235 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/signals-registry.ts","../src/debug.ts","../src/logger.ts","../src/globals.ts","../src/scopes/createIsSupported.ts","../src/errors.ts","../src/utils/isSSR.ts","../src/scopes/wrappers/wrapSafe.ts","../src/scopes/wrappers/createWrapSafe.ts","../src/scopes/wrappers/createWrapComplete.ts","../src/scopes/wrappers/createWrapSupported.ts","../src/scopes/components/back-button/back-button.ts","../src/scopes/defineNonConcurrentFn.ts","../src/scopes/defineMountFn.ts","../src/scopes/components/biometry/signals.ts","../src/scopes/components/biometry/requestBiometry.ts","../src/utils/ignoreCanceled.ts","../src/scopes/signalCancel.ts","../src/scopes/components/biometry/methods.ts","../src/scopes/wrappers/createWrapMounted.ts","../src/scopes/wrappers/createWrapBasic.ts","../src/scopes/components/closing-behavior/closing-behavior.ts","../src/scopes/components/cloud-storage/cloud-storage.ts","../src/scopes/components/haptic-feedback/haptic-feedback.ts","../src/scopes/components/init-data/init-data.ts","../src/scopes/components/invoice/invoice.ts","../src/scopes/components/location-manager/location-manager.ts","../src/utils/removeUndefined.ts","../src/utils/isColorDark.ts","../src/scopes/components/theme-params/signals.ts","../src/scopes/components/main-button/signals.ts","../src/scopes/components/main-button/methods.ts","../src/utils/css-vars.ts","../src/scopes/components/theme-params/methods.ts","../src/scopes/components/mini-app/utils.ts","../src/scopes/components/mini-app/signals.ts","../src/scopes/components/mini-app/methods.ts","../src/scopes/components/popup/prepareParams.ts","../src/scopes/components/popup/popup.ts","../src/scopes/components/qr-scanner/qr-scanner.ts","../src/scopes/components/secondary-button/signals.ts","../src/scopes/components/secondary-button/methods.ts","../src/scopes/components/settings-button/settings-button.ts","../src/scopes/components/swipe-behavior/swipe-behavior.ts","../src/scopes/components/viewport/const.ts","../src/scopes/components/viewport/wrappers.ts","../src/scopes/components/viewport/signals.ts","../src/scopes/components/viewport/static.ts","../src/scopes/components/viewport/mounting.ts","../src/scopes/components/viewport/css-vars.ts","../src/scopes/components/viewport/expand.ts","../src/scopes/components/viewport/fullscreen.ts","../src/scopes/utilities/emoji-status/requestEmojiStatusAccess.ts","../src/scopes/utilities/emoji-status/setEmojiStatus.ts","../src/scopes/utilities/home-screen/add-to-home-screen-failed.ts","../src/scopes/utilities/home-screen/added-to-home-screen.ts","../src/scopes/utilities/home-screen/addToHomeScreen.ts","../src/scopes/utilities/home-screen/checkHomeScreenStatus.ts","../src/scopes/utilities/links/openLink.ts","../src/scopes/utilities/links/openTelegramLink.ts","../src/scopes/utilities/links/shareURL.ts","../src/utils/sleep.ts","../src/scopes/utilities/privacy/requestPhoneAccess.ts","../src/scopes/utilities/privacy/requestContact.ts","../src/scopes/utilities/privacy/requestWriteAccess.ts","../src/scopes/utilities/uncategorized/copyTextToClipboard.ts","../src/scopes/utilities/uncategorized/downloadFile.ts","../src/scopes/utilities/uncategorized/getCurrentTime.ts","../src/scopes/utilities/uncategorized/readTextFromClipboard.ts","../src/scopes/utilities/uncategorized/retrieveAndroidDeviceDataFrom.ts","../src/scopes/utilities/uncategorized/retrieveAndroidDeviceData.ts","../src/scopes/utilities/uncategorized/sendData.ts","../src/scopes/utilities/uncategorized/shareMessage.ts","../src/scopes/utilities/uncategorized/shareStory.ts","../src/scopes/utilities/uncategorized/switchInlineQuery.ts","../src/utils/safeCall.ts","../src/init.ts"],"sourcesContent":["import {\n computed,\n type Computed,\n type Signal,\n signal,\n type SignalOptions,\n} from '@telegram-apps/signals';\n\nexport type SignalsTuple<T> = [Signal<T>, Computed<T>];\n\nconst signals: (Signal<any> | Computed<any>)[] = [];\n\n/**\n * Creates a new signal with the initial value.\n * @param initialValue - the initial value.\n * @param options - additional options.\n */\nexport function createSignal<T>(\n initialValue: T,\n options?: SignalOptions<T>,\n): Signal<T>;\n\n/**\n * Creates a new signal without the initial value.\n * @param initialValue - the initial value.\n * @param options - additional options.\n */\nexport function createSignal<T>(\n initialValue?: T,\n options?: SignalOptions<T | undefined>,\n): Signal<T | undefined>;\n\n// #__NO_SIDE_EFFECTS__\nexport function createSignal<T>(\n initialValue?: T,\n options?: SignalOptions<T | undefined>,\n): Signal<T | undefined> {\n const s = signal(initialValue, options);\n signals.push(s);\n return s;\n}\n\n/**\n * Creates a signal, which wil be automatically updated if some of its dependant signals were\n * modified.\n * @param fn - computation function.\n * @param options - additional functions.\n */\n// #__NO_SIDE_EFFECTS__\nexport function createComputed<T>(fn: (prev?: T) => T, options?: SignalOptions<T>): Computed<T> {\n const s = computed(fn, options);\n signals.push(s);\n return s;\n}\n\n/**\n * Resets all signals states.\n */\nexport function resetSignals() {\n signals.forEach(s => {\n s.unsubAll();\n 'reset' in s && s.reset();\n });\n}\n\n/**\n * @returns A tuple, containing a manual and computed signals. The computed signal is based on\n * the manual one.\n * @param initialValue - the initial value.\n * @param options - additional options.\n */\nexport function createSignalsTuple<T>(\n initialValue: T,\n options?: SignalOptions<T>,\n): SignalsTuple<T>;\n\n/**\n * @returns A tuple, containing a manual and computed signals. The computed signal is based on\n * the manual one.\n * @param initialValue - an initial value.\n * @param options - additional options.\n */\nexport function createSignalsTuple<T>(\n initialValue?: T,\n options?: SignalOptions<T | undefined>,\n): SignalsTuple<T | undefined>;\n\n// #__NO_SIDE_EFFECTS__\nexport function createSignalsTuple<T>(\n initialValue?: T,\n options?: SignalOptions<T | undefined>,\n): SignalsTuple<T | undefined> {\n const s = createSignal(initialValue, options);\n return [s, createComputed(s)];\n}","import { setDebug as setBridgeDebug } from '@telegram-apps/bridge';\n\n/**\n * The package debug mode.\n *\n * Enabling debug mode leads to printing additional messages in the console related to the\n * processes inside the package.\n */\nexport let debug = false;\n\n/**\n * Sets the package debug mode leading to outputting additional logs. This function also modifies\n * debug mode set in the `@telegram-apps/bridge` package.\n * @param value - enable debug mode.\n */\nexport function setDebug(value: boolean): void {\n debug = value;\n setBridgeDebug(value);\n}","import { createLogger, type Logger } from '@telegram-apps/toolkit';\nimport { signal } from '@telegram-apps/signals';\n\nimport { debug } from '@/debug.js';\n\nexport type { Logger };\nexport const logger = signal<Logger>(createLogger('Bridge', {\n bgColor: 'forestgreen',\n textColor: 'white',\n shouldLog() {\n return debug;\n },\n}));\n","import {\n retrieveLaunchParams,\n postEvent as _postEvent,\n request as _request,\n invokeCustomMethod as _invokeCustomMethod,\n createPostEvent,\n type PostEventFn,\n type RequestFn,\n type InvokeCustomMethodOptions,\n type CustomMethodParams,\n type CustomMethodName,\n} from '@telegram-apps/bridge';\nimport type { AbortablePromise } from 'better-promises';\nimport type { LaunchParamsLike } from '@telegram-apps/transformers';\n\nimport { createComputed, createSignal, createSignalsTuple } from '@/signals-registry.js';\nimport { logger } from '@/logger.js';\n\n/**\n * Launch parameters stored in the package state.\n */\nexport type PackageLaunchParams =\n & Omit<LaunchParamsLike, 'tgWebAppThemeParams'>\n & Partial<Pick<LaunchParamsLike, 'tgWebAppThemeParams'>>;\n\nexport interface ConfigureOptions {\n /**\n * Launch parameters used across the package.\n * @default Being extracted using the `retrieveLaunchParams` function.\n * @see retrieveLaunchParams\n */\n launchParams?: PackageLaunchParams;\n /**\n * Custom postEvent function.\n * @default The `createPostEvent` function will be used with the version, specified in\n * the `launchParams` option.\n * @see createPostEvent\n */\n postEvent?: PostEventFn;\n}\n\nconst $lastRequestId = createSignal(0);\nexport const $postEvent = createSignal<PostEventFn>(_postEvent);\nexport const [_$launchParams, $launchParams] = createSignalsTuple<PackageLaunchParams>({\n tgWebAppPlatform: 'unknown',\n tgWebAppVersion: '0.0',\n});\n\nexport const version = createComputed(() => $launchParams().tgWebAppVersion);\n\n/**\n * Configures package global dependencies.\n * @param options - configuration additional options.\n */\nexport function configure(options?: ConfigureOptions): void {\n options ||= {};\n const { postEvent } = options;\n const lp = options.launchParams || retrieveLaunchParams();\n _$launchParams.set(lp);\n $postEvent.set(\n typeof postEvent === 'function'\n ? postEvent\n : createPostEvent(lp.tgWebAppVersion),\n );\n logger().log('The package was configured. Launch params:', _$launchParams());\n}\n\n/**\n * @returns A new request identifier.\n */\nexport function createRequestId(): string {\n $lastRequestId.set($lastRequestId() + 1);\n return $lastRequestId().toString();\n}\n\n/**\n * Invokes known custom method. Returns method execution result.\n * @param method - method name.\n * @param params - method parameters.\n * @param options - additional options.\n * @throws {InvokeCustomMethodError} Invocation completed with some error.\n */\nexport function invokeCustomMethod<M extends CustomMethodName>(\n method: M,\n params: CustomMethodParams<M>,\n options?: InvokeCustomMethodOptions,\n): AbortablePromise<unknown>;\n\n/**\n * Invokes unknown custom method. Returns method execution result.\n * @param method - method name.\n * @param params - method parameters.\n * @param options - additional options.\n * @throws {InvokeCustomMethodError} Invocation completed with some error.\n */\nexport function invokeCustomMethod(\n method: string,\n params: object,\n options?: InvokeCustomMethodOptions,\n): AbortablePromise<unknown>;\n\nexport function invokeCustomMethod(\n method: string,\n params: object,\n options?: InvokeCustomMethodOptions,\n): AbortablePromise<unknown> {\n return _invokeCustomMethod(method, params, createRequestId(), {\n ...options || {},\n postEvent: postEvent,\n });\n}\n\n/**\n * `request` function from the bridge with applied global `postEvent` option.\n */\nexport const request = ((method: any, eventOrEvents: any, options: any) => {\n options ||= {};\n options.postEvent ||= postEvent;\n return _request(method, eventOrEvents, options);\n}) as RequestFn;\n\n/**\n * Shortcut for $postEvent call.\n */\nexport const postEvent = ((method: any, params: any) => {\n return $postEvent()(method, params);\n}) as PostEventFn;\n","import { type Computed } from '@telegram-apps/signals';\nimport { type MethodName, supports } from '@telegram-apps/bridge';\n\nimport { version } from '@/globals.js';\nimport { createComputed } from '@/signals-registry.js';\n\n/**\n * @returns A signal indicating if the specified Mini Apps method is supported.\n * @param method - Mini Apps method name\n */\nexport function createIsSupported(method: MethodName): Computed<boolean> {\n return createComputed(() => supports(method, version()));\n}","import { errorClass } from 'error-kid';\n\nfunction proxyMessage(message?: string): [string?] {\n return [message];\n}\n\nexport const [\n CSSVarsBoundError,\n isCSSVarsBoundError,\n] = errorClass('CSSVarsBoundError', 'CSS variables are already bound');\n\nexport const [\n NotAvailableError,\n isNotAvailableError,\n] = errorClass<[message: string]>('NotAvailableError', proxyMessage);\n\nexport const [\n InvalidEnvError,\n isInvalidEnvError,\n] = errorClass<[message?: string]>('InvalidEnvError', proxyMessage);\n\nexport const [\n FunctionUnavailableError,\n isFunctionNotAvailableError,\n] = errorClass<[message?: string]>('FunctionNotAvailableError', proxyMessage);\n\nexport const [\n InvalidArgumentsError,\n isInvalidArguments,\n] = errorClass<[message: string, cause?: unknown]>(\n 'InvalidArgumentsError',\n (message, cause) => [message, { cause }],\n);\n\nexport const [\n ConcurrentCallError,\n isConcurrentCallError,\n] = errorClass<[message: string]>('ConcurrentCallError', proxyMessage);\n\nexport const [\n SetEmojiStatusError,\n isSetEmojiStatusError,\n] = errorClass<[error: string]>(\n 'SetEmojiStatusError',\n error => [`Failed to set emoji status: ${error}`],\n);\n\nexport const [\n AccessDeniedError,\n isAccessDeniedError,\n] = errorClass<[message: string]>('AccessDeniedError', proxyMessage);\n\nexport const [\n FullscreenFailedError,\n isFullscreenFailedError,\n] = errorClass<[message: string]>('FullscreenFailedError', proxyMessage);\n\nexport const [\n ShareMessageError,\n isShareMessageError,\n] = errorClass<[error: string]>('ShareMessageError', proxyMessage);\n\nexport const [\n UnknownThemeParamsKeyError,\n isUnknownThemeParamsKeyError,\n] = errorClass<[key: string]>('UnknownThemeParamsKeyError', key => {\n return [`Unknown theme params key passed: ${key}`];\n});","/**\n * @returns True, if current environment is server.\n */\nexport function isSSR(): boolean {\n return typeof window === 'undefined';\n}\n","import {\n type MethodName,\n supports,\n isTMA,\n type MethodNameWithVersionedParams,\n type MethodVersionedParams,\n} from '@telegram-apps/bridge';\nimport type { Computed } from '@telegram-apps/signals';\nimport type { If, IsNever } from '@telegram-apps/toolkit';\n\nimport { version } from '@/globals.js';\nimport { FunctionUnavailableError } from '@/errors.js';\nimport { isSSR } from '@/utils/isSSR.js';\nimport type { AnyFn } from '@/types.js';\nimport { createComputed } from '@/signals-registry.js';\n\nexport type CustomSupportValidatorFn = () => string | undefined;\n\nexport type IsSupportedType =\n | MethodName\n | CustomSupportValidatorFn\n | (MethodName | CustomSupportValidatorFn)[]\n | { any: (MethodName | CustomSupportValidatorFn)[] };\n\n/**\n * A map where the key is a method name with versioned parameters, and the value is a tuple\n * containing the method and parameter names. The third tuple value is a function accepting\n * the wrapped function arguments and returning true if support check must be applied.\n */\nexport type Supports<Fn extends AnyFn> = Record<string, {\n [M in MethodNameWithVersionedParams]: [\n method: M,\n param: MethodVersionedParams<M>,\n shouldCheck: (...args: Parameters<Fn>) => boolean,\n ];\n}[MethodNameWithVersionedParams]>;\n\nexport type IfAvailableFnResult<Data> = [called: true, data: Data] | [called: false];\n\nexport type SafeWrapped<\n Fn extends AnyFn,\n HasSupportCheck extends boolean,\n SupportsSchema extends Record<string, any>\n> =\n & Fn\n & {\n /**\n * The signal returning `true` if the function is available in the current environment and\n * conditions.\n *\n * To be more accurate, the method checks the following:\n * 1. The current environment is Telegram Mini Apps.\n * 2. The SDK package is initialized.\n * 3. If passed, the `isSupported` signal returns true.\n * 4. If passed, the `isMounted` signal returns true.\n *\n * *You should use this function when possible because it provides must-have code security\n * mechanisms and makes a developer sure that he is using the package properly.*\n *\n * @returns True if the function is available in the current environment.\n * @example\n * if (showBackButton.isAvailable()) {\n * showBackButton();\n * }\n */\n isAvailable: Computed<boolean>;\n /**\n * Calls the function only in case it is available.\n *\n * It uses the `isAvailable` internally to check if the function is supported.\n * @example\n * showBackButton.ifAvailable();\n */\n ifAvailable(...args: Parameters<Fn>): IfAvailableFnResult<ReturnType<Fn>>;\n}\n & If<HasSupportCheck, {\n /**\n * The signal returning `true` if the function is supported by the Telegram client,\n * including some possible additional conditions.\n *\n * It is highly recommended to use this signal only in certain narrow cases when only the\n * function support check is required, but not its availability.\n *\n * This signal is not applying additional operations like checking if the current environment\n * is Mini Apps and the SDK is initialized.\n *\n * To check if the function is available for use, use the `isAvailable` signal.\n *\n * @returns True if this function is supported.\n * @see isAvailable\n * @example\n * if (setMiniAppBottomBarColor.isSupported()) {\n * console.log('Mini App bottom bar is supported, but the function may be unavailable');\n * }\n */\n isSupported: Computed<boolean>;\n}, {}>\n & If<IsNever<SupportsSchema>, {}, {\n /**\n * A map where the key is the function-specific option name and value is a signal indicating\n * if it is supported by the current environment.\n * @example\n * if (setHeaderColor.isAvailable()) {\n * if (setHeaderColor.supports.rgb()) {\n * setHeaderColor('#ffaabb');\n * } else {\n * setHeaderColor('bg_color');\n * }\n * }\n */\n supports: Record<keyof SupportsSchema, Computed<boolean>>\n}>\n\nexport interface WrapSafeOptions<Fn extends AnyFn> {\n /**\n * The component name owning the wrapped function.\n */\n component?: string;\n /**\n * Signal returning true if the owning component is mounted.\n */\n isMounted?: () => boolean;\n /**\n * Signal returning true if the owning component is mounting.\n */\n isMounting?: () => boolean;\n /**\n * Value determining if the function is supported by the current environment.\n */\n isSupported?: IsSupportedType;\n /**\n * A map where the key is a method name with versioned parameters, and the value is a tuple\n * containing the method and parameter names. The third tuple value is a function accepting\n * the wrapped function arguments and returning true if support check must be applied.\n */\n supports?: Supports<Fn>,\n}\n\n/**\n * Wraps the function enhancing it with the useful utilities described in the SafeWrapped type.\n * @see SafeWrapped\n * @param method - method name\n * @param fn - wrapped function\n */\nexport function wrapSafe<Fn extends AnyFn>(method: string, fn: Fn): SafeWrapped<Fn, false, never>;\n/**\n * Wraps the function enhancing it with the useful utilities described in the SafeWrapped type.\n * @see SafeWrapped\n * @param method - method name\n * @param fn - wrapped function\n * @param options - additional options\n */\nexport function wrapSafe<Fn extends AnyFn, O extends WrapSafeOptions<Fn>>(\n method: string,\n fn: Fn,\n options: O,\n): SafeWrapped<\n Fn,\n O extends { isSupported: any } ? true : false,\n O extends { supports: any } ? O['supports'] : never\n>\n/*@__NO_SIDE_EFFECTS__*/\nexport function wrapSafe<Fn extends AnyFn>(\n method: string,\n fn: Fn,\n options?: WrapSafeOptions<Fn>,\n): SafeWrapped<Fn, boolean, Record<string, any> | never> {\n options ||= {};\n const {\n isSupported: optionsIsSupported,\n isMounted,\n isMounting,\n component,\n supports: optionSupports,\n } = options || {};\n\n const functionId = `${component ? `${component}.` : ''}${method}()`;\n\n // Simplify the isSupported value to work with an array of validators or a single object.\n const isSupported = optionsIsSupported\n ? Array.isArray(optionsIsSupported)\n // (MethodName | CustomSupportValidator)[]\n ? optionsIsSupported\n : typeof optionsIsSupported === 'object' && 'any' in optionsIsSupported\n // { any: (MethodName | CustomSupportValidator)[] }\n ? optionsIsSupported\n // MethodName | CustomSupportValidator\n : [optionsIsSupported]\n : undefined;\n\n /**\n * @returns True if the specified option is supported.\n * @param option - option name.\n */\n function supportsOption(option: string): boolean {\n if (optionSupports) {\n const tuple = optionSupports[option];\n return supports(tuple[0], tuple[1], version());\n }\n return true;\n }\n\n /**\n * @returns All found errors according to the isSupported variable value.\n */\n function supportError(): string | undefined {\n // isSupported was not specified.\n // In this case, we assume that the function has no dependencies and is always supported.\n if (!isSupported) {\n return;\n }\n\n function getError(item: MethodName | CustomSupportValidatorFn): string | undefined {\n return typeof item === 'function'\n ? item()\n : supports(item, version())\n ? undefined\n : `it is unsupported in Mini Apps version ${version()}`;\n }\n\n const isSupportedItems = Array.isArray(isSupported) ? isSupported : isSupported.any;\n const errors = isSupportedItems.map(getError).filter(Boolean) as string[];\n\n return Array.isArray(isSupported)\n // An array is passed. It means, the function is supported only in case no errors were\n // returned.\n ? errors[0]\n // An object with the \"any\" property is passed.\n // Should return nothing if at least one item didn't return an error.\n : errors.length === isSupportedItems.length\n ? errors[errors.length - 1]\n : undefined;\n }\n\n /**\n * @returns An error related to supports.<name> check.\n */\n function supportsOptionError(...args: Parameters<Fn>): string | undefined {\n for (const k in optionSupports) {\n if (optionSupports[k][2](...args) && !supportsOption(k)) {\n return `option ${k} is not supported in Mini Apps version ${version()}`;\n }\n }\n }\n\n let supportsMap: Record<string, Computed<boolean>> | undefined;\n if (optionSupports) {\n supportsMap = {};\n for (const option in optionSupports) {\n supportsMap[option] = createComputed(() => supportsOption(option));\n }\n }\n\n const $isSupported = createComputed(() => !supportError());\n const $isInitialized = createComputed(() => version() !== '0.0');\n const $isMounted = createComputed(() => !isMounted || isMounted());\n const $isAvailable = createComputed(\n () => isTMA()\n && !isSSR()\n && $isInitialized()\n && $isSupported()\n && $isMounted(),\n );\n\n return Object.assign(\n (...args: Parameters<Fn>): ReturnType<Fn> => {\n const errMessagePrefix = `Unable to call the ${functionId} ${component ? 'method' : 'function'}:`;\n\n if (isSSR() || !isTMA()) {\n throw new FunctionUnavailableError(`${errMessagePrefix} it can't be called outside Mini Apps`);\n }\n if (!$isInitialized()) {\n throw new FunctionUnavailableError(`${errMessagePrefix} the SDK was not initialized. Use the SDK init() function`);\n }\n const supportErr = supportError();\n if (supportErr) {\n throw new FunctionUnavailableError(`${errMessagePrefix} ${supportErr}`);\n }\n const supportsOptionErr = supportsOptionError(...args);\n if (supportsOptionErr) {\n throw new FunctionUnavailableError(`${errMessagePrefix} ${supportsOptionErr}`);\n }\n if (!$isMounted()) {\n const message = isMounting && isMounting()\n ? 'mounting. Wait for the mount completion'\n : `unmounted. Use the ${component}.mount() method`;\n throw new FunctionUnavailableError(`${errMessagePrefix} the component is ${message}`);\n }\n return fn(...args);\n },\n fn,\n {\n isAvailable: $isAvailable,\n ifAvailable(...args: Parameters<Fn>): IfAvailableFnResult<ReturnType<Fn>> {\n return $isAvailable() ? [true, fn(...args)] : [false];\n },\n },\n isSupported ? { isSupported: $isSupported } : {},\n supportsMap ? { supports: supportsMap } : {},\n );\n}\n","import type { AnyFn } from '@/types.js';\nimport {\n wrapSafe,\n type IsSupportedType,\n type SafeWrapped,\n type Supports,\n} from '@/scopes/wrappers/wrapSafe.js';\n\nexport interface SafeWrapFn<S extends boolean> {\n <Fn extends AnyFn>(method: string, fn: Fn): SafeWrapped<Fn, S, never>;\n <Fn extends AnyFn>(method: string, fn: Fn, isSupported: IsSupportedType): SafeWrapped<Fn, true, never>;\n <Fn extends AnyFn, S extends Supports<Fn>>(\n method: string,\n fn: Fn,\n isSupported: IsSupportedType,\n supports: S,\n ): SafeWrapped<Fn, true, S>;\n}\n\ninterface Options {\n isMounted?: () => boolean;\n isSupported?: IsSupportedType;\n}\n\nexport function createWrapSafe(component?: string): SafeWrapFn<false>;\n\nexport function createWrapSafe<O extends Options>(\n component: string,\n options: O,\n): SafeWrapFn<O extends { isSupported: any } ? true : false>;\n\nexport function createWrapSafe(\n component?: string,\n options?: Options,\n): SafeWrapFn<boolean> {\n options ||= {};\n return ((method, fn, overrideIsSupported, supports) => wrapSafe(method, fn, {\n ...options,\n isSupported: overrideIsSupported || options.isSupported,\n supports,\n component,\n })) as SafeWrapFn<boolean>;\n}\n","import type { IsSupportedType } from '@/scopes/wrappers/wrapSafe.js';\nimport { createWrapSafe, type SafeWrapFn } from '@/scopes/wrappers/createWrapSafe.js';\n\nexport function createWrapComplete(\n component: string,\n isMounted: () => boolean,\n isSupported: IsSupportedType,\n): SafeWrapFn<true> {\n return createWrapSafe(component, { isSupported, isMounted });\n}\n","import {\n createWrapSafe,\n type SafeWrapFn,\n} from '@/scopes/wrappers/createWrapSafe.js';\nimport type { IsSupportedType } from '@/scopes/wrappers/wrapSafe.js';\n\nexport function createWrapSupported(\n component: string,\n isSupported: IsSupportedType,\n): SafeWrapFn<true> {\n return createWrapSafe(component, { isSupported });\n}","import { off, on, type EventListener } from '@telegram-apps/bridge';\nimport { getStorageValue, setStorageValue } from '@telegram-apps/toolkit';\nimport { isPageReload } from '@telegram-apps/navigation';\n\nimport { createSignalsTuple } from '@/signals-registry.js';\nimport { postEvent } from '@/globals.js';\nimport { createIsSupported } from '@/scopes/createIsSupported.js';\nimport { createWrapComplete } from '@/scopes/wrappers/createWrapComplete.js';\nimport { createWrapSupported } from '@/scopes/wrappers/createWrapSupported.js';\n\ntype StorageValue = boolean;\n\nconst SETUP_METHOD_NAME = 'web_app_setup_back_button';\nconst CLICK_EVENT_NAME = 'back_button_pressed';\nconst COMPONENT_NAME = 'backButton';\n\n/**\n * Signal indicating if the Back Button is currently visible.\n */\nexport const [_isVisible, isVisible] = createSignalsTuple(false);\n\n/**\n * Signal indicating if the Back Button is currently mounted.\n */\nexport const [_isMounted, isMounted] = createSignalsTuple(false);\n\n/**\n * Signal indicating if the Back Button is supported.\n */\nexport const isSupported = createIsSupported(SETUP_METHOD_NAME);\n\nconst wrapComplete = createWrapComplete(COMPONENT_NAME, _isMounted, SETUP_METHOD_NAME);\nconst wrapSupported = createWrapSupported(COMPONENT_NAME, SETUP_METHOD_NAME);\n\n/**\n * Hides the Back Button.\n * @param\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @since Mini Apps v6.1\n * @example\n * if (hide.isAvailable()) {\n * hide();\n * }\n */\nexport const hide = wrapComplete('hide', (): void => {\n setVisibility(false);\n});\n\n/**\n * Mounts the Back Button restoring its state.\n * @param\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @since Mini Apps v6.1\n * @example\n * if (mount.isAvailable()) {\n * mount();\n * }\n */\nexport const mount = wrapSupported('mount', (): void => {\n if (!_isMounted()) {\n setVisibility(isPageReload() && getStorageValue<StorageValue>(COMPONENT_NAME) || false);\n _isMounted.set(true);\n }\n});\n\nfunction setVisibility(value: boolean): void {\n if (value !== _isVisible()) {\n postEvent(SETUP_METHOD_NAME, { is_visible: value });\n setStorageValue<StorageValue>(COMPONENT_NAME, value);\n _isVisible.set(value);\n }\n}\n\n/**\n * Adds a new Back Button click listener.\n * @param fn - event listener.\n * @returns A function to remove bound listener.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @since Mini Apps v6.1\n * @example\n * if (onClick.isAvailable()) {\n * const off = onClick(() => {\n * console.log('User clicked the Back Button');\n * off();\n * });\n * }\n */\nexport const onClick = wrapSupported(\n 'onClick',\n (fn: EventListener<'back_button_pressed'>): VoidFunction => on(CLICK_EVENT_NAME, fn),\n);\n\n/**\n * Removes the Back Button click listener.\n * @param fn - an event listener.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @since Mini Apps v6.1\n * @example\n * if (offClick.isAvailable()) {\n * function listener() {\n * console.log('User clicked the Back Button');\n * offClick(listener);\n * }\n * onClick(listener);\n * }\n */\nexport const offClick = wrapSupported(\n 'offClick',\n (fn: EventListener<'back_button_pressed'>): void => {\n off(CLICK_EVENT_NAME, fn);\n },\n);\n\n/**\n * Shows the Back Button.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @since Mini Apps v6.1\n * @example\n * if (show.isAvailable()) {\n * show();\n * }\n */\nexport const show = wrapComplete('show', (): void => {\n setVisibility(true);\n});\n\n/**\n * Unmounts the Back Button.\n *\n * Note that this function does not remove listeners added via the `onClick`\n * function, so you have to remove them on your own.\n * @see onClick\n */\nexport function unmount(): void {\n _isMounted.set(false);\n}\n","import { AbortablePromise } from 'better-promises';\nimport {\n batch,\n type Computed,\n type Signal,\n} from '@telegram-apps/signals';\nimport { createComputed, createSignalsTuple, type SignalsTuple } from '@/signals-registry.js';\nimport { ConcurrentCallError } from '@/errors.js';\n\nexport function defineNonConcurrentFn<Fn extends (...args: any) => AbortablePromise<any>>(\n fn: Fn,\n errorMessage: string,\n options?: {\n /**\n * A signal with the promise to use instead of the generated one.\n */\n promise?: Signal<AbortablePromise<Awaited<ReturnType<Fn>>> | undefined>;\n /**\n * A signal with the error to use instead of the generated one.\n */\n error?: Signal<Error | undefined>;\n },\n): [\n fn: Fn,\n promise: [\n ...SignalsTuple<AbortablePromise<Awaited<ReturnType<Fn>>> | undefined>,\n isRequesting: Computed<boolean>,\n ],\n error: SignalsTuple<Error | undefined>\n] {\n options ||= {};\n const {\n promise: optionsPromise,\n error: optionsError,\n } = options;\n const [_promise, promise] =\n optionsPromise\n ? [optionsPromise, createComputed(optionsPromise)]\n : createSignalsTuple<AbortablePromise<Awaited<ReturnType<Fn>>> | undefined>();\n const [_error, error] =\n optionsError\n ? [optionsError, createComputed(optionsError)]\n : createSignalsTuple<Error | undefined>();\n\n return [\n Object.assign((...args: Parameters<Fn>): AbortablePromise<Awaited<ReturnType<Fn>>> => {\n if (_promise()) {\n const err = new ConcurrentCallError(errorMessage);\n _error.set(err);\n return AbortablePromise.reject(err);\n }\n\n batch(() => {\n _promise.set(fn(...args));\n _error.set(undefined);\n });\n\n let error: Error | undefined;\n return _promise()!\n .catch(e => {\n error = e;\n throw e;\n })\n .finally(() => {\n batch(() => {\n _promise.set(undefined);\n _error.set(error);\n });\n });\n }, fn),\n [_promise, promise, createComputed(() => !!_promise())],\n [_error, error],\n ];\n}","import { batch, type Computed } from '@telegram-apps/signals';\nimport { AbortablePromise } from 'better-promises';\n\nimport { defineNonConcurrentFn } from '@/scopes/defineNonConcurrentFn.js';\nimport { createSignalsTuple, type SignalsTuple } from '@/signals-registry.js';\n\n/**\n * Creates a mount function for a component.\n * @param component - the component name\n * @param mount - function mounting the component\n * @param onMounted - function that will be called whenever mount was completed.\n */\n// #__NO_SIDE_EFFECTS__\nexport function defineMountFn<Fn extends (...args: any) => AbortablePromise<any>>(\n component: string,\n mount: Fn,\n onMounted: (result: Awaited<ReturnType<Fn>>) => void,\n): [\n fn: (...args: Parameters<Fn>) => AbortablePromise<void>,\n promise: [\n ...SignalsTuple<AbortablePromise<Awaited<ReturnType<Fn>>> | undefined>,\n isRequesting: Computed<boolean>,\n ],\n error: SignalsTuple<Error | undefined>,\n isMounted: SignalsTuple<boolean>,\n] {\n const [fn, ...rest] =\n defineNonConcurrentFn(mount, `The ${component} component is already mounting`);\n const [_isMounted, isMounted] = createSignalsTuple(false);\n\n return [\n (...args) => _isMounted()\n ? AbortablePromise.resolve()\n : fn(...args).then(data => {\n batch(() => {\n _isMounted.set(true);\n onMounted(data);\n });\n }),\n ...rest,\n [_isMounted, isMounted],\n ];\n}\n","import { createComputed, createSignalsTuple } from '@/signals-registry.js';\n\nimport type { State } from './types.js';\n\n/**\n * Complete biometry manager state.\n */\nexport const [_state, state] = createSignalsTuple<State>({\n available: false,\n type: '',\n accessGranted: false,\n accessRequested: false,\n deviceId: '',\n tokenSaved: false,\n});\n\n/**\n * Signal indicating biometry is available.\n */\nexport const isAvailable = createComputed(() => _state().available);\n","import type { EventPayload } from '@telegram-apps/bridge';\nimport type { AbortablePromise } from 'better-promises';\n\nimport { request } from '@/globals.js';\nimport { wrapSafe } from '@/scopes/wrappers/wrapSafe.js';\nimport type { RequestOptionsNoCapture } from '@/types.js';\n\nconst METHOD_NAME = 'web_app_biometry_get_info';\n\n/**\n * Requests biometry information.\n * @since Mini Apps v7.2\n * @param options - additional execution options.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @example\n * if (requestBiometry.isAvailable()) {\n * const biometryState = await requestBiometry();\n * }\n */\nexport const requestBiometry = wrapSafe(\n 'requestBiometry',\n (options?: RequestOptionsNoCapture): AbortablePromise<EventPayload<'biometry_info_received'>> => {\n return request(METHOD_NAME, 'biometry_info_received', options);\n },\n { isSupported: METHOD_NAME },\n);\n","import { isCancelledError } from 'better-promises';\n\n/**\n * Throw the value if is not CanceledError.\n * @param e - value to check.\n */\nexport function ignoreCanceled(e: unknown): never | void {\n if (!isCancelledError(e)) {\n throw e;\n }\n}","import type { AbortablePromise } from 'better-promises';\nimport { ignoreCanceled } from '@/utils/ignoreCanceled.js';\n\n/**\n * Cancels the promise stored in the signal.\n * @param signal - signal with promise.\n */\nexport function signalCancel(signal: () => (AbortablePromise<any> | undefined)): void {\n const p = signal();\n p && p.catch(ignoreCanceled).cancel();\n}","import {\n on,\n off,\n type BiometryTokenUpdateStatus,\n type BiometryAuthRequestStatus,\n type EventListener,\n type EventPayload,\n} from '@telegram-apps/bridge';\nimport { isPageReload } from '@telegram-apps/navigation';\nimport { getStorageValue, setStorageValue } from '@telegram-apps/toolkit';\nimport { AbortablePromise } from 'better-promises';\n\nimport { postEvent, request } from '@/globals.js';\nimport { defineMountFn } from '@/scopes/defineMountFn.js';\nimport { createIsSupported } from '@/scopes/createIsSupported.js';\nimport { createWrapComplete } from '@/scopes/wrappers/createWrapComplete.js';\nimport { createWrapSupported } from '@/scopes/wrappers/createWrapSupported.js';\nimport { defineNonConcurrentFn } from '@/scopes/defineNonConcurrentFn.js';\nimport { NotAvailableError } from '@/errors.js';\n\nimport { _state } from './signals.js';\nimport { requestBiometry } from './requestBiometry.js';\nimport type {\n State,\n AuthenticateOptions,\n RequestAccessOptions,\n UpdateTokenOptions,\n} from './types.js';\nimport { signalCancel } from '@/scopes/signalCancel.js';\n\ntype StorageValue = State;\n\nconst COMPONENT_NAME = 'biometry';\nconst REQUEST_AUTH_METHOD = 'web_app_biometry_request_auth';\nconst INFO_RECEIVED_EVENT = 'biometry_info_received';\n\nconst onBiometryInfoReceived: EventListener<'biometry_info_received'> = e => {\n setState(eventToState(e));\n};\n\nfunction throwNotAvailable(): never {\n throw new NotAvailableError('Biometry is not available');\n}\n\n/**\n * Converts `biometry_info_received` to some common shape.\n * @param event - event payload.\n * @see biometry_info_received\n */\nfunction eventToState(event: EventPayload<'biometry_info_received'>): State {\n let available = false;\n let tokenSaved = false;\n let deviceId = '';\n let accessRequested = false;\n let type = '';\n let accessGranted = false;\n if (event.available) {\n available = true;\n tokenSaved = event.token_saved;\n deviceId = event.device_id;\n accessRequested = event.access_requested;\n type = event.type;\n accessGranted = event.access_granted;\n }\n return { available, tokenSaved, deviceId, type, accessGranted, accessRequested };\n}\n\n/**\n * @returns True if the biometry manager is supported.\n */\nexport const isSupported = createIsSupported(REQUEST_AUTH_METHOD);\n\nconst [\n mountFn,\n tMountPromise,\n tMountError,\n tIsMounted,\n] = defineMountFn(\n COMPONENT_NAME,\n abortSignal => {\n const s = isPageReload() && getStorageValue<StorageValue>(COMPONENT_NAME);\n return s ? AbortablePromise.resolve(s) : requestBiometry({ abortSignal }).then(eventToState);\n },\n s => {\n on(INFO_RECEIVED_EVENT, onBiometryInfoReceived);\n setState(s);\n },\n);\n\nconst wrapSupported = createWrapSupported(COMPONENT_NAME, REQUEST_AUTH_METHOD);\nconst wrapComplete = createWrapComplete(COMPONENT_NAME, tIsMounted[0], REQUEST_AUTH_METHOD);\n\n/**\n * Mounts the Biometry component.\n * @since Mini Apps v7.2\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @example\n * if (mount.isAvailable()) {\n * await mount();\n * }\n */\nexport const mount = wrapSupported('mount', mountFn);\nexport const [, mountPromise, isMounting] = tMountPromise;\nexport const [, mountError] = tMountError;\nexport const [_isMounted, isMounted] = tIsMounted;\n\nconst [\n authFn,\n tAuthPromise,\n tAuthError,\n] = defineNonConcurrentFn(\n (options?: AuthenticateOptions): AbortablePromise<{\n /**\n * Authentication status.\n */\n status: BiometryAuthRequestStatus;\n /**\n * Token from the local secure storage saved previously.\n */\n token?: string;\n }> => {\n return AbortablePromise.fn(async context => {\n const s = _state();\n if (!s.available) {\n throwNotAvailable();\n }\n const data = await request(REQUEST_AUTH_METHOD, 'biometry_auth_requested', {\n ...options,\n ...context,\n params: { reason: ((options || {}).reason || '').trim() },\n });\n const { token } = data;\n if (typeof token === 'string') {\n setState({ ...s, token });\n }\n return data;\n }, options);\n },\n 'Biometry authentication is already in progress',\n);\n\n/**\n * Attempts to authenticate a user using biometrics and fetch a previously stored secure token.\n * @param options - method options.\n * @since Mini Apps v7.2\n * @returns Token from the local secure storage saved previously or undefined.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @throws {ConcurrentCallError} Biometry authentication is already in progress\n * @throws {NotAvailableError} Biometry is not available\n * @example\n * if (authenticate.isAvailable()) {\n * const { status, token } = await authenticate({\n * reason: 'Authenticate to open wallet',\n * });\n * }\n */\nexport const authenticate = wrapComplete('authenticate', authFn);\nexport const [, authPromise, isAuthenticating] = tAuthPromise;\nexport const [, authError] = tAuthError;\n\n/**\n * Opens the biometric access settings for bots. Useful when you need to request biometrics\n * access to users who haven't granted it yet.\n *\n * _Note that this method can be called only in response to user interaction with the Mini App\n * interface (e.g. a click inside the Mini App or on the main button)_.\n * @since Mini Apps v7.2\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @example\n * if (openSettings.isAvailable()) {\n * openSettings();\n * }\n */\nexport const openSettings = wrapSupported('openSettings', (): void => {\n postEvent('web_app_biometry_open_settings');\n});\n\nconst [\n requestAccessFn,\n tRequestAccessPromise,\n tRequestAccessError,\n] = defineNonConcurrentFn(\n (options?: RequestAccessOptions): AbortablePromise<boolean> => {\n return AbortablePromise.fn(async context => {\n const data = await request('web_app_biometry_request_access', INFO_RECEIVED_EVENT, {\n ...options,\n ...context,\n params: { reason: (options || {}).reason || '' },\n }).then(eventToState);\n\n if (!data.available) {\n throwNotAvailable();\n }\n setState(data);\n\n return data.accessGranted;\n }, options);\n },\n 'Biometry access request is already in progress',\n);\n\n/**\n * Requests permission to use biometrics.\n * @since Mini Apps v7.2\n * @returns Promise with true, if access was granted.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @throws {ConcurrentCallError} Biometry access request is already in progress\n * @throws {NotAvailableError} Biometry is not available\n * @example\n * if (requestAccess.isAvailable()) {\n * const accessGranted = await requestAccess({\n * reason: 'Authenticate to open wallet',\n * });\n * }\n */\nexport const requestAccess = wrapComplete('requestAccess', requestAccessFn);\nexport const [, requestAccessPromise, isRequestingAccess] = tRequestAccessPromise;\nexport const [, requestAccessError] = tRequestAccessError;\n\nfunction setState(s: State): void {\n _state.set(s);\n setStorageValue<StorageValue>(COMPONENT_NAME, s);\n}\n\n/**\n * Unmounts the component.\n */\nexport function unmount() {\n [authPromise, requestAccessPromise, mountPromise].forEach(signalCancel);\n off(INFO_RECEIVED_EVENT, onBiometryInfoReceived);\n _isMounted.set(false);\n}\n\n/**\n * Updates the biometric token in a secure storage on the device.\n * @since Mini Apps v7.2\n * @returns Promise with `true`, if token was updated.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} The function is not supported\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @example Setting a new token\n * if (updateToken.isAvailable()) {\n * updateToken({\n * token: 'abcdef',\n * })\n * }\n * @example Deleting the token\n * if (updateToken.isAvailable()) {\n * updateToken();\n * }\n */\nexport const updateToken = wrapComplete(\n 'updateToken',\n (options?: UpdateTokenOptions): AbortablePromise<BiometryTokenUpdateStatus> => {\n options ||= {};\n return request('web_app_biometry_update_token', 'biometry_token_updated', {\n ...options,\n params: {\n token: options.token || '',\n reason: options.reason,\n },\n }).then(r => r.status);\n },\n);\n","import { createWrapSafe, type SafeWrapFn } from '@/scopes/wrappers/createWrapSafe.js';\n\nexport function createWrapMounted(\n component: string,\n isMounted: () => boolean,\n): SafeWrapFn<false> {\n return createWrapSafe(component, { isMounted });\n}","import { createWrapSafe } from '@/scopes/wrappers/createWrapSafe.js';\n\nexport const createWrapBasic = createWrapSafe;","import { isPageReload } from '@telegram-apps/navigation';\nimport { getStorageValue, setStorageValue } from '@telegram-apps/toolkit';\n\nimport { postEvent } from '@/globals.js';\nimport { createWrapMounted } from '@/scopes/wrappers/createWrapMounted.js';\nimport { createWrapBasic } from '@/scopes/wrappers/createWrapBasic.js';\nimport { createSignalsTuple } from '@/signals-registry.js';\n\ntype StorageValue = boolean;\n\nconst COMPONENT_NAME = 'closingBehavior';\n\n/**\n * Signal indicating if the confirmation dialog should be shown, while the user\n * is trying to close the Mini App.\n */\nexport const [_isConfirmationEnabled, isConfirmationEnabled] = createSignalsTuple(false);\n\n/**\n * Signal indicating if the Closing Behavior component is currently mounted.\n */\nexport const [_isMounted, isMounted] = createSignalsTuple(false);\n\nconst wrapMounted = createWrapMounted(COMPONENT_NAME, isMounted);\nconst wrapBasic = createWrapBasic(COMPONENT_NAME);\n\n/**\n * Disables the closing confirmation dialog.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @example\n * if (disableConfirmation.isAvailable()) {\n * disableConfirmation();\n * }\n */\nexport const disableConfirmation = wrapMounted('disableConfirmation', (): void => {\n setClosingConfirmation(false);\n});\n\n/**\n * Enables the closing confirmation dialog.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The parent component is not mounted\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @example\n * if (enableConfirmation.isAvailable()) {\n * enableConfirmation();\n * }\n */\nexport const enableConfirmation = wrapMounted('enableConfirmation', (): void => {\n setClosingConfirmation(true);\n});\n\n/**\n * Mounts the Closing Behavior component restoring its state.\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @example\n * if (mount.isAvailable()) {\n * mount();\n * }\n */\nexport const mount = wrapBasic('mount', (): void => {\n if (!_isMounted()) {\n setClosingConfirmation(\n isPageReload() && getStorageValue<StorageValue>(COMPONENT_NAME) || false,\n );\n _isMounted.set(true);\n }\n});\n\nfunction setClosingConfirmation(value: boolean): void {\n if (value !== _isConfirmationEnabled()) {\n postEvent('web_app_setup_closing_behavior', { need_confirmation: value });\n setStorageValue<StorageValue>(COMPONENT_NAME, value);\n _isConfirmationEnabled.set(value);\n }\n}\n\n/**\n * Unmounts the Closing Behavior component.\n */\nexport function unmount(): void {\n _isMounted.set(false);\n}\n","import { AbortablePromise } from 'better-promises';\nimport { array, parse, record, string } from 'valibot';\n\nimport { invokeCustomMethod } from '@/globals.js';\nimport { createIsSupported } from '@/scopes/createIsSupported.js';\nimport { createWrapSupported } from '@/scopes/wrappers/createWrapSupported.js';\nimport type { InvokeCustomMethodOptions } from '@telegram-apps/bridge';\n\nconst INVOKE_METHOD_NAME = 'web_app_invoke_custom_method';\nconst wrapSupported = createWrapSupported('cloudStorage', INVOKE_METHOD_NAME);\n\n/**\n * Signal indicating if the Cloud Storage is supported.\n */\nexport const isSupported = createIsSupported(INVOKE_METHOD_NAME);\n\n/**\n * Deletes specified key or keys from the cloud storage.\n * @param keyOrKeys - key or keys to delete.\n * @param options - request execution options.\n * @since Mini Apps v6.9\n * @throws {FunctionNotAvailableError} The environment is unknown\n * @throws {FunctionNotAvailableError} The SDK is not initialized\n * @throws {FunctionNotAvailableError} Th