Мост
Мост — единственный выход приложения из песочницы. Объект window.pairx появляется до первого скрипта страницы; его нельзя подменить.
| Свойство | Что это |
|---|---|
pairx.version | Версия моста, сейчас "1.0". |
pairx.call(method, params?) | Вызов метода; Promise с результатом или ошибкой. Вызов вместе с параметрами — до 64 КиБ JSON. |
pairx.on(event, callback) | Подписка на событие; возвращает функцию, которая отписывает. |
pairx.launch | Параметры запуска — неизменяемый объект, см. ниже. |
try {
const { id } = await pairx.call("user.get");
} catch (error) {
console.log(error.code, error.message); // "unsupported", "offline", …
}
const off = pairx.on("storage.changed", ({ changes }) => { /* … */ });
off();Имя метода — сегменты через точку, каждый начинается со строчной латинской буквы: ui.mainButton, storage.write. Неизвестный метод отклоняется с кодом unsupported; проверить заранее — app.supports.
Методы#
| Метод | Что делает |
|---|---|
app.ready | Интерфейс готов: Pairx убирает заставку. |
app.close | Закрыть приложение. |
app.supports | Есть ли метод в этой версии Pairx — для возможностей, которые появляются позже. |
user.get | Кто открыл приложение. id — человек внутри этого приложения: в другом приложении у него другой ID; по нему нельзя узнать аккаунт Pairx. |
context.get | Где открыто приложение: общий экземпляр в чате, личный контекст или предпросмотр автора перед отправкой. |
ui.theme | Тема Pairx: светлая или тёмная и её цвета. |
ui.safeArea | Отступы от краёв, которые не закрывает Pairx (шапку и нативную кнопку Pairx рисует сам, их отступы уже учтены). |
ui.mainButton | Нативная кнопка Pairx внизу экрана. |
ui.backButton | «Назад» в шапке Pairx вместо «Закрыть» — для своих экранов приложения; нажатие приходит событием ui.backButton.clicked. |
ui.popup | Нативное окно; в заголовке Pairx пишет название приложения и «код пользователя», чтобы окно нельзя было выдать за окно Pairx. |
ui.toast | Короткая подсказка внизу экрана. |
storage.snapshot | Всё состояние общих данных на одном seq — см. «Общие данные». |
storage.write | Одна запись в общее хранилище; операции — в справочнике хранилища. |
storage.private.set | Личные данные человека. |
clipboard.writeText | Скопировать текст, до 10 000 символов; только по нажатию человека. |
diagnostics.error | Сообщить об ошибке приложения. |
app.ready#
Интерфейс готов: Pairx убирает заставку. Вызывайте сразу, как нарисован первый экран.
Результат: true
app.close#
Закрыть приложение.
Результат: true
app.supports#
Есть ли метод в этой версии Pairx — для возможностей, которые появляются позже.
| Параметр | Тип | Что |
|---|---|---|
name | string | Имя метода. |
Результат: boolean
if (await pairx.call('app.supports', { name: 'share.toChat' })) { /* … */ }user.get#
Кто открыл приложение. id — человек внутри этого приложения: в другом приложении у него другой ID; по нему нельзя узнать аккаунт Pairx.
Результат: { id: string, locale: string }
const { id } = await pairx.call('user.get');context.get#
Где открыто приложение: общий экземпляр в чате, личный контекст или предпросмотр автора перед отправкой.
Результат: { kind: "chat" | "personal" | "preview", preview: boolean }
ui.theme#
Тема Pairx: светлая или тёмная и её цвета. CSS prefers-color-scheme в приложении следует той же теме.
Результат: { scheme: "light" | "dark", colors: { accent, background, surface, text, muted } }
ui.safeArea#
Отступы от краёв, которые не закрывает Pairx (шапку и нативную кнопку Pairx рисует сам, их отступы уже учтены).
Результат: { top, bottom, left, right }
ui.mainButton#
Нативная кнопка Pairx внизу экрана. Нажатие приходит событием ui.mainButton.clicked.
| Параметр | Тип | Что |
|---|---|---|
text | string | Надпись, до 40 символов; пустая прячет кнопку. |
visible | boolean? | Показать (по умолчанию true) или спрятать. |
enabled | boolean? | Доступна ли (по умолчанию true). |
progress | boolean? | Индикатор вместо надписи, пока идёт запись. |
Результат: true
await pairx.call('ui.mainButton', { text: 'Отправить', visible: true });
pairx.on('ui.mainButton.clicked', send);ui.backButton#
«Назад» в шапке Pairx вместо «Закрыть» — для своих экранов приложения; нажатие приходит событием ui.backButton.clicked.
| Параметр | Тип | Что |
|---|---|---|
visible | boolean | Показать «Назад» (true) или вернуть «Закрыть». |
Результат: true
ui.popup#
Нативное окно; в заголовке Pairx пишет название приложения и «код пользователя», чтобы окно нельзя было выдать за окно Pairx. До трёх кнопок; ответ — id нажатой.
| Параметр | Тип | Что |
|---|---|---|
message | string | Текст, до 500 символов. |
buttons | { id, text, type? }[]? | Кнопки, надпись до 40 символов; type — cancel или destructive. Без кнопок — одна «OK». |
Результат: string
const choice = await pairx.call('ui.popup', {
message: 'Удалить запись?',
buttons: [{ id: 'no', text: 'Отмена', type: 'cancel' }, { id: 'yes', text: 'Удалить', type: 'destructive' }],
});ui.toast#
Короткая подсказка внизу экрана.
| Параметр | Тип | Что |
|---|---|---|
text | string | До 200 символов. |
Результат: true
storage.snapshot#
Всё состояние общих данных на одном seq — см. «Общие данные».
Результат: { seq: number, private: object, stores: { [name]: Store } }
storage.write#
Одна запись в общее хранилище; операции — в справочнике хранилища. Изменение приходит всем участникам, и автору тоже, событием storage.changed на своём месте в порядке; обычно автору — до ответа на вызов, но полагаться на это нельзя.
| Параметр | Тип | Что |
|---|---|---|
op | string | Операция: log.append, log.retract, slot.set, slot.clear, doc.set, counter.add. |
store | string | Имя хранилища из манифеста. |
… | Поля операции. |
Результат: { seq: number, … }
await pairx.call('storage.write', { op: 'log.append', store: 'queue', value: 'join' });storage.private.set#
Личные данные человека. Обычно не вызывается напрямую: это делает localStorage.
| Параметр | Тип | Что |
|---|---|---|
items | { [key]: string } | Все пары ключ — строка, до 256 КиБ вместе. |
Результат: { ok: true }
clipboard.writeText#
Скопировать текст, до 10 000 символов; только по нажатию человека.
| Параметр | Тип | Что |
|---|---|---|
text | string | Текст. |
Результат: true
diagnostics.error#
Сообщить об ошибке приложения. Сейчас Pairx принимает вызов и никуда его не отправляет; отчёты для автора придут позже, без данных хранилища.
| Параметр | Тип | Что |
|---|---|---|
message | string | Что случилось. |
Результат: true
События#
| Событие | Данные | Когда |
|---|---|---|
storage.changed | { changes: Change[] } | Изменения общих данных от всех участников, по порядку seq — см. «Формы изменений». |
storage.reset | null | Перечитайте снимок: кто-то удалил свои данные или изменений слишком много. |
theme.changed | Theme | Тема Pairx сменилась при открытом приложении (сейчас на iPhone; на Android тема задаётся при открытии). |
ui.mainButton.clicked | null | Нажата нативная кнопка Pairx. |
ui.backButton.clicked | null | Нажата «Назад» в шапке или системный жест «назад». |
Ошибки#
Ошибка вызова — Error с полем code:
| Код | Когда |
|---|---|
unsupported | Метода нет, его параметры не те или Pairx в этой версии его не знает. |
forbidden | Нельзя: не хватает прав (например, писать в хранилище автора) или чужая запись. |
consent_required | Человек ещё не дал приложению разрешение. |
rate_limited | Слишком часто: больше 10 записей в секунду или 300 в минуту от человека. |
too_large | Слишком большое значение, запись, вызов (больше 64 КиБ) или превышен объём хранилища. |
conflict | Документ уже изменён: версия устарела — перечитайте снимок и повторите. |
offline | Нет соединения с Pairx; запись можно повторить с тем же write_id. |
not_found | Нет такой записи, хранилища или контекста (например, сообщение с приложением удалили). |
internal | Ошибка на стороне Pairx. |
Параметры запуска#
pairx.launch есть сразу, без вызова:
| Поле | Тип | Что |
|---|---|---|
app | string | ID приложения, 22 символа. |
context | "chat" | "personal" | "preview" | Где открыто: общий экземпляр в чате, личный контекст (по ссылке, из профиля) или предпросмотр автора. |
version | number | Номер версии приложения. |
token | string? | Подписанный токен запуска (Ed25519, aud — ID приложения); пригодится серверам мини-приложений. |
user | string? | ID человека внутри этого приложения. |
Токен запуска#
pairx.launch.token — JWT, который Pairx подписывает при каждом открытии ключом Ed25519. Он нужен, когда у приложения появится свой сервер: сервер проверяет подпись по открытым ключам Pairx и узнаёт, кто и где открыл приложение, без общих секретов. Само приложение токену доверять не должно — внутри песочницы его можно только передать.
Алгоритм EdDSA, издатель pairx-apps, срок — 60 минут. Открытые ключи — https://api.pairx.org/.well-known/pairx-apps-keys.json (JWKS; ключ выбирается по kid из заголовка токена).
| Поле | Что |
|---|---|
iss | Всегда pairx-apps. |
aud | ID приложения: токен одного приложения бесполезен для другого. |
sub | ID человека внутри приложения — тот же, что в user.get. |
iat, exp | Время выдачи и окончания, секунды Unix; токен живёт час. |
jti | Уникальный ID токена. |
ver | Номер запущенной версии. |
ctx | Контекст: kind (chat, personal, preview), id, can_write, author; в чате ещё chat (dm, group, self) и role (owner, admin, member). |
start | Параметр из ссылки pairx.org/app/<id>?start=…, если он был. |
name | Имя человека — только с разрешением profile.basic. |
Будет позже#
Методы, которые появятся в следующих версиях моста. Проверяйте их через app.supports, а не по версии Pairx:
ui.secondaryButton— Вторая нативная кнопка.share.toChat— Отправить приложение с параметром в другой чат.links.openApp— Открыть другое приложение Pairx.context.members— Участники чата (с разрешениемchat.members).user.get → name— Имя человека (с разрешениемprofile.basic).