Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/gorgeous-forks-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@telegram-apps/sdk": patch
---

Remove some errors exported from bridge.
5 changes: 5 additions & 0 deletions .changeset/polite-spies-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@telegram-apps/bridge": minor
---

Implement `retrieveRawLaunchParams`.
13 changes: 2 additions & 11 deletions packages/bridge/src/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { errorClass, errorClassWithData } from 'error-kid';
import { errorClass } from 'error-kid';
import type { Version } from '@telegram-apps/types';

export const [
Expand Down Expand Up @@ -30,11 +30,7 @@ const retrieveLaunchParamsError = [
export const [
LaunchParamsRetrieveError,
isLaunchParamsRetrieveError,
] = errorClassWithData<unknown[], [errors: unknown[]]>(
'LaunchParamsRetrieveError',
errors => errors,
retrieveLaunchParamsError,
);
] = errorClass<unknown[]>('LaunchParamsRetrieveError', retrieveLaunchParamsError);

export const [
InvalidLaunchParamsError,
Expand All @@ -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 [
Expand Down
3 changes: 1 addition & 2 deletions packages/bridge/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -55,8 +56,6 @@ export {
isMethodMethodParameterUnsupportedError,
UnknownEnvError,
isUnknownEnvError,
InitDataRetrieveError,
isInitDataRetrieveError,
InvalidLaunchParamsError,
isInvalidLaunchParamsError,
} from '@/errors.js';
Expand Down
21 changes: 2 additions & 19 deletions packages/bridge/src/launch-params/retrieveLaunchParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof LaunchParamsSchema>;
export type RetrieveLPResultCamelCased =
Expand Down Expand Up @@ -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;
}
25 changes: 3 additions & 22 deletions packages/bridge/src/launch-params/retrieveRawInitData.ts
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions packages/bridge/src/launch-params/retrieveRawLaunchParams.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -14,25 +19,27 @@ 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.
() => fromURL(window.location.href),
// 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<string>('launchParams') || '',
() => getStorageValue<string>(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();
}
3 changes: 1 addition & 2 deletions packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export {
on,
off,
retrieveLaunchParams,
retrieveRawLaunchParams,
retrieveRawInitData,
type RetrieveLPResult,
type RetrieveLPResultCamelCased,
Expand Down Expand Up @@ -114,8 +115,6 @@ export {
isLaunchParamsRetrieveError,
LaunchParamsRetrieveError,
InvalidLaunchParamsError,
InitDataRetrieveError,
isInitDataRetrieveError,
isInvalidLaunchParamsError,
type BackgroundColor,
type PopupParams,
Expand Down