@tma.js/sdk 1.0.2 → 1.2.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/bridge/events/parsers/phoneRequested.d.ts +1 -1
- package/dist/dts/bridge/index.d.ts +1 -0
- package/dist/dts/bridge/invoke-custom-method.d.ts +18 -0
- package/dist/dts/bridge/methods/custom-methods.d.ts +56 -0
- package/dist/dts/bridge/methods/index.d.ts +1 -1
- package/dist/dts/bridge/methods/methods.d.ts +1 -1
- package/dist/dts/bridge/request.d.ts +3 -12
- package/dist/dts/cloud-storage/CloudStorage.d.ts +7 -16
- package/dist/dts/index.d.ts +8 -6
- package/dist/dts/init/creators/createMiniApp.d.ts +3 -1
- package/dist/dts/init/creators/createSettingsButton.d.ts +10 -0
- package/dist/dts/init/creators/index.d.ts +1 -0
- package/dist/dts/init/init.d.ts +1 -0
- package/dist/dts/init/types.d.ts +2 -0
- package/dist/dts/mini-app/MiniApp.d.ts +34 -4
- package/dist/dts/mini-app/contactParser.d.ts +2 -0
- package/dist/dts/mini-app/types.d.ts +12 -0
- package/dist/dts/settings-button/SettingsButton.d.ts +42 -0
- package/dist/dts/settings-button/index.d.ts +2 -0
- package/dist/dts/settings-button/types.d.ts +10 -0
- package/dist/dts/storage.d.ts +3 -0
- package/dist/dts/timeout/index.d.ts +1 -0
- package/dist/dts/timeout/sleep.d.ts +5 -0
- package/dist/dts/timeout/withTimeout.d.ts +5 -12
- package/dist/dts/types/index.d.ts +1 -0
- package/dist/dts/types/methods.d.ts +15 -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 +854 -670
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/bridge/events/parsers/phoneRequested.ts +1 -1
- package/src/bridge/index.ts +1 -0
- package/src/bridge/invoke-custom-method.ts +56 -0
- package/src/bridge/methods/custom-methods.ts +68 -0
- package/src/bridge/methods/index.ts +1 -1
- package/src/bridge/methods/methods.ts +3 -5
- package/src/bridge/request.ts +35 -44
- package/src/cloud-storage/CloudStorage.ts +36 -53
- package/src/index.ts +14 -20
- package/src/init/creators/createMiniApp.ts +4 -0
- package/src/init/creators/createSettingsButton.ts +25 -0
- package/src/init/creators/createViewport.ts +16 -5
- package/src/init/creators/index.ts +1 -0
- package/src/init/init.ts +9 -5
- package/src/init/types.ts +2 -0
- package/src/mini-app/MiniApp.ts +131 -20
- package/src/mini-app/contactParser.ts +29 -0
- package/src/mini-app/types.ts +13 -0
- package/src/settings-button/SettingsButton.ts +85 -0
- package/src/settings-button/index.ts +2 -0
- package/src/settings-button/types.ts +15 -0
- package/src/storage.ts +3 -0
- package/src/timeout/index.ts +1 -0
- package/src/timeout/sleep.ts +10 -0
- package/src/timeout/withTimeout.ts +10 -22
- package/src/types/index.ts +1 -0
- package/src/types/methods.ts +18 -0
- package/dist/dts/bridge/methods/invoke-custom-method.d.ts +0 -24
- package/src/bridge/methods/invoke-custom-method.ts +0 -25
package/src/init/init.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
createClosingBehavior,
|
|
8
8
|
createMainButton,
|
|
9
9
|
createMiniApp,
|
|
10
|
-
createRequestIdGenerator,
|
|
10
|
+
createRequestIdGenerator, createSettingsButton,
|
|
11
11
|
createThemeParams, createViewportAsync,
|
|
12
12
|
createViewportSync,
|
|
13
13
|
} from '~/init/creators/index.js';
|
|
@@ -23,7 +23,9 @@ import type { InitOptions, InitResult } from './types.js';
|
|
|
23
23
|
|
|
24
24
|
type ComputedInitResult<O> = O extends { async: true } ? Promise<InitResult> : InitResult;
|
|
25
25
|
|
|
26
|
-
export function init
|
|
26
|
+
export function init(): InitResult;
|
|
27
|
+
export function init<O extends InitOptions>(options: O): ComputedInitResult<O>;
|
|
28
|
+
export function init(options: InitOptions = {}): InitResult | Promise<InitResult> {
|
|
27
29
|
const {
|
|
28
30
|
async = false,
|
|
29
31
|
cssVars = false,
|
|
@@ -79,11 +81,13 @@ export function init<O extends InitOptions>(options: O): ComputedInitResult<O> {
|
|
|
79
81
|
themeParams.backgroundColor || '#ffffff',
|
|
80
82
|
version,
|
|
81
83
|
botInline,
|
|
84
|
+
createRequestId,
|
|
82
85
|
postEvent,
|
|
83
86
|
),
|
|
84
87
|
popup: new Popup(version, postEvent),
|
|
85
88
|
postEvent,
|
|
86
89
|
qrScanner: new QRScanner(version, postEvent),
|
|
90
|
+
settingsButton: createSettingsButton(isPageReload, version, postEvent),
|
|
87
91
|
themeParams: createThemeParams(themeParams),
|
|
88
92
|
utils: new Utils(version, createRequestId, postEvent),
|
|
89
93
|
...(initData
|
|
@@ -112,7 +116,7 @@ export function init<O extends InitOptions>(options: O): ComputedInitResult<O> {
|
|
|
112
116
|
...result,
|
|
113
117
|
viewport: vp,
|
|
114
118
|
};
|
|
115
|
-
})
|
|
119
|
+
});
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
processCSSVars(
|
|
@@ -122,10 +126,10 @@ export function init<O extends InitOptions>(options: O): ComputedInitResult<O> {
|
|
|
122
126
|
viewport,
|
|
123
127
|
);
|
|
124
128
|
|
|
125
|
-
return { ...result, viewport }
|
|
129
|
+
return { ...result, viewport };
|
|
126
130
|
} catch (e) {
|
|
127
131
|
if (async) {
|
|
128
|
-
return Promise.reject(e)
|
|
132
|
+
return Promise.reject(e);
|
|
129
133
|
}
|
|
130
134
|
throw e;
|
|
131
135
|
}
|
package/src/init/types.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { MainButton } from '~/main-button/index.js';
|
|
|
9
9
|
import type { MiniApp } from '~/mini-app/index.js';
|
|
10
10
|
import type { Popup } from '~/popup/index.js';
|
|
11
11
|
import type { QRScanner } from '~/qr-scanner/index.js';
|
|
12
|
+
import type { SettingsButton } from '~/settings-button/index.js';
|
|
12
13
|
import type { ThemeParams } from '~/theme-params/index.js';
|
|
13
14
|
import type { CreateRequestIdFunc } from '~/types/index.js';
|
|
14
15
|
import type { Utils } from '~/utils/index.js';
|
|
@@ -28,6 +29,7 @@ export interface InitResult {
|
|
|
28
29
|
popup: Popup;
|
|
29
30
|
postEvent: PostEvent;
|
|
30
31
|
qrScanner: QRScanner;
|
|
32
|
+
settingsButton: SettingsButton;
|
|
31
33
|
themeParams: ThemeParams;
|
|
32
34
|
utils: Utils;
|
|
33
35
|
viewport: Viewport;
|
package/src/mini-app/MiniApp.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
invokeCustomMethod,
|
|
2
3
|
type PhoneRequestedStatus,
|
|
3
4
|
type PostEvent,
|
|
4
5
|
postEvent as defaultPostEvent,
|
|
@@ -18,11 +19,14 @@ import {
|
|
|
18
19
|
createSupportsParamFunc,
|
|
19
20
|
type SupportsFunc,
|
|
20
21
|
} from '~/supports/index.js';
|
|
22
|
+
import { sleep, withTimeout } from '~/timeout/index.js';
|
|
23
|
+
import type { CreateRequestIdFunc, ExecuteWithTimeout } from '~/types/index.js';
|
|
21
24
|
|
|
25
|
+
import { contactParser } from './contactParser.js';
|
|
22
26
|
import type {
|
|
23
27
|
MiniAppEvents,
|
|
24
28
|
MiniAppHeaderColor, MiniAppProps,
|
|
25
|
-
MiniAppState,
|
|
29
|
+
MiniAppState, RequestedContact,
|
|
26
30
|
} from './types.js';
|
|
27
31
|
|
|
28
32
|
/**
|
|
@@ -37,6 +41,12 @@ export class MiniApp {
|
|
|
37
41
|
|
|
38
42
|
private readonly postEvent: PostEvent;
|
|
39
43
|
|
|
44
|
+
private readonly createRequestId: CreateRequestIdFunc;
|
|
45
|
+
|
|
46
|
+
private requestingPhoneAccess = false;
|
|
47
|
+
|
|
48
|
+
private requestingWriteAccess = false;
|
|
49
|
+
|
|
40
50
|
constructor(props: MiniAppProps) {
|
|
41
51
|
const {
|
|
42
52
|
postEvent = defaultPostEvent,
|
|
@@ -44,6 +54,7 @@ export class MiniApp {
|
|
|
44
54
|
backgroundColor,
|
|
45
55
|
version,
|
|
46
56
|
botInline,
|
|
57
|
+
createRequestId,
|
|
47
58
|
} = props;
|
|
48
59
|
|
|
49
60
|
const isSupported = createSupportsFunc(version, {
|
|
@@ -56,6 +67,7 @@ export class MiniApp {
|
|
|
56
67
|
|
|
57
68
|
this.postEvent = postEvent;
|
|
58
69
|
this.botInline = botInline;
|
|
70
|
+
this.createRequestId = createRequestId;
|
|
59
71
|
this.supports = (method) => {
|
|
60
72
|
if (!isSupported(method)) {
|
|
61
73
|
return false;
|
|
@@ -66,7 +78,6 @@ export class MiniApp {
|
|
|
66
78
|
if (method === 'switchInlineQuery' && !botInline) {
|
|
67
79
|
return false;
|
|
68
80
|
}
|
|
69
|
-
|
|
70
81
|
return true;
|
|
71
82
|
};
|
|
72
83
|
|
|
@@ -76,6 +87,22 @@ export class MiniApp {
|
|
|
76
87
|
});
|
|
77
88
|
}
|
|
78
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Attempts to get requested contact.
|
|
92
|
+
*/
|
|
93
|
+
private async getRequestedContact(): Promise<RequestedContact> {
|
|
94
|
+
return invokeCustomMethod(
|
|
95
|
+
'getRequestedContact',
|
|
96
|
+
{},
|
|
97
|
+
this.createRequestId(),
|
|
98
|
+
{
|
|
99
|
+
postEvent: this.postEvent,
|
|
100
|
+
timeout: 10000,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
.then((data) => contactParser.parse(data));
|
|
104
|
+
}
|
|
105
|
+
|
|
79
106
|
/**
|
|
80
107
|
* The Mini App background color.
|
|
81
108
|
*/
|
|
@@ -111,6 +138,20 @@ export class MiniApp {
|
|
|
111
138
|
return isColorDark(this.backgroundColor);
|
|
112
139
|
}
|
|
113
140
|
|
|
141
|
+
/**
|
|
142
|
+
* True if phone access is currently being requested.
|
|
143
|
+
*/
|
|
144
|
+
get isRequestingPhoneAccess(): boolean {
|
|
145
|
+
return this.requestingPhoneAccess;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* True if write access is currently being requested.
|
|
150
|
+
*/
|
|
151
|
+
get isRequestingWriteAccess(): boolean {
|
|
152
|
+
return this.requestingWriteAccess;
|
|
153
|
+
}
|
|
154
|
+
|
|
114
155
|
/**
|
|
115
156
|
* Adds new event listener.
|
|
116
157
|
*/
|
|
@@ -135,25 +176,95 @@ export class MiniApp {
|
|
|
135
176
|
}
|
|
136
177
|
|
|
137
178
|
/**
|
|
138
|
-
* Requests current user
|
|
179
|
+
* Requests current user contact information. In contrary to requestPhoneAccess, this method
|
|
180
|
+
* returns promise with contact information that rejects in case, user denied access, or request
|
|
181
|
+
* failed.
|
|
182
|
+
* @param options - additional options.
|
|
139
183
|
*/
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
184
|
+
async requestContact({ timeout = 5000 }: ExecuteWithTimeout = {}): Promise<RequestedContact> {
|
|
185
|
+
// First of all, let's try to get the requested contact. Probably, we already requested
|
|
186
|
+
// it before.
|
|
187
|
+
try {
|
|
188
|
+
return await this.getRequestedContact();
|
|
189
|
+
} catch (e) { /* empty */
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Then, request access to user's phone.
|
|
193
|
+
const status = await this.requestPhoneAccess();
|
|
194
|
+
if (status !== 'sent') {
|
|
195
|
+
throw new Error('Access denied.');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Expected deadline.
|
|
199
|
+
const deadlineAt = Date.now() + timeout;
|
|
200
|
+
|
|
201
|
+
// Time to wait before executing the next request.
|
|
202
|
+
let sleepTime = 50;
|
|
203
|
+
|
|
204
|
+
return withTimeout(async () => {
|
|
205
|
+
// We are trying to retrieve the requested contact until deadline was reached.
|
|
206
|
+
while (Date.now() < deadlineAt) {
|
|
207
|
+
try {
|
|
208
|
+
// eslint-disable-next-line no-await-in-loop
|
|
209
|
+
return await this.getRequestedContact();
|
|
210
|
+
} catch (e) { /* empty */
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Sleep for some time.
|
|
214
|
+
// eslint-disable-next-line no-await-in-loop
|
|
215
|
+
await sleep(sleepTime);
|
|
216
|
+
|
|
217
|
+
// Increase the sleep time not to kill the backend service.
|
|
218
|
+
sleepTime += 50;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
throw new Error('Unable to retrieve requested contact.');
|
|
222
|
+
}, timeout);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Requests current user phone access. Method returns promise, which resolves
|
|
227
|
+
* status of the request. In case, user accepted the request, Mini App bot will receive
|
|
228
|
+
* the according notification.
|
|
229
|
+
*
|
|
230
|
+
* To obtain the retrieved information instead, utilize the requestContact method.
|
|
231
|
+
* @param options - additional options.
|
|
232
|
+
* @see requestContact
|
|
233
|
+
*/
|
|
234
|
+
requestPhoneAccess(options: ExecuteWithTimeout = {}): Promise<PhoneRequestedStatus> {
|
|
235
|
+
if (this.requestingPhoneAccess) {
|
|
236
|
+
throw new Error('Phone access is already being requested.');
|
|
237
|
+
}
|
|
238
|
+
this.requestingPhoneAccess = true;
|
|
239
|
+
|
|
240
|
+
return request('web_app_request_phone', 'phone_requested', {
|
|
241
|
+
...options,
|
|
242
|
+
postEvent: this.postEvent,
|
|
243
|
+
})
|
|
244
|
+
.then((data) => data.status)
|
|
245
|
+
.finally(() => {
|
|
246
|
+
this.requestingPhoneAccess = false;
|
|
247
|
+
});
|
|
146
248
|
}
|
|
147
249
|
|
|
148
250
|
/**
|
|
149
251
|
* Requests write message access to current user.
|
|
252
|
+
* @param options - additional options.
|
|
150
253
|
*/
|
|
151
|
-
requestWriteAccess(): Promise<WriteAccessRequestedStatus> {
|
|
152
|
-
|
|
153
|
-
'
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
254
|
+
requestWriteAccess(options: ExecuteWithTimeout = {}): Promise<WriteAccessRequestedStatus> {
|
|
255
|
+
if (this.requestingWriteAccess) {
|
|
256
|
+
throw new Error('Write access is already being requested.');
|
|
257
|
+
}
|
|
258
|
+
this.requestingWriteAccess = true;
|
|
259
|
+
|
|
260
|
+
return request('web_app_request_write_access', 'write_access_requested', {
|
|
261
|
+
...options,
|
|
262
|
+
postEvent: this.postEvent,
|
|
263
|
+
})
|
|
264
|
+
.then((data) => data.status)
|
|
265
|
+
.finally(() => {
|
|
266
|
+
this.requestingWriteAccess = false;
|
|
267
|
+
});
|
|
157
268
|
}
|
|
158
269
|
|
|
159
270
|
/**
|
|
@@ -203,11 +314,11 @@ export class MiniApp {
|
|
|
203
314
|
* Checks if specified method is supported by current component.
|
|
204
315
|
*/
|
|
205
316
|
supports: SupportsFunc<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
317
|
+
| 'requestWriteAccess'
|
|
318
|
+
| 'requestPhoneAccess'
|
|
319
|
+
| 'switchInlineQuery'
|
|
320
|
+
| 'setHeaderColor'
|
|
321
|
+
| 'setBackgroundColor'
|
|
211
322
|
>;
|
|
212
323
|
|
|
213
324
|
/**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { date, json, number, searchParams, string } from '~/parsing/index.js';
|
|
2
|
+
|
|
3
|
+
import type { RequestedContact } from './types.js';
|
|
4
|
+
|
|
5
|
+
export const contactParser = searchParams<RequestedContact>({
|
|
6
|
+
contact: json({
|
|
7
|
+
userId: {
|
|
8
|
+
type: number(),
|
|
9
|
+
from: 'user_id',
|
|
10
|
+
},
|
|
11
|
+
phoneNumber: {
|
|
12
|
+
type: string(),
|
|
13
|
+
from: 'phone_number',
|
|
14
|
+
},
|
|
15
|
+
firstName: {
|
|
16
|
+
type: string(),
|
|
17
|
+
from: 'first_name',
|
|
18
|
+
},
|
|
19
|
+
lastName: {
|
|
20
|
+
type: string(),
|
|
21
|
+
from: 'last_name',
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
authDate: {
|
|
25
|
+
type: date(),
|
|
26
|
+
from: 'auth_date',
|
|
27
|
+
},
|
|
28
|
+
hash: string(),
|
|
29
|
+
});
|
package/src/mini-app/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { HeaderColorKey, PostEvent } from '~/bridge/index.js';
|
|
2
2
|
import type { RGB } from '~/colors/index.js';
|
|
3
3
|
import type { StateEvents } from '~/state/index.js';
|
|
4
|
+
import type { CreateRequestIdFunc } from '~/types/index.js';
|
|
4
5
|
import type { Version } from '~/version/index.js';
|
|
5
6
|
|
|
6
7
|
export interface MiniAppProps {
|
|
@@ -8,6 +9,7 @@ export interface MiniAppProps {
|
|
|
8
9
|
backgroundColor: RGB;
|
|
9
10
|
version: Version;
|
|
10
11
|
botInline: boolean;
|
|
12
|
+
createRequestId: CreateRequestIdFunc;
|
|
11
13
|
postEvent?: PostEvent;
|
|
12
14
|
}
|
|
13
15
|
|
|
@@ -23,3 +25,14 @@ export type MiniAppEvents = StateEvents<MiniAppState>;
|
|
|
23
25
|
export type MiniAppEventName = keyof MiniAppEvents;
|
|
24
26
|
|
|
25
27
|
export type MiniAppEventListener<E extends MiniAppEventName> = MiniAppEvents[E];
|
|
28
|
+
|
|
29
|
+
export interface RequestedContact {
|
|
30
|
+
contact: {
|
|
31
|
+
userId: number;
|
|
32
|
+
phoneNumber: string;
|
|
33
|
+
firstName: string;
|
|
34
|
+
lastName: string;
|
|
35
|
+
};
|
|
36
|
+
authDate: Date;
|
|
37
|
+
hash: string;
|
|
38
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
off,
|
|
3
|
+
on,
|
|
4
|
+
type PostEvent,
|
|
5
|
+
postEvent as defaultPostEvent,
|
|
6
|
+
} from '~/bridge/index.js';
|
|
7
|
+
import { EventEmitter } from '~/event-emitter/index.js';
|
|
8
|
+
import { State } from '~/state/index.js';
|
|
9
|
+
import { createSupportsFunc, type SupportsFunc } from '~/supports/index.js';
|
|
10
|
+
import type { Version } from '~/version/index.js';
|
|
11
|
+
|
|
12
|
+
import type { SettingsButtonEvents, SettingsButtonState } from './types.js';
|
|
13
|
+
|
|
14
|
+
type Emitter = EventEmitter<SettingsButtonEvents>;
|
|
15
|
+
|
|
16
|
+
export class SettingsButton {
|
|
17
|
+
private readonly ee: Emitter = new EventEmitter();
|
|
18
|
+
|
|
19
|
+
private readonly state: State<SettingsButtonState>;
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
isVisible: boolean,
|
|
23
|
+
version: Version,
|
|
24
|
+
private readonly postEvent: PostEvent = defaultPostEvent,
|
|
25
|
+
) {
|
|
26
|
+
this.state = new State({ isVisible }, this.ee);
|
|
27
|
+
this.supports = createSupportsFunc(version, {
|
|
28
|
+
show: 'web_app_setup_settings_button',
|
|
29
|
+
hide: 'web_app_setup_settings_button',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private set isVisible(visible: boolean) {
|
|
34
|
+
this.state.set('isVisible', visible);
|
|
35
|
+
this.postEvent('web_app_setup_settings_button', { is_visible: visible });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* True if SettingsButton is currently visible.
|
|
40
|
+
*/
|
|
41
|
+
get isVisible(): boolean {
|
|
42
|
+
return this.state.get('isVisible');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Hides the SettingsButton.
|
|
47
|
+
*/
|
|
48
|
+
hide(): void {
|
|
49
|
+
this.isVisible = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Adds event listener.
|
|
54
|
+
* @param event - event name.
|
|
55
|
+
* @param listener - event listener.
|
|
56
|
+
*/
|
|
57
|
+
on: Emitter['on'] = (event, listener) => (
|
|
58
|
+
event === 'click'
|
|
59
|
+
? on('settings_button_pressed', listener)
|
|
60
|
+
: this.ee.on(event, listener)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Removes event listener.
|
|
65
|
+
* @param event - event name.
|
|
66
|
+
* @param listener - event listener.
|
|
67
|
+
*/
|
|
68
|
+
off: Emitter['off'] = (event, listener) => (
|
|
69
|
+
event === 'click'
|
|
70
|
+
? off('settings_button_pressed', listener)
|
|
71
|
+
: this.ee.off(event, listener)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Shows the SettingsButton.
|
|
76
|
+
*/
|
|
77
|
+
show(): void {
|
|
78
|
+
this.isVisible = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Checks if specified method is supported by current component.
|
|
83
|
+
*/
|
|
84
|
+
supports: SupportsFunc<'show' | 'hide'>;
|
|
85
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MiniAppsEventListener } from '~/bridge/index.js';
|
|
2
|
+
import type { StateEvents } from '~/state/index.js';
|
|
3
|
+
|
|
4
|
+
export interface SettingsButtonState {
|
|
5
|
+
isVisible: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface SettingsButtonEvents extends StateEvents<SettingsButtonState> {
|
|
9
|
+
click: MiniAppsEventListener<'settings_button_pressed'>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type SettingsButtonEventName = keyof SettingsButtonEvents;
|
|
13
|
+
|
|
14
|
+
export type SettingsButtonEventListener<E extends SettingsButtonEventName> =
|
|
15
|
+
SettingsButtonEvents[E];
|
package/src/storage.ts
CHANGED
package/src/timeout/index.ts
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Awaits for specified amount of time.
|
|
3
|
+
* @param duration - duration to await.
|
|
4
|
+
*/
|
|
5
|
+
export function sleep(duration: number): Promise<void> {
|
|
6
|
+
// eslint-disable-next-line no-await-in-loop,@typescript-eslint/no-loop-func
|
|
7
|
+
return new Promise((res) => {
|
|
8
|
+
setTimeout(res, duration);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -1,36 +1,24 @@
|
|
|
1
1
|
import { TimeoutError } from './TimeoutError.js';
|
|
2
2
|
|
|
3
|
-
type AnyAsyncFunction = (...args: any[]) => Promise<any>;
|
|
4
|
-
|
|
5
3
|
/**
|
|
6
4
|
* Creates promise which rejects after timeout milliseconds.
|
|
7
5
|
* @param timeout - timeout in milliseconds.
|
|
8
6
|
*/
|
|
9
|
-
function createTimeoutPromise(timeout: number): Promise<
|
|
7
|
+
function createTimeoutPromise(timeout: number): Promise<never> {
|
|
10
8
|
return new Promise((_, rej) => {
|
|
11
9
|
setTimeout(rej, timeout, new TimeoutError(timeout));
|
|
12
10
|
});
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @param
|
|
14
|
+
* Accepts specified function and instantly executes. It waits for timeout milliseconds for
|
|
15
|
+
* it to complete and throws an error in case, deadline was reached.
|
|
16
|
+
* @param func - function to execute.
|
|
17
|
+
* @param timeout - completion timeout.
|
|
19
18
|
*/
|
|
20
|
-
export function withTimeout<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*/
|
|
26
|
-
export function withTimeout<F extends AnyAsyncFunction>(func: F, timeout: number): F;
|
|
27
|
-
export function withTimeout(funcOrPromise: Promise<any> | AnyAsyncFunction, timeout: number) {
|
|
28
|
-
if (typeof funcOrPromise === 'function') {
|
|
29
|
-
return (...args: any[]) => Promise.race([
|
|
30
|
-
funcOrPromise(...args),
|
|
31
|
-
createTimeoutPromise(timeout),
|
|
32
|
-
]);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return Promise.race([funcOrPromise, createTimeoutPromise(timeout)]);
|
|
19
|
+
export function withTimeout<T>(func: () => Promise<T>, timeout: number): Promise<T> {
|
|
20
|
+
return Promise.race([
|
|
21
|
+
func(),
|
|
22
|
+
createTimeoutPromise(timeout),
|
|
23
|
+
]);
|
|
36
24
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PostEvent } from '~/bridge/index.js';
|
|
2
|
+
|
|
3
|
+
export interface ExecuteWithTimeout {
|
|
4
|
+
/**
|
|
5
|
+
* Timeout to execute method.
|
|
6
|
+
*/
|
|
7
|
+
timeout?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ExecuteWithPostEvent {
|
|
11
|
+
/**
|
|
12
|
+
* postEvent function to use to call Telegram Mini Apps methods.
|
|
13
|
+
*/
|
|
14
|
+
postEvent?: PostEvent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ExecuteWithOptions extends ExecuteWithTimeout, ExecuteWithPostEvent {
|
|
18
|
+
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { RequestId } from '../../types/index.js';
|
|
2
|
-
interface CreateInvokeCustomMethodParams<M extends string, Params extends object> {
|
|
3
|
-
/**
|
|
4
|
-
* Unique request identifier.
|
|
5
|
-
*/
|
|
6
|
-
req_id: RequestId;
|
|
7
|
-
/**
|
|
8
|
-
* Method name.
|
|
9
|
-
*/
|
|
10
|
-
method: M;
|
|
11
|
-
/**
|
|
12
|
-
* Method specific parameters.
|
|
13
|
-
*/
|
|
14
|
-
params: Params;
|
|
15
|
-
}
|
|
16
|
-
export type AnyInvokeCustomMethodParams = CreateInvokeCustomMethodParams<'deleteStorageValues', {
|
|
17
|
-
keys: string | string[];
|
|
18
|
-
}> | CreateInvokeCustomMethodParams<'getStorageValues', {
|
|
19
|
-
keys: string | string[];
|
|
20
|
-
}> | CreateInvokeCustomMethodParams<'getStorageKeys', {}> | CreateInvokeCustomMethodParams<'saveStorageValue', {
|
|
21
|
-
key: string;
|
|
22
|
-
value: string;
|
|
23
|
-
}> | CreateInvokeCustomMethodParams<string, any>;
|
|
24
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { RequestId } from '~/types/index.js';
|
|
2
|
-
|
|
3
|
-
interface CreateInvokeCustomMethodParams<M extends string, Params extends object> {
|
|
4
|
-
/**
|
|
5
|
-
* Unique request identifier.
|
|
6
|
-
*/
|
|
7
|
-
req_id: RequestId;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Method name.
|
|
11
|
-
*/
|
|
12
|
-
method: M;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Method specific parameters.
|
|
16
|
-
*/
|
|
17
|
-
params: Params;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export type AnyInvokeCustomMethodParams =
|
|
21
|
-
| CreateInvokeCustomMethodParams<'deleteStorageValues', { keys: string | string[] }>
|
|
22
|
-
| CreateInvokeCustomMethodParams<'getStorageValues', { keys: string | string[] }>
|
|
23
|
-
| CreateInvokeCustomMethodParams<'getStorageKeys', {}>
|
|
24
|
-
| CreateInvokeCustomMethodParams<'saveStorageValue', { key: string, value: string }>
|
|
25
|
-
| CreateInvokeCustomMethodParams<string, any>;
|