bridge-analytics
v1.1.0
Published
Lightweight TypeScript client for Bridge BaaS analytics (POST /analytics/track). Works in React Native (fetch).
Downloads
242
Maintainers
Readme
bridge-analytics
Cliente TypeScript leve para o endpoint de analytics do Bridge BaaS (POST /v1/analytics/track). É um wrapper em volta de fetch: sem dependências em runtime, adequado para Node 18+, browser e React Native.
Além do nome do evento e do userId opcional, podes enviar metadata: um objeto JSON dinâmico por evento (modelo de IA, ecrã, SKU, duração, etc.) — a lib serializa e envia tal como o Bridge espera.
Índice
- Instalação
- Conceitos (Bridge)
- Metadados dinâmicos (
metadata) - Início rápido
- Configuração (
createBridgeAnalytics) - Enviar eventos (
track) - Comportamento assíncrono
- Erros
- React Native
- Instância self-hosted
- Referência de tipos (TypeScript)
- Licença
Instalação
npm install bridge-analyticsyarn add bridge-analyticspnpm add bridge-analyticsConceitos (Bridge)
O Bridge identifica a tua aplicação pelo header x-api-key (a “API key” da app no painel). Cada pedido de analytics fica isolado por app (multitenancy).
No corpo do evento o Bridge aceita:
| Campo | Obrigatório | Descrição |
|------------|-------------|-----------|
| name | Sim | Nome do evento (ex.: app_open, image_generated). |
| userId | Não | Se enviado, tem de ser um User.id válido desta app; IDs inválidos ou de outra app → 400. Sem userId, o evento pode ser anónimo. |
| metadata | Não | Objeto JSON arbitrário (strings, números, booleanos, objetos/arrays aninhados). O Bridge limita tamanho (~8KB) e profundidade no servidor. Útil para modelo, ecrã, créditos gastos, etc. |
Enviar userId em eventos como “abertura da app” ajuda o Bridge a saber a última atividade do utilizador (útil para campanhas com inactiveOnlyDays em push/broadcast, conforme a documentação do teu BaaS).
Esta biblioteca não envia appId no body: o servidor deriva o contexto pela API key. O campo appId na configuração do cliente é opcional e serve só para o teu código (logs, multi-app no cliente).
Metadados dinâmicos (metadata)
A partir da API atual do Bridge, cada evento pode incluir um campo opcional metadata: qualquer objeto JSON que queiras associar ao evento, sem schema fixo na lib. Tu defines as chaves em runtime conforme a app (ex.: model, screen, creditsSpent, predictionId).
O que podes enviar
| Tipo no metadata | Exemplo |
|--------------------|---------|
| string | "model": "google/gemini-3-flash" |
| number | "credits": 5 |
| boolean | "isPremium": true |
| null | "error": null |
| Objetos aninhados | "context": { "screen": "editor", "tab": "export" } |
| Arrays | "tags": ["ai", "image"] |
A lib tipa isto com BridgeAnalyticsMetadata / BridgeAnalyticsMetadataValue em TypeScript. O Bridge persiste o JSON no servidor; no painel /dashboard/analytics vês os eventos com o contexto que enviaste.
Limites (servidor Bridge)
- Tamanho aproximado ~8 KB por pedido de
metadata. - Profundidade de objetos aninhados limitada no servidor.
- Se excederes, o Bridge responde 400 — trata com
BridgeAnalyticsError.
Como enviar na lib
Forma 1 — terceiro argumento (igual ao SDK mínimo do Bridge):
await analytics.track('image_generated', user.id, {
model: 'wan-video/wan-2.7-image-pro',
generatedAt: new Date().toISOString(),
});Forma 2 — objeto completo (recomendado quando só queres metadata, sem userId):
await analytics.track({
name: 'screen_view',
metadata: { screen: 'paywall', source: 'deep_link' },
});Forma 3 — evento identificado + metadados ricos:
await analytics.track({
name: 'ai_run_complete',
userId: user.id,
metadata: {
model: 'google/nano-banana-2',
outputKind: 'IMAGE',
durationMs: 4200,
private: true,
},
});metadata é sempre opcional. Se não passares, o body fica só { "name": "..." } (e userId se existir) — como antes, para pings anónimos ou simples.
Exemplos de uso
| Cenário | name | metadata sugerido |
|---------|--------|---------------------|
| Geração de imagem | image_generated | { model, generatedAt } |
| Paywall | purchase_tap | { screen, sku, tier } |
| Navegação | screen_view | { screen, previousScreen } |
| Erro de fluxo | checkout_failed | { step, errorCode } |
React Native (fire-and-forget com metadata)
analytics
.track('app_open', user.id, { build: '1.2.0', platform: 'ios' })
.catch((err) => console.warn('[analytics]', err));Início rápido
import { createBridgeAnalytics } from 'bridge-analytics';
const analytics = createBridgeAnalytics({
apiKey: 'sua_chave_da_app',
});
// Utilizador identificado (userId Bridge)
await analytics.track('app_open', user.id);
// Só nome do evento (sem userId no body)
await analytics.track({ name: 'screen_settings' });
// Evento com metadados dinâmicos
await analytics.track('image_generated', user.id, {
model: 'wan-video/wan-2.7-image-pro',
generatedAt: new Date().toISOString(),
});
await analytics.track({
name: 'purchase_tap',
metadata: { screen: 'paywall', sku: 'com.app.premium.month' },
});Configuração (createBridgeAnalytics)
import { createBridgeAnalytics } from 'bridge-analytics';
const analytics = createBridgeAnalytics({
apiKey: string; // obrigatório → header x-api-key
appId?: string; // opcional, não vai no POST
baseUrl?: string; // opcional; ver secção self-hosted
fetch?: typeof fetch; // opcional; para testes ou polyfill
});| Opção | Tipo | Descrição |
|-----------|----------|-----------|
| apiKey | string | Chave da app no Bridge. Enviada em cada pedido como x-api-key. |
| appId | string | Opcional. Exposto em analytics.appId para referência no cliente; não é enviado no body de /analytics/track. |
| baseUrl | string | Raiz da API com sufixo /v1. |
| fetch | fetch | Opcional. Por omissão usa globalThis.fetch. |
O cliente devolvido inclui:
appId— o valor que passaste emconfig.appId, ouundefined.track— ver abaixo.
Enviar eventos (track)
Cada chamada envia name (obrigatório), userId (opcional) e metadata (opcional). Ver Metadados dinâmicos para detalhes e exemplos.
Duas formas de chamar:
// 1) Nome + userId + metadata opcionais (mesma ordem do SDK Bridge)
await analytics.track('clicked_buy_button', userId);
await analytics.track('image_generated', userId, { model: 'google/gemini-3-flash' });
// Metadados sem userId (passa undefined no userId)
await analytics.track('screen_view', undefined, { screen: 'home' });
// 2) Objeto (igual ao body JSON do Bridge)
await analytics.track({ name: 'clicked_buy_button', userId });
await analytics.track({
name: 'image_generated',
userId,
metadata: { model: 'wan-video/wan-2.7-image-pro' },
});
await analytics.track({ name: 'anonymous_ping' }); // sem userId nem metadataRegras:
nameé obrigatório e tem de ser uma string não vazia; caso contrário a lib lançaTypeErrorantes do pedido HTTP.userId/metadataomitidos ouundefined→ essas chaves não entram no JSON (variante com argumentos posicionais).metadatasó é enviado quando definido; podes usar objeto aninhado conforme a API Bridge (respeita os limites do servidor).
O pedido HTTP é:
- Método:
POST - URL:
{baseUrl}/analytics/track - Headers:
Content-Type: application/json,x-api-key: <apiKey> - Body:
JSON.stringify({ name, userId?, metadata? })
Comportamento assíncrono
track devolve uma Promise<void>: o trabalho de rede é assíncrono e não bloqueia a UI do React Native enquanto o fetch decorre.
Podes disparar sem await (fire-and-forget); o evento é enviado desde que o fetch arranque. Recomenda-se tratar falhas para evitar unhandled rejection:
analytics.track('app_open', user.id).catch((err) => {
console.warn('[bridge-analytics]', err);
});Erros
BridgeAnalyticsError
Para respostas HTTP não OK (4xx/5xx), a lib lança BridgeAnalyticsError:
| Propriedade | Tipo | Descrição |
|------------|-----------|-----------|
| message | string | Mensagem; preferencialmente o campo error do JSON do Bridge, se existir. |
| status | number | Código HTTP (ex.: 400, 429). |
| body | unknown | Corpo parseado como JSON ou texto bruto. |
import { BridgeAnalyticsError } from 'bridge-analytics';
try {
await analytics.track('x', 'user_invalido');
} catch (e) {
if (e instanceof BridgeAnalyticsError) {
console.error(e.status, e.body);
}
throw e;
}Payload de erro da API (BridgeApiErrorPayload)
O Bridge costuma responder com algo como:
{ "error": "Human readable message", "details": "..." }O tipo exportado BridgeApiErrorPayload reflete error e details opcionais para tipares o body quando fizer sentido.
fetch indisponível
Se não existir fetch global e não passares fetch na config, a lib lança Error com uma mensagem a indicar que deves injectar fetch ou usar um runtime com fetch.
React Native
- Usa apenas
fetcheJSON: compatível com o ambiente JS do Metro/Hermes em versões recentes. - Não uses credenciais hardcoded: preferência por variáveis de ambiente no build (ex.
EXPO_PUBLIC_*,react-native-config, etc.) ou um segredo injetado em CI.
Exemplo com metadados dinâmicos:
import { Platform } from 'react-native';
import { createBridgeAnalytics } from 'bridge-analytics';
export const analytics = createBridgeAnalytics({
apiKey: process.env.EXPO_PUBLIC_BRIDGE_API_KEY!,
appId: process.env.EXPO_PUBLIC_BRIDGE_APP_ID,
});
// Abertura da app + contexto da build
analytics.track('app_open', userId, {
version: '1.2.0',
platform: Platform.OS,
}).catch(console.warn);Instância self-hosted
Se o teu Bridge estiver noutro domínio, define baseUrl com a raiz da API incluindo /v1:
const analytics = createBridgeAnalytics({
apiKey: '...',
baseUrl: 'https://api.teu-dominio.com/v1',
});Barra final em baseUrl é normalizada (removida) antes de concatenar /analytics/track.
Referência de tipos (TypeScript)
Exportações principais:
| Símbolo | Descrição |
|---------|-----------|
| createBridgeAnalytics | Fábrica do cliente (também default export). |
| BRIDGE_ANALYTICS_DEFAULT_BASE_URL | Constante da URL base pública do Bridge (…/v1). |
| BridgeAnalyticsClient | Tipo do objeto { appId, track }. |
| BridgeAnalyticsClientConfig | Opções do createBridgeAnalytics. |
| BridgeAnalyticsTrackBody | Forma do body { name, userId?, metadata? }. |
| BridgeAnalyticsMetadata | Tipo dos metadados dinâmicos (JSON serializável). |
| BridgeAnalyticsMetadataValue | Valores permitidos dentro de metadata. |
| BridgeAnalyticsError | Erro lançado em falhas HTTP. |
| BridgeApiErrorPayload | Forma típica do JSON de erro da API. |
import createBridgeAnalytics, {
BRIDGE_ANALYTICS_DEFAULT_BASE_URL,
type BridgeAnalyticsClient,
BridgeAnalyticsError,
} from 'bridge-analytics';Licença
MIT — ver ficheiro LICENSE.
