@tma.js/sdk 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dts/index.d.ts +1 -1
- package/dist/dts/init/creators/createViewport.d.ts +2 -9
- package/dist/dts/init/init.d.ts +2 -0
- package/dist/dts/init/types.d.ts +7 -4
- package/dist/dts/launch-params/index.d.ts +1 -0
- package/dist/dts/launch-params/retrieveFromUrl.d.ts +6 -0
- package/dist/dts/launch-params/types.d.ts +12 -8
- package/dist/dts/types/platform.d.ts +1 -1
- package/dist/dts/viewport/index.d.ts +1 -0
- package/dist/dts/viewport/isStableViewportPlatform.d.ts +7 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.iife.js +1 -1
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +469 -467
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/globals.ts +39 -0
- package/src/back-button/__tests__/BackButton.ts +129 -0
- package/src/bridge/__tests__/request.ts +236 -0
- package/src/bridge/env/__tests__/hasExternalNotify.ts +15 -0
- package/src/bridge/env/__tests__/hasWebviewProxy.ts +15 -0
- package/src/bridge/env/__tests__/isIframe.ts +30 -0
- package/src/bridge/events/__tests__/createEmitter.ts +143 -0
- package/src/bridge/events/__tests__/off.ts +34 -0
- package/src/bridge/events/__tests__/on.ts +49 -0
- package/src/bridge/events/__tests__/onTelegramEvent.ts +51 -0
- package/src/bridge/events/__tests__/once.ts +64 -0
- package/src/bridge/events/__tests__/singletonEmitter.ts +22 -0
- package/src/bridge/events/__tests__/subscribe.ts +49 -0
- package/src/bridge/events/__tests__/unsubscribe.ts +34 -0
- package/src/bridge/events/parsers/__tests__/clipboardTextReceived.ts +21 -0
- package/src/bridge/events/parsers/__tests__/invoiceClosed.ts +12 -0
- package/src/bridge/events/parsers/__tests__/popupClosed.ts +10 -0
- package/src/bridge/events/parsers/__tests__/qrTextReceived.ts +9 -0
- package/src/bridge/events/parsers/__tests__/theme-changed.ts +42 -0
- package/src/bridge/events/parsers/__tests__/viewportChanged.ts +49 -0
- package/src/bridge/methods/__tests__/createPostEvent.ts +37 -0
- package/src/bridge/methods/__tests__/postEvent.ts +137 -0
- package/src/classnames/__tests__/classNames.ts +20 -0
- package/src/classnames/__tests__/mergeClassNames.ts +21 -0
- package/src/closing-behavior/__tests__/ClosingBehavior.ts +86 -0
- package/src/colors/__tests__/isColorDark.ts +12 -0
- package/src/colors/__tests__/isRGB.ts +13 -0
- package/src/colors/__tests__/isRGBShort.ts +13 -0
- package/src/colors/__tests__/toRGB.ts +23 -0
- package/src/event-emitter/__tests__/EventEmitter.ts +145 -0
- package/src/haptic-feedback/__tests__/HapticFeedback.ts +68 -0
- package/src/index.ts +1 -0
- package/src/init/creators/__tests__/createViewport.ts +96 -0
- package/src/init/creators/createViewport.ts +60 -81
- package/src/init/init.ts +13 -15
- package/src/init/types.ts +8 -4
- package/src/init-data/__tests__/InitData.ts +98 -0
- package/src/init-data/__tests__/chatParser.ts +102 -0
- package/src/init-data/__tests__/initDataParser.ts +136 -0
- package/src/init-data/__tests__/parseInitData.ts +136 -0
- package/src/init-data/__tests__/userParser.ts +96 -0
- package/src/launch-params/__tests__/retrieveFromUrl.ts +19 -0
- package/src/launch-params/index.ts +1 -0
- package/src/launch-params/launchParamsParser.ts +4 -0
- package/src/launch-params/retrieveFromLocation.ts +2 -2
- package/src/launch-params/retrieveFromPerformance.ts +2 -7
- package/src/launch-params/retrieveFromUrl.ts +19 -0
- package/src/launch-params/types.ts +13 -8
- package/src/logger/__tests__/Logger.ts +107 -0
- package/src/main-button/__tests__/MainButton.ts +346 -0
- package/src/mini-app/__tests__/MiniApp.ts +140 -0
- package/src/misc/__tests__/isRecord.ts +21 -0
- package/src/navigation/HashNavigator/__tests__/HashNavigator.ts +144 -0
- package/src/navigation/HashNavigator/__tests__/drop.ts +42 -0
- package/src/navigation/HashNavigator/__tests__/go.ts +9 -0
- package/src/parsing/__tests__/ArrayValueParser.ts +18 -0
- package/src/parsing/__tests__/toRecord.ts +10 -0
- package/src/parsing/parsers/__tests__/array.ts +39 -0
- package/src/parsing/parsers/__tests__/boolean.ts +31 -0
- package/src/parsing/parsers/__tests__/date.ts +25 -0
- package/src/parsing/parsers/__tests__/json.ts +80 -0
- package/src/parsing/parsers/__tests__/number.ts +23 -0
- package/src/parsing/parsers/__tests__/rgb.ts +22 -0
- package/src/parsing/parsers/__tests__/searchParams.ts +105 -0
- package/src/parsing/parsers/__tests__/string.ts +25 -0
- package/src/popup/__tests__/Popup.ts +130 -0
- package/src/popup/__tests__/preparePopupParams.ts +85 -0
- package/src/supports/__tests__/supports.ts +123 -0
- package/src/theme-params/__tests__/keys.ts +19 -0
- package/src/theme-params/__tests__/parseThemeParams.ts +29 -0
- package/src/theme-params/__tests__/serializeThemeParams.ts +29 -0
- package/src/theme-params/__tests__/themeParamsParser.ts +29 -0
- package/src/timeout/__tests__/isTimeoutError.ts +9 -0
- package/src/timeout/__tests__/withTimeout.ts +28 -0
- package/src/types/platform.ts +2 -2
- package/src/version/__tests__/compareVersions.ts +19 -0
- package/src/viewport/__tests__/isStableViewportPlatform.ts +15 -0
- package/src/viewport/__tests__/utils.ts +12 -0
- package/src/viewport/index.ts +1 -0
- package/src/viewport/isStableViewportPlatform.ts +10 -0
package/src/init/init.ts
CHANGED
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
createClosingBehavior,
|
|
8
8
|
createMainButton,
|
|
9
9
|
createMiniApp,
|
|
10
|
-
createRequestIdGenerator,
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
createRequestIdGenerator,
|
|
11
|
+
createSettingsButton,
|
|
12
|
+
createThemeParams,
|
|
13
|
+
createViewport,
|
|
13
14
|
} from '~/init/creators/index.js';
|
|
14
15
|
import { processCSSVars } from '~/init/css/index.js';
|
|
15
16
|
import { InitData } from '~/init-data/index.js';
|
|
@@ -21,13 +22,16 @@ import { Utils } from '~/utils/index.js';
|
|
|
21
22
|
|
|
22
23
|
import type { InitOptions, InitResult } from './types.js';
|
|
23
24
|
|
|
24
|
-
type ComputedInitResult<O> = O extends { async: true }
|
|
25
|
+
type ComputedInitResult<O> = O extends { async: true } | { complete: true }
|
|
26
|
+
? Promise<InitResult>
|
|
27
|
+
: InitResult;
|
|
25
28
|
|
|
26
29
|
export function init(): InitResult;
|
|
27
30
|
export function init<O extends InitOptions>(options: O): ComputedInitResult<O>;
|
|
28
31
|
export function init(options: InitOptions = {}): InitResult | Promise<InitResult> {
|
|
29
32
|
const {
|
|
30
33
|
async = false,
|
|
34
|
+
complete = async,
|
|
31
35
|
cssVars = false,
|
|
32
36
|
acceptCustomStyles = false,
|
|
33
37
|
} = options;
|
|
@@ -99,12 +103,9 @@ export function init(options: InitOptions = {}): InitResult | Promise<InitResult
|
|
|
99
103
|
: {}),
|
|
100
104
|
};
|
|
101
105
|
|
|
102
|
-
const viewport =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (viewport instanceof Promise) {
|
|
107
|
-
return viewport.then((vp) => {
|
|
106
|
+
const viewport = createViewport(isPageReload, platform, postEvent, complete);
|
|
107
|
+
if (viewport instanceof Promise || complete) {
|
|
108
|
+
return Promise.resolve(viewport).then((vp) => {
|
|
108
109
|
processCSSVars(
|
|
109
110
|
cssVars,
|
|
110
111
|
result.miniApp,
|
|
@@ -112,10 +113,7 @@ export function init(options: InitOptions = {}): InitResult | Promise<InitResult
|
|
|
112
113
|
vp,
|
|
113
114
|
);
|
|
114
115
|
|
|
115
|
-
return {
|
|
116
|
-
...result,
|
|
117
|
-
viewport: vp,
|
|
118
|
-
};
|
|
116
|
+
return { ...result, viewport: vp };
|
|
119
117
|
});
|
|
120
118
|
}
|
|
121
119
|
|
|
@@ -128,7 +126,7 @@ export function init(options: InitOptions = {}): InitResult | Promise<InitResult
|
|
|
128
126
|
|
|
129
127
|
return { ...result, viewport };
|
|
130
128
|
} catch (e) {
|
|
131
|
-
if (
|
|
129
|
+
if (complete) {
|
|
132
130
|
return Promise.reject(e);
|
|
133
131
|
}
|
|
134
132
|
throw e;
|
package/src/init/types.ts
CHANGED
|
@@ -62,10 +62,7 @@ export type InitCSSVarsOption = boolean | InitCSSVarsSpecificOption;
|
|
|
62
62
|
|
|
63
63
|
export interface InitOptions {
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
* perform async operations. One of them is the actual viewport state retrieving from the
|
|
67
|
-
* Telegram application. Otherwise, viewport state will be retrieved later.
|
|
68
|
-
* @default false
|
|
65
|
+
* @deprecated This option name was considered inappropriate. Use `complete` instead.
|
|
69
66
|
*/
|
|
70
67
|
async?: boolean;
|
|
71
68
|
|
|
@@ -87,4 +84,11 @@ export interface InitOptions {
|
|
|
87
84
|
* @default false
|
|
88
85
|
*/
|
|
89
86
|
cssVars?: InitCSSVarsOption;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* True if initialization must be performed completely. This includes retrieving some components
|
|
90
|
+
* state from the Telegram application, and as a result, this makes initialization asynchronous.
|
|
91
|
+
* @default false
|
|
92
|
+
*/
|
|
93
|
+
complete?: boolean;
|
|
90
94
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { InitData } from '../InitData';
|
|
4
|
+
|
|
5
|
+
it('should return fields specified in constructor', () => {
|
|
6
|
+
const authDate = new Date(123);
|
|
7
|
+
const data1 = new InitData({ authDate, hash: 'hash' });
|
|
8
|
+
expect(data1.authDate).toBe(authDate);
|
|
9
|
+
expect(data1.canSendAfter).toBeUndefined();
|
|
10
|
+
expect(data1.chat).toBeUndefined();
|
|
11
|
+
expect(data1.chatType).toBeUndefined();
|
|
12
|
+
expect(data1.chatInstance).toBeUndefined();
|
|
13
|
+
expect(data1.hash).toBe('hash');
|
|
14
|
+
expect(data1.queryId).toBeUndefined();
|
|
15
|
+
expect(data1.receiver).toBeUndefined();
|
|
16
|
+
expect(data1.startParam).toBeUndefined();
|
|
17
|
+
expect(data1.user).toBeUndefined();
|
|
18
|
+
|
|
19
|
+
const canSendAfter = 1;
|
|
20
|
+
const data2 = new InitData({
|
|
21
|
+
authDate,
|
|
22
|
+
canSendAfter,
|
|
23
|
+
chat: {
|
|
24
|
+
id: 999,
|
|
25
|
+
photoUrl: 'photo',
|
|
26
|
+
type: 'group',
|
|
27
|
+
title: 'Title',
|
|
28
|
+
},
|
|
29
|
+
chatType: 'sender',
|
|
30
|
+
chatInstance: 'abc',
|
|
31
|
+
hash: 'joke',
|
|
32
|
+
queryId: 'query id',
|
|
33
|
+
receiver: {
|
|
34
|
+
id: 1000,
|
|
35
|
+
photoUrl: 'receiver photo',
|
|
36
|
+
firstName: 'a',
|
|
37
|
+
lastName: 'b',
|
|
38
|
+
username: 'c',
|
|
39
|
+
isBot: false,
|
|
40
|
+
isPremium: false,
|
|
41
|
+
languageCode: 'en',
|
|
42
|
+
},
|
|
43
|
+
startParam: 'param',
|
|
44
|
+
user: {
|
|
45
|
+
id: 2000,
|
|
46
|
+
photoUrl: 'user photo',
|
|
47
|
+
firstName: 'a',
|
|
48
|
+
lastName: 'b',
|
|
49
|
+
username: 'c',
|
|
50
|
+
languageCode: 'en',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
expect(data2.authDate).toBe(authDate);
|
|
54
|
+
expect(data2.canSendAfter).toBe(canSendAfter);
|
|
55
|
+
expect(data2.chat).toStrictEqual({
|
|
56
|
+
id: 999,
|
|
57
|
+
photoUrl: 'photo',
|
|
58
|
+
type: 'group',
|
|
59
|
+
title: 'Title',
|
|
60
|
+
});
|
|
61
|
+
expect(data2.chatType).toBe('sender');
|
|
62
|
+
expect(data2.chatInstance).toBe('abc');
|
|
63
|
+
expect(data2.hash).toBe('joke');
|
|
64
|
+
expect(data2.queryId).toBe('query id');
|
|
65
|
+
expect(data2.receiver).toStrictEqual({
|
|
66
|
+
id: 1000,
|
|
67
|
+
photoUrl: 'receiver photo',
|
|
68
|
+
firstName: 'a',
|
|
69
|
+
lastName: 'b',
|
|
70
|
+
username: 'c',
|
|
71
|
+
isBot: false,
|
|
72
|
+
isPremium: false,
|
|
73
|
+
languageCode: 'en',
|
|
74
|
+
});
|
|
75
|
+
expect(data2.startParam).toBe('param');
|
|
76
|
+
expect(data2.user).toStrictEqual({
|
|
77
|
+
id: 2000,
|
|
78
|
+
photoUrl: 'user photo',
|
|
79
|
+
firstName: 'a',
|
|
80
|
+
lastName: 'b',
|
|
81
|
+
username: 'c',
|
|
82
|
+
languageCode: 'en',
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should have canSendAfterData equal to authDate + canSendAfter seconds', () => {
|
|
87
|
+
const authDate = new Date();
|
|
88
|
+
const initData = new InitData({
|
|
89
|
+
authDate,
|
|
90
|
+
hash: 'abc',
|
|
91
|
+
canSendAfter: 32000,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(initData.canSendAfter).toBe(32000);
|
|
95
|
+
expect(initData.canSendAfterDate).toStrictEqual(
|
|
96
|
+
new Date(authDate.getTime() + 32000000),
|
|
97
|
+
);
|
|
98
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { chatParser } from '../chatParser';
|
|
4
|
+
|
|
5
|
+
describe('id', () => {
|
|
6
|
+
it('should throw an error in case, this property is missing', () => {
|
|
7
|
+
expect(
|
|
8
|
+
() => chatParser().parse({
|
|
9
|
+
type: 'group chat',
|
|
10
|
+
title: 'My chat',
|
|
11
|
+
}),
|
|
12
|
+
).toThrow();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should parse source property as number and pass it to the "id" property', () => {
|
|
16
|
+
expect(
|
|
17
|
+
chatParser().parse({
|
|
18
|
+
id: 882,
|
|
19
|
+
type: 'group chat',
|
|
20
|
+
title: 'My chat',
|
|
21
|
+
}),
|
|
22
|
+
).toMatchObject({
|
|
23
|
+
id: 882,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('type', () => {
|
|
29
|
+
it('should throw an error in case, this property is missing', () => {
|
|
30
|
+
expect(
|
|
31
|
+
() => chatParser().parse({
|
|
32
|
+
id: 223,
|
|
33
|
+
title: 'My chat',
|
|
34
|
+
}),
|
|
35
|
+
).toThrow();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should parse source property as number and pass it to the "type" property', () => {
|
|
39
|
+
expect(
|
|
40
|
+
chatParser().parse({
|
|
41
|
+
id: 882,
|
|
42
|
+
type: 'group chat',
|
|
43
|
+
title: 'My chat',
|
|
44
|
+
}),
|
|
45
|
+
).toMatchObject({
|
|
46
|
+
type: 'group chat',
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('title', () => {
|
|
52
|
+
it('should throw an error in case, this property is missing', () => {
|
|
53
|
+
expect(
|
|
54
|
+
() => chatParser().parse({
|
|
55
|
+
id: 223,
|
|
56
|
+
type: 'group chat',
|
|
57
|
+
}),
|
|
58
|
+
).toThrow();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should parse source property as number and pass it to the "title" property', () => {
|
|
62
|
+
expect(
|
|
63
|
+
chatParser().parse({
|
|
64
|
+
id: 882,
|
|
65
|
+
type: 'group chat',
|
|
66
|
+
title: 'My chat',
|
|
67
|
+
}),
|
|
68
|
+
).toMatchObject({
|
|
69
|
+
title: 'My chat',
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('photo_url', () => {
|
|
75
|
+
it('should parse source property as number and pass it to the "photoUrl" property', () => {
|
|
76
|
+
expect(
|
|
77
|
+
chatParser().parse({
|
|
78
|
+
id: 882,
|
|
79
|
+
type: 'group chat',
|
|
80
|
+
title: 'My chat',
|
|
81
|
+
photo_url: 'https://image.com',
|
|
82
|
+
}),
|
|
83
|
+
).toMatchObject({
|
|
84
|
+
photoUrl: 'https://image.com',
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('username', () => {
|
|
90
|
+
it('should parse source property as number and pass it to the "username" property', () => {
|
|
91
|
+
expect(
|
|
92
|
+
chatParser().parse({
|
|
93
|
+
id: 882,
|
|
94
|
+
type: 'group chat',
|
|
95
|
+
title: 'My chat',
|
|
96
|
+
username: 'Johny Bravo',
|
|
97
|
+
}),
|
|
98
|
+
).toMatchObject({
|
|
99
|
+
username: 'Johny Bravo',
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { toSearchParams } from 'test-utils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { initDataParser } from '../initDataParser';
|
|
5
|
+
|
|
6
|
+
describe('auth_date', () => {
|
|
7
|
+
it('should throw an error in case, this property is missing', () => {
|
|
8
|
+
expect(() => initDataParser().parse(toSearchParams({ hash: 'abcd' }))).toThrow();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should parse source property as Date and pass it to the "authDate" property', () => {
|
|
12
|
+
expect(initDataParser().parse(toSearchParams({ auth_date: 1, hash: 'abcd' }))).toMatchObject({
|
|
13
|
+
authDate: new Date(1000),
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('can_send_after', () => {
|
|
19
|
+
it('should parse source property as Date and pass it to the "canSendAfter" property', () => {
|
|
20
|
+
expect(
|
|
21
|
+
initDataParser().parse(toSearchParams({
|
|
22
|
+
auth_date: 1,
|
|
23
|
+
hash: 'abcd',
|
|
24
|
+
can_send_after: 8882,
|
|
25
|
+
})),
|
|
26
|
+
).toMatchObject({
|
|
27
|
+
canSendAfter: 8882,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('chat', () => {
|
|
33
|
+
it('should parse source property as Chat and pass it to the "chat" property', () => {
|
|
34
|
+
expect(
|
|
35
|
+
initDataParser().parse(toSearchParams({
|
|
36
|
+
auth_date: 1,
|
|
37
|
+
hash: 'abcd',
|
|
38
|
+
chat: {
|
|
39
|
+
id: 5,
|
|
40
|
+
type: 'group chat',
|
|
41
|
+
title: 'My Chat',
|
|
42
|
+
photo_url: 'https://johny.com',
|
|
43
|
+
username: 'Johny Chat',
|
|
44
|
+
},
|
|
45
|
+
})),
|
|
46
|
+
).toMatchObject({
|
|
47
|
+
chat: {
|
|
48
|
+
id: 5,
|
|
49
|
+
type: 'group chat',
|
|
50
|
+
title: 'My Chat',
|
|
51
|
+
photoUrl: 'https://johny.com',
|
|
52
|
+
username: 'Johny Chat',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('hash', () => {
|
|
59
|
+
it('should throw an error in case, this property is missing', () => {
|
|
60
|
+
expect(
|
|
61
|
+
() => initDataParser().parse(toSearchParams({
|
|
62
|
+
auth_date: 1,
|
|
63
|
+
})),
|
|
64
|
+
).toThrow();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should parse source property as string and pass it to the "hash" property', () => {
|
|
68
|
+
expect(
|
|
69
|
+
initDataParser().parse(toSearchParams({
|
|
70
|
+
auth_date: 1,
|
|
71
|
+
hash: 'abcd',
|
|
72
|
+
})),
|
|
73
|
+
).toMatchObject({
|
|
74
|
+
hash: 'abcd',
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
[
|
|
80
|
+
['chat_instance', 'chatInstance'],
|
|
81
|
+
['chat_type', 'chatType'],
|
|
82
|
+
['query_id', 'queryId'],
|
|
83
|
+
['start_param', 'startParam'],
|
|
84
|
+
].forEach(([from, to]) => {
|
|
85
|
+
describe(from, () => {
|
|
86
|
+
it(`should parse source property as string and pass it to the "${to}" property`, () => {
|
|
87
|
+
expect(
|
|
88
|
+
initDataParser().parse(toSearchParams({
|
|
89
|
+
auth_date: 1,
|
|
90
|
+
hash: 'abcd',
|
|
91
|
+
[from]: 'my custom property',
|
|
92
|
+
})),
|
|
93
|
+
).toMatchObject({
|
|
94
|
+
[to]: 'my custom property',
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
['user', 'receiver'].forEach((property) => {
|
|
101
|
+
describe(property, () => {
|
|
102
|
+
it('should parse source property as User and pass it to the property with the same name', () => {
|
|
103
|
+
expect(
|
|
104
|
+
initDataParser().parse(toSearchParams({
|
|
105
|
+
auth_date: 1,
|
|
106
|
+
hash: 'abcd',
|
|
107
|
+
[property]: {
|
|
108
|
+
added_to_attachment_menu: true,
|
|
109
|
+
allows_write_to_pm: false,
|
|
110
|
+
first_name: 'Johny',
|
|
111
|
+
id: 333,
|
|
112
|
+
is_bot: false,
|
|
113
|
+
is_premium: true,
|
|
114
|
+
language_code: 'en',
|
|
115
|
+
last_name: 'Bravo',
|
|
116
|
+
photo_url: 'https://johny.com',
|
|
117
|
+
username: 'johnybravo',
|
|
118
|
+
},
|
|
119
|
+
})),
|
|
120
|
+
).toMatchObject({
|
|
121
|
+
[property]: {
|
|
122
|
+
addedToAttachmentMenu: true,
|
|
123
|
+
allowsWriteToPm: false,
|
|
124
|
+
firstName: 'Johny',
|
|
125
|
+
id: 333,
|
|
126
|
+
isBot: false,
|
|
127
|
+
isPremium: true,
|
|
128
|
+
languageCode: 'en',
|
|
129
|
+
lastName: 'Bravo',
|
|
130
|
+
photoUrl: 'https://johny.com',
|
|
131
|
+
username: 'johnybravo',
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { toSearchParams } from 'test-utils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { parseInitData } from '../parseInitData';
|
|
5
|
+
|
|
6
|
+
describe('auth_date', () => {
|
|
7
|
+
it('should throw an error in case, this property is missing', () => {
|
|
8
|
+
expect(() => parseInitData(toSearchParams({ hash: 'abcd' }))).toThrow();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should parse source property as Date and pass it to the "authDate" property', () => {
|
|
12
|
+
expect(parseInitData(toSearchParams({ auth_date: 1, hash: 'abcd' }))).toMatchObject({
|
|
13
|
+
authDate: new Date(1000),
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('can_send_after', () => {
|
|
19
|
+
it('should parse source property as Date and pass it to the "canSendAfter" property', () => {
|
|
20
|
+
expect(
|
|
21
|
+
parseInitData(toSearchParams({
|
|
22
|
+
auth_date: 1,
|
|
23
|
+
hash: 'abcd',
|
|
24
|
+
can_send_after: 8882,
|
|
25
|
+
})),
|
|
26
|
+
).toMatchObject({
|
|
27
|
+
canSendAfter: 8882,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('chat', () => {
|
|
33
|
+
it('should parse source property as Chat and pass it to the "chat" property', () => {
|
|
34
|
+
expect(
|
|
35
|
+
parseInitData(toSearchParams({
|
|
36
|
+
auth_date: 1,
|
|
37
|
+
hash: 'abcd',
|
|
38
|
+
chat: {
|
|
39
|
+
id: 5,
|
|
40
|
+
type: 'group chat',
|
|
41
|
+
title: 'My Chat',
|
|
42
|
+
photo_url: 'https://johny.com',
|
|
43
|
+
username: 'Johny Chat',
|
|
44
|
+
},
|
|
45
|
+
})),
|
|
46
|
+
).toMatchObject({
|
|
47
|
+
chat: {
|
|
48
|
+
id: 5,
|
|
49
|
+
type: 'group chat',
|
|
50
|
+
title: 'My Chat',
|
|
51
|
+
photoUrl: 'https://johny.com',
|
|
52
|
+
username: 'Johny Chat',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('hash', () => {
|
|
59
|
+
it('should throw an error in case, this property is missing', () => {
|
|
60
|
+
expect(
|
|
61
|
+
() => parseInitData(toSearchParams({
|
|
62
|
+
auth_date: 1,
|
|
63
|
+
})),
|
|
64
|
+
).toThrow();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should parse source property as string and pass it to the "hash" property', () => {
|
|
68
|
+
expect(
|
|
69
|
+
parseInitData(toSearchParams({
|
|
70
|
+
auth_date: 1,
|
|
71
|
+
hash: 'abcd',
|
|
72
|
+
})),
|
|
73
|
+
).toMatchObject({
|
|
74
|
+
hash: 'abcd',
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
[
|
|
80
|
+
['chat_instance', 'chatInstance'],
|
|
81
|
+
['chat_type', 'chatType'],
|
|
82
|
+
['query_id', 'queryId'],
|
|
83
|
+
['start_param', 'startParam'],
|
|
84
|
+
].forEach(([from, to]) => {
|
|
85
|
+
describe(from, () => {
|
|
86
|
+
it(`should parse source property as string and pass it to the "${to}" property`, () => {
|
|
87
|
+
expect(
|
|
88
|
+
parseInitData(toSearchParams({
|
|
89
|
+
auth_date: 1,
|
|
90
|
+
hash: 'abcd',
|
|
91
|
+
[from]: 'my custom property',
|
|
92
|
+
})),
|
|
93
|
+
).toMatchObject({
|
|
94
|
+
[to]: 'my custom property',
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
['user', 'receiver'].forEach((property) => {
|
|
101
|
+
describe(property, () => {
|
|
102
|
+
it('should parse source property as User and pass it to the property with the same name', () => {
|
|
103
|
+
expect(
|
|
104
|
+
parseInitData(toSearchParams({
|
|
105
|
+
auth_date: 1,
|
|
106
|
+
hash: 'abcd',
|
|
107
|
+
[property]: {
|
|
108
|
+
added_to_attachment_menu: true,
|
|
109
|
+
allows_write_to_pm: false,
|
|
110
|
+
first_name: 'Johny',
|
|
111
|
+
id: 333,
|
|
112
|
+
is_bot: false,
|
|
113
|
+
is_premium: true,
|
|
114
|
+
language_code: 'en',
|
|
115
|
+
last_name: 'Bravo',
|
|
116
|
+
photo_url: 'https://johny.com',
|
|
117
|
+
username: 'johnybravo',
|
|
118
|
+
},
|
|
119
|
+
})),
|
|
120
|
+
).toMatchObject({
|
|
121
|
+
[property]: {
|
|
122
|
+
addedToAttachmentMenu: true,
|
|
123
|
+
allowsWriteToPm: false,
|
|
124
|
+
firstName: 'Johny',
|
|
125
|
+
id: 333,
|
|
126
|
+
isBot: false,
|
|
127
|
+
isPremium: true,
|
|
128
|
+
languageCode: 'en',
|
|
129
|
+
lastName: 'Bravo',
|
|
130
|
+
photoUrl: 'https://johny.com',
|
|
131
|
+
username: 'johnybravo',
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { userParser } from '../userParser';
|
|
4
|
+
|
|
5
|
+
describe('first_name', () => {
|
|
6
|
+
it('should throw an error in case, this property is missing', () => {
|
|
7
|
+
expect(() => userParser().parse({ id: 123 })).toThrow();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should parse source property as string and pass it to the "firstName" property', () => {
|
|
11
|
+
expect(
|
|
12
|
+
userParser().parse({ id: 123, first_name: 'Pavel' }),
|
|
13
|
+
).toMatchObject({
|
|
14
|
+
firstName: 'Pavel',
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('id', () => {
|
|
20
|
+
it('should throw an error in case, this property is missing', () => {
|
|
21
|
+
expect(() => userParser().parse({ first_name: 'Pavel' })).toThrow();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should parse source property as number and pass it to the "id" property', () => {
|
|
25
|
+
expect(
|
|
26
|
+
userParser().parse({
|
|
27
|
+
id: 123,
|
|
28
|
+
first_name: 'Pavel',
|
|
29
|
+
}),
|
|
30
|
+
).toMatchObject({
|
|
31
|
+
id: 123,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Check optional booleans.
|
|
37
|
+
[
|
|
38
|
+
['added_to_attachment_menu', 'addedToAttachmentMenu'],
|
|
39
|
+
['allows_write_to_pm', 'allowsWriteToPm'],
|
|
40
|
+
['is_bot', 'isBot'],
|
|
41
|
+
['is_premium', 'isPremium'],
|
|
42
|
+
].forEach(([from, to]) => {
|
|
43
|
+
describe(from, () => {
|
|
44
|
+
it(`should parse source property as boolean and pass it to the "${to}" property`, () => {
|
|
45
|
+
expect(
|
|
46
|
+
userParser().parse({
|
|
47
|
+
id: 123,
|
|
48
|
+
first_name: 'Pavel',
|
|
49
|
+
[from]: false,
|
|
50
|
+
}),
|
|
51
|
+
).toMatchObject({
|
|
52
|
+
[to]: false,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(
|
|
56
|
+
() => userParser().parse({
|
|
57
|
+
id: 123,
|
|
58
|
+
first_name: 'Pavel',
|
|
59
|
+
[from]: 'non-boolean',
|
|
60
|
+
}),
|
|
61
|
+
).toThrow();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Check optional strings.
|
|
67
|
+
[
|
|
68
|
+
['language_code', 'languageCode'],
|
|
69
|
+
['last_name', 'lastName'],
|
|
70
|
+
['photo_url', 'photoUrl'],
|
|
71
|
+
['username', 'username'],
|
|
72
|
+
].forEach(([from, to]) => {
|
|
73
|
+
describe(from, () => {
|
|
74
|
+
it(`should parse source property as string and pass it to the "${to}" property`, () => {
|
|
75
|
+
expect(
|
|
76
|
+
userParser().parse({
|
|
77
|
+
id: 123,
|
|
78
|
+
first_name: 'Pavel',
|
|
79
|
+
[from]: 'my custom property',
|
|
80
|
+
}),
|
|
81
|
+
).toMatchObject({
|
|
82
|
+
[to]: 'my custom property',
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(
|
|
86
|
+
() => userParser().parse({
|
|
87
|
+
id: 123,
|
|
88
|
+
first_name: 'Pavel',
|
|
89
|
+
[from]: {
|
|
90
|
+
key: 'cant parse it',
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
).toThrow();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { expect, it } from 'vitest';
|
|
2
|
+
import { retrieveFromUrl } from '../retrieveFromUrl';
|
|
3
|
+
|
|
4
|
+
it('should return launch parameters based on hash only in case, URL does not contain the query part', () => {
|
|
5
|
+
expect(retrieveFromUrl('#tgWebAppPlatform=tdesktop&tgWebAppVersion=7.0&tgWebAppThemeParams=%7B%7D')).toEqual({
|
|
6
|
+
platform: 'tdesktop',
|
|
7
|
+
version: '7.0',
|
|
8
|
+
themeParams: {},
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return launch parameters based on query params and hash in case, URL contains both parts', () => {
|
|
13
|
+
expect(retrieveFromUrl('?tgWebAppStartParam=900#tgWebAppPlatform=tdesktop&tgWebAppVersion=7.0&tgWebAppThemeParams=%7B%7D')).toEqual({
|
|
14
|
+
platform: 'tdesktop',
|
|
15
|
+
version: '7.0',
|
|
16
|
+
themeParams: {},
|
|
17
|
+
startParam: '900',
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -6,6 +6,7 @@ export * from './parseLaunchParams.js';
|
|
|
6
6
|
export * from './retrieveCurrent.js';
|
|
7
7
|
export * from './retrieveFromLocation.js';
|
|
8
8
|
export * from './retrieveFromPerformance.js';
|
|
9
|
+
export * from './retrieveFromUrl.js';
|
|
9
10
|
export * from './retrieveLaunchData.js';
|
|
10
11
|
export * from './serializeLaunchParams.js';
|
|
11
12
|
export * from './storage.js';
|
|
@@ -29,6 +29,10 @@ export function launchParamsParser() {
|
|
|
29
29
|
type: boolean().optional(),
|
|
30
30
|
from: 'tgWebAppShowSettings',
|
|
31
31
|
},
|
|
32
|
+
startParam: {
|
|
33
|
+
type: string().optional(),
|
|
34
|
+
from: 'tgWebAppStartParam',
|
|
35
|
+
},
|
|
32
36
|
themeParams: {
|
|
33
37
|
type: themeParamsParser(),
|
|
34
38
|
from: 'tgWebAppThemeParams',
|