@tma.js/bridge 1.3.2

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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +28 -0
  3. package/dist/lib/browser.js +2 -0
  4. package/dist/lib/browser.js.map +1 -0
  5. package/dist/lib/index.cjs +2 -0
  6. package/dist/lib/index.cjs.map +1 -0
  7. package/dist/lib/index.mjs +2 -0
  8. package/dist/lib/index.mjs.map +1 -0
  9. package/dist/types/env.d.ts +29 -0
  10. package/dist/types/events/emitter.d.ts +11 -0
  11. package/dist/types/events/events.d.ts +113 -0
  12. package/dist/types/events/index.d.ts +7 -0
  13. package/dist/types/events/off.d.ts +7 -0
  14. package/dist/types/events/on.d.ts +10 -0
  15. package/dist/types/events/onTelegramEvent.d.ts +7 -0
  16. package/dist/types/events/once.d.ts +9 -0
  17. package/dist/types/events/parsing.d.ts +38 -0
  18. package/dist/types/events/payloads.d.ts +47 -0
  19. package/dist/types/events/subscribe.d.ts +9 -0
  20. package/dist/types/events/unsubscribe.d.ts +6 -0
  21. package/dist/types/globals.d.ts +27 -0
  22. package/dist/types/index.d.ts +6 -0
  23. package/dist/types/methods/haptic.d.ts +40 -0
  24. package/dist/types/methods/index.d.ts +5 -0
  25. package/dist/types/methods/invoke-custom-method.d.ts +24 -0
  26. package/dist/types/methods/params.d.ts +227 -0
  27. package/dist/types/methods/popup.d.ts +50 -0
  28. package/dist/types/methods/postEvent.d.ts +31 -0
  29. package/dist/types/request.d.ts +66 -0
  30. package/dist/types/shared.d.ts +5 -0
  31. package/dist/types/supports.d.ts +22 -0
  32. package/package.json +67 -0
  33. package/src/env.ts +49 -0
  34. package/src/events/emitter.ts +125 -0
  35. package/src/events/events.ts +152 -0
  36. package/src/events/index.ts +7 -0
  37. package/src/events/off.ts +12 -0
  38. package/src/events/on.ts +17 -0
  39. package/src/events/onTelegramEvent.ts +83 -0
  40. package/src/events/once.ts +16 -0
  41. package/src/events/parsing.ts +94 -0
  42. package/src/events/payloads.ts +65 -0
  43. package/src/events/subscribe.ts +16 -0
  44. package/src/events/unsubscribe.ts +11 -0
  45. package/src/globals.ts +44 -0
  46. package/src/index.ts +6 -0
  47. package/src/methods/haptic.ts +52 -0
  48. package/src/methods/index.ts +5 -0
  49. package/src/methods/invoke-custom-method.ts +25 -0
  50. package/src/methods/params.ts +245 -0
  51. package/src/methods/popup.ts +55 -0
  52. package/src/methods/postEvent.ts +103 -0
  53. package/src/request.ts +171 -0
  54. package/src/shared.ts +5 -0
  55. package/src/supports.ts +99 -0
package/src/request.ts ADDED
@@ -0,0 +1,171 @@
1
+ import { withTimeout, isRecord } from '@tma.js/utils';
2
+
3
+ import type { And, If, IsNever } from '@tma.js/util-types';
4
+
5
+ import { postEvent as defaultPostEvent, type PostEvent } from './methods/postEvent.js';
6
+ import { on, type EventName, type EventParams, type EventHasParams } from './events/index.js';
7
+
8
+ import type {
9
+ EmptyMethodName, MethodHasParams,
10
+ MethodName,
11
+ MethodParams,
12
+ NonEmptyMethodName,
13
+ } from './methods/params.js';
14
+
15
+ /**
16
+ * Names of methods, which require passing "req_id" parameter.
17
+ */
18
+ type MethodNameWithRequestId = {
19
+ [Method in MethodName]: If<
20
+ And<MethodHasParams<Method>, MethodParams<Method> extends { req_id: string } ? true : false>,
21
+ Method,
22
+ never
23
+ >;
24
+ }[MethodName];
25
+
26
+ /**
27
+ * Names of events, which contain "req_id" parameter.
28
+ */
29
+ type EventNameWithRequestId = {
30
+ [Event in EventName]: If<
31
+ And<EventHasParams<Event>, EventParams<Event> extends { req_id: string } ? true : false>,
32
+ Event,
33
+ never
34
+ >;
35
+ }[EventName];
36
+
37
+ export interface RequestOptions {
38
+ /**
39
+ * Bridge postEvent method.
40
+ * @default Global postEvent method.
41
+ */
42
+ postEvent?: PostEvent;
43
+
44
+ /**
45
+ * Execution timeout.
46
+ */
47
+ timeout?: number;
48
+ }
49
+
50
+ export interface RequestOptionsAdvanced<EventPayload> extends RequestOptions {
51
+ /**
52
+ * Should return true in case, this event should be captured. If not specified,
53
+ * request is not skipping captured events.
54
+ */
55
+ capture?: If<IsNever<EventPayload>, () => boolean, (payload: EventPayload) => boolean>;
56
+ }
57
+
58
+ /**
59
+ * Calls specified TWA method and captures one of the specified events. Returns promise
60
+ * which will be resolved in case, event with specified in method request identifier
61
+ * was captured.
62
+ * @param method - method to execute.
63
+ * @param params - method parameters.
64
+ * @param event - event or events to listen.
65
+ * @param options - additional execution options.
66
+ */
67
+ export function request<
68
+ Method extends MethodNameWithRequestId,
69
+ Event extends EventNameWithRequestId,
70
+ >(
71
+ method: Method,
72
+ params: MethodParams<Method>,
73
+ event: Event | Event[],
74
+ options?: RequestOptions,
75
+ ): Promise<EventParams<Event>>;
76
+
77
+ /**
78
+ * Calls specified TWA method and captures one of the specified events. Returns promise
79
+ * which will be resolved in case, specified event was captured.
80
+ * @param method - method to execute.
81
+ * @param event - event or events to listen.
82
+ * @param options - additional execution options.
83
+ */
84
+ export function request<Method extends EmptyMethodName, Event extends EventName>(
85
+ method: Method,
86
+ event: Event | Event[],
87
+ options?: RequestOptionsAdvanced<EventParams<Event>>,
88
+ ): Promise<EventParams<Event>>;
89
+
90
+ /**
91
+ * Calls specified TWA method and captures one of the specified events. Returns promise
92
+ * which will be resolved in case, specified event was captured.
93
+ * @param method - method to execute
94
+ * @param params - method parameters.
95
+ * @param event - event or events to listen
96
+ * @param options - additional execution options.
97
+ */
98
+ export function request<Method extends NonEmptyMethodName, Event extends EventName>(
99
+ method: Method,
100
+ params: MethodParams<Method>,
101
+ event: Event | Event[],
102
+ options?: RequestOptionsAdvanced<EventParams<Event>>,
103
+ ): Promise<EventParams<Event>>;
104
+
105
+ export function request(
106
+ method: MethodName,
107
+ eventOrParams: EventName | EventName[] | EventParams<any>,
108
+ eventOrOptions?: EventName | EventName[] | RequestOptions | RequestOptionsAdvanced<any>,
109
+ options?: RequestOptions | RequestOptionsAdvanced<any>,
110
+ ): Promise<any> {
111
+ let executionOptions: RequestOptions | RequestOptionsAdvanced<any> | undefined;
112
+ let methodParams: EventParams<any> | undefined;
113
+ let events: EventName[];
114
+ let requestId: string | undefined;
115
+
116
+ if (typeof eventOrParams === 'string' || Array.isArray(eventOrParams)) {
117
+ // Override: [method, event, options?]
118
+ events = Array.isArray(eventOrParams) ? eventOrParams : [eventOrParams] as EventName[];
119
+ executionOptions = eventOrOptions as (RequestOptionsAdvanced<any> | undefined);
120
+ } else {
121
+ // Override: [method, params, event, options?]
122
+ methodParams = eventOrParams as EventParams<any>;
123
+ events = Array.isArray(eventOrOptions) ? eventOrOptions : [eventOrOptions] as EventName[];
124
+ executionOptions = options;
125
+ }
126
+
127
+ // In case, method parameters were passed, and they contained request identifier, we should store
128
+ // it and wait for the event with this identifier to occur.
129
+ if (isRecord(methodParams) && typeof methodParams.req_id === 'string') {
130
+ requestId = methodParams.req_id;
131
+ }
132
+
133
+ const { postEvent = defaultPostEvent, timeout } = executionOptions || {};
134
+ const capture = executionOptions && 'capture' in executionOptions
135
+ ? executionOptions.capture
136
+ : null;
137
+
138
+ const promise = new Promise((res, rej) => {
139
+ // Iterate over each event and create event listener.
140
+ const stoppers = events.map((ev) => on(ev, (data?) => {
141
+ // If request identifier was specified, we are waiting for event with the same value
142
+ // to occur.
143
+ if (typeof requestId === 'string' && (!isRecord(data) || data.req_id !== requestId)) {
144
+ return;
145
+ }
146
+
147
+ if (typeof capture === 'function' && !capture(data)) {
148
+ return;
149
+ }
150
+
151
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
152
+ stopListening();
153
+ res(data);
154
+ }));
155
+
156
+ // Function which removes all event listeners.
157
+ const stopListening = () => stoppers.forEach((stop) => stop());
158
+
159
+ try {
160
+ // We are wrapping this call in try catch, because it can throw errors in case,
161
+ // compatibility check was enabled. We want an error to be captured by promise, not by
162
+ // another one external try catch.
163
+ postEvent(method as any, methodParams);
164
+ } catch (e) {
165
+ stopListening();
166
+ rej(e);
167
+ }
168
+ });
169
+
170
+ return typeof timeout === 'number' ? withTimeout(promise, timeout) : promise;
171
+ }
package/src/shared.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Request identifier which should be generated locally. Native Telegram application
3
+ * uses it to generate a response to called method.
4
+ */
5
+ export type RequestId = string;
@@ -0,0 +1,99 @@
1
+ import { compareVersions, type Version } from '@tma.js/utils';
2
+
3
+ import type {
4
+ HasCheckSupportMethodParam,
5
+ HasCheckSupportMethodName,
6
+ MethodName,
7
+ MethodParams,
8
+ NonEmptyMethodName,
9
+ } from './methods/index.js';
10
+
11
+ function lessOrEqual(a: Version, b: Version): boolean {
12
+ return compareVersions(a, b) <= 0;
13
+ }
14
+
15
+ /**
16
+ * By specified method and parameters extracts properties which could be used by
17
+ * supports function as TWA method parameter.
18
+ * @param method - TWA method.
19
+ * @param params - method parameters.
20
+ */
21
+ export function detectSupportParams<M extends NonEmptyMethodName>(
22
+ method: M,
23
+ params: MethodParams<M>,
24
+ ): HasCheckSupportMethodParam<HasCheckSupportMethodName>[] {
25
+ if (method === 'web_app_open_link') {
26
+ if ('try_instant_view' in params) {
27
+ return ['try_instant_view'];
28
+ }
29
+ }
30
+
31
+ if (method === 'web_app_set_header_color') {
32
+ if ('color' in params) {
33
+ return ['color'];
34
+ }
35
+ }
36
+
37
+ return [];
38
+ }
39
+
40
+ /**
41
+ * Returns true in case, passed parameter in specified method is supported.
42
+ * @param method - method name
43
+ * @param param - method parameter
44
+ * @param inVersion - platform version.
45
+ */
46
+ export function supports<M extends HasCheckSupportMethodName>(
47
+ method: M,
48
+ param: HasCheckSupportMethodParam<M>,
49
+ inVersion: Version,
50
+ ): boolean;
51
+ /**
52
+ * Returns true in case, specified method is supported in passed version.
53
+ * @param method - method name.
54
+ * @param inVersion - platform version.
55
+ */
56
+ export function supports(method: MethodName, inVersion: Version): boolean;
57
+ export function supports(
58
+ method: MethodName,
59
+ paramOrVersion: Version | string,
60
+ inVersion?: string,
61
+ ): boolean {
62
+ // Method name, parameter, target version.
63
+ if (typeof inVersion === 'string') {
64
+ if (method === 'web_app_open_link') {
65
+ if (paramOrVersion === 'try_instant_view') {
66
+ return lessOrEqual('6.4', inVersion);
67
+ }
68
+ }
69
+
70
+ if (method === 'web_app_set_header_color') {
71
+ if (paramOrVersion === 'color') {
72
+ return lessOrEqual('6.9', inVersion);
73
+ }
74
+ }
75
+ }
76
+
77
+ // Method name, target version.
78
+ switch (method) {
79
+ case 'web_app_open_tg_link':
80
+ case 'web_app_open_invoice':
81
+ case 'web_app_setup_back_button':
82
+ case 'web_app_set_background_color':
83
+ case 'web_app_set_header_color':
84
+ case 'web_app_trigger_haptic_feedback':
85
+ return lessOrEqual('6.1', paramOrVersion);
86
+ case 'web_app_open_popup':
87
+ return lessOrEqual('6.2', paramOrVersion);
88
+ case 'web_app_close_scan_qr_popup':
89
+ case 'web_app_open_scan_qr_popup':
90
+ case 'web_app_read_text_from_clipboard':
91
+ return lessOrEqual('6.4', paramOrVersion);
92
+ case 'web_app_invoke_custom_method':
93
+ case 'web_app_request_write_access':
94
+ case 'web_app_request_phone':
95
+ return lessOrEqual('6.9', paramOrVersion);
96
+ default:
97
+ return true;
98
+ }
99
+ }