JS Core

JS Core #

JS Core — это сердце SDK, содержит всю основную логику. Плагины под игровые движки (Unity, Godot, Construct) являются лишь надстройкой над JS Core. JS Core можно использовать напрямую без каких-либо плагинов в веб-движках (PlayCanvas, PixiJS, Phaser и т.д.).

Подключение #

Скачайте файл instant-games-bridge.js со страницы релизов на гитхаб, добавьте в свой проект и подключите в index.html:

index.html
<html>
    <head>
        <script src="./instant-games-bridge.js"></script>
    </head>
    <body>...</body>
</html>

При запуске игры на поддерживаемых платформах SDK автоматически подключит нужные скрипты платформ. На неподдерживаемой платформе не будет каких-либо ошибок, подставится платформа-заглушка mock и при вызове какого-либо запроса будет возвращаться false, reject и т.д.

Инициализация #

Перед использованием SDK нужно вызвать метод инициализации и дождаться его завершения.

index.html
<html>
    <head>...</head>
    <body>...</body>
    <script>
        // простой вариант инициализации
        bridge.initialize()
            .then(() => {
                // инициализация прошла успешно, можно использовать SDK
            })
            .catch(error => {
                // ошибка, что-то пошло не так
            })

        // второй вариант инициализации с передачей дополнительных настроек
        let options = {
            // если присутствует данный параметр, то автоопределение платформы пропустится
            // и бридж подключит SDK указанной платформы
            forciblySetPlatformId: 'yandex',

            platforms: {
                // если вы выпускаете игру на Game Distribution, то необходимо указать её айди
                'game_distribution': { 
                    gameId: '74473b0d8a42415db75fef0a005b9654'
                },
                // если вы выпускаете игру в VK Play, то необходимо указать её айди
                'vk_play': { 
                    gameId: '33134'
                }
            } 
        }
        bridge.initialize(options)
            .then(() => {
                // инициализация прошла успешно, можно использовать SDK
            })
            .catch(error => {
                // ошибка, что-то пошло не так
            })
    </script>
</html>

Информация о платформе #

ID платформы #

bridge.platform.id

Возвращает ID платформы, на которой запущена игра в данный момент. Возможные значения: playgama, vk, ok, yandex, crazy_games, absolute_games, game_distribution, vk_play, mock.

Нативный SDK #

bridge.platform.sdk

Возвращает нативный SDK платформы.

Платформа Содержание
Playgama Playgama SDK
VK VK Bridge
OK OK SDK
Yandex Yandex Games SDK
Crazy Games Crazy Games SDK
Absolute Games Absolute Games SDK
Game Distribution Game Distribution SDK
VK Play VK Play SDK
Mock null

Язык #

bridge.platform.language

Если платформа предоставляет данные об языке пользователя — то это будет язык, который установлен у пользователя на платформе. Если не предоставляет — это будет язык браузера пользователя.

Формат: ISO 639-1. Пример: ru, en.

Параметр из адресной строки #

bridge.platform.payload

С помощью данного параметра можно в ссылку на игру встраивать какую-либо вспомогательную информацию.

Платформа Формат ссылки
Playgama
VK vk.com/app8056947#your-info
OK
Yandex yandex.com/games/play/183100?payload=your-info
Crazy Games crazygames.com/game/example?payload=your-info
Absolute Games
Game Distribution
VK Play
Mock site.com/game?payload=your-info

Информация о домене #

bridge.platform.tld
Платформа Возможные значения
Playgama null
VK null
OK null
Yandex com, ru, etc.
Crazy Games null
Absolute Games null
Game Distribution null
VK Play null
Mock null

Отправка сообщения платформе #

bridge.platform.sendMessage(message)
Сообщение Описание Где поддерживается
game_ready Игра загрузилась, все загрузочные экраны прошли, игрок может взаимодействовать с игрой. yandex
in_game_loading_started Началась какая-либо загрузка внутри игры. Например, когда идёт загрузка уровня. crazy_games
in_game_loading_stopped Загрузка внутри игры окончена. crazy_games
gameplay_started Начался геймплей. Например, игрок зашёл в уровень с главного меню. crazy_games
gameplay_stopped Геймплей закончился/приостановился. Например, при выходе с уровня в главное меню, открытии меню паузы и т.д. crazy_games
player_got_achievement Игрок достиг особенного момента. Например, победил босса, установил рекорд и т.д. crazy_games

Информация о девайсе #

Тип девайса #

bridge.device.type

Возвращает тип девайса, с которого пользователь запустил игру. Возможные значения: mobile, tablet, desktop, tv.

Информация об игроке #

Поддержка авторизации #

bridge.player.isAuthorizationSupported
Платформа Возможные значения
Playgama false
VK true
OK true
Yandex true
Crazy Games false
Absolute Games true
Game Distribution false
VK Play true
Mock false

Авторизован ли игрок в данный момент #

bridge.player.isAuthorized
Платформа Возможные значения
Playgama false
VK true
OK true
Yandex true / false
Crazy Games false
Absolute Games true / false
Game Distribution false
VK Play true / false
Mock false

ID игрока #

bridge.player.id

Если авторизация поддерживается на платформе и игрок авторизован в данный момент – возвращает его ID на платформе, иначе — null.

Имя игрока #

bridge.player.name
Платформа Возможные значения
Playgama null
VK Имя игрока
OK Имя игрока
Yandex Если игрок авторизован и дал игре доступ к личной информации — имя игрока, иначе — null
Crazy Games null
Absolute Games Если игрок авторизован — имя игрока, иначе — null
Game Distribution null
VK Play Если игрок авторизован — имя игрока, иначе — null
Mock null

Аватар игрока #

bridge.player.photos

Массив аватаров игрока, упорядоченный по возрастанию разрешения.

Платформа Возможные значения
Playgama Пустой массив
VK Массив ссылок на изображения
OK Массив ссылок на изображения
Yandex Если игрок авторизован и дал игре доступ к личной информации — массив ссылок на изображения, иначе — пустой массив
Crazy Games Пустой массив
Absolute Games Если игрок авторизован — массив ссылок на изображения, иначе — пустой массив
Game Distribution Пустой массив
VK Play Если игрок авторизован — массив ссылок на изображения, иначе — пустой массив
Mock Пустой массив

Авторизация игрока #

// необязательный параметр
let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            scopes: true  // запросить у игрока доступ к имени и фото
        }
        break
}

bridge.player.authorize(options)
    .then(() => {
        // игрок успешно авторизован
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })
Платформа Возможные значения
Playgama rejected
VK resolved
OK resolved
Yandex Если игрок уже авторизован — resolved. Если не авторизован — показывается диалоговое окно авторизации. Далее resolved / rejected зависит от того авторизуется игрок или нет.
Crazy Games rejected
Absolute Games Если игрок уже авторизован или открылось окно авторизации — resolved. После авторизации происходит перезагрузка страницы. rejected в случае ошибки.
Game Distribution rejected
VK Play Если игрок авторизован — resolved. Если игрок авторизуется — resolved (после этого произойдёт перезагрузка страницы). rejected в случае ошибки.
Mock rejected

Информация об игре #

Текущее состояние видимости #

bridge.game.visibilityState

// Отслеживать изменение состояния можно подписавшись на событие
bridge.game.on(bridge.EVENT_NAME.VISIBILITY_STATE_CHANGED, state => { console.log('Visibility state:', state) })

Возвращает текущее состояние видимости игры (вкладки с игрой). Возможные значения: visible, hidden.

📝 Примечание
Нужно реагировать на изменение состояния видимости. Например, выключать звук в игре при hidden и включать при visible.

Пользовательские данные #

Есть два типа хранилища: локальное local_storage и внутреннее platform_internal. При записи в локальное — данные сохраняются у игрока на конкретном девайсе, при записи во внутреннее — данные сохраняются на серверах платформы.

Текущий тип хранилища #

bridge.storage.defaultType
Платформа Возможные значения
Playgama local_storage
VK platform_internal
OK Если игрок дал доступ — platform_internal, если нет — local_storage
Yandex Если игрок авторизован — platform_internal, если нет — local_storage
Crazy Games local_storage
Absolute Games Если игрок авторизован — platform_internal, если нет — local_storage
Game Distribution local_storage
VK Play local_storage
Mock local_storage

Проверка на поддержку #

bridge.storage.isSupported(storageType)
Платформа local_storage platform_internal
Playgama true false
VK true true
OK true true
Yandex true true
Crazy Games true false
Absolute Games true true
Game Distribution true false
VK Play true false
Mock true false

Проверка на доступность #

bridge.storage.isAvailable(storageType)
Платформа local_storage platform_internal
Playgama true false
VK true true
OK true Если игрок дал доступ — true, если нет — false
Yandex true Если игрок авторизован — true, если нет — false
Crazy Games true false
Absolute Games true Если игрок авторизован — true, если нет — false
Game Distribution true false
VK Play true false
Mock true false

Загрузка данных #

// загрузить данные по ключу
bridge.storage.get('key')
    .then(data => {
        // данные загружены и вы можете работать с ними
        // data = null если для такого ключа нет данных
        console.log('Data: ', data)
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

// загрузить данные по нескольким ключам
bridge.storage.get(['key_1', 'key2'])
    .then(data => {
        // данные загружены и вы можете работать с ними
        // data[n] = null если для такого ключа нет данных
        console.log('Data: ', data)
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Сохранение данных #

// сохранить данные по ключу
bridge.storage.set('key', 'value')
    .then(() => {
        // данные успешно сохранены
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

// сохранить данные по нескольким ключам
bridge.storage.set(['key_1', 'key2'], ['value_1', 'value_2'])
    .then(() => {
        // данные успешно сохранены
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Удаление данных #

// удалить данные по ключу
bridge.storage.delete('key')
    .then(() => {
        // данные успешно удалены
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })
    
// удалить данные по нескольким ключам
bridge.storage.delete(['key_1', 'key2'])
    .then(() => {
        // данные успешно удалены
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Все операции с данными взаимодействуют с текущим хранилища платформы. Вы можете передать вторым аргументом конкретный тип хранилища, который нужно использовать. Перед этим убедитесь что хранилище доступно.

let storageType = bridge.STORAGE_TYPE.LOCAL_STORAGE
bridge.storage.get('key', storageType)
bridge.storage.set('key', 'value', storageType)
bridge.storage.delete('key', storageType)
bridge.advertisement.isBannerSupported
Платформа Возможные значения
Playgama false
VK true
OK true
Yandex true
Crazy Games true
Absolute Games false
Game Distribution true
VK Play false
Mock false
📝 Примечание
Чтобы баннеры работали в Yandex — необходимо их включить в настройках игры.
📝 Примечание
Чтобы баннеры работали в Crazy Games — необходимо в index.html добавить контейнер <div> нужных размеров и передать его идентификатор в showBanner(). Подробнее про размеры: https://docs.crazygames.com/sdk/html5/#responsive-banners.
📝 Примечание
Чтобы баннеры работали в Game Distribution — необходимо в index.html добавить контейнер <div> нужных размеров и передать его идентификатор в showBanner(). Подробнее про размеры: https://github.com/GameDistribution/GD-HTML5/wiki/Display-Ads.
let options = { }

switch (bridge.platform.id) {
    case 'vk': 
        options = {
            position: 'top', // необязательный параметр, по умолчанию = bottom
            layoutType: 'resize', // необязательный параметр
            canClose = false // необязательный параметр
        }
        break
    case 'crazy_games': 
        options = {
            containerId: 'div-container-id'
        }
        break
    case 'game_distribution':
        options = {
            containerId: 'div-container-id'
        }
        break
}

bridge.advertisement.showBanner(options)
bridge.advertisement.hideBanner()
bridge.advertisement.bannerState

// отслеживать изменение состояния можно подписавшись на событие
bridge.advertisement.on(bridge.EVENT_NAME.BANNER_STATE_CHANGED, state => console.log('Banner state: ', state))

Текущее состояние баннера. Возможные значения: loading, shown, hidden, failed.

Межстраничная реклама. Обычно показывается в момент загрузки уровня/поражения и т.д.

// значение по умолчанию = 60 секунд
bridge.advertisement.minimumDelayBetweenInterstitial

Между показами Interstitial-рекламы нужно соблюдать временные интервалы. Например, Yandex просто не покажет рекламу если вызывать слишком часто, а VK будет показывать так часто, как вызывается метод.

Для удобства, в данном SDK есть встроенный механизм таймера между показами. Вам нужно лишь указать нужный интервал и можно дёргать метод показа рекламы сколько угодно. По умолчанию интервал = 60 секунд.

let seconds = 120
bridge.advertisement.setMinimumDelayBetweenInterstitial(seconds)
bridge.advertisement.interstitialState

// отслеживать изменение состояния можно подписавшись на событие
bridge.advertisement.on(bridge.EVENT_NAME.INTERSTITIAL_STATE_CHANGED, state => console.log('Interstitial state: ', state))

Текущее состояние рекламы. Возможные значения: loading, opened, closed, failed.

📝 Примечание
Нужно реагировать на изменение состояния рекламы. Например, выключать звук в игре при opened и включать при closed и failed.

bridge.advertisement.showInterstitial()

Реклама за вознаграждение.

bridge.advertisement.rewardedState

// отслеживать изменение состояния можно подписавшись на событие
bridge.advertisement.on(bridge.EVENT_NAME.REWARDED_STATE_CHANGED, state => console.log('Rewarded state: ', state))

Текущее состояние рекламы. Возможные значения: loading, opened, closed, rewarded, failed.

📝 Примечание
Нужно реагировать на изменение состояния рекламы. Например, выключать звук в игре при opened и включать при closed и failed.

⚠️ Предупреждение
Награду игроку нужно выдавать только при наступлении состояния rewarded.
bridge.advertisement.showRewarded()

Социальные взаимодействия #

Поделиться #

bridge.social.isShareSupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgama false
VK true
OK false
Yandex false
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'vk':
        options = {
            link: 'https://vk.com/mewton.games'
        }
        break
}

bridge.social.share(options)
    .then(() => {
        // игрок успешно поделился
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Вступить в сообщество #

bridge.social.isJoinCommunitySupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgame false
VK true
OK true
Yandex false
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'vk':
        options = {
            groupId: '199747461'
        }
        break
    case 'ok':
        options = {
            groupId: '62984239710374'
        }
        break
}

bridge.social.joinCommunity(options)
    .then(() => {
        // игрок успешно вступил
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Пригласить друзей #

bridge.social.isInviteFriendsSupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgama false
VK true
OK true
Yandex false
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'ok':
        options = {
            text: 'Hello World!'
        }
        break
}

bridge.social.inviteFriends(options)
    .then(() => {
        // игрок успешно пригласил друзей
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Опубликовать пост #

bridge.social.isCreatePostSupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgama false
VK true
OK true
Yandex false
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'vk':
        options = {
            message: 'Hello world!',
            attachments: 'photo-199747461_457239629'
        }
        break
    case 'ok':
        options = {
            media: [
                {
                    'type': 'text',
                    'text': 'Hello World!'
                },
                {
                    'type': 'link',
                    'url': 'https://apiok.ru'
                },
                {
                    'type': 'poll',
                    'question': 'Do you like our API?',
                    'answers': [
                        { 'text': 'Yes' },
                        { 'text': 'No' }
                    ],
                    'options': 'SingleChoice,AnonymousVoting'
                }
            ]
        }
        break
}

bridge.social.createPost(options)
    .then(() => {
        // игрок успешно опубликовал пост
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Добавить в избранное #

bridge.social.isAddToFavoritesSupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgama false
VK true
OK false
Yandex false
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
bridge.social.addToFavorites()
    .then(() => {
        // игрок успешно добавил игру в избранное
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Добавить на рабочий стол #

bridge.social.isAddToHomeScreenSupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgama false
VK Android: true.
Desktop, iOS: false.
OK false
Yandex true / false
Доступность опции зависит от девайса игрока, внутренних правил браузера и ограничений платформы.
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
bridge.social.addToHomeScreen()
    .then(() => {
        // игрок успешно добавил игру на рабочий стол
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Оценить игру #

bridge.social.isRateSupported

Поддерживается ли функционал на платформе.

Платформа Возможные значения
Playgama false
VK false
OK true
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
bridge.social.rate()
    .then(() => {
        // игрок успешно оценил игру
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })
bridge.social.isExternalLinksAllowed

Разрешены ли внешние ссылки на платформе.

Платформа Возможные значения
Playgama false
VK true
OK false
Yandex false
Crazy Games true
Absolute Games false
Game Distribution false
VK Play false
Mock false

Лидерборды #

Поддержка #

bridge.leaderboard.isSupported
Платформа Возможные значения
Playgama false
VK true*
OK false
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
⚠️ Предупреждение
* В VK с клиента можно только показать нативный popup, для всего остального потребуется свой сервер.

Нативный popup #

bridge.leaderboard.isNativePopupSupported

Поддерживается ли нативный popup.

Платформа Возможные значения
Playgama false
VK Android, iOS, Mobile Web: true
Desktop: false
OK false
Yandex false
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
// показать нативный popup
let options = { }

switch (bridge.platform.id) {
    case 'vk':
        options = {
            userResult: 42,
            global: true // по умолчанию = false
        }
        break
}

bridge.leaderboard.showNativePopup(options)
    .then(() => {
        // popup успешно показан
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Очки игрока #

Запись #

bridge.leaderboard.isSetScoreSupported

Поддерживается ли запись очков игрока.

Платформа Возможные значения
Playgama false
VK false
OK false
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            leaderboardName: 'YOU_LEADERBOARD_NAME',
            score: 42
        }
        break
}

bridge.leaderboard.setScore(options)
    .then(() => {
        // очки успешно записаны
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Чтение #

bridge.leaderboard.isGetScoreSupported

Поддерживается ли чтение очков игрока.

Платформа Возможные значения
Playgama false
VK false
OK false
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            leaderboardName: 'YOU_LEADERBOARD_NAME',
        }
        break
}

bridge.leaderboard.getScore(options)
    .then(score => {
        console.log('Score: ' + score)
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Записи таблицы #

bridge.leaderboard.isGetEntriesSupported

Поддерживается ли чтение полной таблицы.

Платформа Возможные значения
Playgama false
VK false
OK false
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false
let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            leaderboardName: 'YOU_LEADERBOARD_NAME',
            includeUser: true, // по умолчанию = false
            quantityAround: 10, // по умолчанию = 5
            quantityTop: 10 // по умолчанию = 5
        }
        break
}

bridge.leaderboard.getEntries(options)
    .then(entries => {
        // данные успешно получены
        entries.forEach(e => {
            console.log('ID: ' + e.id + ', name: ' + e.name + ', score: ' + e.score + ', rank: ' + e.rank + ', small photo: ' + e.photos[0])
        })
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Внутриигровые покупки #

Существуют два типа покупок — постоянные (например, отключение рекламы) и расходуемые (например, внутриигровые монеты).

Поддержка #

bridge.payments.isSupported
Платформа Возможные значения
Playgama false
VK false
OK false
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false

Покупка #

let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            id: 'PURCHASE_ID' // ID покупки который указан в настройках игры
        }
        break
}

bridge.payments.purchase(options)
    .then(() => {
        // игрок успешно купил
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Расходование #

let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            purchaseToken: 'PURCHASE_TOKEN' // токен купленной покупки
        }
        break
}

bridge.payments.consumePurchase(options)
    .then(() => {
        // покупка успешно израсходована и не будет выведена при вызове getPurchases
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Каталог всех товаров #

bridge.payments.getCatalog()
    .then(catalogItems => {
        // данные успешно получены
        catalogItems.forEach(catalogItem => {
            console.log('ITEM ID: ', catalogItem.id)
            console.log('ITEM TITLE: ', catalogItem.title)
            console.log('ITEM DESCRIPTION: ', catalogItem.description)
            console.log('ITEM ICON: ', catalogItem.imageURI)
            console.log('ITEM PRICE: ', catalogItem.price)
            console.log('ITEM PRICE VALUE: ', catalogItem.priceValue)
            console.log('ITEM PRICE CURRENCY CODE: ', catalogItem.priceCurrencyCode)
        })
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Список купленных товаров #

bridge.payments.getPurchases()
    .then(purchases => {
        // данные успешно получены
        purchases.forEach(purchase => {
            console.log('PURCHASE ID: ', purchase.productID)
            console.log('PURCHASE TOKEN: ', purchase.purchaseToken)
        })
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })

Удаленная конфигурация #

С помощью удаленной конфигурации вы можете управлять настройками вашей игры не выпуская обновлений.

Поддержка #

bridge.remoteConfig.isSupported
Платформа Возможные значения
Playgama false
VK false
OK false
Yandex true
Crazy Games false
Absolute Games false
Game Distribution false
VK Play false
Mock false

Загрузка значений #

let options = { }

switch (bridge.platform.id) {
    case 'yandex':
        options = {
            clientFeatures: [ // необязательный параметр
                { name: 'levels', value: '5' }
            ]
        }
        break
}

bridge.remoteConfig.get(options)
    .then((flags) => {
        // data содержит объект ключ-значение, которые указаны в настройках игры
        // например: { showFullscreenAdOnStart: 'no', difficult: 'hard' }
    })
    .catch(error => {
        // ошибка, что-то пошло не так
    })
← Введение Construct →