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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@horizon-apps/integration-toolkit

v1.3.0

Published

Toolkit genérico para integração de APIs e sistemas - Profiling, Downloaders, Converters e Utilities

Readme

@horizon-modules/integration-toolkit

Toolkit genérico para integração de APIs e sistemas. Ferramentas reutilizáveis para profiling de dados, análise de datasets e utilitários de integração.

📦 Instalação

npm install @horizon-modules/integration-toolkit
# ou
pnpm add @horizon-modules/integration-toolkit

🛠️ Ferramentas Disponíveis

🚀 BatchApiUploader

Serviço para upload em lote de dados JSON para APIs. Processa arquivos JSON de uma pasta e envia para qualquer endpoint configurado.

🔄 BatchFileConverter

Serviço para conversão em lote de arquivos JSON. Lê arquivos de uma pasta, aplica função de conversão e salva os resultados convertidos em outra pasta.

🎯 ObjectTransformer

Serviço genérico para transformação de objetos JSON baseado em regras declarativas. Permite aplicar transformações complexas através de configurações em vez de código.

✨ Características do BatchFileConverter

  • 📁 Processamento em lote: Converte todos os arquivos de uma pasta automaticamente
  • 🔄 Função customizável: Aceita qualquer função de conversão TypeScript
  • 📊 Relatórios detalhados: Estatísticas de conversão e tratamento de erros
  • 🎯 Filtros flexíveis: Filtra arquivos por padrões regex ou string
  • ⚙️ Configurável: Prefixos de saída, verbose mode e mais
  • 🛡️ Type-safe: Suporte completo a TypeScript com tipagem genérica

🚀 Uso Básico do BatchFileConverter

import { BatchFileConverter } from '@horizon-modules/integration-toolkit'
import { convertJetimobPropertyToHorizon } from './converter'

// Converter dados Jetimob para formato Horizon
const converter = new BatchFileConverter({
  inputDir: './data/downloads-do-crm',
  outputDir: './data/properties-converted',
  converter: convertJetimobPropertyToHorizon,
  filePattern: /page-\d+\.json$/,
  outputPrefix: 'converted-',
  verbose: true
})

const result = await converter.convert()

console.log(`✅ ${result.totalConvertedObjects}/${result.totalInputObjects} objetos convertidos`)
console.log(`📊 Taxa de sucesso: ${result.successRate.toFixed(1)}%`)

⚙️ Configuração Avançada do BatchFileConverter

import { BatchFileConverter } from '@horizon-modules/integration-toolkit'

// Converter produtos e-commerce
const converter = new BatchFileConverter({
  inputDir: '/data/raw-products',
  outputDir: '/data/normalized-products', 
  converter: (rawProduct) => ({
    id: rawProduct.codigo,
    name: rawProduct.nome,
    price: parseFloat(rawProduct.preco),
    category: rawProduct.categoria?.nome || 'Sem categoria'
  }),
  filePattern: 'product-', // String pattern
  outputPrefix: 'normalized-',
  verbose: true
})

const result = await converter.convert()

// Resultado detalhado
// {
//   success: true,
//   totalFiles: 5,
//   totalInputObjects: 1000,
//   totalConvertedObjects: 985,
//   totalErrors: 15,
//   successRate: 98.5,
//   errors: ['file1.json - Item 5: Missing required field'],
//   stats: {}
// }

📋 Interface BatchFileConverterConfig

interface BatchFileConverterConfig<TInput = any, TOutput = any> {
  inputDir: string                          // Pasta com arquivos de entrada
  outputDir: string                         // Pasta para arquivos convertidos  
  converter: (input: TInput) => TOutput     // Função de conversão
  filePattern?: RegExp | string             // Filtro de arquivos (padrão: /\.json$/)
  outputPrefix?: string                     // Prefixo de saída (padrão: 'converted-')
  verbose?: boolean                         // Logs detalhados (padrão: false)
}

interface ConvertResult {
  success: boolean                    // Se a operação foi bem-sucedida
  totalFiles: number                 // Arquivos processados
  totalInputObjects: number          // Objetos de entrada encontrados
  totalConvertedObjects: number      // Objetos convertidos com sucesso
  totalErrors: number               // Total de erros
  successRate: number               // Taxa de sucesso em %
  errors: string[]                  // Lista de erros detalhados
  stats: Record<string, number>     // Estatísticas customizadas
}

✨ Características do BatchApiUploader

  • 📁 Leitura automática: Processa todos os .json de uma pasta
  • 🌐 HTTP flexível: Suporte a POST/PUT com headers customizáveis
  • 📊 Relatórios completos: Estatísticas de sincronização (inseridos/atualizados/erros)
  • ⚙️ Configurável: Endpoint, método HTTP, campo de batch, delays
  • 🔧 Genérico: Funciona com qualquer tipo de dados (imóveis, produtos, etc.)
  • ⏱️ Rate limiting: Delay configurável entre requisições

🚀 Uso Básico do BatchApiUploader

import { BatchApiUploader } from '@horizon-modules/integration-toolkit'

// Upload de dados de uma pasta para API
const result = await BatchApiUploader.syncData({
  inputDir: '/data/downloads-do-crm',
  endpoint: 'http://localhost:3000/api/property/sync',
  batchField: 'properties',
  method: 'PUT',
  verbose: true
})

console.log(result)
// {
//   success: true,
//   totalFiles: 5,
//   totalObjects: 250,
//   totalSynced: 248,
//   totalErrors: 2,
//   successRate: 99.2,
//   errors: ['file1.json: HTTP 400: Bad Request']
// }

⚙️ Configuração Avançada do BatchApiUploader

import { BatchApiUploader } from '@horizon-modules/integration-toolkit'

const uploader = new BatchApiUploader({
  inputDir: '/integrations/jetimob/__dev__/data/downloads-do-crm',
  endpoint: 'https://api.example.com/sync',
  method: 'POST',
  headers: {
    'Authorization': 'Bearer token123',
    'Content-Type': 'application/json',
    'X-API-Version': '2.0'
  },
  batchField: 'data',        // Campo que vai conter o array
  delayMs: 500,              // 500ms entre requisições
  verbose: true
})

const result = await uploader.upload()

🎯 Casos de Uso

// Jetimob CRM → Property API
await BatchApiUploader.syncData({
  inputDir: '/integrations/jetimob/__dev__/data/downloads-do-crm',
  endpoint: 'http://localhost:3000/api/property/sync',
  batchField: 'properties',
  method: 'PUT'
})

// E-commerce → Inventory API  
await BatchApiUploader.syncData({
  inputDir: '/data/products',
  endpoint: 'https://inventory.example.com/api/bulk',
  batchField: 'products',
  method: 'POST',
  headers: { 'X-Store-ID': 'store123' }
})

// Logs → Analytics API
await BatchApiUploader.syncData({
  inputDir: '/logs/processed',
  endpoint: 'https://analytics.example.com/events',
  batchField: 'events',
  delayMs: 100
})

📋 Interface BatchApiUploaderConfig

interface BatchApiUploaderConfig {
  inputDir: string                    // Pasta com arquivos JSON
  endpoint: string                    // URL da API de destino
  method?: 'POST' | 'PUT'            // Método HTTP (padrão: PUT)
  headers?: Record<string, string>    // Headers customizados
  batchField?: string                 // Campo do payload (padrão: 'data')
  delayMs?: number                   // Delay entre requisições (padrão: 100ms)
  verbose?: boolean                  // Logs detalhados (padrão: false)
}

interface UploadResult {
  success: boolean         // Se a operação foi bem-sucedida
  totalFiles: number      // Total de arquivos processados  
  totalObjects: number    // Total de objetos encontrados
  totalSynced: number     // Total sincronizado com sucesso
  totalErrors: number     // Total de erros
  successRate: number     // Taxa de sucesso em %
  errors: string[]        // Lista de erros detalhados
}

📊 ProfilerService

Serviço genérico para análise e profiling de dados JSON. Analisa estruturas de dados, extrai exemplos de campos e gera relatórios estatísticos.

✨ Características

  • 📁 Análise de arquivos: Processa arquivos JSON em diretórios
  • 💾 Análise em memória: Trabalha com dados carregados em memória
  • 🔍 Profiling profundo: Analisa objetos aninhados e arrays
  • 📊 Deduplicação: Remove duplicatas baseado em campo chave
  • ⚙️ Configurável: Controle de exemplos por campo
  • 📈 Relatórios JSON: Saída em formato JSON estruturado

🔧 JsonToZodGenerator

Gerador automático de schemas Zod a partir de dados JSON. Analisa estruturas de dados e cria validações TypeScript type-safe.

✨ Características

  • 🔍 Análise automática: Detecta tipos de dados automaticamente
  • 🛡️ Type-safe: Gera schemas Zod com tipagem forte
  • 🎯 Configurável: Opções de geração personalizáveis
  • 📝 Documentação: Adiciona comentários aos schemas gerados
  • 🔄 Reutilizável: Detecta e reutiliza interfaces comuns

🚀 Uso Básico

import { JsonToZodGenerator } from '@horizon-modules/integration-toolkit'

const generator = new JsonToZodGenerator({
  outputPath: './src/schemas/generated.ts',
  interfaceName: 'UserData'
})

const userData = {
  id: 1,
  name: 'João',
  email: '[email protected]',
  profile: {
    age: 30,
    city: 'São Paulo'
  }
}

await generator.generateFromData(userData)

// Gera arquivo com:
// export const UserDataSchema = z.object({
//   id: z.number(),
//   name: z.string(),
//   email: z.string().email(),
//   profile: z.object({
//     age: z.number(),
//     city: z.string()
//   })
// })

🚀 Uso do ProfilerService

import { ProfilerService } from '@horizon-modules/integration-toolkit'

// Análise de arquivos
const profiler = new ProfilerService({
  inputDir: './data/json-files',
  outputDir: './output',
  dataLabel: 'produtos',
  serviceLabel: 'API E-commerce'
})

const result = await profiler.profile()
console.log(result)
// {
//   "id": [1, 2, 3],
//   "name": ["Produto A", "Produto B"],
//   "category.name": ["Eletrônicos", "Casa"]
// }

💾 Análise em Memória

import { ProfilerService } from '@horizon-modules/integration-toolkit'

// Dados diretos em memória
const data = [
  { id: 1, name: 'João', city: 'São Paulo' },
  { id: 2, name: 'Maria', city: 'Rio de Janeiro' }
]

const profiler = new ProfilerService({
  inputData: data,
  dataLabel: 'usuários'
})

const result = await profiler.profile()

// Método estático para uso rápido
const quickResult = await ProfilerService.profileData(data, {
  defaultMaxExamples: 5
})

⚙️ Configuração Avançada

const profiler = new ProfilerService({
  inputDir: './data',
  outputDir: './reports',
  outputFileName: 'custom-profile.json',
  verbose: true,
  dataLabel: 'imóveis',
  serviceLabel: 'CRM Imobiliário',
  uniqueField: 'codigo', // Campo para deduplicação
  defaultMaxExamples: 20,
  fieldConfigs: {
    'endereco.cidade': { maxExamples: 50 },
    'caracteristicas': { maxExamples: 100 }
  }
})

// Análise com deduplicação
const uniqueResult = await profiler.profileUnique()

📋 Interface ProfilerConfig

interface ProfilerConfig {
  inputDir?: string              // Diretório com arquivos JSON
  inputData?: any[]             // Dados em memória (alternativa)
  outputDir?: string            // Onde salvar resultado (opcional)
  outputFileName?: string       // Nome do arquivo de saída
  fieldConfigs?: Record<string, FieldConfig>  // Config por campo
  defaultMaxExamples?: number   // Padrão de exemplos (10)
  verbose?: boolean             // Logs detalhados
  uniqueField?: string          // Campo para deduplicação
  dataLabel?: string            // Label dos dados
  serviceLabel?: string         // Label do serviço
}

interface FieldConfig {
  maxExamples?: number          // Quantos exemplos guardar
}

🎯 Exemplos de Uso

📋 PropertyCustomerRules - Regras de Transformação para Imóveis

Exemplo completo de regras de transformação para padronização de dados imobiliários, localizado em examples/object-transformer/property-customer-rules.ts.

🚀 Uso

import { ObjectTransformer } from '@horizon-integrations/dev-toolkit'
// Copie o arquivo examples/object-transformer/property-customer-rules.ts para seu projeto
import { PropertyCustomerRules } from './path/to/property-customer-rules'

// Usar regras do exemplo para transformação de imóveis
const transformer = new ObjectTransformer({ rules: PropertyCustomerRules })

const propriedade = {
  tipo: 'Casa de Condomínio',
  vagas: 2,
  caracteristicas: ['Sem mobília', 'Churrasqueira'],
  corretor_id: 'elvis-ghisi'
}

const transformada = transformer.transform(propriedade)
// Resultado:
// {
//   tipo: 'Casa/Sobrado',
//   subtipo: 'Casa', 
//   vagas_garagem: 2,
//   caracteristicas: ['Churrasqueira'],
//   mobilia: 'Sem mobília',
//   tags: ['em-condominio'],
//   corretor_slug: 'elvis-ghisi',
//   corretor_nome: 'Elvis Ghisi'
// }

📋 Transformações Incluídas

🏠 Tipos de Imóveis:

  • Residenciais: Apartamento → Apartamento, Casa → Casa/Sobrado, Sobrado → Casa/Sobrado
  • Apartamentos: Duplex, Triplex, Cobertura, Loft, Studio, Flat, Garden
  • Casas Especiais: Quitinete, Bangalô, Edícula, Chalé, Casa de Condomínio
  • Terrenos: Terreno → Terreno/Lote, Lote → Terreno/Lote
  • Comerciais: Sala, Loja, Ponto, Conjunto → Comercial (com subtipos)
  • Rurais: Fazenda, Sítio, Chácara, Granja → Rural (com tag "rural")
  • Industriais: Galpão/Barracão → normalização

🔧 Mapeamentos de Campos:

  • vagasvagas_garagem (renomeação)
  • caracteristicas → processamento de "Sem mobília" → campo mobilia
  • corretor_idcorretor_slug + corretor_nome (exemplo)
  • tags → mapeamento de agentes para corretores

🎯 Casos de Uso

// Pipeline completo de transformação
import { BatchFileConverter, ObjectTransformer } from '@horizon-integrations/dev-toolkit'
// Copie o arquivo de exemplo para seu projeto
import { PropertyCustomerRules } from './config/property-customer-rules'

const converter = new BatchFileConverter({
  inputDir: './data/raw-properties',
  outputDir: './data/normalized-properties',
  converter: (rawProperty) => {
    const transformer = new ObjectTransformer({ rules: PropertyCustomerRules })
    return transformer.transform(rawProperty)
  },
  verbose: true
})

const result = await converter.convert()
console.log(`${result.totalConvertedObjects} imóveis normalizados`)

📊 Exemplos Práticos

🔄 Sincronização Jetimob → Property API

import { DataSyncService } from '@horizon-modules/integration-toolkit'

// Sincronizar downloads do CRM Jetimob
const result = await DataSyncService.syncData({
  inputDir: '/integrations/jetimob/__dev__/data/downloads-do-crm',
  endpoint: 'http://localhost:3000/api/property/sync',
  batchField: 'properties',
  method: 'PUT',
  headers: {
    'X-Source': 'jetimob-crm'
  },
  verbose: true
})

console.log(`✅ ${result.totalSynced}/${result.totalObjects} imóveis sincronizados`)
console.log(`📊 Taxa de sucesso: ${result.successRate}%`)

🏠 Análise de Dados Imobiliários

import { ProfilerService } from '@horizon-modules/integration-toolkit'

const profiler = new ProfilerService({
  inputDir: './data/imoveis',
  outputDir: './profiling',
  outputFileName: 'imoveis-profile.json',
  dataLabel: 'imóveis',
  serviceLabel: 'CRM Jetimob',
  uniqueField: 'codigo',
  fieldConfigs: {
    'endereco_cidade': { maxExamples: 30 },
    'tipo': { maxExamples: 10 },
    'caracteristicas': { maxExamples: 50 }
  }
})

const result = await profiler.profileUnique()
console.log(`Campos analisados: ${Object.keys(result).length}`)

📦 Análise de Produtos E-commerce

import { ProfilerService } from '@horizon-modules/integration-toolkit'

const produtos = [
  {
    id: 1,
    nome: 'Smartphone',
    categoria: { id: 10, nome: 'Eletrônicos' },
    preco: 899.99,
    tags: ['oferta', 'destaque']
  },
  // ... mais produtos
]

const result = await ProfilerService.profileData(produtos, {
  dataLabel: 'produtos',
  serviceLabel: 'API Loja',
  defaultMaxExamples: 15
})

// Resultado:
// {
//   "id": [1, 2, 3],
//   "nome": ["Smartphone", "Laptop", "Tablet"],
//   "categoria.id": [10, 20, 30],
//   "categoria.nome": ["Eletrônicos", "Informática"],
//   "tags": ["oferta", "destaque", "novo"]
// }

📈 Análise de Logs de API

import { ProfilerService } from '@horizon-modules/integration-toolkit'

const profiler = new ProfilerService({
  inputDir: './logs/api-calls',
  outputDir: './analytics',
  dataLabel: 'requisições',
  serviceLabel: 'API Gateway',
  fieldConfigs: {
    'endpoint': { maxExamples: 20 },
    'method': { maxExamples: 10 },
    'status_code': { maxExamples: 15 }
  }
})

const result = await profiler.profile()

🎯 ObjectTransformer - Transformação Baseada em Regras

O ObjectTransformer permite transformar objetos JSON através de regras declarativas, eliminando a necessidade de escrever código de transformação customizado para cada caso.

✨ Características

  • 🎯 Baseado em regras: Configure transformações via JSON, não código
  • 🔄 Transformações complexas: Suporte a condições, arrays, campos aninhados
  • 🛡️ Type-safe: Tipagem TypeScript com generics
  • 📝 Tags na description: Processa tags especiais em campos de texto
  • 🔧 Actions flexíveis: upsertField, removeField, addToArray, removeFromArray

🚀 Uso Básico

import { ObjectTransformer } from '@horizon-modules/integration-toolkit'

// Configurar regras de transformação
const rules = {
  fieldRules: [
    {
      key: 'tipo',
      condition: { eq: 'Casa' },
      rules: [
        { fn: 'upsertField', key: 'categoria', value: 'Residencial' },
        { fn: 'upsertField', key: 'subtipo', value: 'Casa' }
      ]
    },
    {
      key: 'caracteristicas',
      condition: { has_any: ['Piscina'] },
      rules: [
        { fn: 'removeFromArray', key: 'caracteristicas', value: 'Piscina' },
        { fn: 'upsertField', key: 'tem_piscina', value: true }
      ]
    }
  ]
}

// Criar transformer
const transformer = new ObjectTransformer({ rules })

// Transformar objeto
const propriedade = {
  reference: 'PROP001',
  tipo: 'Casa',
  caracteristicas: ['Piscina', 'Churrasqueira']
}

const transformed = transformer.transform(propriedade)
// Resultado:
// {
//   reference: 'PROP001',
//   tipo: 'Casa',
//   categoria: 'Residencial',
//   subtipo: 'Casa', 
//   caracteristicas: ['Churrasqueira'],
//   tem_piscina: true
// }

🔄 Combinando com BatchFileConverter

import { BatchFileConverter, ObjectTransformer } from '@horizon-modules/integration-toolkit'
import transformRules from './config/transform-rules'

// Criar transformer com regras
const transformer = new ObjectTransformer({ rules: transformRules })

// Usar com BatchFileConverter
const batchConverter = new BatchFileConverter({
  inputDir: './data/input',
  outputDir: './data/output',
  converter: (obj) => transformer.transform(obj), // Closure com transformer
  verbose: true
})

const result = await batchConverter.convert()

📋 Condições Suportadas

// Igualdade
condition: { eq: 'Apartamento' }
condition: { not_eq: 'Casa' }

// Arrays
condition: { has: ['churrasqueira'] }          // Tem todos os valores
condition: { has_any: ['piscina', 'sauna'] }   // Tem qualquer um dos valores
condition: { not_has: ['mobiliado'] }          // Não tem o valor

// Numéricos
condition: { gt: 100 }    // Maior que
condition: { gte: 100 }   // Maior ou igual
condition: { lt: 1000 }   // Menor que
condition: { lte: 1000 }  // Menor ou igual

// Texto
condition: { contains: 'apartamento' }
condition: { starts_with: 'Casa' }
condition: { ends_with: 'Comercial' }

// Booleanos
condition: { is_true: true }
condition: { is_false: true }

// Existência
condition: { exists: true }     // Campo existe
condition: { not_exists: true } // Campo não existe

🛠️ Actions Disponíveis

// Criar/atualizar campo
{ fn: 'upsertField', key: 'novo_campo', value: 'valor' }

// Remover campo
{ fn: 'removeField', key: 'campo_antigo' }

// Adicionar valores a array
{ fn: 'addToArray', key: 'tags', value: ['nova-tag'] }

// Remover valores de array
{ fn: 'removeFromArray', key: 'caracteristicas', value: 'Sem mobília' }

📝 Processamento de Tags na Description

O ObjectTransformer processa automaticamente tags especiais em campos de texto:

const objeto = {
  description: `Casa linda [[description-en]]Beautiful house[[/description-en]] 
  [[custom-attributes]]
  {
    "energia_solar": true,
    "classificacao": "A+"
  }
  [[/custom-attributes]]
  Com vista para o mar`
}

const transformer = new ObjectTransformer({
  rules: {},
  processDescriptionTags: true // Padrão: true
})

const resultado = transformer.transform(objeto)
// Resultado:
// {
//   description: 'Casa linda Com vista para o mar',
//   description_en: 'Beautiful house',
//   energia_solar: true,
//   classificacao: 'A+'
// }

⚙️ Interface Completa

interface TransformRules<T = any> {
  referenceRules?: Record<string, TransformAction[]>  // Regras por reference
  fieldRules?: FieldRule<T>[]                         // Regras por field
}

interface FieldRule<T = any> {
  key: keyof T | string                    // Campo a verificar
  condition?: Record<string, any>          // Condição para aplicar regras
  rules: TransformAction[]                 // Actions a executar
}

interface TransformAction {
  fn: 'upsertField' | 'removeField' | 'addToArray' | 'removeFromArray'
  key: string        // Campo alvo da action
  value?: any        // Valor para a action
  type?: string      // Tipo do campo (informativo)
  label?: string     // Label do campo (informativo)  
}

🧪 Testes

# Executar testes
npm run test

# Testes com cobertura
npm run test:coverage

# Verificar tipos
npm run typecheck

🔧 Build

# Build para produção
npm run build

# Build com watch
npm run dev

📈 Roadmap

  • ✅ DataSyncService: Sincronização genérica de dados JSON com APIs
  • ✅ ProfilerService: Profiling e análise de estruturas de dados
  • ✅ JsonToZodGenerator: Geração automática de schemas Zod
  • BaseDownloader: Classe base para downloaders de API
  • BaseConverter: Utilitários para conversão de dados
  • ApiClient: Cliente HTTP genérico com retry e rate limiting
  • DataTransformer: Transformações de dados baseadas em regras
  • ValidationUtils: Utilitários de validação genéricos

📄 Licença

MIT - veja LICENSE para detalhes.

Desenvolvido pela Horizon Modules 🏗️