SDK
@pairx/apps-sdk — тонкая типизированная обёртка над мостом для проектов со сборкой. Без зависимостей, ESM, TypeScript. Всё, что делает SDK, можно сделать и прямыми вызовами pairx.call — SDK избавляет от рутины: порядка seq, storage.reset, повторов при conflict.
npm install https://dev.pairx.org/download/pairx-apps-sdk-0.1.0.tgzПриложение со сборкой отправляется в Pairx одним HTML-файлом: соберите проект в один файл (для Vite — vite-plugin-singlefile).
Пример: очередь#
import { app, openStorage, ui } from "@pairx/apps-sdk";
const storage = await openStorage();
const queue = storage.log<string>("queue");
function render() {
const people = queue.entries();
list.textContent = people.map((e, i) => `${i + 1}. ${e.user === storage.me ? "Вы" : "Участник"}`).join("\n");
ui.mainButton.setText(queue.mine().length ? "Выйти из очереди" : "Встать в очередь");
}
ui.mainButton.show("Встать в очередь", async () => {
const mine = queue.mine()[0];
ui.mainButton.setProgress(true);
try { mine ? await queue.retract(mine.entry) : await queue.append("join"); }
finally { ui.mainButton.setProgress(false); }
});
storage.subscribe(render);
render();
await app.ready();Приложение и человек#
| API | Что делает |
|---|---|
app.ready() | Убрать заставку Pairx. |
app.close() | Закрыть приложение. |
app.launch() | Параметры запуска: приложение, контекст, версия, токен. |
user() | { id, locale } — человек внутри этого приложения. |
context() | { kind, preview } — где открыто приложение. |
inPairx() | Запущено ли внутри Pairx (или эмулятора) — для тестов и сборки. |
call(method, params), on(event, cb) | Прямой доступ к мосту с типами. |
Хранилище#
openStorage() читает снимок и подписывается на ленту изменений; дальше состояние всегда текущее.
| API | Что делает |
|---|---|
storage.me | ID текущего человека. |
storage.subscribe(cb) | Вызывается после каждого применённого изменения и после storage.reset; возвращает отписку. |
storage.reload() | Перечитать снимок. |
storage.log(name) | entries(), all() (вместе с убранными), mine(), append(value), retract(entry). |
storage.slot(name) | get(user?), values(), set(value), clear(). |
storage.doc(name) | value, version, set(value, version?), update(fn) — сам повторяет при conflict. |
storage.counter(name) | total(key), mine(key), totals(), add(key, amount). |
const board = storage.doc<{ items: string[] }>("board");
await board.update((current) => ({ items: [...(current?.items ?? []), "Новый пункт"] }));Интерфейс#
| API | Что делает |
|---|---|
ui.mainButton.show(text, onClick) | Показать нативную кнопку; возвращает функцию, которая снимает этот обработчик. |
ui.mainButton.setText, setEnabled, setProgress, hide, onClick | Управление кнопкой. |
ui.backButton.show(onClick), hide(), onClick | «Назад» в шапке Pairx. |
ui.theme(), ui.onTheme(cb) | Тема Pairx и её смена. |
ui.applyTheme(theme) | Ставит CSS-переменные --pairx-accent, --pairx-background, --pairx-surface, --pairx-text, --pairx-muted и color-scheme. |
ui.popup(message, buttons), ui.toast(text) | Окна и подсказки Pairx. |
clipboard.writeText(text) | Копирование по нажатию человека. |
Ошибки#
Методы SDK бросают PairxError с полем code — те же коды моста:
import { PairxError } from "@pairx/apps-sdk";
try { await queue.append("join"); }
catch (error) {
if (error instanceof PairxError && error.code === "rate_limited") ui.toast("Слишком часто");
}Тесты приложения#
inPairx() отвечает false вне Pairx: логику приложения можно тестировать без моста, подставив свой window.pairx. Сами тесты SDK идут против хозяина Pairx в памяти с правилами хранилища сервиса.