From 498cc0f9864dfcd95910e035cdb137c1fae97d88 Mon Sep 17 00:00:00 2001 From: Vladislav Kibenko Date: Tue, 16 Apr 2024 21:34:49 +0300 Subject: [PATCH 001/169] feat(rework): huge work in progress --- .../build-utils/src/createVitestConfig.ts | 5 +- packages/eslint-config-custom/base.js | 1 - packages/eslint-config-custom/rules.js | 2 + packages/sdk-react/package.json | 6 +- packages/sdk-react/src/index.ts | 2 + packages/sdk-solid/package.json | 4 +- packages/sdk-solid/src/index.ts | 2 + ...ptureSameReq.ts => captureSameReq.test.ts} | 7 +- packages/sdk/src/bridge/captureSameReq.ts | 4 +- ...nalNotify.ts => hasExternalNotify.test.ts} | 2 +- .../sdk/src/bridge/env/hasExternalNotify.ts | 15 +- ...ebviewProxy.ts => hasWebviewProxy.test.ts} | 2 +- .../sdk/src/bridge/env/hasWebviewProxy.ts | 15 +- .../bridge/errors/MethodUnsupportedError.ts | 12 - .../errors/ParameterUnsupportedError.ts | 12 - ...createEmitter.ts => createEmitter.test.ts} | 8 +- .../sdk/src/bridge/events/createEmitter.ts | 38 ++-- .../events/{__tests__/off.ts => off.test.ts} | 8 +- packages/sdk/src/bridge/events/off.ts | 2 +- .../events/{__tests__/on.ts => on.test.ts} | 6 +- packages/sdk/src/bridge/events/on.ts | 6 +- ...legramEvent.ts => onTelegramEvent.test.ts} | 10 +- .../{__tests__/once.ts => once.test.ts} | 6 +- packages/sdk/src/bridge/events/once.ts | 6 +- ...eived.ts => clipboardTextReceived.test.ts} | 2 +- .../events/parsers/clipboardTextReceived.ts | 29 +-- .../parsers/customMethodInvoked.test.ts | 22 ++ .../events/parsers/customMethodInvoked.ts | 27 +-- ...invoiceClosed.ts => invoiceClosed.test.ts} | 2 +- .../bridge/events/parsers/invoiceClosed.ts | 30 +-- .../events/parsers/phoneRequested.test.ts | 17 ++ .../bridge/events/parsers/phoneRequested.ts | 18 +- .../popupClosed.ts => popupClosed.test.ts} | 2 +- .../src/bridge/events/parsers/popupClosed.ts | 23 +- ...TextReceived.ts => qrTextReceived.test.ts} | 2 +- .../bridge/events/parsers/qrTextReceived.ts | 18 +- ...theme-changed.ts => theme-changed.test.ts} | 2 +- .../bridge/events/parsers/theme-changed.ts | 54 +---- ...portChanged.ts => viewportChanged.test.ts} | 2 +- .../bridge/events/parsers/viewportChanged.ts | 32 +-- .../parsers/writeAccessRequested.test.ts | 17 ++ .../events/parsers/writeAccessRequested.ts | 18 +- ...tonEmitter.ts => singletonEmitter.test.ts} | 6 +- .../sdk/src/bridge/events/singletonEmitter.ts | 4 +- .../subscribe.ts => subscribe.test.ts} | 11 +- packages/sdk/src/bridge/events/subscribe.ts | 6 +- packages/sdk/src/bridge/events/types.ts | 4 - .../src/bridge/events/{ => types}/events.ts | 43 ++-- packages/sdk/src/bridge/events/types/misc.ts | 4 + .../sdk/src/bridge/events/types/payloads.ts | 140 ++++++++++++ .../unsubscribe.ts => unsubscribe.test.ts} | 8 +- packages/sdk/src/bridge/events/unsubscribe.ts | 2 +- packages/sdk/src/bridge/invokeCustomMethod.ts | 13 +- ...tePostEvent.ts => createPostEvent.test.ts} | 23 +- .../sdk/src/bridge/methods/createPostEvent.ts | 24 +- .../postEvent.ts => postEvent.test.ts} | 8 +- packages/sdk/src/bridge/methods/postEvent.ts | 25 ++- .../methods/{ => types}/custom-methods.ts | 6 +- .../src/bridge/methods/{ => types}/haptic.ts | 1 - .../src/bridge/methods/{ => types}/methods.ts | 36 +-- .../src/bridge/methods/{ => types}/popup.ts | 0 .../parseMessage.ts => parseMessage.test.ts} | 6 +- packages/sdk/src/bridge/parseMessage.ts | 8 +- .../{__tests__/request.ts => request.test.ts} | 32 +-- packages/sdk/src/bridge/request.ts | 17 +- packages/sdk/src/bridge/target-origin.test.ts | 13 ++ .../{globals.ts => bridge/target-origin.ts} | 18 -- .../WithStateAndSupports.ts | 31 +++ .../sdk/src/classes/with-state/WithState.ts | 76 +++++++ packages/sdk/src/classes/with-state/types.ts | 33 +++ .../src/classes/with-supports/WithSupports.ts | 24 ++ .../classNames.ts => classNames.test.ts} | 2 +- packages/sdk/src/classnames/classNames.ts | 42 ++-- ...eClassNames.ts => mergeClassNames.test.ts} | 2 +- .../sdk/src/classnames/mergeClassNames.ts | 7 +- .../isColorDark.ts => isColorDark.test.ts} | 2 +- packages/sdk/src/colors/isColorDark.ts | 5 +- .../{__tests__/isRGB.ts => isRGB.test.ts} | 2 +- .../isRGBShort.ts => isRGBShort.test.ts} | 2 +- .../{__tests__/toRGB.ts => toRGB.test.ts} | 2 +- packages/sdk/src/colors/toRGB.ts | 7 +- .../BackButton.ts => BackButton.test.ts} | 2 +- .../src/components/back-button/BackButton.ts | 66 +----- .../components/back-button/initBackButton.ts | 11 + .../back-button/offBackButtonClick.ts | 11 + .../back-button/onBackButtonClick.ts | 13 ++ .../sdk/src/components/back-button/types.ts | 22 +- .../closing-behavior/ClosingBehavior.ts | 53 ++--- .../closing-behavior/initClosingBehavior.ts | 11 + .../src/components/closing-behavior/types.ts | 14 +- .../components/cloud-storage/CloudStorage.ts | 94 ++++---- .../cloud-storage/initCloudStorage.ts | 11 + packages/sdk/src/components/createInitFn.ts | 103 +++++++++ .../haptic-feedback/HapticFeedback.ts | 30 +-- .../haptic-feedback/initHapticFeedback.ts | 9 + .../sdk/src/components/init-data/InitData.ts | 9 +- .../src/components/init-data/chatParser.ts | 21 -- .../src/components/init-data/parseInitData.ts | 4 +- .../__tests__/chat.ts} | 18 +- .../__tests__/initData.ts} | 18 +- .../__tests__/user.ts} | 18 +- .../src/components/init-data/parsers/chat.ts | 21 ++ .../initData.ts} | 25 ++- .../{userParser.ts => parsers/user.ts} | 14 +- .../sdk/src/components/init-data/types.ts | 27 +-- .../sdk/src/components/invoice/Invoice.ts | 92 +++----- .../sdk/src/components/invoice/initInvoice.ts | 10 + packages/sdk/src/components/invoice/types.ts | 14 +- .../src/components/main-button/MainButton.ts | 135 ++++------- .../components/main-button/initMainButton.ts | 27 +++ .../main-button/offMainButtonClick.ts | 11 + .../main-button/onMainButtonClick.ts | 13 ++ .../sdk/src/components/main-button/types.ts | 47 ++-- .../{__tests__/MiniApp.ts => MiniApp.test.ts} | 39 ++-- .../sdk/src/components/mini-app/MiniApp.ts | 211 ++++++++---------- .../src/components/mini-app/contactParser.ts | 32 --- .../src/components/mini-app/initMiniApp.ts | 21 ++ .../mini-app/parsers/contact.test.ts | 32 +++ .../components/mini-app/parsers/contact.ts | 39 ++++ packages/sdk/src/components/mini-app/types.ts | 46 ++-- packages/sdk/src/components/popup/Popup.ts | 75 ++----- .../sdk/src/components/popup/initPopup.ts | 10 + .../components/popup/preparePopupParams.ts | 11 +- packages/sdk/src/components/popup/types.ts | 2 +- .../src/components/qr-scanner/QRScanner.ts | 56 ++--- .../components/qr-scanner/initQRScanner.ts | 10 + .../sdk/src/components/qr-scanner/types.ts | 14 +- .../settings-button/SettingsButton.ts | 63 +----- .../settings-button/initSettingsButton.ts | 14 ++ .../settings-button/offSettingsButtonClick.ts | 11 + .../settings-button/onSettingsButtonClick.ts | 13 ++ .../src/components/settings-button/types.ts | 22 +- .../components/theme-params/ThemeParams.ts | 80 +++---- .../components/theme-params/__tests__/keys.ts | 19 -- .../src/components/theme-params/keys.test.ts | 19 ++ .../sdk/src/components/theme-params/keys.ts | 14 +- ...hemeParams.ts => parseThemeParams.test.ts} | 10 +- .../theme-params/parseThemeParams.ts | 4 +- .../themeParams.test.ts} | 14 +- .../theme-params/parsers/themeParams.ts | 23 ++ .../theme-params/requestThemeParams.ts | 5 +- ...Params.ts => serializeThemeParams.test.ts} | 10 +- .../theme-params/serializeThemeParams.ts | 14 +- .../theme-params/themeParamsParser.ts | 23 -- .../sdk/src/components/theme-params/types.ts | 30 ++- packages/sdk/src/components/utils/Utils.ts | 47 ++-- .../sdk/src/components/utils/initUtils.ts | 11 + .../sdk/src/components/viewport/Viewport.ts | 157 ++++++------- .../components/viewport/__tests__/utils.ts | 12 - .../src/components/viewport/initViewport.ts | 17 ++ ...rm.ts => isStableViewportPlatform.test.ts} | 4 +- .../viewport/isStableViewportPlatform.ts | 8 +- .../components/viewport/requestViewport.ts | 17 +- packages/sdk/src/components/viewport/types.ts | 24 +- packages/sdk/src/components/viewport/utils.ts | 7 - .../bindMiniAppCSSVars.test.ts} | 69 +++--- .../sdk/src/css-vars/bindMiniAppCSSVars.ts | 46 ++++ .../bindThemeCSSVars.test.ts} | 26 ++- .../src/{css => css-vars}/bindThemeCSSVars.ts | 28 +-- .../bindViewportCSSVars.test.ts} | 16 +- .../{css => css-vars}/bindViewportCSSVars.ts | 3 +- .../setCSSVar.test.ts} | 9 +- .../sdk/src/{css => css-vars}/setCSSVar.ts | 0 packages/sdk/src/css/bindMiniAppCSSVars.ts | 51 ----- .../globals.ts => debug/debug.test.ts} | 15 +- packages/sdk/src/debug/debug.ts | 50 +++++ .../isIframe.ts => env/isIframe.test.ts} | 2 +- packages/sdk/src/{misc => env}/isIframe.ts | 0 packages/sdk/src/env/isTMA.test.ts | 24 ++ packages/sdk/src/env/isTMA.ts | 13 ++ packages/sdk/src/errors/SDKError.ts | 11 + packages/sdk/src/errors/createError.test.ts | 11 + packages/sdk/src/errors/createError.ts | 13 ++ packages/sdk/src/errors/errors.ts | 43 ++++ packages/sdk/src/errors/isSDKError.test.ts | 10 + packages/sdk/src/errors/isSDKError.ts | 9 + .../sdk/src/errors/isSDKErrorOfType.test.ts | 10 + packages/sdk/src/errors/isSDKErrorOfType.ts | 11 + .../EventEmitter.ts => EventEmitter.test.ts} | 6 +- .../sdk/src/event-emitter/EventEmitter.ts | 51 ++--- packages/sdk/src/event-emitter/types.ts | 10 +- packages/sdk/src/index.ts | 40 ++-- packages/sdk/src/init/catchCustomStyles.ts | 17 -- .../sdk/src/init/creators/createBackButton.ts | 25 --- .../init/creators/createClosingBehavior.ts | 24 -- .../sdk/src/init/creators/createMainButton.ts | 51 ----- .../sdk/src/init/creators/createMiniApp.ts | 48 ---- .../src/init/creators/createSettingsButton.ts | 25 --- .../src/init/creators/createThemeParams.ts | 4 +- .../sdk/src/init/creators/createViewport.ts | 15 +- .../sdk/src/init/css/processCSSVarsOption.ts | 13 +- packages/sdk/src/init/init.ts | 181 +++++---------- packages/sdk/src/init/types.ts | 33 +-- .../src/launch-params/parseLaunchParams.ts | 4 +- .../launchParams.ts} | 23 +- .../launch-params/retrieveFromPerformance.ts | 3 +- ...ieveFromUrl.ts => retrieveFromUrl.test.ts} | 3 +- .../src/launch-params/retrieveLaunchData.ts | 15 -- .../src/launch-params/retrieveLaunchParams.ts | 3 +- .../launch-params/serializeLaunchParams.ts | 3 +- packages/sdk/src/launch-params/storage.ts | 14 +- packages/sdk/src/launch-params/types.ts | 14 +- packages/sdk/src/logger/Logger.test.ts | 56 +++++ packages/sdk/src/logger/Logger.ts | 50 ++--- packages/sdk/src/logger/__tests__/Logger.ts | 107 --------- .../isRecord.ts => isRecord.test.ts} | 2 +- packages/sdk/src/misc/isTMA.ts | 13 -- .../navigation/HashNavigator/HashNavigator.ts | 3 +- .../sdk/src/navigation/Navigator/Navigator.ts | 2 +- .../__tests__/getFirstNavigationEntry.ts | 2 +- .../__tests__/isPageReload.ts | 2 +- .../getFirstNavigationEntry.ts | 0 .../src/{misc => navigation}/isPageReload.ts | 0 .../ArrayParser.test.ts} | 8 +- .../src/parsing/ArrayParser/ArrayParser.ts | 64 ++++++ packages/sdk/src/parsing/ArrayParser/types.ts | 24 ++ packages/sdk/src/parsing/ArrayValueParser.ts | 79 ------- packages/sdk/src/parsing/ParseError.ts | 27 --- .../sdk/src/parsing/ParseSchemaFieldError.ts | 21 -- packages/sdk/src/parsing/ValueParser.ts | 70 ------ .../src/parsing/ValueParser/ValueParser.ts | 43 ++++ packages/sdk/src/parsing/ValueParser/types.ts | 39 ++++ packages/sdk/src/parsing/createTypeError.ts | 10 + .../src/parsing/createValueParserGenerator.ts | 2 +- packages/sdk/src/parsing/parseBySchema.ts | 36 +-- .../{__tests__/array.ts => array.test.ts} | 4 +- packages/sdk/src/parsing/parsers/array.ts | 6 +- .../{__tests__/boolean.ts => boolean.test.ts} | 2 +- packages/sdk/src/parsing/parsers/boolean.ts | 4 +- .../{__tests__/date.ts => date.test.ts} | 2 +- .../{__tests__/json.ts => json.test.ts} | 8 +- packages/sdk/src/parsing/parsers/json.ts | 3 +- .../{__tests__/number.ts => number.test.ts} | 2 +- packages/sdk/src/parsing/parsers/number.ts | 4 +- .../parsers/{__tests__/rgb.ts => rgb.test.ts} | 2 +- packages/sdk/src/parsing/parsers/rgb.ts | 5 +- .../searchParams.ts => searchParams.test.ts} | 20 +- .../sdk/src/parsing/parsers/searchParams.ts | 6 +- .../{__tests__/string.ts => string.test.ts} | 2 +- packages/sdk/src/parsing/parsers/string.ts | 4 +- .../toRecord.ts => toRecord.test.ts} | 2 +- packages/sdk/src/parsing/toRecord.ts | 4 +- .../sdk/src/parsing/unexpectedTypeError.ts | 6 - .../createRequestIdGenerator.ts | 4 +- .../request-id.ts => request-id/types.ts} | 2 +- packages/sdk/src/state/State.ts | 66 ------ packages/sdk/src/state/types.ts | 31 --- packages/sdk/src/storage.ts | 69 ------ packages/sdk/src/storage/storage.ts | 61 +++++ packages/sdk/src/supports/createSupportsFn.ts | 20 ++ .../sdk/src/supports/createSupportsFunc.ts | 17 -- ...sParamFunc.ts => createSupportsParamFn.ts} | 15 +- .../supports.ts => supports.test.ts} | 35 +-- packages/sdk/src/supports/supports.ts | 6 +- packages/sdk/src/supports/types.ts | 2 +- packages/sdk/src/timeout/TimeoutError.ts | 6 - .../src/timeout/__tests__/isTimeoutError.ts | 9 - .../sdk/src/timeout/createTimeoutError.ts | 11 + packages/sdk/src/timeout/isTimeoutError.ts | 9 - packages/sdk/src/timeout/sleep.ts | 3 +- .../withTimeout.ts => withTimeout.test.ts} | 8 +- packages/sdk/src/timeout/withTimeout.ts | 21 +- packages/sdk/src/types/methods.ts | 2 +- packages/sdk/src/types/platform.ts | 2 +- ...areVersions.ts => compareVersions.test.ts} | 2 +- packages/sdk/test-utils/types.ts | 6 + packages/sdk/tsconfig.build.json | 10 +- packages/sdk/tsconfig.json | 7 +- packages/sdk/tsconfig.test.json | 18 ++ 269 files changed, 2860 insertions(+), 2880 deletions(-) rename packages/sdk/src/bridge/{__tests__/captureSameReq.ts => captureSameReq.test.ts} (70%) rename packages/sdk/src/bridge/env/{__tests__/hasExternalNotify.ts => hasExternalNotify.test.ts} (87%) rename packages/sdk/src/bridge/env/{__tests__/hasWebviewProxy.ts => hasWebviewProxy.test.ts} (89%) delete mode 100644 packages/sdk/src/bridge/errors/MethodUnsupportedError.ts delete mode 100644 packages/sdk/src/bridge/errors/ParameterUnsupportedError.ts rename packages/sdk/src/bridge/events/{__tests__/createEmitter.ts => createEmitter.test.ts} (92%) rename packages/sdk/src/bridge/events/{__tests__/off.ts => off.test.ts} (72%) rename packages/sdk/src/bridge/events/{__tests__/on.ts => on.test.ts} (83%) rename packages/sdk/src/bridge/events/{__tests__/onTelegramEvent.ts => onTelegramEvent.test.ts} (81%) rename packages/sdk/src/bridge/events/{__tests__/once.ts => once.test.ts} (86%) rename packages/sdk/src/bridge/events/parsers/{__tests__/clipboardTextReceived.ts => clipboardTextReceived.test.ts} (89%) create mode 100644 packages/sdk/src/bridge/events/parsers/customMethodInvoked.test.ts rename packages/sdk/src/bridge/events/parsers/{__tests__/invoiceClosed.ts => invoiceClosed.test.ts} (87%) create mode 100644 packages/sdk/src/bridge/events/parsers/phoneRequested.test.ts rename packages/sdk/src/bridge/events/parsers/{__tests__/popupClosed.ts => popupClosed.test.ts} (89%) rename packages/sdk/src/bridge/events/parsers/{__tests__/qrTextReceived.ts => qrTextReceived.test.ts} (86%) rename packages/sdk/src/bridge/events/parsers/{__tests__/theme-changed.ts => theme-changed.test.ts} (95%) rename packages/sdk/src/bridge/events/parsers/{__tests__/viewportChanged.ts => viewportChanged.test.ts} (95%) create mode 100644 packages/sdk/src/bridge/events/parsers/writeAccessRequested.test.ts rename packages/sdk/src/bridge/events/{__tests__/singletonEmitter.ts => singletonEmitter.test.ts} (65%) rename packages/sdk/src/bridge/events/{__tests__/subscribe.ts => subscribe.test.ts} (76%) delete mode 100644 packages/sdk/src/bridge/events/types.ts rename packages/sdk/src/bridge/events/{ => types}/events.ts (84%) create mode 100644 packages/sdk/src/bridge/events/types/misc.ts create mode 100644 packages/sdk/src/bridge/events/types/payloads.ts rename packages/sdk/src/bridge/events/{__tests__/unsubscribe.ts => unsubscribe.test.ts} (68%) rename packages/sdk/src/bridge/methods/{__tests__/createPostEvent.ts => createPostEvent.test.ts} (57%) rename packages/sdk/src/bridge/methods/{__tests__/postEvent.ts => postEvent.test.ts} (95%) rename packages/sdk/src/bridge/methods/{ => types}/custom-methods.ts (95%) rename packages/sdk/src/bridge/methods/{ => types}/haptic.ts (96%) rename packages/sdk/src/bridge/methods/{ => types}/methods.ts (97%) rename packages/sdk/src/bridge/methods/{ => types}/popup.ts (100%) rename packages/sdk/src/bridge/{__tests__/parseMessage.ts => parseMessage.test.ts} (89%) rename packages/sdk/src/bridge/{__tests__/request.ts => request.test.ts} (88%) create mode 100644 packages/sdk/src/bridge/target-origin.test.ts rename packages/sdk/src/{globals.ts => bridge/target-origin.ts} (56%) create mode 100644 packages/sdk/src/classes/with-state-and-supports/WithStateAndSupports.ts create mode 100644 packages/sdk/src/classes/with-state/WithState.ts create mode 100644 packages/sdk/src/classes/with-state/types.ts create mode 100644 packages/sdk/src/classes/with-supports/WithSupports.ts rename packages/sdk/src/classnames/{__tests__/classNames.ts => classNames.test.ts} (92%) rename packages/sdk/src/classnames/{__tests__/mergeClassNames.ts => mergeClassNames.test.ts} (91%) rename packages/sdk/src/colors/{__tests__/isColorDark.ts => isColorDark.test.ts} (90%) rename packages/sdk/src/colors/{__tests__/isRGB.ts => isRGB.test.ts} (89%) rename packages/sdk/src/colors/{__tests__/isRGBShort.ts => isRGBShort.test.ts} (87%) rename packages/sdk/src/colors/{__tests__/toRGB.ts => toRGB.test.ts} (94%) rename packages/sdk/src/components/back-button/{__tests__/BackButton.ts => BackButton.test.ts} (98%) create mode 100644 packages/sdk/src/components/back-button/initBackButton.ts create mode 100644 packages/sdk/src/components/back-button/offBackButtonClick.ts create mode 100644 packages/sdk/src/components/back-button/onBackButtonClick.ts create mode 100644 packages/sdk/src/components/closing-behavior/initClosingBehavior.ts create mode 100644 packages/sdk/src/components/cloud-storage/initCloudStorage.ts create mode 100644 packages/sdk/src/components/createInitFn.ts create mode 100644 packages/sdk/src/components/haptic-feedback/initHapticFeedback.ts delete mode 100644 packages/sdk/src/components/init-data/chatParser.ts rename packages/sdk/src/components/init-data/{__tests__/chatParser.ts => parsers/__tests__/chat.ts} (87%) rename packages/sdk/src/components/init-data/{__tests__/initDataParser.ts => parsers/__tests__/initData.ts} (85%) rename packages/sdk/src/components/init-data/{__tests__/userParser.ts => parsers/__tests__/user.ts} (83%) create mode 100644 packages/sdk/src/components/init-data/parsers/chat.ts rename packages/sdk/src/components/init-data/{initDataParser.ts => parsers/initData.ts} (51%) rename packages/sdk/src/components/init-data/{userParser.ts => parsers/user.ts} (68%) create mode 100644 packages/sdk/src/components/invoice/initInvoice.ts create mode 100644 packages/sdk/src/components/main-button/initMainButton.ts create mode 100644 packages/sdk/src/components/main-button/offMainButtonClick.ts create mode 100644 packages/sdk/src/components/main-button/onMainButtonClick.ts rename packages/sdk/src/components/mini-app/{__tests__/MiniApp.ts => MiniApp.test.ts} (79%) delete mode 100644 packages/sdk/src/components/mini-app/contactParser.ts create mode 100644 packages/sdk/src/components/mini-app/initMiniApp.ts create mode 100644 packages/sdk/src/components/mini-app/parsers/contact.test.ts create mode 100644 packages/sdk/src/components/mini-app/parsers/contact.ts create mode 100644 packages/sdk/src/components/popup/initPopup.ts create mode 100644 packages/sdk/src/components/qr-scanner/initQRScanner.ts create mode 100644 packages/sdk/src/components/settings-button/initSettingsButton.ts create mode 100644 packages/sdk/src/components/settings-button/offSettingsButtonClick.ts create mode 100644 packages/sdk/src/components/settings-button/onSettingsButtonClick.ts delete mode 100644 packages/sdk/src/components/theme-params/__tests__/keys.ts create mode 100644 packages/sdk/src/components/theme-params/keys.test.ts rename packages/sdk/src/components/theme-params/{__tests__/parseThemeParams.ts => parseThemeParams.test.ts} (77%) rename packages/sdk/src/components/theme-params/{__tests__/themeParamsParser.ts => parsers/themeParams.test.ts} (62%) create mode 100644 packages/sdk/src/components/theme-params/parsers/themeParams.ts rename packages/sdk/src/components/theme-params/{__tests__/serializeThemeParams.ts => serializeThemeParams.test.ts} (76%) delete mode 100644 packages/sdk/src/components/theme-params/themeParamsParser.ts create mode 100644 packages/sdk/src/components/utils/initUtils.ts delete mode 100644 packages/sdk/src/components/viewport/__tests__/utils.ts create mode 100644 packages/sdk/src/components/viewport/initViewport.ts rename packages/sdk/src/components/viewport/{__tests__/isStableViewportPlatform.ts => isStableViewportPlatform.test.ts} (72%) delete mode 100644 packages/sdk/src/components/viewport/utils.ts rename packages/sdk/src/{css/__tests__/bindMiniAppCSSVars.ts => css-vars/bindMiniAppCSSVars.test.ts} (67%) create mode 100644 packages/sdk/src/css-vars/bindMiniAppCSSVars.ts rename packages/sdk/src/{css/__tests__/bindThemeCSSVars.ts => css-vars/bindThemeCSSVars.test.ts} (57%) rename packages/sdk/src/{css => css-vars}/bindThemeCSSVars.ts (57%) rename packages/sdk/src/{css/__tests__/bindViewportCSSVars.ts => css-vars/bindViewportCSSVars.test.ts} (77%) rename packages/sdk/src/{css => css-vars}/bindViewportCSSVars.ts (94%) rename packages/sdk/src/{css/__tests__/setCSSVar.ts => css-vars/setCSSVar.test.ts} (82%) rename packages/sdk/src/{css => css-vars}/setCSSVar.ts (100%) delete mode 100644 packages/sdk/src/css/bindMiniAppCSSVars.ts rename packages/sdk/src/{__tests__/globals.ts => debug/debug.test.ts} (67%) create mode 100644 packages/sdk/src/debug/debug.ts rename packages/sdk/src/{misc/__tests__/isIframe.ts => env/isIframe.test.ts} (94%) rename packages/sdk/src/{misc => env}/isIframe.ts (100%) create mode 100644 packages/sdk/src/env/isTMA.test.ts create mode 100644 packages/sdk/src/env/isTMA.ts create mode 100644 packages/sdk/src/errors/SDKError.ts create mode 100644 packages/sdk/src/errors/createError.test.ts create mode 100644 packages/sdk/src/errors/createError.ts create mode 100644 packages/sdk/src/errors/errors.ts create mode 100644 packages/sdk/src/errors/isSDKError.test.ts create mode 100644 packages/sdk/src/errors/isSDKError.ts create mode 100644 packages/sdk/src/errors/isSDKErrorOfType.test.ts create mode 100644 packages/sdk/src/errors/isSDKErrorOfType.ts rename packages/sdk/src/event-emitter/{__tests__/EventEmitter.ts => EventEmitter.test.ts} (95%) delete mode 100644 packages/sdk/src/init/catchCustomStyles.ts delete mode 100644 packages/sdk/src/init/creators/createBackButton.ts delete mode 100644 packages/sdk/src/init/creators/createClosingBehavior.ts delete mode 100644 packages/sdk/src/init/creators/createMainButton.ts delete mode 100644 packages/sdk/src/init/creators/createMiniApp.ts delete mode 100644 packages/sdk/src/init/creators/createSettingsButton.ts rename packages/sdk/src/launch-params/{launchParamsParser.ts => parsers/launchParams.ts} (52%) rename packages/sdk/src/launch-params/{__tests__/retrieveFromUrl.ts => retrieveFromUrl.test.ts} (95%) delete mode 100644 packages/sdk/src/launch-params/retrieveLaunchData.ts create mode 100644 packages/sdk/src/logger/Logger.test.ts delete mode 100644 packages/sdk/src/logger/__tests__/Logger.ts rename packages/sdk/src/misc/{__tests__/isRecord.ts => isRecord.test.ts} (91%) delete mode 100644 packages/sdk/src/misc/isTMA.ts rename packages/sdk/src/{misc => navigation}/__tests__/getFirstNavigationEntry.ts (98%) rename packages/sdk/src/{misc => navigation}/__tests__/isPageReload.ts (93%) rename packages/sdk/src/{misc => navigation}/getFirstNavigationEntry.ts (100%) rename packages/sdk/src/{misc => navigation}/isPageReload.ts (100%) rename packages/sdk/src/parsing/{__tests__/ArrayValueParser.ts => ArrayParser/ArrayParser.test.ts} (62%) create mode 100644 packages/sdk/src/parsing/ArrayParser/ArrayParser.ts create mode 100644 packages/sdk/src/parsing/ArrayParser/types.ts delete mode 100644 packages/sdk/src/parsing/ArrayValueParser.ts delete mode 100644 packages/sdk/src/parsing/ParseError.ts delete mode 100644 packages/sdk/src/parsing/ParseSchemaFieldError.ts delete mode 100644 packages/sdk/src/parsing/ValueParser.ts create mode 100644 packages/sdk/src/parsing/ValueParser/ValueParser.ts create mode 100644 packages/sdk/src/parsing/ValueParser/types.ts create mode 100644 packages/sdk/src/parsing/createTypeError.ts rename packages/sdk/src/parsing/parsers/{__tests__/array.ts => array.test.ts} (94%) rename packages/sdk/src/parsing/parsers/{__tests__/boolean.ts => boolean.test.ts} (96%) rename packages/sdk/src/parsing/parsers/{__tests__/date.ts => date.test.ts} (95%) rename packages/sdk/src/parsing/parsers/{__tests__/json.ts => json.test.ts} (93%) rename packages/sdk/src/parsing/parsers/{__tests__/number.ts => number.test.ts} (95%) rename packages/sdk/src/parsing/parsers/{__tests__/rgb.ts => rgb.test.ts} (95%) rename packages/sdk/src/parsing/parsers/{__tests__/searchParams.ts => searchParams.test.ts} (82%) rename packages/sdk/src/parsing/parsers/{__tests__/string.ts => string.test.ts} (95%) rename packages/sdk/src/parsing/{__tests__/toRecord.ts => toRecord.test.ts} (88%) delete mode 100644 packages/sdk/src/parsing/unexpectedTypeError.ts rename packages/sdk/src/{init/creators => request-id}/createRequestIdGenerator.ts (54%) rename packages/sdk/src/{types/request-id.ts => request-id/types.ts} (82%) delete mode 100644 packages/sdk/src/state/State.ts delete mode 100644 packages/sdk/src/state/types.ts delete mode 100644 packages/sdk/src/storage.ts create mode 100644 packages/sdk/src/storage/storage.ts create mode 100644 packages/sdk/src/supports/createSupportsFn.ts delete mode 100644 packages/sdk/src/supports/createSupportsFunc.ts rename packages/sdk/src/supports/{createSupportsParamFunc.ts => createSupportsParamFn.ts} (71%) rename packages/sdk/src/supports/{__tests__/supports.ts => supports.test.ts} (79%) delete mode 100644 packages/sdk/src/timeout/TimeoutError.ts delete mode 100644 packages/sdk/src/timeout/__tests__/isTimeoutError.ts create mode 100644 packages/sdk/src/timeout/createTimeoutError.ts delete mode 100644 packages/sdk/src/timeout/isTimeoutError.ts rename packages/sdk/src/timeout/{__tests__/withTimeout.ts => withTimeout.test.ts} (70%) rename packages/sdk/src/version/{__tests__/compareVersions.ts => compareVersions.test.ts} (91%) create mode 100644 packages/sdk/test-utils/types.ts create mode 100644 packages/sdk/tsconfig.test.json diff --git a/packages/build-utils/src/createVitestConfig.ts b/packages/build-utils/src/createVitestConfig.ts index 5e9944fdd..c3c4b6f2d 100644 --- a/packages/build-utils/src/createVitestConfig.ts +++ b/packages/build-utils/src/createVitestConfig.ts @@ -11,7 +11,10 @@ export function createVitestConfig(options: Options = {}): InlineConfig { coverage, } = options; const config: InlineConfig = { - include: ['src/**/__tests__/**/*.ts'], + include: [ + 'src/**/__tests__/**/*.ts', + 'src/**/*.test.ts' + ], }; if (environment) { diff --git a/packages/eslint-config-custom/base.js b/packages/eslint-config-custom/base.js index f8b3d072e..a985fcd21 100644 --- a/packages/eslint-config-custom/base.js +++ b/packages/eslint-config-custom/base.js @@ -8,7 +8,6 @@ module.exports = { }, plugins: [ 'simple-import-sort', - 'import', ], rules: require('./rules'), ignorePatterns: ['**/__tests__/*'], diff --git a/packages/eslint-config-custom/rules.js b/packages/eslint-config-custom/rules.js index 8dfb9d04f..3cf3f63fb 100644 --- a/packages/eslint-config-custom/rules.js +++ b/packages/eslint-config-custom/rules.js @@ -11,6 +11,7 @@ module.exports = { 'import/no-duplicates': 'error', // We have extraneous deps, because we have workspace. 'import/no-extraneous-dependencies': 0, + 'import/order': 0, // We don't use default exports anywhere. 'import/prefer-default-export': 0, // We select line endings depending on current OS. @@ -23,6 +24,7 @@ module.exports = { // Sometimes we need to write "void promise". 'no-void': 0, 'object-curly-newline': ['error', { consistent: true }], + 'simple-import-sort/exports': 'error', 'simple-import-sort/imports': [ 2, { diff --git a/packages/sdk-react/package.json b/packages/sdk-react/package.json index a8ab6cd97..a08156ee1 100644 --- a/packages/sdk-react/package.json +++ b/packages/sdk-react/package.json @@ -41,10 +41,12 @@ "typecheck": "tsc --noEmit", "build": "vite build" }, + "dependencies": { + "@tma.js/sdk": "workspace:*" + }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "@tma.js/sdk": "workspace:*" + "react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { diff --git a/packages/sdk-react/src/index.ts b/packages/sdk-react/src/index.ts index 66445a600..badc9fa63 100644 --- a/packages/sdk-react/src/index.ts +++ b/packages/sdk-react/src/index.ts @@ -1,3 +1,5 @@ +export * from '@tma.js/sdk'; + export { useThemeParams, useInitData, diff --git a/packages/sdk-solid/package.json b/packages/sdk-solid/package.json index 5d5e75fa3..6f046cc10 100644 --- a/packages/sdk-solid/package.json +++ b/packages/sdk-solid/package.json @@ -41,8 +41,10 @@ "typecheck": "tsc --noEmit", "build": "vite build" }, + "dependencies": { + "@tma.js/sdk": "workspace:*" + }, "peerDependencies": { - "@tma.js/sdk": "workspace:*", "solid-js": "^1.0.0" }, "devDependencies": { diff --git a/packages/sdk-solid/src/index.ts b/packages/sdk-solid/src/index.ts index 2abf7d689..e3d574df4 100644 --- a/packages/sdk-solid/src/index.ts +++ b/packages/sdk-solid/src/index.ts @@ -1,3 +1,5 @@ +export * from '@tma.js/sdk'; + export { useThemeParams, useInitData, diff --git a/packages/sdk/src/bridge/__tests__/captureSameReq.ts b/packages/sdk/src/bridge/captureSameReq.test.ts similarity index 70% rename from packages/sdk/src/bridge/__tests__/captureSameReq.ts rename to packages/sdk/src/bridge/captureSameReq.test.ts index be623332b..19b5c1ba5 100644 --- a/packages/sdk/src/bridge/__tests__/captureSameReq.ts +++ b/packages/sdk/src/bridge/captureSameReq.test.ts @@ -1,7 +1,8 @@ -import { it, expect } from 'vitest'; -import { captureSameReq } from '../captureSameReq'; +import { expect, it } from 'vitest'; + +import { captureSameReq } from './captureSameReq.js'; it('should return function which returns true, if initially passed value equals the dynamic one', () => { expect(captureSameReq('abc')({ req_id: 'abc' })).toBe(true); expect(captureSameReq('abc')({ req_id: '111' })).toBe(false); -}); \ No newline at end of file +}); diff --git a/packages/sdk/src/bridge/captureSameReq.ts b/packages/sdk/src/bridge/captureSameReq.ts index f854bcb1b..d7297ceaf 100644 --- a/packages/sdk/src/bridge/captureSameReq.ts +++ b/packages/sdk/src/bridge/captureSameReq.ts @@ -6,7 +6,5 @@ type CaptureSameReqFn = (payload: { req_id: string }) => boolean; * @param reqId - request identifier. */ export function captureSameReq(reqId: string): CaptureSameReqFn { - return ({ req_id }: { req_id: string }): boolean => { - return req_id === reqId; - }; + return ({ req_id }) => req_id === reqId; } diff --git a/packages/sdk/src/bridge/env/__tests__/hasExternalNotify.ts b/packages/sdk/src/bridge/env/hasExternalNotify.test.ts similarity index 87% rename from packages/sdk/src/bridge/env/__tests__/hasExternalNotify.ts rename to packages/sdk/src/bridge/env/hasExternalNotify.test.ts index b05d7794c..9679d4db1 100644 --- a/packages/sdk/src/bridge/env/__tests__/hasExternalNotify.ts +++ b/packages/sdk/src/bridge/env/hasExternalNotify.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { hasExternalNotify } from '../hasExternalNotify.js'; +import { hasExternalNotify } from './hasExternalNotify.js'; it('should return true if passed object contains path property "external.notify" and "notify" is a function property.', () => { expect(hasExternalNotify({})).toBe(false); diff --git a/packages/sdk/src/bridge/env/hasExternalNotify.ts b/packages/sdk/src/bridge/env/hasExternalNotify.ts index cd3aefccd..ada530b4f 100644 --- a/packages/sdk/src/bridge/env/hasExternalNotify.ts +++ b/packages/sdk/src/bridge/env/hasExternalNotify.ts @@ -1,17 +1,16 @@ -import { isRecord } from '../../misc/isRecord.js'; - -type WithExternalNotify = T & { - external: { - notify: (...args: any) => any; - }; -}; +import { isRecord } from '@/misc/isRecord.js'; /** * Returns true in case, passed value contains path `external.notify` property and `notify` is a * function. * @param value - value to check. */ -export function hasExternalNotify(value: T): value is WithExternalNotify { +export function hasExternalNotify(value: T): value is ( + T & { + external: { + notify: (...args: any) => any; + }; +}) { return 'external' in value && isRecord(value.external) && 'notify' in value.external diff --git a/packages/sdk/src/bridge/env/__tests__/hasWebviewProxy.ts b/packages/sdk/src/bridge/env/hasWebviewProxy.test.ts similarity index 89% rename from packages/sdk/src/bridge/env/__tests__/hasWebviewProxy.ts rename to packages/sdk/src/bridge/env/hasWebviewProxy.test.ts index fee1e6965..de0dabc62 100644 --- a/packages/sdk/src/bridge/env/__tests__/hasWebviewProxy.ts +++ b/packages/sdk/src/bridge/env/hasWebviewProxy.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { hasWebviewProxy } from '../hasWebviewProxy.js'; +import { hasWebviewProxy } from './hasWebviewProxy.js'; it('should return true if passed object contains path property "TelegramWebviewProxy.postEvent" and "postEvent" is a function property.', () => { expect(hasWebviewProxy({})).toBe(false); diff --git a/packages/sdk/src/bridge/env/hasWebviewProxy.ts b/packages/sdk/src/bridge/env/hasWebviewProxy.ts index 7dd3f985d..59887c390 100644 --- a/packages/sdk/src/bridge/env/hasWebviewProxy.ts +++ b/packages/sdk/src/bridge/env/hasWebviewProxy.ts @@ -1,17 +1,16 @@ -import { isRecord } from '../../misc/isRecord.js'; - -type WithWebviewProxy = T & { - TelegramWebviewProxy: { - postEvent: (...args: any) => any; - } -}; +import { isRecord } from '@/misc/isRecord.js'; /** * Returns true in case, passed value contains path `TelegramWebviewProxy.postEvent` property and * `postEvent` is a function. * @param value - value to check. */ -export function hasWebviewProxy(value: T): value is WithWebviewProxy { +export function hasWebviewProxy(value: T): value is ( + T & { + TelegramWebviewProxy: { + postEvent: (...args: any) => any; + } +}) { return 'TelegramWebviewProxy' in value && isRecord(value.TelegramWebviewProxy) && 'postEvent' in value.TelegramWebviewProxy diff --git a/packages/sdk/src/bridge/errors/MethodUnsupportedError.ts b/packages/sdk/src/bridge/errors/MethodUnsupportedError.ts deleted file mode 100644 index c2ca5a41a..000000000 --- a/packages/sdk/src/bridge/errors/MethodUnsupportedError.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Version } from '../../version/types.js'; -import type { MiniAppsMethodName } from '../methods/methods.js'; - -/** - * Error thrown in case, unsupported method was called. - */ -export class MethodUnsupportedError extends Error { - constructor(method: MiniAppsMethodName, version: Version) { - super(`Method "${method}" is unsupported in the Mini Apps version ${version}.`); - Object.setPrototypeOf(this, MethodUnsupportedError.prototype); - } -} diff --git a/packages/sdk/src/bridge/errors/ParameterUnsupportedError.ts b/packages/sdk/src/bridge/errors/ParameterUnsupportedError.ts deleted file mode 100644 index ae639ea28..000000000 --- a/packages/sdk/src/bridge/errors/ParameterUnsupportedError.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Version } from '../../version/types.js'; -import type { MiniAppsMethodName } from '../methods/methods.js'; - -/** - * Error thrown in case, unsupported parameter was used. - */ -export class ParameterUnsupportedError extends Error { - constructor(method: MiniAppsMethodName, param: string, version: Version) { - super(`Parameter "${param}" in method "${method}" is unsupported in the Mini Apps version ${version}.`); - Object.setPrototypeOf(this, ParameterUnsupportedError.prototype); - } -} diff --git a/packages/sdk/src/bridge/events/__tests__/createEmitter.ts b/packages/sdk/src/bridge/events/createEmitter.test.ts similarity index 92% rename from packages/sdk/src/bridge/events/__tests__/createEmitter.ts rename to packages/sdk/src/bridge/events/createEmitter.test.ts index f2b00769e..57ec42f9e 100644 --- a/packages/sdk/src/bridge/events/__tests__/createEmitter.ts +++ b/packages/sdk/src/bridge/events/createEmitter.test.ts @@ -1,9 +1,9 @@ +import { createWindow, type WindowSpy } from '@test-utils/createWindow.js'; +import { dispatchWindowMessageEvent } from '@test-utils/dispatchWindowMessageEvent.js'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { createWindow, type WindowSpy } from '../../../../test-utils/createWindow'; -import { dispatchWindowMessageEvent } from '../../../../test-utils/dispatchWindowMessageEvent'; -import { createEmitter } from '../createEmitter'; -import type { MiniAppsEventName, MiniAppsEventParams } from '../events'; +import { createEmitter } from './createEmitter.js'; +import type { MiniAppsEventName, MiniAppsEventParams } from './types/events.js'; type TestCase = | [input: any, expected: MiniAppsEventParams] diff --git a/packages/sdk/src/bridge/events/createEmitter.ts b/packages/sdk/src/bridge/events/createEmitter.ts index 283f83e04..bb91b0702 100644 --- a/packages/sdk/src/bridge/events/createEmitter.ts +++ b/packages/sdk/src/bridge/events/createEmitter.ts @@ -1,4 +1,7 @@ -import type { MiniAppsEventEmitter, MiniAppsEventName } from './events.js'; +import { error, log } from '@/debug/debug.js'; +import { EventEmitter } from '@/event-emitter/EventEmitter.js'; +import { string } from '@/parsing/parsers/string.js'; + import { onTelegramEvent } from './onTelegramEvent.js'; import { clipboardTextReceived } from './parsers/clipboardTextReceived.js'; import { customMethodInvoked } from './parsers/customMethodInvoked.js'; @@ -9,9 +12,7 @@ import { qrTextReceived } from './parsers/qrTextReceived.js'; import { themeChanged } from './parsers/theme-changed.js'; import { viewportChanged } from './parsers/viewportChanged.js'; import { writeAccessRequested } from './parsers/writeAccessRequested.js'; -import { EventEmitter } from '../../event-emitter/EventEmitter.js'; -import { logger } from '../../globals.js'; -import { string } from '../../parsing/parsers/string.js'; +import type { MiniAppsEventEmitter, MiniAppsEventName } from './types/events.js'; /** * Returns event emitter which could be safely used, to process events from @@ -20,7 +21,13 @@ import { string } from '../../parsing/parsers/string.js'; export function createEmitter(): MiniAppsEventEmitter { const emitter: MiniAppsEventEmitter = new EventEmitter(); const emit: MiniAppsEventEmitter['emit'] = (event: any, ...data: any[]) => { - logger.log('Emitting processed event:', event, ...data); + log( + 'emittedEvent', + 'Emitting processed event:', + data.length + ? { event, args: data } + : { event }, + ); emitter.emit(event, ...data); }; @@ -40,7 +47,7 @@ export function createEmitter(): MiniAppsEventEmitter { // In case, any Telegram event was received, we should prepare data before // passing it to emitter. onTelegramEvent((eventType: MiniAppsEventName | string, eventData): void => { - logger.log('Received raw event:', eventType, eventData); + log('rawEvent', 'Received raw event:', { eventType, eventData }); try { switch (eventType) { @@ -51,17 +58,7 @@ export function createEmitter(): MiniAppsEventEmitter { return emit(eventType, themeChanged().parse(eventData)); case 'popup_closed': - // FIXME: Payloads are different on different platforms. - // Issue: https://github.com/Telegram-Mini-Apps/tma.js/issues/2 - if ( - // Sent on desktop. - eventData === undefined - // Sent on iOS. - || eventData === null - ) { - return emit(eventType, {}); - } - return emit(eventType, popupClosed().parse(eventData)); + return emit(eventType, popupClosed().parse(eventData || {})); case 'set_custom_style': return emit(eventType, string().parse(eventData)); @@ -97,7 +94,12 @@ export function createEmitter(): MiniAppsEventEmitter { return emit(eventType as any, eventData); } } catch (cause) { - logger.error('Error processing event:', cause); + error( + null, + 'There was an error processing an event from the Telegram application. Please, file an issue here: https://github.com/Telegram-Mini-Apps/tma.js/issues/new/choose', + { eventType, eventData }, + cause, + ); } }); diff --git a/packages/sdk/src/bridge/events/__tests__/off.ts b/packages/sdk/src/bridge/events/off.test.ts similarity index 72% rename from packages/sdk/src/bridge/events/__tests__/off.ts rename to packages/sdk/src/bridge/events/off.test.ts index 161f7a777..00f6beb15 100644 --- a/packages/sdk/src/bridge/events/__tests__/off.ts +++ b/packages/sdk/src/bridge/events/off.test.ts @@ -1,9 +1,9 @@ +import { createWindow, type WindowSpy } from '@test-utils/createWindow.js'; +import { dispatchWindowMessageEvent } from '@test-utils/dispatchWindowMessageEvent.js'; import { afterEach, beforeEach, expect, it, vi } from 'vitest'; -import { createWindow, type WindowSpy } from '../../../../test-utils/createWindow'; -import { dispatchWindowMessageEvent } from '../../../../test-utils/dispatchWindowMessageEvent'; -import { off } from '../off'; -import { on } from '../on'; +import { off } from './off.js'; +import { on } from './on.js'; let windowSpy: WindowSpy; diff --git a/packages/sdk/src/bridge/events/off.ts b/packages/sdk/src/bridge/events/off.ts index 614e306d4..8e7044fab 100644 --- a/packages/sdk/src/bridge/events/off.ts +++ b/packages/sdk/src/bridge/events/off.ts @@ -1,5 +1,5 @@ -import type { MiniAppsEventListener, MiniAppsEventName } from './events.js'; import { singletonEmitter } from './singletonEmitter.js'; +import type { MiniAppsEventListener, MiniAppsEventName } from './types/events.js'; /** * Removes listener from specified event. diff --git a/packages/sdk/src/bridge/events/__tests__/on.ts b/packages/sdk/src/bridge/events/on.test.ts similarity index 83% rename from packages/sdk/src/bridge/events/__tests__/on.ts rename to packages/sdk/src/bridge/events/on.test.ts index 108f34828..ce42b5af5 100644 --- a/packages/sdk/src/bridge/events/__tests__/on.ts +++ b/packages/sdk/src/bridge/events/on.test.ts @@ -1,8 +1,8 @@ +import { createWindow, type WindowSpy } from '@test-utils/createWindow.js'; +import { dispatchWindowMessageEvent } from '@test-utils/dispatchWindowMessageEvent.js'; import { afterEach, beforeEach, expect, it, vi } from 'vitest'; -import { createWindow, type WindowSpy } from '../../../../test-utils/createWindow'; -import { dispatchWindowMessageEvent } from '../../../../test-utils/dispatchWindowMessageEvent'; -import { on } from '../on'; +import { on } from './on.js'; let windowSpy: WindowSpy; diff --git a/packages/sdk/src/bridge/events/on.ts b/packages/sdk/src/bridge/events/on.ts index 4c9a27c20..829f670ce 100644 --- a/packages/sdk/src/bridge/events/on.ts +++ b/packages/sdk/src/bridge/events/on.ts @@ -1,7 +1,7 @@ -import type { MiniAppsEventListener, MiniAppsEventName } from './events.js'; import { off } from './off.js'; import { singletonEmitter } from './singletonEmitter.js'; -import type { RemoveListenerFn } from './types.js'; +import type { MiniAppsEventListener, MiniAppsEventName } from './types/events.js'; +import type { CleanupFn } from './types/misc.js'; /** * Adds new listener to the specified event. Returns handler @@ -12,7 +12,7 @@ import type { RemoveListenerFn } from './types.js'; export function on( event: E, listener: MiniAppsEventListener, -): RemoveListenerFn { +): CleanupFn { singletonEmitter().on(event, listener); return () => off(event, listener); } diff --git a/packages/sdk/src/bridge/events/__tests__/onTelegramEvent.ts b/packages/sdk/src/bridge/events/onTelegramEvent.test.ts similarity index 81% rename from packages/sdk/src/bridge/events/__tests__/onTelegramEvent.ts rename to packages/sdk/src/bridge/events/onTelegramEvent.test.ts index 73bc0f2cd..7286de125 100644 --- a/packages/sdk/src/bridge/events/__tests__/onTelegramEvent.ts +++ b/packages/sdk/src/bridge/events/onTelegramEvent.test.ts @@ -1,11 +1,11 @@ -import { afterEach, beforeEach, expect, it, vi } from 'vitest'; +import { createWindow } from '@test-utils/createWindow.js'; +import { dispatchWindowMessageEvent } from '@test-utils/dispatchWindowMessageEvent.js'; +import { afterEach, expect, it, vi } from 'vitest'; -import { createWindow, type WindowSpy } from '../../../../test-utils/createWindow'; -import { dispatchWindowMessageEvent } from '../../../../test-utils/dispatchWindowMessageEvent'; -import { onTelegramEvent } from '../onTelegramEvent'; +import { onTelegramEvent } from './onTelegramEvent.js'; afterEach(() => { - vi.restoreAllMocks() + vi.restoreAllMocks(); }); it('should call passed callback with event type and data in case, window generated "message" event with data, presented as object with properties "eventType" (string) and "eventData" (unknown). Object is converted to string.', () => { diff --git a/packages/sdk/src/bridge/events/__tests__/once.ts b/packages/sdk/src/bridge/events/once.test.ts similarity index 86% rename from packages/sdk/src/bridge/events/__tests__/once.ts rename to packages/sdk/src/bridge/events/once.test.ts index 41e05dcfc..872148eb6 100644 --- a/packages/sdk/src/bridge/events/__tests__/once.ts +++ b/packages/sdk/src/bridge/events/once.test.ts @@ -1,8 +1,8 @@ +import { createWindow, type WindowSpy } from '@test-utils/createWindow.js'; +import { dispatchWindowMessageEvent } from '@test-utils/dispatchWindowMessageEvent.js'; import { afterEach, beforeEach, expect, it, vi } from 'vitest'; -import { createWindow, type WindowSpy } from '../../../../test-utils/createWindow'; -import { dispatchWindowMessageEvent } from '../../../../test-utils/dispatchWindowMessageEvent'; -import { once } from '../once'; +import { once } from './once.js'; let windowSpy: WindowSpy; diff --git a/packages/sdk/src/bridge/events/once.ts b/packages/sdk/src/bridge/events/once.ts index 9c5cb125f..8d04ff69e 100644 --- a/packages/sdk/src/bridge/events/once.ts +++ b/packages/sdk/src/bridge/events/once.ts @@ -1,7 +1,7 @@ -import type { MiniAppsEventListener, MiniAppsEventName } from './events.js'; import { off } from './off.js'; import { singletonEmitter } from './singletonEmitter.js'; -import type { RemoveListenerFn } from './types.js'; +import type { MiniAppsEventListener, MiniAppsEventName } from './types/events.js'; +import type { CleanupFn } from './types/misc.js'; /** * Works the same as "on" method, but after catching the event, will remove event listener. @@ -11,7 +11,7 @@ import type { RemoveListenerFn } from './types.js'; export function once( event: E, listener: MiniAppsEventListener, -): RemoveListenerFn { +): CleanupFn { singletonEmitter().once(event, listener); return () => off(event, listener); } diff --git a/packages/sdk/src/bridge/events/parsers/__tests__/clipboardTextReceived.ts b/packages/sdk/src/bridge/events/parsers/clipboardTextReceived.test.ts similarity index 89% rename from packages/sdk/src/bridge/events/parsers/__tests__/clipboardTextReceived.ts rename to packages/sdk/src/bridge/events/parsers/clipboardTextReceived.test.ts index 5f50b7dfc..b51277245 100644 --- a/packages/sdk/src/bridge/events/parsers/__tests__/clipboardTextReceived.ts +++ b/packages/sdk/src/bridge/events/parsers/clipboardTextReceived.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { clipboardTextReceived } from '../clipboardTextReceived'; +import { clipboardTextReceived } from './clipboardTextReceived.js'; it('should return parsed value in case, passed value satisfies schema', () => { const cases = [ diff --git a/packages/sdk/src/bridge/events/parsers/clipboardTextReceived.ts b/packages/sdk/src/bridge/events/parsers/clipboardTextReceived.ts index 150fd86c6..44adcbd19 100644 --- a/packages/sdk/src/bridge/events/parsers/clipboardTextReceived.ts +++ b/packages/sdk/src/bridge/events/parsers/clipboardTextReceived.ts @@ -1,27 +1,14 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; -import type { RequestId } from '../../../types/request-id.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export interface ClipboardTextReceivedPayload { - /** - * Passed during the `web_app_read_text_from_clipboard` method invocation `req_id` value. - */ - req_id: RequestId; +import type { ClipboardTextReceivedPayload } from '../types/payloads.js'; - /** - * Data extracted from the clipboard. The returned value will have the type `string` only in - * the case, application has access to the clipboard. - */ - data?: string | null; -} - -export function clipboardTextReceived() { - return json({ +export function clipboardTextReceived(): ValueParser { + return json({ req_id: string(), data: (value) => ( - value === null - ? value - : string().optional().parse(value) + value === null ? value : string().optional().parse(value) ), - }); + }, 'ClipboardTextReceivedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/customMethodInvoked.test.ts b/packages/sdk/src/bridge/events/parsers/customMethodInvoked.test.ts new file mode 100644 index 000000000..828401782 --- /dev/null +++ b/packages/sdk/src/bridge/events/parsers/customMethodInvoked.test.ts @@ -0,0 +1,22 @@ +import { expect, it } from 'vitest'; + +import { customMethodInvoked } from './customMethodInvoked.js'; + +it('should return parsed value in case, passed value satisfies schema', () => { + const cases = [ + { req_id: 'abc', result: 'ok' }, + { req_id: 'abc', result: 'not sure if ok', error: 'ERROR' }, + { req_id: 'abc' }, + { req_id: 'abc', error: 'ERROR' }, + ]; + + cases.forEach((value) => { + expect(customMethodInvoked().parse(value)).toStrictEqual(value); + expect(customMethodInvoked().parse(JSON.stringify(value))) + .toStrictEqual(value); + }); +}); + +it('should throw an error in case, passed value does not satisfy schema', () => { + expect(() => customMethodInvoked().parse({})).toThrow(); +}); diff --git a/packages/sdk/src/bridge/events/parsers/customMethodInvoked.ts b/packages/sdk/src/bridge/events/parsers/customMethodInvoked.ts index 9f6d00956..6da0cfbfc 100644 --- a/packages/sdk/src/bridge/events/parsers/customMethodInvoked.ts +++ b/packages/sdk/src/bridge/events/parsers/customMethodInvoked.ts @@ -1,26 +1,13 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; -import type { RequestId } from '../../../types/request-id.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export interface CustomMethodInvokedPayload { - /** - * Unique identifier of this invocation. - */ - req_id: RequestId; - /** - * Method invocation successful result. - */ - result?: R; - /** - * Method invocation error code. - */ - error?: string; -} +import type { CustomMethodInvokedPayload } from '../types/payloads.js'; -export function customMethodInvoked() { - return json({ +export function customMethodInvoked(): ValueParser { + return json({ req_id: string(), result: (value) => value, error: string().optional(), - }); + }, 'CustomMethodInvokedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/__tests__/invoiceClosed.ts b/packages/sdk/src/bridge/events/parsers/invoiceClosed.test.ts similarity index 87% rename from packages/sdk/src/bridge/events/parsers/__tests__/invoiceClosed.ts rename to packages/sdk/src/bridge/events/parsers/invoiceClosed.test.ts index 32ccc37dc..75a37f298 100644 --- a/packages/sdk/src/bridge/events/parsers/__tests__/invoiceClosed.ts +++ b/packages/sdk/src/bridge/events/parsers/invoiceClosed.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { invoiceClosed } from '../invoiceClosed'; +import { invoiceClosed } from './invoiceClosed.js'; it('should return parsed value in case, passed value satisfies schema', () => { const value = { slug: 'abc', status: 'def' }; diff --git a/packages/sdk/src/bridge/events/parsers/invoiceClosed.ts b/packages/sdk/src/bridge/events/parsers/invoiceClosed.ts index 87fc44111..6dc090602 100644 --- a/packages/sdk/src/bridge/events/parsers/invoiceClosed.ts +++ b/packages/sdk/src/bridge/events/parsers/invoiceClosed.ts @@ -1,27 +1,9 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export type InvoiceStatus = - | 'paid' - | 'failed' - | 'pending' - | 'cancelled' - | string; +import type { InvoiceClosedPayload } from '../types/payloads.js'; -export interface InvoiceClosedPayload { - /** - * Passed during the `web_app_open_invoice` method invocation `slug` value. - */ - slug: string; - /** - * Invoice status - */ - status: InvoiceStatus; -} - -export function invoiceClosed() { - return json({ - slug: string(), - status: string(), - }); +export function invoiceClosed(): ValueParser { + return json({ slug: string(), status: string() }, 'InvoiceClosedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/phoneRequested.test.ts b/packages/sdk/src/bridge/events/parsers/phoneRequested.test.ts new file mode 100644 index 000000000..e9d25c4b5 --- /dev/null +++ b/packages/sdk/src/bridge/events/parsers/phoneRequested.test.ts @@ -0,0 +1,17 @@ +import { expect, it } from 'vitest'; + +import { phoneRequested } from './phoneRequested.js'; + +it('should return parsed value in case, passed value satisfies schema', () => { + const cases = [{ status: 'sent' }]; + + cases.forEach((value) => { + expect(phoneRequested().parse(value)).toStrictEqual(value); + expect(phoneRequested().parse(JSON.stringify(value))) + .toStrictEqual(value); + }); +}); + +it('should throw an error in case, passed value does not satisfy schema', () => { + expect(() => phoneRequested().parse({})).toThrow(); +}); diff --git a/packages/sdk/src/bridge/events/parsers/phoneRequested.ts b/packages/sdk/src/bridge/events/parsers/phoneRequested.ts index 2b5ce3720..146f1dc34 100644 --- a/packages/sdk/src/bridge/events/parsers/phoneRequested.ts +++ b/packages/sdk/src/bridge/events/parsers/phoneRequested.ts @@ -1,15 +1,9 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export type PhoneRequestedStatus = 'sent' | 'cancelled' | string; +import type { PhoneRequestedPayload } from '../types/payloads.js'; -export interface PhoneRequestedPayload { - /** - * Request status. - */ - status: PhoneRequestedStatus; -} - -export function phoneRequested() { - return json({ status: string() }); +export function phoneRequested(): ValueParser { + return json({ status: string() }, 'PhoneRequestedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/__tests__/popupClosed.ts b/packages/sdk/src/bridge/events/parsers/popupClosed.test.ts similarity index 89% rename from packages/sdk/src/bridge/events/parsers/__tests__/popupClosed.ts rename to packages/sdk/src/bridge/events/parsers/popupClosed.test.ts index 0bfa2132c..229209641 100644 --- a/packages/sdk/src/bridge/events/parsers/__tests__/popupClosed.ts +++ b/packages/sdk/src/bridge/events/parsers/popupClosed.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { popupClosed } from '../popupClosed'; +import { popupClosed } from './popupClosed.js'; it('should return parsed value in case, passed value satisfies schema', () => { expect(popupClosed().parse({ button_id: 'ok' })).toStrictEqual({ button_id: 'ok' }); diff --git a/packages/sdk/src/bridge/events/parsers/popupClosed.ts b/packages/sdk/src/bridge/events/parsers/popupClosed.ts index 2fd90f4ce..428b1a76c 100644 --- a/packages/sdk/src/bridge/events/parsers/popupClosed.ts +++ b/packages/sdk/src/bridge/events/parsers/popupClosed.ts @@ -1,20 +1,13 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export interface PopupClosedPayload { - /** - * Identifier of the clicked button. In case, the popup was closed without clicking any button, - * this property will be omitted. - */ - button_id?: string; -} +import type { PopupClosedPayload } from '../types/payloads.js'; -export function popupClosed() { - return json({ +export function popupClosed(): ValueParser { + return json({ button_id: (value) => ( - value === null || value === undefined - ? undefined - : string().parse(value) + value === null || value === undefined ? undefined : string().parse(value) ), - }); + }, 'PopupClosedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/__tests__/qrTextReceived.ts b/packages/sdk/src/bridge/events/parsers/qrTextReceived.test.ts similarity index 86% rename from packages/sdk/src/bridge/events/parsers/__tests__/qrTextReceived.ts rename to packages/sdk/src/bridge/events/parsers/qrTextReceived.test.ts index 318fa5480..e4e77bf89 100644 --- a/packages/sdk/src/bridge/events/parsers/__tests__/qrTextReceived.ts +++ b/packages/sdk/src/bridge/events/parsers/qrTextReceived.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { qrTextReceived } from '../qrTextReceived'; +import { qrTextReceived } from './qrTextReceived.js'; it('should return parsed value in case, passed value satisfies schema', () => { expect(qrTextReceived().parse({ data: 'ok' })).toStrictEqual({ data: 'ok' }); diff --git a/packages/sdk/src/bridge/events/parsers/qrTextReceived.ts b/packages/sdk/src/bridge/events/parsers/qrTextReceived.ts index cbbfccdd1..e2001c7b3 100644 --- a/packages/sdk/src/bridge/events/parsers/qrTextReceived.ts +++ b/packages/sdk/src/bridge/events/parsers/qrTextReceived.ts @@ -1,15 +1,9 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export interface QrTextReceivedPayload { - /** - * Data extracted from the QR. - */ - data?: string; -} +import type { QrTextReceivedPayload } from '../types/payloads.js'; -export function qrTextReceived() { - return json({ - data: string().optional(), - }); +export function qrTextReceived(): ValueParser { + return json({ data: string().optional() }, 'QrTextReceivedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/__tests__/theme-changed.ts b/packages/sdk/src/bridge/events/parsers/theme-changed.test.ts similarity index 95% rename from packages/sdk/src/bridge/events/parsers/__tests__/theme-changed.ts rename to packages/sdk/src/bridge/events/parsers/theme-changed.test.ts index 0074a6e0b..380de7d94 100644 --- a/packages/sdk/src/bridge/events/parsers/__tests__/theme-changed.ts +++ b/packages/sdk/src/bridge/events/parsers/theme-changed.test.ts @@ -1,6 +1,6 @@ import { expect, it } from 'vitest'; -import { themeChanged } from '../theme-changed'; +import { themeChanged } from './theme-changed.js'; it('should return parsed value in case, passed value satisfies schema', () => { const values = [ diff --git a/packages/sdk/src/bridge/events/parsers/theme-changed.ts b/packages/sdk/src/bridge/events/parsers/theme-changed.ts index c50e3d287..c1758c942 100644 --- a/packages/sdk/src/bridge/events/parsers/theme-changed.ts +++ b/packages/sdk/src/bridge/events/parsers/theme-changed.ts @@ -1,51 +1,13 @@ -import type { RGB } from '../../../colors/types.js'; -import { json } from '../../../parsing/parsers/json.js'; -import { rgb } from '../../../parsing/parsers/rgb.js'; -import { toRecord } from '../../../parsing/toRecord.js'; +import type { RGB } from '@/colors/types.js'; +import { json } from '@/parsing/parsers/json.js'; +import { rgb } from '@/parsing/parsers/rgb.js'; +import { toRecord } from '@/parsing/toRecord.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export interface ThemeChangedPayload { - /** - * Map where the key is a theme stylesheet key and value is the corresponding color in - * `#RRGGBB` format. - */ - theme_params: { - /** - * @since v6.10 - */ - accent_text_color?: RGB; - bg_color?: RGB; - button_color?: RGB; - button_text_color?: RGB; - /** - * @since v6.10 - */ - destructive_text_color?: RGB; - /** - * @since v6.10 - */ - header_bg_color?: RGB; - hint_color?: RGB; - link_color?: RGB; - secondary_bg_color?: RGB; - /** - * @since v6.10 - */ - section_bg_color?: RGB; - /** - * @since v6.10 - */ - section_header_text_color?: RGB; - /** - * @since v6.10 - */ - subtitle_text_color?: RGB; - text_color?: RGB; - [key: string]: RGB | undefined; // Future unknown palette keys. - }; -} +import type { ThemeChangedPayload } from '../types/payloads.js'; -export function themeChanged() { - return json({ +export function themeChanged(): ValueParser { + return json({ theme_params: (value) => { const parser = rgb().optional(); diff --git a/packages/sdk/src/bridge/events/parsers/__tests__/viewportChanged.ts b/packages/sdk/src/bridge/events/parsers/viewportChanged.test.ts similarity index 95% rename from packages/sdk/src/bridge/events/parsers/__tests__/viewportChanged.ts rename to packages/sdk/src/bridge/events/parsers/viewportChanged.test.ts index f8f446135..89b0bb38e 100644 --- a/packages/sdk/src/bridge/events/parsers/__tests__/viewportChanged.ts +++ b/packages/sdk/src/bridge/events/parsers/viewportChanged.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, expect, it, vi } from 'vitest'; -import { viewportChanged } from '../viewportChanged'; +import { viewportChanged } from './viewportChanged.js'; const windowSpy = vi.spyOn(window, 'window', 'get'); // const innerWidth = 2000; diff --git a/packages/sdk/src/bridge/events/parsers/viewportChanged.ts b/packages/sdk/src/bridge/events/parsers/viewportChanged.ts index 9494afd68..2c1e32102 100644 --- a/packages/sdk/src/bridge/events/parsers/viewportChanged.ts +++ b/packages/sdk/src/bridge/events/parsers/viewportChanged.ts @@ -1,28 +1,12 @@ -import { boolean } from '../../../parsing/parsers/boolean.js'; -import { json } from '../../../parsing/parsers/json.js'; -import { number } from '../../../parsing/parsers/number.js'; +import { boolean } from '@/parsing/parsers/boolean.js'; +import { json } from '@/parsing/parsers/json.js'; +import { number } from '@/parsing/parsers/number.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export interface ViewportChangedPayload { - /** - * The viewport height. - */ - height: number; - /** - * The viewport width. - */ - width: number; - /** - * Is the viewport currently expanded. - */ - is_expanded: boolean; - /** - * Is the viewport current state stable and not going to change in the next moment. - */ - is_state_stable: boolean; -} +import type { ViewportChangedPayload } from '../types/payloads.js'; -export function viewportChanged() { - return json({ +export function viewportChanged(): ValueParser { + return json({ height: number(), width: (value) => ( value === null || value === undefined @@ -31,5 +15,5 @@ export function viewportChanged() { ), is_state_stable: boolean(), is_expanded: boolean(), - }); + }, 'ViewportChangedPayload'); } diff --git a/packages/sdk/src/bridge/events/parsers/writeAccessRequested.test.ts b/packages/sdk/src/bridge/events/parsers/writeAccessRequested.test.ts new file mode 100644 index 000000000..f2d2c1a63 --- /dev/null +++ b/packages/sdk/src/bridge/events/parsers/writeAccessRequested.test.ts @@ -0,0 +1,17 @@ +import { expect, it } from 'vitest'; + +import { writeAccessRequested } from './writeAccessRequested.js'; + +it('should return parsed value in case, passed value satisfies schema', () => { + const cases = [{ status: 'sent' }]; + + cases.forEach((value) => { + expect(writeAccessRequested().parse(value)).toStrictEqual(value); + expect(writeAccessRequested().parse(JSON.stringify(value))) + .toStrictEqual(value); + }); +}); + +it('should throw an error in case, passed value does not satisfy schema', () => { + expect(() => writeAccessRequested().parse({})).toThrow(); +}); diff --git a/packages/sdk/src/bridge/events/parsers/writeAccessRequested.ts b/packages/sdk/src/bridge/events/parsers/writeAccessRequested.ts index 5b2139f54..0d9bd20f0 100644 --- a/packages/sdk/src/bridge/events/parsers/writeAccessRequested.ts +++ b/packages/sdk/src/bridge/events/parsers/writeAccessRequested.ts @@ -1,15 +1,9 @@ -import { json } from '../../../parsing/parsers/json.js'; -import { string } from '../../../parsing/parsers/string.js'; +import { json } from '@/parsing/parsers/json.js'; +import { string } from '@/parsing/parsers/string.js'; +import type { ValueParser } from '@/parsing/ValueParser/ValueParser.js'; -export type WriteAccessRequestedStatus = 'allowed' | string; +import type { WriteAccessRequestedPayload } from '../types/payloads.js'; -export interface WriteAccessRequestedPayload { - /** - * Request status. - */ - status: WriteAccessRequestedStatus; -} - -export function writeAccessRequested() { - return json({ status: string() }); +export function writeAccessRequested(): ValueParser { + return json({ status: string() }, 'WriteAccessRequestedPayload'); } diff --git a/packages/sdk/src/bridge/events/__tests__/singletonEmitter.ts b/packages/sdk/src/bridge/events/singletonEmitter.test.ts similarity index 65% rename from packages/sdk/src/bridge/events/__tests__/singletonEmitter.ts rename to packages/sdk/src/bridge/events/singletonEmitter.test.ts index 46da6d8c3..3e28a6aee 100644 --- a/packages/sdk/src/bridge/events/__tests__/singletonEmitter.ts +++ b/packages/sdk/src/bridge/events/singletonEmitter.test.ts @@ -1,8 +1,8 @@ +import type { WindowSpy } from '@test-utils/createWindow.js'; +import { createWindow } from '@test-utils/createWindow.js'; import { afterEach, beforeEach, expect, it } from 'vitest'; -import type { WindowSpy } from '../../../../test-utils/createWindow'; -import { createWindow } from '../../../../test-utils/createWindow'; -import { singletonEmitter } from '../singletonEmitter'; +import { singletonEmitter } from './singletonEmitter.js'; let windowSpy: WindowSpy; diff --git a/packages/sdk/src/bridge/events/singletonEmitter.ts b/packages/sdk/src/bridge/events/singletonEmitter.ts index 52bc8941f..5802a133b 100644 --- a/packages/sdk/src/bridge/events/singletonEmitter.ts +++ b/packages/sdk/src/bridge/events/singletonEmitter.ts @@ -1,7 +1,7 @@ import { createEmitter } from './createEmitter.js'; -import type { MiniAppsEventEmitter } from './events.js'; +import type { MiniAppsEventEmitter } from './types/events.js'; -const CACHED_EMITTER = 'telegram-mini-apps-cached-emitter'; +const CACHED_EMITTER = '@tma.js/cached-emitter'; /** * Returns singleton instance of bridge EventEmitter. Also, defines diff --git a/packages/sdk/src/bridge/events/__tests__/subscribe.ts b/packages/sdk/src/bridge/events/subscribe.test.ts similarity index 76% rename from packages/sdk/src/bridge/events/__tests__/subscribe.ts rename to packages/sdk/src/bridge/events/subscribe.test.ts index b2d3504f5..e9b04740f 100644 --- a/packages/sdk/src/bridge/events/__tests__/subscribe.ts +++ b/packages/sdk/src/bridge/events/subscribe.test.ts @@ -1,8 +1,8 @@ +import { createWindow, type WindowSpy } from '@test-utils/createWindow.js'; +import { dispatchWindowMessageEvent } from '@test-utils/dispatchWindowMessageEvent.js'; import { afterEach, beforeEach, expect, it, vi } from 'vitest'; -import { createWindow, type WindowSpy } from '../../../../test-utils/createWindow'; -import { dispatchWindowMessageEvent } from '../../../../test-utils/dispatchWindowMessageEvent'; -import { subscribe } from '../subscribe'; +import { subscribe } from './subscribe.js'; let windowSpy: WindowSpy; @@ -27,7 +27,10 @@ it('should call listener in case, Telegram event was created', () => { dispatchWindowMessageEvent('viewport_changed', eventData); expect(listener).toHaveBeenCalledTimes(1); - expect(listener).toHaveBeenCalledWith('viewport_changed', eventData); + expect(listener).toHaveBeenCalledWith({ + event: 'viewport_changed', + args: [eventData], + }); }); it('should remove listener in case, returned callback was called', () => { diff --git a/packages/sdk/src/bridge/events/subscribe.ts b/packages/sdk/src/bridge/events/subscribe.ts index af3b611e5..0b21da892 100644 --- a/packages/sdk/src/bridge/events/subscribe.ts +++ b/packages/sdk/src/bridge/events/subscribe.ts @@ -1,6 +1,6 @@ -import type { MiniAppsGlobalEventListener } from './events.js'; import { singletonEmitter } from './singletonEmitter.js'; -import type { RemoveListenerFn } from './types.js'; +import type { MiniAppsGlobalEventListener } from './types/events.js'; +import type { CleanupFn } from './types/misc.js'; import { unsubscribe } from './unsubscribe.js'; /** @@ -8,7 +8,7 @@ import { unsubscribe } from './unsubscribe.js'; * Returns function used to remove added event listener. * @param listener - event listener. */ -export function subscribe(listener: MiniAppsGlobalEventListener): RemoveListenerFn { +export function subscribe(listener: MiniAppsGlobalEventListener): CleanupFn { singletonEmitter().subscribe(listener); return () => unsubscribe(listener); } diff --git a/packages/sdk/src/bridge/events/types.ts b/packages/sdk/src/bridge/events/types.ts deleted file mode 100644 index 874d4428a..000000000 --- a/packages/sdk/src/bridge/events/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Removes event listener. - */ -export type RemoveListenerFn = () => void; diff --git a/packages/sdk/src/bridge/events/events.ts b/packages/sdk/src/bridge/events/types/events.ts similarity index 84% rename from packages/sdk/src/bridge/events/events.ts rename to packages/sdk/src/bridge/events/types/events.ts index 594ef1172..13f766544 100644 --- a/packages/sdk/src/bridge/events/events.ts +++ b/packages/sdk/src/bridge/events/types/events.ts @@ -1,16 +1,19 @@ -import type { ClipboardTextReceivedPayload } from './parsers/clipboardTextReceived.js'; -import type { CustomMethodInvokedPayload } from './parsers/customMethodInvoked.js'; -import type { InvoiceClosedPayload } from './parsers/invoiceClosed.js'; -import type { PhoneRequestedPayload } from './parsers/phoneRequested.js'; -import type { PopupClosedPayload } from './parsers/popupClosed.js'; -import type { QrTextReceivedPayload } from './parsers/qrTextReceived.js'; -import type { ThemeChangedPayload } from './parsers/theme-changed.js'; -import type { ViewportChangedPayload } from './parsers/viewportChanged.js'; -import type { WriteAccessRequestedPayload } from './parsers/writeAccessRequested.js'; -import type { EventEmitter } from '../../event-emitter/EventEmitter.js'; -import type { AnySubscribeListener, EventListener, EventParams } from '../../event-emitter/types.js'; -import type { Not } from '../../types/logical.js'; -import type { IsNever } from '../../types/utils.js'; +import type { EventEmitter } from '@/event-emitter/EventEmitter.js'; +import type { AnySubscribeListener, EventListener, EventParams } from '@/event-emitter/types.js'; +import type { Not } from '@/types/logical.js'; +import type { IsNever } from '@/types/utils.js'; + +import type { + ClipboardTextReceivedPayload, + CustomMethodInvokedPayload, + InvoiceClosedPayload, + PhoneRequestedPayload, + PopupClosedPayload, + QrTextReceivedPayload, + ThemeChangedPayload, + ViewportChangedPayload, + WriteAccessRequestedPayload, +} from './payloads.js'; /** * Map where key is known event name, and value is its listener. @@ -23,7 +26,6 @@ export interface MiniAppsEvents { * @see https://docs.telegram-mini-apps.com/platform/events#back-button-pressed */ back_button_pressed: () => void; - /** * Telegram application attempted to extract text from clipboard. * @param payload - event payload. @@ -31,7 +33,6 @@ export interface MiniAppsEvents { * @see https://docs.telegram-mini-apps.com/platform/events#clipboard-text-received */ clipboard_text_received: (payload: ClipboardTextReceivedPayload) => void; - /** * Custom method invocation completed. * @param payload - event payload. @@ -39,20 +40,17 @@ export interface MiniAppsEvents { * @see https://docs.telegram-mini-apps.com/platform/events#custom-method-invoked */ custom_method_invoked: (payload: CustomMethodInvokedPayload) => void; - /** * An invoice was closed. * @param payload - invoice close information. * @see https://docs.telegram-mini-apps.com/platform/events#invoice-closed */ invoice_closed: (payload: InvoiceClosedPayload) => void; - /** * User clicked the Main Button. * @see https://docs.telegram-mini-apps.com/platform/events#main-button-pressed */ main_button_pressed: () => void; - /** * Application received phone access request status. * @param payload - event payload. @@ -60,20 +58,17 @@ export interface MiniAppsEvents { * @see https://docs.telegram-mini-apps.com/platform/events#phone-requested */ phone_requested: (payload: PhoneRequestedPayload) => void; - /** * Popup was closed. * @param payload - event payload. * @see https://docs.telegram-mini-apps.com/platform/events#popup-closed */ popup_closed: (payload: PopupClosedPayload) => void; - /** * Parent iframe requested current iframe reload. * @see https://docs.telegram-mini-apps.com/platform/events#reload-iframe */ reload_iframe: () => void; - /** * The QR scanner scanned some QR and extracted its content. * @param payload - event payload. @@ -81,14 +76,12 @@ export interface MiniAppsEvents { * @see https://docs.telegram-mini-apps.com/platform/events#qr-text-received */ qr_text_received: (payload: QrTextReceivedPayload) => void; - /** * QR scanner was closed. * @since v6.4 * @see https://docs.telegram-mini-apps.com/platform/events#scan-qr-popup-closed */ scan_qr_popup_closed: () => void; - /** * The event which is usually sent by the Telegram web application. Its payload represents * `