Mini App: Correctly respond for unsupported APIs (#5848)

This commit is contained in:
zubiden 2025-04-23 18:59:15 +02:00 committed by Alexander Zinchuk
parent ec66c16f21
commit 2bbfc15dd5
3 changed files with 292 additions and 156 deletions

View File

@ -1060,7 +1060,7 @@ const WebAppModalTabContent: FC<OwnProps & StateProps> = ({
src={url} src={url}
title={`${bot?.firstName} Web App`} title={`${bot?.firstName} Web App`}
sandbox={SANDBOX_ATTRIBUTES} sandbox={SANDBOX_ATTRIBUTES}
allow="camera; microphone; geolocation;" allow="camera; microphone; geolocation; clipboard-write;"
allowFullScreen allowFullScreen
ref={frameRef} ref={frameRef}
/> />

View File

@ -265,6 +265,78 @@ const useWebAppFrame = (
}); });
} }
if (eventType === 'web_app_device_storage_clear'
|| eventType === 'web_app_device_storage_get_key'
|| eventType === 'web_app_device_storage_save_key') {
const { req_id } = eventData;
sendEvent({
eventType: 'device_storage_failed',
eventData: {
req_id,
error: 'UNSUPPORTED',
},
});
}
if (eventType === 'web_app_secure_storage_clear'
|| eventType === 'web_app_secure_storage_get_key'
|| eventType === 'web_app_secure_storage_restore_key'
|| eventType === 'web_app_secure_storage_save_key') {
const { req_id } = eventData;
sendEvent({
eventType: 'secure_storage_failed',
eventData: {
req_id,
error: 'UNSUPPORTED',
},
});
}
if (eventType === 'web_app_start_accelerometer') {
sendEvent({
eventType: 'accelerometer_failed',
eventData: {
error: 'UNSUPPORTED',
},
});
}
if (eventType === 'web_app_start_gyroscope') {
sendEvent({
eventType: 'gyroscope_failed',
eventData: {
error: 'UNSUPPORTED',
},
});
}
if (eventType === 'web_app_start_device_orientation') {
sendEvent({
eventType: 'device_orientation_failed',
eventData: {
error: 'UNSUPPORTED',
},
});
}
if (eventType === 'web_app_add_to_home_screen') {
sendEvent({
eventType: 'home_screen_failed',
eventData: {
error: 'UNSUPPORTED',
},
});
}
if (eventType === 'web_app_check_home_screen') {
sendEvent({
eventType: 'home_screen_checked',
eventData: {
status: 'unsupported',
},
});
}
if (eventType === 'web_app_set_emoji_status') { if (eventType === 'web_app_set_emoji_status') {
const { custom_emoji_id, duration } = eventData; const { custom_emoji_id, duration } = eventData;

View File

@ -60,105 +60,115 @@ export type SafeArea = {
right: number; right: number;
}; };
export type WebAppInboundEvent = interface WebAppInboundEventMap {
WebAppEvent<'iframe_ready', { iframe_ready: { reload_supported?: boolean };
reload_supported?: boolean; web_app_data_send: { data: string };
}> | web_app_setup_main_button: WebAppButtonOptions;
WebAppEvent<'web_app_data_send', { web_app_setup_secondary_button: WebAppButtonOptions;
data: string; web_app_setup_back_button: { is_visible: boolean };
}> | web_app_setup_settings_button: { is_visible: boolean };
WebAppEvent<'web_app_setup_main_button', WebAppButtonOptions> | web_app_open_link: { url: string; try_instant_view?: boolean };
WebAppEvent<'web_app_setup_secondary_button', WebAppButtonOptions> | web_app_open_tg_link: { path_full: string; force_request?: boolean };
WebAppEvent<'web_app_setup_back_button', { web_app_open_invoice: { slug: string };
is_visible: boolean; web_app_trigger_haptic_feedback: {
}> |
WebAppEvent<'web_app_setup_settings_button', {
is_visible: boolean;
}> |
WebAppEvent<'web_app_open_link', {
url: string;
try_instant_view?: boolean;
}> |
WebAppEvent<'web_app_open_tg_link', {
path_full: string;
force_request?: boolean;
}> |
WebAppEvent<'web_app_open_invoice', {
slug: string;
}> |
WebAppEvent<'web_app_trigger_haptic_feedback', {
type: 'impact' | 'notification' | 'selection_change'; type: 'impact' | 'notification' | 'selection_change';
impact_style?: 'light' | 'medium' | 'heavy'; impact_style?: 'light' | 'medium' | 'heavy';
notification_type?: 'error' | 'success' | 'warning'; notification_type?: 'error' | 'success' | 'warning';
}> | };
WebAppEvent<'web_app_set_bottom_bar_color', { web_app_set_bottom_bar_color: { color: string };
color: string; web_app_set_background_color: { color: string };
}> | web_app_set_header_color: { color_key?: 'bg_color' | 'secondary_bg_color'; color?: string };
WebAppEvent<'web_app_set_background_color', { web_app_open_popup: PopupOptions;
color: string; web_app_setup_closing_behavior: { need_confirmation: boolean };
}> | web_app_open_scan_qr_popup: { text?: string };
WebAppEvent<'web_app_set_header_color', { web_app_read_text_from_clipboard: { req_id: string };
color_key?: 'bg_color' | 'secondary_bg_color'; web_app_switch_inline_query: {
color?: string;
}> |
WebAppEvent<'web_app_open_popup', PopupOptions> |
WebAppEvent<'web_app_setup_closing_behavior', {
need_confirmation: boolean;
}> |
WebAppEvent<'web_app_open_scan_qr_popup', {
text?: string;
}> |
WebAppEvent<'web_app_read_text_from_clipboard', {
req_id: string;
}> |
WebAppEvent<'web_app_switch_inline_query', {
query: string; query: string;
chat_types: ('users' | 'bots' | 'groups' | 'channels')[]; chat_types: ('users' | 'bots' | 'groups' | 'channels')[];
}> | };
WebAppEvent<'web_app_invoke_custom_method', { web_app_invoke_custom_method: { req_id: string; method: string; params: object };
web_app_biometry_request_access: { reason: string };
web_app_biometry_request_auth: { reason: string };
web_app_biometry_update_token: { token: string };
web_app_set_emoji_status: { custom_emoji_id: string; duration?: number };
web_app_request_file_download: { url: string; file_name: string };
web_app_send_prepared_message: { id: string };
web_app_device_storage_save_key: {
req_id: string; req_id: string;
method: string; key: string;
params: object; value: unknown | null;
}> | };
WebAppEvent<'web_app_biometry_request_access', { web_app_device_storage_get_key: {
reason: string; req_id: string;
}> | key: string;
WebAppEvent<'web_app_biometry_request_auth', { };
reason: string; web_app_device_storage_clear: {
}> | req_id: string;
WebAppEvent<'web_app_biometry_update_token', { };
token: string; web_app_secure_storage_save_key: {
}> | req_id: string;
WebAppEvent<'web_app_set_emoji_status', { key: string;
custom_emoji_id: string; value: unknown | null;
duration?: number; };
}> | web_app_secure_storage_get_key: {
WebAppEvent<'web_app_request_file_download', { req_id: string;
url: string; key: string;
file_name: string; };
}> | web_app_secure_storage_restore_key: {
WebAppEvent<'web_app_send_prepared_message', { req_id: string;
id: string; key: string;
}> | };
WebAppEvent<'web_app_request_viewport' | 'web_app_request_theme' | 'web_app_ready' | 'web_app_expand' web_app_secure_storage_clear: {
| 'web_app_request_phone' | 'web_app_close' | 'web_app_close_scan_qr_popup' req_id: string;
| 'web_app_request_write_access' | 'iframe_will_reload' };
| 'web_app_biometry_get_info' | 'web_app_biometry_open_settings' | 'web_app_request_emoji_status_access' web_app_start_accelerometer: {
| 'web_app_check_location' | 'web_app_request_location' | 'web_app_open_location_settings' refresh_rate?: number;
| 'web_app_request_fullscreen' | 'web_app_exit_fullscreen' };
| 'web_app_request_safe_area' | 'web_app_request_content_safe_area', web_app_start_gyroscope: {
null>; refresh_rate?: number;
};
web_app_start_device_orientation: {
refresh_rate?: number;
need_absolute?: boolean;
};
export type WebAppOutboundEvent = // No payload
WebAppEvent<'viewport_changed', { web_app_request_viewport: null;
web_app_request_theme: null;
web_app_ready: null;
web_app_expand: null;
web_app_request_phone: null;
web_app_close: null;
web_app_close_scan_qr_popup: null;
web_app_request_write_access: null;
iframe_will_reload: null;
web_app_biometry_get_info: null;
web_app_biometry_open_settings: null;
web_app_request_emoji_status_access: null;
web_app_check_location: null;
web_app_request_location: null;
web_app_open_location_settings: null;
web_app_request_fullscreen: null;
web_app_exit_fullscreen: null;
web_app_request_safe_area: null;
web_app_request_content_safe_area: null;
web_app_stop_accelerometer: null;
web_app_stop_gyroscope: null;
web_app_stop_device_orientation: null;
web_app_add_to_home_screen: null;
web_app_check_home_screen: null;
}
interface WebAppOutboundEventMap {
viewport_changed: {
height: number; height: number;
width?: number; width?: number;
is_expanded?: boolean; is_expanded?: boolean;
is_state_stable?: boolean; is_state_stable?: boolean;
}> | };
WebAppEvent<'content_safe_area_changed', SafeArea> | content_safe_area_changed: SafeArea;
WebAppEvent<'safe_area_changed', SafeArea> | safe_area_changed: SafeArea;
WebAppEvent<'theme_changed', { theme_changed: {
theme_params: { theme_params: {
bg_color: string; bg_color: string;
text_color: string; text_color: string;
@ -168,76 +178,69 @@ export type WebAppOutboundEvent =
button_text_color: string; button_text_color: string;
secondary_bg_color: string; secondary_bg_color: string;
}; };
}> | };
WebAppEvent<'set_custom_style', string> | set_custom_style: string;
WebAppEvent<'invoice_closed', { invoice_closed: {
slug: string; slug: string;
status: 'paid' | 'cancelled' | 'pending' | 'failed'; status: 'paid' | 'cancelled' | 'pending' | 'failed';
}> | };
WebAppEvent<'phone_requested', { phone_requested: {
phone_number: string; status: 'sent' | 'cancelled';
}> | };
WebAppEvent<'popup_closed', { popup_closed: {
button_id?: string; button_id?: string;
}> | };
WebAppEvent<'fullscreen_changed', { fullscreen_changed: {
is_fullscreen: boolean; is_fullscreen: boolean;
}> | };
WebAppEvent<'visibility_changed', { visibility_changed: {
is_visible: boolean; is_visible: boolean;
}> | };
WebAppEvent<'fullscreen_failed', { fullscreen_failed: {
error: 'UNSUPPORTED' | string; error: 'UNSUPPORTED' | string;
}> | };
WebAppEvent<'qr_text_received', { qr_text_received: {
data: string; data: string;
}> | };
WebAppEvent<'clipboard_text_received', { clipboard_text_received: {
req_id: string; req_id: string;
data: string | null; data: string | null;
}> | };
WebAppEvent<'write_access_requested', { write_access_requested: {
status: 'allowed' | 'cancelled'; status: 'allowed' | 'cancelled';
}> | };
WebAppEvent<'phone_requested', { custom_method_invoked: {
status: 'sent' | 'cancelled';
}> |
WebAppEvent<'custom_method_invoked', {
req_id: string; req_id: string;
} & ({ } & (
result: object; { result: object } |
} | { { error: string }
error: string; );
})> | biometry_info_received:
WebAppEvent<'biometry_info_received', { | { available: false }
available: false; | {
} | {
available: true; available: true;
type: 'finger' | 'face' | 'unknown'; type: 'finger' | 'face' | 'unknown';
access_requested: boolean; access_requested: boolean;
access_granted: boolean; access_granted: boolean;
token_saved: boolean; token_saved: boolean;
device_id: string; device_id: string;
}> | };
WebAppEvent<'biometry_auth_requested', { biometry_auth_requested:
status: 'authorized'; | { status: 'authorized'; token: string }
token: string; | { status: 'failed' };
} | { biometry_token_updated: {
status: 'failed';
}> |
WebAppEvent<'biometry_token_updated', {
status: 'updated' | 'removed' | 'failed'; status: 'updated' | 'removed' | 'failed';
}> | };
WebAppEvent<'location_checked', { location_checked:
available: false; | { available: false }
} | { | {
available: boolean; available: boolean;
access_requested: boolean; access_requested: boolean;
access_granted?: boolean; access_granted?: boolean;
}> | };
WebAppEvent<'location_requested', { location_requested:
available: boolean; | { available: boolean }
} | { | {
available: boolean; available: boolean;
latitude: number; latitude: number;
longitude: number; longitude: number;
@ -248,24 +251,85 @@ export type WebAppOutboundEvent =
vertical_accuracy: number | null; vertical_accuracy: number | null;
course_accuracy: number | null; course_accuracy: number | null;
speed_accuracy: number | null; speed_accuracy: number | null;
}> | };
WebAppEvent<'emoji_status_access_requested', { emoji_status_access_requested: {
status: 'allowed' | 'cancelled'; status: 'allowed' | 'cancelled';
}> | };
WebAppEvent<'access_requested', { access_requested: {
available: true; available: true;
}> | };
WebAppEvent<'emoji_status_failed', { emoji_status_failed: {
error: 'UNSUPPORTED' | 'USER_DECLINED' | 'SUGGESTED_EMOJI_INVALID' error:
| 'DURATION_INVALID' | 'SERVER_ERROR' | 'UNKNOWN_ERROR'; | 'UNSUPPORTED'
}> | | 'USER_DECLINED'
WebAppEvent<'file_download_requested', { | 'SUGGESTED_EMOJI_INVALID'
| 'DURATION_INVALID'
| 'SERVER_ERROR'
| 'UNKNOWN_ERROR';
};
file_download_requested: {
status: 'cancelled' | 'downloading'; status: 'cancelled' | 'downloading';
}> | };
WebAppEvent<'prepared_message_failed', { prepared_message_failed: {
error: 'UNSUPPORTED' | 'MESSAGE_EXPIRED' | 'MESSAGE_SEND_FAILED' error:
| 'USER_DECLINED' | 'UNKNOWN_ERROR'; | 'UNSUPPORTED'
}> | | 'MESSAGE_EXPIRED'
WebAppEvent<'main_button_pressed' | | 'MESSAGE_SEND_FAILED'
'secondary_button_pressed' | 'back_button_pressed' | 'settings_button_pressed' | 'scan_qr_popup_closed' | 'USER_DECLINED'
| 'reload_iframe' | 'prepared_message_sent' | 'emoji_status_set', null>; | 'UNKNOWN_ERROR';
};
device_storage_failed: {
req_id: string;
error:
| 'UNSUPPORTED'
| 'KEY_INVALID'
| 'VALUE_INVALID'
| 'QUOTA_EXCEEDED'
| 'UNKNOWN_ERROR';
};
secure_storage_failed: {
req_id: string;
error:
| 'UNSUPPORTED'
| 'KEY_INVALID'
| 'VALUE_INVALID'
| 'QUOTA_EXCEEDED'
| 'STORAGE_NOT_EMPTY'
| 'RESTORE_UNAVAILABLE'
| 'RESTORE_CANCELLED'
| 'UNKNOWN_ERROR';
};
accelerometer_failed: {
error: 'UNSUPPORTED';
};
gyroscope_failed: {
error: 'UNSUPPORTED';
};
device_orientation_failed: {
error: 'UNSUPPORTED';
};
home_screen_failed: {
error: 'UNSUPPORTED';
};
home_screen_checked: {
status: 'unsupported' | 'unknown' | 'added' | 'missed';
};
main_button_pressed: null;
secondary_button_pressed: null;
back_button_pressed: null;
settings_button_pressed: null;
scan_qr_popup_closed: null;
reload_iframe: null;
prepared_message_sent: null;
emoji_status_set: null;
}
export type WebAppInboundEvent =
{ [K in keyof WebAppInboundEventMap]:
WebAppEvent<K, WebAppInboundEventMap[K]>
}[keyof WebAppInboundEventMap];
export type WebAppOutboundEvent =
{ [K in keyof WebAppOutboundEventMap]:
WebAppEvent<K, WebAppOutboundEventMap[K]>
}[keyof WebAppOutboundEventMap];