@tma.js/sdk 1.3.0 → 1.4.1
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 -0
- 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/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 +253 -238
- 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 +12 -0
- package/src/init/creators/__tests__/createViewport.ts +96 -0
- 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/version/__tests__/compareVersions.ts +19 -0
- package/src/viewport/__tests__/isStableViewportPlatform.ts +15 -0
- package/src/viewport/__tests__/utils.ts +12 -0
|
@@ -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',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { retrieveFromUrl } from './retrieveFromUrl.js';
|
|
2
2
|
import type { LaunchParams } from './types.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -6,5 +6,5 @@ import type { LaunchParams } from './types.js';
|
|
|
6
6
|
* @throws {Error} window.location.hash contains invalid data.
|
|
7
7
|
*/
|
|
8
8
|
export function retrieveFromLocation(): LaunchParams {
|
|
9
|
-
return
|
|
9
|
+
return retrieveFromUrl(window.location.href);
|
|
10
10
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getFirstNavigationEntry } from './getFirstNavigationEntry.js';
|
|
2
|
-
import {
|
|
2
|
+
import { retrieveFromUrl } from './retrieveFromUrl.js';
|
|
3
3
|
import type { LaunchParams } from './types.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -14,10 +14,5 @@ export function retrieveFromPerformance(): LaunchParams {
|
|
|
14
14
|
throw new Error('Unable to get first navigation entry.');
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
if (!hashMatch) {
|
|
19
|
-
throw new Error('First navigation entry does not contain hash part.');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return parseLaunchParams(hashMatch[1]);
|
|
17
|
+
return retrieveFromUrl(navigationEntry.name);
|
|
23
18
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { parseLaunchParams } from '~/launch-params/parseLaunchParams.js';
|
|
2
|
+
import type { LaunchParams } from '~/launch-params/types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Retrieves launch parameters from the specified URL.
|
|
6
|
+
* @param url - URL to extract launch parameters from.
|
|
7
|
+
*/
|
|
8
|
+
export function retrieveFromUrl(url: string): LaunchParams {
|
|
9
|
+
const queryParams = url.includes('?')
|
|
10
|
+
// If URL includes "?", we expect it to possibly contain "#". The reason is TMA allows passing
|
|
11
|
+
// start parameter via tgWebAppStartParam **query** parameter. Replacing "#" with "&" we
|
|
12
|
+
// expect merging query parameters with hash parameters and creating complete launch
|
|
13
|
+
// parameters information.
|
|
14
|
+
? url.replace('#', '&').slice(url.indexOf('?') + 1)
|
|
15
|
+
// Otherwise, we expect specifying launch parameters only in the hash part.
|
|
16
|
+
: url.slice(url.indexOf('#') + 1);
|
|
17
|
+
|
|
18
|
+
return parseLaunchParams(queryParams);
|
|
19
|
+
}
|
|
@@ -8,9 +8,9 @@ import type { Platform } from '~/types/index.js';
|
|
|
8
8
|
*/
|
|
9
9
|
export interface LaunchParams {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* True if Mini App is currently launched in inline mode.
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
botInline?: boolean;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Current launch init data. Can be missing in case, application was launched via
|
|
@@ -29,19 +29,24 @@ export interface LaunchParams {
|
|
|
29
29
|
platform: Platform;
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* True if application is required to show the Settings Button.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
showSettings?: boolean;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* Start parameter passed in the application link.
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
startParam?: string;
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Mini App palette settings.
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
themeParams: ThemeParamsParsed;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Current Mini Apps version.
|
|
48
|
+
*/
|
|
49
|
+
version: string;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
export interface LaunchData {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterAll,
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeAll,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
vi,
|
|
9
|
+
} from 'vitest';
|
|
10
|
+
|
|
11
|
+
import { Logger } from '../Logger';
|
|
12
|
+
|
|
13
|
+
const now = new Date('2022-11-04T09:09:43.007Z');
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.resetAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
beforeAll(() => {
|
|
20
|
+
vi.useFakeTimers().setSystemTime(now);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterAll(() => {
|
|
24
|
+
vi.useRealTimers();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should not call console methods if logger is disabled', () => {
|
|
28
|
+
const logger = new Logger('', false);
|
|
29
|
+
const spy = vi.fn();
|
|
30
|
+
|
|
31
|
+
vi.spyOn(console, 'log').mockImplementation(spy);
|
|
32
|
+
vi.spyOn(console, 'warn').mockImplementation(spy);
|
|
33
|
+
vi.spyOn(console, 'error').mockImplementation(spy);
|
|
34
|
+
|
|
35
|
+
logger.log();
|
|
36
|
+
logger.warn();
|
|
37
|
+
logger.error();
|
|
38
|
+
expect(spy).not.toHaveBeenCalled();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('enable', () => {
|
|
42
|
+
it('should start logging messages into console', () => {
|
|
43
|
+
const logger = new Logger('', false);
|
|
44
|
+
const spy = vi.fn();
|
|
45
|
+
|
|
46
|
+
vi.spyOn(console, 'log').mockImplementation(spy);
|
|
47
|
+
logger.log();
|
|
48
|
+
expect(spy).not.toHaveBeenCalled();
|
|
49
|
+
|
|
50
|
+
logger.enable();
|
|
51
|
+
logger.log();
|
|
52
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('disable', () => {
|
|
57
|
+
it('should stop logging messages into console', () => {
|
|
58
|
+
const logger = new Logger('', true);
|
|
59
|
+
const spy = vi.fn();
|
|
60
|
+
|
|
61
|
+
vi.spyOn(console, 'log').mockImplementation(spy);
|
|
62
|
+
logger.log();
|
|
63
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
64
|
+
|
|
65
|
+
spy.mockReset();
|
|
66
|
+
|
|
67
|
+
logger.disable();
|
|
68
|
+
logger.log();
|
|
69
|
+
expect(spy).not.toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('error', () => {
|
|
74
|
+
it('should call console.error()', () => {
|
|
75
|
+
const logger = new Logger('My prefix', true);
|
|
76
|
+
const spy = vi.fn();
|
|
77
|
+
vi.spyOn(console, 'error').mockImplementation(spy);
|
|
78
|
+
|
|
79
|
+
logger.error('Test');
|
|
80
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
81
|
+
expect(spy).toHaveBeenCalledWith('[09:09:43.007]', 'My prefix', 'Test');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('log', () => {
|
|
86
|
+
it('should call console.log()', () => {
|
|
87
|
+
const logger = new Logger('My prefix', true);
|
|
88
|
+
const spy = vi.fn();
|
|
89
|
+
vi.spyOn(console, 'log').mockImplementation(spy);
|
|
90
|
+
|
|
91
|
+
logger.log('Test');
|
|
92
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
93
|
+
expect(spy).toHaveBeenCalledWith('[09:09:43.007]', 'My prefix', 'Test');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('warn', () => {
|
|
98
|
+
it('should call console.warn()', () => {
|
|
99
|
+
const logger = new Logger('My prefix', true);
|
|
100
|
+
const spy = vi.fn();
|
|
101
|
+
vi.spyOn(console, 'warn').mockImplementation(spy);
|
|
102
|
+
|
|
103
|
+
logger.warn('Test');
|
|
104
|
+
expect(spy).toHaveBeenCalledOnce();
|
|
105
|
+
expect(spy).toHaveBeenCalledWith('[09:09:43.007]', 'My prefix', 'Test');
|
|
106
|
+
});
|
|
107
|
+
});
|