diff --git a/.changeset/gorgeous-forks-clap.md b/.changeset/gorgeous-forks-clap.md new file mode 100644 index 000000000..f3721a8d1 --- /dev/null +++ b/.changeset/gorgeous-forks-clap.md @@ -0,0 +1,5 @@ +--- +"@telegram-apps/sdk": patch +--- + +Remove some errors exported from bridge. diff --git a/.changeset/polite-spies-nail.md b/.changeset/polite-spies-nail.md new file mode 100644 index 000000000..8aba0b35c --- /dev/null +++ b/.changeset/polite-spies-nail.md @@ -0,0 +1,5 @@ +--- +"@telegram-apps/bridge": minor +--- + +Implement `retrieveRawLaunchParams`. diff --git a/packages/bridge/src/errors.ts b/packages/bridge/src/errors.ts index 435f1ead5..5408fb0dd 100644 --- a/packages/bridge/src/errors.ts +++ b/packages/bridge/src/errors.ts @@ -1,4 +1,4 @@ -import { errorClass, errorClassWithData } from 'error-kid'; +import { errorClass } from 'error-kid'; import type { Version } from '@telegram-apps/types'; export const [ @@ -30,11 +30,7 @@ const retrieveLaunchParamsError = [ export const [ LaunchParamsRetrieveError, isLaunchParamsRetrieveError, -] = errorClassWithData( - 'LaunchParamsRetrieveError', - errors => errors, - retrieveLaunchParamsError, -); +] = errorClass('LaunchParamsRetrieveError', retrieveLaunchParamsError); export const [ InvalidLaunchParamsError, @@ -43,11 +39,6 @@ export const [ `Invalid value for launch params: ${value}`, ]); -export const [ - InitDataRetrieveError, - isInitDataRetrieveError, -] = errorClass('InitDataRetrieveError', retrieveLaunchParamsError); - export const [UnknownEnvError, isUnknownEnvError] = errorClass('UnknownEnvError'); export const [ diff --git a/packages/bridge/src/index.ts b/packages/bridge/src/index.ts index 9e7b98594..ca69d53c5 100644 --- a/packages/bridge/src/index.ts +++ b/packages/bridge/src/index.ts @@ -13,6 +13,7 @@ export { type RetrieveLPResultCamelCased, type RetrieveLPResult, } from '@/launch-params/retrieveLaunchParams.js'; +export { retrieveRawLaunchParams } from '@/launch-params/retrieveRawLaunchParams.js'; export { retrieveRawInitData } from '@/launch-params/retrieveRawInitData.js'; export type * from '@/methods/types/index.js'; @@ -55,8 +56,6 @@ export { isMethodMethodParameterUnsupportedError, UnknownEnvError, isUnknownEnvError, - InitDataRetrieveError, - isInitDataRetrieveError, InvalidLaunchParamsError, isInvalidLaunchParamsError, } from '@/errors.js'; diff --git a/packages/bridge/src/launch-params/retrieveLaunchParams.ts b/packages/bridge/src/launch-params/retrieveLaunchParams.ts index 0a3fa68db..f63487514 100644 --- a/packages/bridge/src/launch-params/retrieveLaunchParams.ts +++ b/packages/bridge/src/launch-params/retrieveLaunchParams.ts @@ -2,12 +2,10 @@ import { LaunchParamsSchema, parseLaunchParamsQuery } from '@telegram-apps/trans import { type DeepConvertSnakeKeysToCamelCase, deepSnakeToCamelObjKeys, - setStorageValue, } from '@telegram-apps/toolkit'; import type { InferOutput } from 'valibot'; -import { LaunchParamsRetrieveError } from '@/errors.js'; -import { forEachLpSource } from '@/launch-params/forEachLpSource.js'; +import { retrieveRawLaunchParams } from '@/launch-params/retrieveRawLaunchParams.js'; export type RetrieveLPResult = InferOutput; export type RetrieveLPResultCamelCased = @@ -37,21 +35,6 @@ export function retrieveLaunchParams(camelCase: true): RetrieveLPResultCamelCase export function retrieveLaunchParams(camelCase?: boolean): | RetrieveLPResult | RetrieveLPResultCamelCased { - const errors: unknown[] = []; - let launchParams: RetrieveLPResult | undefined; - - forEachLpSource(v => { - try { - launchParams = parseLaunchParamsQuery(v); - setStorageValue('launchParams', v); - return false; - } catch (e) { - errors.push(e); - return true; - } - }); - if (!launchParams) { - throw new LaunchParamsRetrieveError(errors); - } + const launchParams = parseLaunchParamsQuery(retrieveRawLaunchParams()); return camelCase ? deepSnakeToCamelObjKeys(launchParams) : launchParams; } diff --git a/packages/bridge/src/launch-params/retrieveRawInitData.ts b/packages/bridge/src/launch-params/retrieveRawInitData.ts index 37d153ec3..2c9144c7d 100644 --- a/packages/bridge/src/launch-params/retrieveRawInitData.ts +++ b/packages/bridge/src/launch-params/retrieveRawInitData.ts @@ -1,28 +1,9 @@ -import { isLaunchParamsQuery } from '@telegram-apps/transformers'; - -import { forEachLpSource } from '@/launch-params/forEachLpSource.js'; -import { InitDataRetrieveError } from '@/errors.js'; -import { retrieveLaunchParams } from '@/launch-params/retrieveLaunchParams.js'; +import { retrieveRawLaunchParams } from '@/launch-params/retrieveRawLaunchParams.js'; /** * @returns Raw init data from any known source. - * @throws {InitDataRetrieveError} Unable to retrieve init data from any known source. + * @throws {LaunchParamsRetrieveError} Unable to retrieve launch params from any known source. */ export function retrieveRawInitData(): string | undefined { - // Init data depends on the launch parameters. We also want them to be saved. - try { - retrieveLaunchParams(); - } catch { - throw new InitDataRetrieveError(); - } - - let initData: string | undefined; - forEachLpSource(v => { - if (isLaunchParamsQuery(v)) { - initData = new URLSearchParams(v).get('tgWebAppData') || undefined; - return false; - } - return true; - }); - return initData; + return new URLSearchParams(retrieveRawLaunchParams()).get('tgWebAppData') || undefined; } \ No newline at end of file diff --git a/packages/bridge/src/launch-params/retrieveRawLaunchParams.test.ts b/packages/bridge/src/launch-params/retrieveRawLaunchParams.test.ts new file mode 100644 index 000000000..d69a6f24a --- /dev/null +++ b/packages/bridge/src/launch-params/retrieveRawLaunchParams.test.ts @@ -0,0 +1,46 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { retrieveRawLaunchParams } from '@/launch-params/retrieveRawLaunchParams.js'; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('window.location.href contains launch params', () => { + it('should retrieve launch params from the window.location.href. Throw an error if data is invalid or missing', () => { + vi + .spyOn(window.location, 'href', 'get') + .mockImplementationOnce(() => { + return '/abc?tgWebAppStartParam=location_hash#tgWebAppPlatform=tdesktop&tgWebAppVersion=7.0&tgWebAppThemeParams=%7B%7D'; + }); + + expect(retrieveRawLaunchParams()).toBe('tgWebAppStartParam=location_hash&tgWebAppPlatform=tdesktop&tgWebAppVersion=7.0&tgWebAppThemeParams=%7B%7D'); + }); +}); + +describe('first navigation entry contains launch params', () => { + it('should retrieve launch params from the window.performance. Throw an error if data is invalid or missing', () => { + vi + .spyOn(performance, 'getEntriesByType') + .mockImplementationOnce(() => [{ + name: '/abc?tgWebAppStartParam=performance#tgWebAppPlatform=macos&tgWebAppVersion=7.3&tgWebAppThemeParams=%7B%7D', + }] as any); + + expect(retrieveRawLaunchParams()).toBe('tgWebAppStartParam=performance&tgWebAppPlatform=macos&tgWebAppVersion=7.3&tgWebAppThemeParams=%7B%7D'); + }); +}); + +describe('session storage contains launch params', () => { + it('should return launch parameters from the session storage tapps/launchParams key. If data is missing or invalid, throw an error', () => { + const spy = vi + .spyOn(sessionStorage, 'getItem') + .mockImplementationOnce(() => ''); + expect(() => retrieveRawLaunchParams()).toThrow(); + + spy.mockClear(); + spy.mockImplementationOnce(() => { + return '"tgWebAppPlatform=android&tgWebAppThemeParams=%7B%22bg_color%22%3A%22%23ffffff%22%7D&tgWebAppVersion=7.5"'; + }); + expect(retrieveRawLaunchParams()).toBe('tgWebAppPlatform=android&tgWebAppThemeParams=%7B%22bg_color%22%3A%22%23ffffff%22%7D&tgWebAppVersion=7.5'); + }); +}); \ No newline at end of file diff --git a/packages/bridge/src/launch-params/forEachLpSource.ts b/packages/bridge/src/launch-params/retrieveRawLaunchParams.ts similarity index 57% rename from packages/bridge/src/launch-params/forEachLpSource.ts rename to packages/bridge/src/launch-params/retrieveRawLaunchParams.ts index c10eb6bf3..35d23caa0 100644 --- a/packages/bridge/src/launch-params/forEachLpSource.ts +++ b/packages/bridge/src/launch-params/retrieveRawLaunchParams.ts @@ -1,4 +1,9 @@ -import { getStorageValue } from '@telegram-apps/toolkit'; +import { isLaunchParamsQuery } from '@telegram-apps/transformers'; +import { getStorageValue, setStorageValue } from '@telegram-apps/toolkit'; + +import { LaunchParamsRetrieveError } from '@/errors.js'; + +const SESSION_STORAGE_KEY = 'launchParams'; /** * @param urlString - URL to extract launch parameters from. @@ -14,11 +19,11 @@ function fromURL(urlString: string): string { } /** - * Runs the specified function for each value, where the value is one stored in any known - * launch parameters source. - * @param fn - function to run. Should return false when the execution must be stopped. + * @returns Launch parameters in a raw format from any known source. + * @throws {LaunchParamsRetrieveError} Unable to retrieve launch parameters. They are probably + * invalid. */ -export function forEachLpSource(fn: (value: string) => boolean): void { +export function retrieveRawLaunchParams(): string { for (const retrieve of [ // Try to retrieve launch parameters from the current location. This method can return // nothing in case, location was changed, and then the page was reloaded. @@ -26,13 +31,15 @@ export function forEachLpSource(fn: (value: string) => boolean): void { // Then, try using the lower level API - window.performance. () => { const navigationEntry = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined; - return navigationEntry ? fromURL(navigationEntry.name) : undefined; + return navigationEntry && fromURL(navigationEntry.name); }, - () => getStorageValue('launchParams') || '', + () => getStorageValue(SESSION_STORAGE_KEY), ]) { const v = retrieve(); - if (v && !fn(v)) { - return; + if (v && isLaunchParamsQuery(v)) { + setStorageValue(SESSION_STORAGE_KEY, v); + return v; } } + throw new LaunchParamsRetrieveError(); } \ No newline at end of file diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index c9a0c9036..6f5292c71 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -55,6 +55,7 @@ export { on, off, retrieveLaunchParams, + retrieveRawLaunchParams, retrieveRawInitData, type RetrieveLPResult, type RetrieveLPResultCamelCased, @@ -114,8 +115,6 @@ export { isLaunchParamsRetrieveError, LaunchParamsRetrieveError, InvalidLaunchParamsError, - InitDataRetrieveError, - isInitDataRetrieveError, isInvalidLaunchParamsError, type BackgroundColor, type PopupParams,