@kherel/app-bridge
v0.9.0
Published
SDK for Tribe Mini Apps — postMessage bridge between the iframe SPA and the Tribe host shell.
Readme
@kherel/app-bridge
SDK for Tribe Mini Apps — the postMessage bridge between a mini-app
iframe and the Tribe host shell.
npm install @kherel/app-bridgeREAL tips
requestTip opens the platform's confirmation dialog. Only the user's explicit
Send action transfers money. Amounts are positive integer minor-unit strings
('500' = 5 REAL). Keep the request ID for reconciliation; a timeout is not a
failed payment. The default tip timeout is 16 minutes to allow human review.
const requestId = crypto.randomUUID(); // persist with your order
const receipt = await bridge.requestTip({
requestId, recipientUserId, amount: '500', customParams: { orderId: 'order-123' },
});
// After a lost/uncertain response, use the SAME ID. Do not create another tip.
const recovered = await bridge.getTipStatus({ requestId }); // or { tipId }Inspect receipt.status: pending, processing, succeeded, declined,
failed, or expired. Insufficient funds is terminal; topping up requires a
new request and new consent. A receipt contains no balances or host capability.
Use signed server webhooks or authenticated app-server status for reconciliation.
Raw postMessage equivalent (the host derives app identity and sender):
const callId = crypto.randomUUID();
window.parent.postMessage({
type: 'bridge', method: 'TribeAppRequestTip', callId,
params: { requestId, recipientUserId, amount: '500', customParams: {} },
}, trustedHostOrigin);
window.addEventListener('message', event => {
if (event.source !== window.parent || event.origin !== trustedHostOrigin) return;
if (event.data?.type !== 'bridge' || event.data.callId !== callId) return;
// event.data.result is the receipt; event.data.error is {code, message}.
});
// Recovery: same message shape, fresh callId, method 'TribeAppGetTipStatus',
// params {requestId} (or {tipId}). Keep the original requestId.The host requires a separate app hostname outside its shared session-cookie domain. Its exact-origin frame policy blocks redirects to other origins.
Basic usage
import { bridge } from '@kherel/app-bridge';
// Handshake with Tribe host — resolves once the host is ready to
// receive further messages.
await bridge.send('TribeAppInit');
// Who's using the mini app (no server round-trip — data comes from
// the signed launch params).
const me = await bridge.send('TribeAppGetUserInfo');
console.log(`Hi, ${me.firstName}!`);
// Gate premium features on Tribe-side subscription. `subscriptionExpiresAt`
// is an ISO datetime when the user's Tribe subscription expires, or `null`
// if they have no active subscription.
if (me.subscriptionExpiresAt && new Date(me.subscriptionExpiresAt) > new Date()) {
// user has an active Tribe subscription right now
}
// Grab the raw signed launch params. Mini-app backends use this to
// verify identity (the signature is HMAC-SHA256 over a canonical
// query string keyed on the app's own secret).
const { rawQuery } = await bridge.send('TribeAppGetLaunchParams');
// Call your OWN backend directly — not through Tribe. Pass the
// signed params as a header; your backend verifies the signature
// and extracts `tribe_user_id`.
const res = await fetch('https://my-mini-app.example.com/contacts', {
headers: { 'X-Tribe-Signed-Params': rawQuery },
});
// Track an analytics event — surfaces in the developer's Cabinet
// > Analytics tab. Frontend-only API; mini-app backends must NOT
// write events.
bridge.trackEvent('button_clicked', { id: 'cta-checkout' });Methods
| Method | Description |
|---|---|
| TribeAppInit | Handshake with the Tribe host. Call this first. |
| TribeAppClose | Close the mini app, return to Tribe. |
| TribeAppGetLaunchParams | Raw signed launch-params query string. |
| TribeAppGetUserInfo | Current Tribe user (from signed launch params). |
| TribeAppRequestScopes | Prompt the user for scope consent (VK-style modal). |
| TribeAppOpenProfile | Navigate to a Tribe user profile. |
| TribeAppOpenDirectMessage | Open Tribe's DM drawer with a user / prefilled text. |
| TribeAppOpenLink | Open an external https URL in a new tab. |
| TribeAppShowAlert | Native alert modal rendered by the host. |
| TribeAppShowConfirm | Native confirm modal rendered by the host. |
| TribeAppResize | Adjust iframe height. |
| TribeAppGetBilling | Per-app entitlement snapshot (subscription / lifetime). |
| TribeAppRequestPurchase | Open Tribe-hosted paywall for 'subscription' / 'lifetime'. |
| TribeAppTrackEvent | Write an analytics event for this app. Use bridge.trackEvent(). |
Analytics
bridge.trackEvent(name, properties?) writes a single event to the
mini-app's analytics stream. The host attaches the viewer's identity
and app_id from the signed launch params before forwarding to the
Tribe backend, so the mini-app frontend doesn't need any URL, token,
or auth state of its own.
Frontend-only. Mini-app backends (Edge Functions, your own server) MUST NOT call this endpoint directly — the trust path runs through the host on purpose, and writing from the server bypasses session identity and double-counts. Track from React, not from your handlers.
import { bridge } from '@kherel/app-bridge';
// Common pattern: emit `app_open` once at mount.
useEffect(() => {
bridge.trackEvent('app_open');
}, []);
// Feature-level events with custom properties.
function onCheckout() {
bridge.trackEvent('checkout_started', { tier: 'lifetime', amountEur: 19 });
// …
}Constraints: event name ≤120 chars; serialized properties ≤1KB; batches of up to 20 per request. Per-(user, app) sliding-window cap of 120 events/min. Calls are non-blocking — failure surfaces as a rejected promise but does not throw; analytics SHOULD NOT block UX.
Authentication model
Mini apps bring their own backend. Tribe signs launch params with a
per-app HMAC secret (stored in Tribe's mini_apps.secret_key); the
mini-app backend holds the same secret and verifies the signature on
every request. Tribe's API gateway is not in the data path between
the mini-app frontend and its backend, except for analytics
(TribeAppTrackEvent) and other host-managed methods like billing.
License
UNLICENSED — internal to Tribe until further notice.
