npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hibrit/connect

v0.4.0

Published

SDK oficial para integração de produtos ao ecossistema Hibrit Hub

Downloads

139

Readme

@hibrit/connect

SDK oficial para integração de produtos ao ecossistema Hibrit Hub.

Instalação

npm install @hibrit/connect
# ou
pnpm add @hibrit/connect
# ou
yarn add @hibrit/connect

Configuração

Você precisa das credenciais fornecidas pelo Hibrit Hub:

  • apiKey: Chave de API do seu produto (formato: hbt_...)
  • apiSecret: Secret para assinatura de webhooks (formato: whsec_...)
  • productSlug: Slug do seu produto (ex: taktics, leadfloww)
import { HibritConnect } from '@hibrit/connect';

const hub = new HibritConnect({
  apiKey: process.env.HUB_API_KEY,
  apiSecret: process.env.HUB_WEBHOOK_SECRET,
  productSlug: 'taktics',
  baseUrl: 'https://connect.hibrit.com.br', // opcional (default)
});

Sincronização de Organizações

Sincronize organizações/clientes do seu produto com o Hub:

const result = await hub.syncOrganization({
  externalId: 'org-123',        // ID único no seu sistema
  name: 'Empresa ABC',          // Nome da organização
  slug: 'empresa-abc',          // Slug único (opcional)
  email: '[email protected]', // Email de contato (opcional)
  status: 'active',             // active | inactive | trial | suspended
  metadata: {                   // Dados extras (opcional)
    plano: 'premium',
    origem: 'indicacao',
  },
});

if (result.success) {
  console.log('Organização sincronizada:', result.data);
  // { mappingId: '...', hubOrgId: '...', action: 'created' | 'updated' }
} else {
  console.error('Erro:', result.error);
}

Sincronização em Lote

const results = await hub.syncOrganizations([
  { externalId: 'org-1', name: 'Empresa A', status: 'active' },
  { externalId: 'org-2', name: 'Empresa B', status: 'active' },
]);

console.log(`Sucesso: ${results.success}, Falhas: ${results.failed}`);

Buscar Organizações Mapeadas

Recupere todas as organizações do seu produto que estão mapeadas no Hub:

const result = await hub.getOrganizations({
  limit: 100,           // Máx: 500
  offset: 0,            // Para paginação
  includeHubOrg: true,  // Inclui dados da org no Hub
  status: 'synced',     // Filtrar por status de sync (opcional)
});

if (result.success) {
  console.log('Organizações:', result.data);
  console.log('Total:', result.pagination?.total);
  console.log('Mais páginas?', result.pagination?.hasMore);

  // Cada org contém:
  // - external_id: ID no seu sistema
  // - hub_org_id: ID no Hub
  // - sync_status: 'synced' | 'pending' | 'error' | 'conflict'
  // - hubOrg: { id, name, slug, type, status, email } (se includeHubOrg=true)
}

Sincronização de Contratos

Novo na v0.4.0! Sincronize contratos vinculados a organizações:

const result = await hub.syncContract({
  externalId: 'contrato-123',     // ID único no seu sistema
  organizationId: hubOrgId,       // ID da organização no Hub (hub_org_id)
  name: 'Contrato Premium',       // Nome do contrato
  number: 'CPS-2408',             // Número/código do contrato (opcional)
  status: 'active',               // draft | active | paused | completed | cancelled
  startDate: '2024-01-01',        // Data de início (opcional)
  endDate: '2025-01-01',          // Data de término (opcional)
  value: 50000,                   // Valor do contrato (opcional)
  currency: 'BRL',                // Moeda (opcional, default: BRL)
  billingCycle: 'monthly',        // monthly | quarterly | yearly | one-time (opcional)
  metadata: {                     // Dados extras (opcional)
    sigla: 'AGR',
    tipo: 'consultoria',
  },
});

if (result.success) {
  console.log('Contrato sincronizado:', result.data);
  // { contractId: '...', action: 'created' | 'updated' }
} else {
  console.error('Erro:', result.error);
}

Sincronização em Lote de Contratos

const results = await hub.syncContracts([
  {
    externalId: 'contrato-1',
    organizationId: hubOrgId,
    name: 'Contrato A',
    status: 'active',
  },
  {
    externalId: 'contrato-2',
    organizationId: hubOrgId,
    name: 'Contrato B',
    status: 'active',
  },
]);

console.log(`Sucesso: ${results.success}, Falhas: ${results.failed}`);

Exemplo Completo: Organização + Contratos

// 1. Sincronizar organização primeiro
const orgResult = await hub.syncOrganization({
  externalId: 'org-123',
  name: 'Empresa XYZ',
  status: 'active',
});

if (orgResult.success) {
  const hubOrgId = orgResult.data.hubOrgId;

  // 2. Sincronizar contratos da organização
  await hub.syncContract({
    externalId: 'contrato-abc',
    organizationId: hubOrgId,  // ← usar o hub_org_id retornado
    name: 'Contrato Principal',
    number: 'CPS-2408',
    status: 'active',
    value: 100000,
  });
}

Recebendo Webhooks

Quando eventos acontecem no Hub (ex: organização atualizada), você recebe webhooks:

import { verifyWebhookSignature, isTimestampValid } from '@hibrit/connect';

// Em uma API route (Next.js, Express, etc.)
export async function POST(request: Request) {
  const body = await request.text();
  const signature = request.headers.get('x-hub-signature');
  const timestamp = request.headers.get('x-hub-timestamp');

  // Validar timestamp (previne replay attacks)
  if (!isTimestampValid(timestamp, 300)) {
    return Response.json({ error: 'Timestamp expired' }, { status: 401 });
  }

  // Verificar assinatura
  const isValid = verifyWebhookSignature(
    signature,
    timestamp,
    body,
    process.env.HUB_WEBHOOK_SECRET
  );

  if (!isValid) {
    return Response.json({ error: 'Invalid signature' }, { status: 401 });
  }

  // Processar evento
  const event = JSON.parse(body);
  console.log('Evento recebido:', event.type, event.data);

  return Response.json({ received: true });
}

Variáveis de Ambiente

# .env.local
HUB_API_KEY=hbt_sua_api_key_aqui
HUB_WEBHOOK_SECRET=whsec_seu_secret_aqui
HUB_PRODUCT_SLUG=seu-produto
HUB_BASE_URL=https://connect.hibrit.com.br  # opcional

API Reference

HibritConnect

new HibritConnect(config: HibritConnectConfig)

interface HibritConnectConfig {
  apiKey: string;       // Sua API key
  apiSecret: string;    // Seu webhook secret
  productSlug: string;  // Slug do produto
  baseUrl?: string;     // URL da API (default: https://connect.hibrit.com.br)
  timeout?: number;     // Timeout em ms (default: 30000)
  retries?: number;     // Número de retries (default: 3)
}

Métodos

| Método | Descrição | |--------|-----------| | syncOrganization(payload) | Sincroniza uma organização (push) | | syncOrganizations(payloads) | Sincroniza múltiplas organizações em lote | | getOrganizations(options) | Busca organizações mapeadas no Hub | | removeOrganization(externalId) | Remove mapeamento de organização | | syncContract(payload) | [v0.4.0] Sincroniza um contrato (push) | | syncContracts(payloads) | [v0.4.0] Sincroniza múltiplos contratos em lote | | verifyWebhook(options) | Verifica assinatura de webhook | | getLoginUrl(options) | Retorna URL de login SSO | | getConfig() | Retorna configuração (sem secrets) |

Funções Utilitárias

| Função | Descrição | |--------|-----------| | generateSignature(apiKey, timestamp, body, secret) | Gera assinatura HMAC-SHA256 | | verifyWebhookSignature(signature, timestamp, body, secret) | Verifica assinatura de webhook | | isTimestampValid(timestamp, toleranceSeconds) | Valida timestamp (anti-replay) |

Tipos

Organizações

interface SyncOrganizationPayload {
  externalId: string;
  name: string;
  slug?: string;
  email?: string;
  status?: 'active' | 'inactive' | 'trial' | 'suspended';
  plan?: string;
  metadata?: Record<string, unknown>;
}

interface SyncResult {
  success: boolean;
  data?: {
    mappingId: string;
    hubOrgId: string;
    action: 'created' | 'updated';
  };
  error?: {
    code: string;
    message: string;
  };
}

interface BatchSyncResult {
  total: number;
  success: number;
  failed: number;
  errors: Array<{ externalId: string; error: string }>;
}

interface GetOrganizationsOptions {
  limit?: number;    // default: 100, max: 500
  offset?: number;   // default: 0
  status?: 'synced' | 'pending' | 'error' | 'conflict';
  includeHubOrg?: boolean; // default: true
}

interface GetOrganizationsResult {
  success: boolean;
  data?: OrganizationMapping[];
  pagination?: {
    total: number;
    offset: number;
    limit: number;
    hasMore: boolean;
  };
  error?: { code: string; message: string };
}

interface OrganizationMapping {
  id: string;
  hub_org_id: string;
  external_id: string;
  external_name?: string;
  external_email?: string;
  sync_status: 'synced' | 'pending' | 'error' | 'conflict';
  last_sync_at?: string;
  hubOrg?: {
    id: string;
    name: string;
    slug: string;
    type: 'holding' | 'agency' | 'client' | 'partner' | 'internal';
    status: 'active' | 'inactive' | 'suspended' | 'trial' | 'churned';
    email?: string;
  };
}

Contratos (v0.4.0+)

interface SyncContractPayload {
  externalId: string;
  organizationId: string; // hub_org_id da organização
  name: string;
  number?: string;
  status?: 'draft' | 'active' | 'paused' | 'completed' | 'cancelled';
  startDate?: string;
  endDate?: string;
  renewalDate?: string;
  value?: number;
  currency?: string;
  billingCycle?: 'monthly' | 'quarterly' | 'yearly' | 'one-time';
  metadata?: Record<string, unknown>;
}

interface SyncContractResult {
  success: boolean;
  data?: {
    contractId: string;
    action: 'created' | 'updated';
  };
  error?: {
    code: string;
    message: string;
  };
}

interface BatchSyncContractsResult {
  total: number;
  success: number;
  failed: number;
  errors: Array<{
    externalId: string;
    error: string;
  }>;
}

Segurança

  • Todas as requisições são assinadas com HMAC-SHA256
  • Formato da assinatura: sha256={hmac(timestamp.body, secret)}
  • Timestamps são validados para prevenir replay attacks (tolerância: 5 minutos)
  • Nunca exponha apiSecret no client-side

Suporte

  • Documentação: https://docs.hibrit.com.br
  • Issues: https://github.com/hibritoficial/hibrit-connect/issues

Licença

MIT