import { MethodName, MethodNameWithVersionedParams, MethodVersionedParams } from '@tma.js/bridge'; import { Computed } from '@tma.js/signals'; import { If, IsNever, AnyFnAnyEither, RightOfReturn, LeftOfReturn, MaybeMonadReturnTypeToCommon, MaybeCommonReturnTypeToMonad, AnyFn } from '@tma.js/toolkit'; import { Version } from '@tma.js/types'; import { either as E, option as O, taskEither as TE } from 'fp-ts'; import { FunctionUnavailableError } from '../errors.js'; import { MaybeAccessor } from '../types.js'; type IfReturnsTask = ReturnType extends TE.TaskEither ? A : B; type OptionsBasedRequires> = O extends { requires: any; } ? true : false; type OptionsBasedSupports> = O extends { supports: any; } ? Extract : never; type OptionsBasedFn> = (...args: any[]) => (Opts['returns'] extends 'plain' ? any : Opts['returns'] extends 'promise' ? PromiseLike : Opts['returns'] extends 'task' ? TE.TaskEither : E.Either); /** * @returns Error text if something is wrong. */ export type CustomSupportFn = () => string | undefined; export type Require = MethodName | CustomSupportFn | { every: (MethodName | CustomSupportFn)[]; } | { some: (MethodName | CustomSupportFn)[]; }; /** * A map where the key is a method name with versioned parameters, and the value is a tuple * containing the method and parameter names. The third tuple value is a function accepting * the wrapped function arguments and returning true if support check must be applied. */ export type SupportsMap = { [OptionName: string]: { [M in MethodNameWithVersionedParams]: { /** * Method name. * @example 'web_app_set_header_color' */ method: M; /** * Method version-dependent parameter. * @example `color` */ param: MethodVersionedParams; /** * @returns True if the support function should be called. * @param args - function arguments. */ shouldCheck: (...args: Args) => boolean; }; }[MethodNameWithVersionedParams]; }; type WrappedFnReturnType = ReturnType extends E.Either ? E.Either, RightOfReturn> : ReturnType extends TE.TaskEither ? TE.TaskEither, RightOfReturn> : ReturnType extends PromiseLike ? TE.TaskEither : E.Either>; export type WrappedFn = (...args: Parameters) => WrappedFnReturnType; export type WithChecksFp = WrappedFn & { /** * A signal returning `true` if the function is available in the current environment and * conditions. * * To be more accurate, the method checks the following: * 1. The current environment is Telegram Mini Apps. * 2. The SDK package is initialized (if this requirement is specified). * 3. If passed, the `isSupported` signal returned true. * 4. If passed, the `isMounted` signal returned true. * * *You should use this function when possible because it provides must-have code security * mechanisms and makes a developer sure that he is using the package properly.* * * @returns True if the function is available in the current environment. * @example * if (backButton.show.isAvailable()) { * backButton.show(); * } */ isAvailable: Computed; /** * Calls the function only in case it is available. * * It uses the `isAvailable` internally to check if the function is available for call. * @example * backButton.show.ifAvailable(); */ ifAvailable(...args: Parameters): O.Option>; } & If; }, {}> & If, {}, { /** * A map where the key is the function-specific option name and value is a signal indicating * if it is supported by the current environment. * @example * if (miniApp.setHeaderColor.isAvailable()) { * if (miniApp.setHeaderColor.supports('rgb')) { * miniApp.setHeaderColor('#ffaabb'); * } else { * miniApp.setHeaderColor('bg_color'); * } * } */ supports: (key: SupportsMapKeySchema) => boolean; }>; export type WithChecks = ((...args: Parameters) => MaybeMonadReturnTypeToCommon) & Omit, 'ifAvailable'> & { /** * Calls the function only in case it is available. * * It uses the `isAvailable` internally to check if the function is available for call. * @example * backButton.show.ifAvailable(); */ ifAvailable(...args: Parameters): { ok: true; data: MaybeMonadReturnTypeToCommon; } | { ok: false; }; }; export interface WithChecksOptions { /** * Signal returning true if the owning component is mounted. */ isMounted?: () => boolean; /** * Signal returning true if the owning component is mounting. */ isMounting?: () => boolean; /** * A value determining the function requirements. This will enable additional checks for * the function before being called. */ requires?: Require; /** * A signal to retrieve the current Telegram Mini Apps version or the value itself. */ isTma: MaybeAccessor; /** * A map where the key is a method name with versioned parameters, and the value is a tuple * containing the method and parameter names. The third tuple value is a function accepting * the wrapped function arguments and returning true if support check must be applied. */ supports?: SupportsMap>; /** * A signal to retrieve the current Telegram Mini Apps version or the value itself. */ version?: MaybeAccessor; /** * Allows to determine what exactly should be returned from the function - TaskEither or Either. * There is no other way to know it until the function itself is called, but we need to perform * some checks before calling it and return a valid value based on the function return type. */ returns: Fn extends AnyFnAnyEither ? IfReturnsTask : ReturnType extends PromiseLike ? 'promise' : 'plain'; } export declare function withChecksFp>(fn: Fn, options: O): WithChecksFp, OptionsBasedSupports>; export declare function createWithChecksFp>(options: O): >(fn: Fn) => WithChecksFp, OptionsBasedSupports>; export {};