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

jsegd-bpm

v0.1.7

Published

Biblioteca runtime para desenvolvimento EGD BPM — EGD Tecnologia

Downloads

980

Readme

jsEGD BPM

Biblioteca TypeScript de runtime para desenvolvimento de formulários e workflows no ambiente EGD BPM — EGD Tecnologia.
Fornece componentes de anexo, gerenciamento de workers para datasets, controle do ciclo de vida do workflow e utilitários de formulário integrados ao DOM do EGD BPM.

Dependências par obrigatórias: jsegd ≥ 1.1.0 e alpinejs ≥ 3.0.0


Instalação

npm install jsegd-bpm jsegd alpinejs

Entradas do pacote

| Entrada | Importação | Conteúdo | | --------- | ------------- | ----------------------------------------------------------------------------- | | Principal | jsegd-bpm | Workers, anexos, validação, workflow, form-repository, workflow-view e alpine |


WorkerManager — Consultas de Dataset em Web Workers

Gerencia um pool de Web Workers para executar consultas à API de Datasets do EGD BPM fora da thread principal. Suporta deduplicação de requisições, cache em IndexedDB e cancelamento HTTP real via AbortController.

import { WorkerManager, ConstraintsType } from 'jsegd-bpm'
import { LocalCache } from 'jsegd'

// Compartilhando um cache existente entre componentes:
const cache = LocalCache.getInstance()
cache.initialize({ storeName: 'datasets', cacheExpirationMs: 60 * 60 * 1000 })

const manager = new WorkerManager({ poolSize: 4, cache })

const { promise, cancel } = manager.query('https://tenant.bpm.empresa.com', {
    datasetId: 'dsColaboradores',
    field: ['nome', 'email', 'matricula'],
    constraintsField: ['ativo'],
    constraintsInitialValue: ['true'],
    constraintsType: [ConstraintsType.MUST],
})

// Cancelar requisição em andamento, se necessário:
// cancel()

const result = await promise
console.log(result.columns) // ['nome', 'email', 'matricula']
console.log(result.values) // [{ nome: 'Ana', email: '[email protected]', matricula: '1234' }, ...]

// Liberar recursos ao desmontar o componente:
manager.terminate()

WorkerManagerOptions

| Opção | Tipo | Padrão | Descrição | | -------------- | -------------- | ------ | -------------------------------------------------------------- | | poolSize | number | 4 | Número de workers paralelos | | cache | ICache | — | Instância de cache existente (compartilhada entre componentes) | | cacheOptions | CacheOptions | — | Cria um LocalCache interno com storeName e TTL em ms |

Se nem cache nem cacheOptions for informado, o gerenciador opera sem cache.

ConstraintsType — enum: MUST, SHOULD, MUST_NOT.


AttachButton / AttachmentsTable — Componentes de Anexo

Custom Elements prontos para uso em formulários EGD BPM. Registre-os uma vez no ponto de entrada da aplicação.

import { AttachButton, AttachmentsTable } from 'jsegd-bpm'

customElements.define('attachment-button', AttachButton)
customElements.define('attachments-table', AttachmentsTable)

<attachment-button>

Botão com dropdown para upload de arquivos vinculados ao processo.

<!-- Tipo de anexo fixo -->
<attachment-button description="CONTRATO"></attachment-button>

<!-- Prompt ao usuário para informar a descrição no upload -->
<attachment-button></attachment-button>

<!-- Somente leitura: oculta botão de adicionar -->
<attachment-button description="CONTRATO" noaddbutton></attachment-button>

| Atributo | Tipo | Descrição | | ---------------- | -------- | ---------------------------------------------------------------- | | description | string | Tipo do anexo. Vazio abre modal para o usuário informar | | accept | string | Filtro de tipos aceitos pelo seletor nativo (ex: ".pdf,.docx") | | noaddbutton | — | Oculta o botão de adicionar | | noviewbutton | — | Oculta o botão de visualizar | | noeditbutton | — | Oculta o botão de editar descrição | | nodeletebutton | — | Oculta o botão de excluir |

<attachments-table>

Tabela que lista os anexos do processo com suporte a drag-and-drop para reordenação.

<attachments-table mode="edit"></attachments-table>

BeforeSendValidate — Validação com feedback visual

Integra validação de campos com o sistema de erros visuais do tema EGD BPM (data-group / data-helper).

import { BeforeSendValidate } from 'jsegd-bpm'
import type { FieldError } from 'jsegd-bpm'

function validarFormulario() {
    const erros: FieldError[] = []

    const campoNome = document.querySelector<HTMLInputElement>('[name="nome_solicitante"]')
    if (!campoNome?.value) {
        erros.push({ field: campoNome, errorMessage: 'Informe o nome do solicitante' })
    }

    if (erros.length > 0) {
        BeforeSendValidate.throwValidationError(erros)
        // Lança Error com HTML formatado para o widget de processo exibir
    }
}

throwValidationError lança sempre — use dentro de beforeSendValidate do EGD BPM ou em hooks de WorkflowViewPatcher.


WorkflowViewPatcher — Hooks no widget de processo

Substitui métodos do widget nativo ECM_WKFView para interceptar o ciclo de envio do processo sem modificar o EGD BPM.

import { WorkflowViewPatcher } from 'jsegd-bpm'

// 1. Inicializar — aguarda o widget carregar no frame pai
await WorkflowViewPatcher.init()

// 2. Aplicar todos os patches registrados
WorkflowViewPatcher.patchAll()

// 3. Registrar hooks
WorkflowViewPatcher.addBeforeValidate(async () => {
    // Executado antes da validação do widget.
    // Lançar exceção cancela o envio e reabilita os botões.
    const valor = document.querySelector<HTMLInputElement>('[name="campo_critico"]')?.value
    if (!valor) throw new Error('Campo crítico obrigatório')
})

WorkflowViewPatcher.addAfterValidate(async () => {
    // Executado após validação bem-sucedida, antes do envio efetivo.
    await salvarRascunho()
})

WorkflowViewPatcher.addOnMoveSuccess(() => {
    console.log('Processo movimentado com sucesso')
})

WorkflowViewPatcher.addOnMoveError(() => {
    console.error('Erro na movimentação — verifique os logs')
})

WorkflowViewPatcher.addOnCompletionLinkAdd((message) => {
    // Adiciona links à tela de conclusão após a movimentação
    message.links.push({ description: 'Abrir tarefa seguinte', href: '/minha-tarefa' })
})

// Ao desmontar o formulário (SPAs): restaura os métodos originais
WorkflowViewPatcher.restore()

Métodos estáticos

| Método | Descrição | | ---------------------------- | ------------------------------------------------------- | | init(timeout?) | Aguarda ECM_WKFView ficar disponível no frame pai | | patchAll() | Aplica todos os overrides registrados | | patch(attr) | Aplica um override específico | | restore() | Reverte todos os métodos e limpa hooks e flags internos | | addBeforeValidate(fn) | Hook antes da validação do widget | | addAfterValidate(fn) | Hook após validação, antes do envio | | addOnMoveSuccess(fn) | Callback de sucesso na movimentação | | addOnMoveError(fn) | Callback de erro na movimentação | | addOnCompletionLinkAdd(fn) | Manipula links da tela de conclusão |


IFormRepository — Acesso tipado ao formulário

Interface agnóstica ao DOM com duas implementações: BpmFormRepository (produção) e MockFormRepository (testes unitários).

Convenção de nomenclatura de campos

Os campos do formulário EGD BPM devem seguir o padrão:

{domínio}_{atributo_snake_case}

onde {domínio} é o identificador do agregado de negócio ao qual o campo pertence — não a tela em que aparece nem a fase do workflow. O total não deve ultrapassar 30 caracteres (limite de coluna no banco EGD).

| Campo no DOM | Domínio | Atributo no modelo | | ------------------- | ----------- | ------------------ | | contrato_indice | contrato | indice | | imovel_cep | imovel | cep | | vigencia_prazo | vigencia | prazo | | fornecedor_cep | fornecedor| cep |

Importante: o {domínio} é o prefixo persistido no banco pelo Fluig — é parte integrante do nome da coluna e não deve ser omitido no HTML. O load e o save gerenciam a conversão entre o nome DOM e o atributo do modelo de forma transparente.

O moduleId do workflow (quem exibe o campo na tela) e o stage (em que fase do processo estamos) são independentes do domínio do campo — um mesmo módulo pode exibir campos de múltiplos domínios.

Produção — BpmFormRepository

Lê e escreve diretamente nos elementos input, select e textarea do formulário EGD BPM. Encapsula toda a interação com wdkAddChild para tabelas filhas.

load(section) remove o prefixo {section}_ e converte snake_case → camelCase antes de retornar.
save(section, data) faz o caminho inverso: converte camelCase → snake_case e adiciona o prefixo ao escrever no DOM.

import { BpmFormRepository } from 'jsegd-bpm'

interface Contrato {
    indice: string
    primeiroPagamento: string
    reajuste: string
}

interface Imovel {
    cep: string
    logradouro: string
    municipio: string
}

interface ItemTabela {
    descricao: string
    valor: string
}

const repo = new BpmFormRepository()

// Ler domínio 'contrato' — lê campos com name="contrato_*" do DOM
// DOM: contrato_indice, contrato_primeiro_pagamento, contrato_reajuste
const contrato = repo.load<Contrato>('contrato')
console.log(contrato.indice)           // valor de input[name="contrato_indice"]
console.log(contrato.primeiroPagamento) // valor de input[name="contrato_primeiro_pagamento"]

// Ler domínio 'imovel' — desambigua de 'fornecedor_cep', 'contrato_cep', etc.
const imovel = repo.load<Imovel>('imovel')
console.log(imovel.cep) // valor de input[name="imovel_cep"]

// Ler tabela filha
const itens = repo.loadTable<ItemTabela>('tabItens')

// Persistir no DOM — save converte camelCase → prefixo+snake_case
repo.save<Contrato>('contrato', { indice: 'IGPM', primeiroPagamento: '2026-02-01' })
// escreve: input[name="contrato_indice"] e input[name="contrato_primeiro_pagamento"]

// Substituir linhas da tabela filha
repo.saveTable<ItemTabela>('tabItens', [
    { descricao: 'Notebook', valor: '4500.00' },
    { descricao: 'Mouse', valor: '120.00' },
])

Testes — MockFormRepository

Implementação in-memory sem dependência de DOM. Aplica a mesma lógica de prefixo e conversão de BpmFormRepository para que os testes reflitam o comportamento real.

import { MockFormRepository } from 'jsegd-bpm'

interface Vigencia {
    prazo: string
    tipoDePrazo: string
}

const repo = new MockFormRepository()

// save armazena internamente como 'vigencia_prazo', 'vigencia_tipo_de_prazo'
repo.save<Vigencia>('vigencia', { prazo: '12', tipoDePrazo: 'Meses' })

// load recupera { prazo: '12', tipoDePrazo: 'Meses' }
const data = repo.load<Vigencia>('vigencia')
// data.prazo === '12'
// data.tipoDePrazo === 'Meses'

repo.saveTable('tabItens', [{ descricao: 'Cadeira', valor: '800.00' }])
const itens = repo.loadTable('tabItens')

repo.reset() // limpa todos os dados

Processos legados — loadFields

Processos existentes cujos campos não seguem a convenção {domínio}_{atributo} não devem ser alterados para evitar migração de dados no banco. Para esses casos, jsegd-bpm exporta a função utilitária loadFields, que recebe um mapeamento explícito { propriedadeModelo: nomeDOM }:

import { loadFields } from 'jsegd-bpm'

interface Solicitante {
    nome: string
    email: string
}

// Campo legado: sufixo em vez de prefixo — nome_solicitante, email_solicitante
const dados = loadFields<Solicitante>({
    nome: 'nome_solicitante',
    email: 'email_solicitante',
})
// dados.nome === valor de input[name="nome_solicitante"]
// dados.email === valor de input[name="email_solicitante"]

Regra: loadFields não faz parte de IFormRepository — é um utilitário de compatibilidade para processos legados. Novos processos devem usar repository.load(section) exclusivamente.


Módulo workflow/ — Configuração e controle de tela

Conjunto de utilitários para mapear as atividades BPM em estados de tela — barra de progresso, visibilidade de módulos e editabilidade — sem hardcode de números de sequência nos Presenters.

defineWorkflowConfig — Configuração tipada

Define módulos e atividades em uma declaração única. O tipo ModuleId é inferido automaticamente — nenhum type alias manual é necessário.

import { defineWorkflowConfig } from 'jsegd-bpm'

export const workflowConfig = defineWorkflowConfig({
    modules: [
        {
            moduleId: 'solicitante',
            label: 'Dados Iniciais',
            icon: 'file-text',
            order: 1,
            showInNavigation: true,
            renderContent: true,
            contentIncludePath: 'solicitante.html',
        },
        {
            moduleId: 'juridico',
            label: 'Jurídico',
            icon: 'gavel',
            order: 2,
            showInNavigation: true,
            renderContent: true,
            contentIncludePath: 'juridico.html',
        },
        {
            moduleId: 'financeiro',
            label: 'Financeiro',
            icon: 'dollar-sign',
            order: 3,
            showInNavigation: true,
            renderContent: true,
            contentIncludePath: 'financeiro.html',
        },
    ],
    activities: [
        {
            sequence: 9,
            description: 'Solicitação inicial',
            kind: 'human',
            stage: 'solicitacao',
            modules: { visible: ['solicitante'], editable: ['solicitante'], active: 'solicitante' },
        },
        {
            sequence: 53,
            description: 'Aprovação jurídica',
            kind: 'human',
            stage: 'juridico',
            modules: { visible: ['solicitante', 'juridico'], editable: ['juridico'], active: 'juridico' },
        },
        {
            sequence: 61,
            description: 'Análise financeira',
            kind: 'human',
            stage: 'financeiro',
            modules: { visible: ['solicitante', 'juridico', 'financeiro'], editable: ['financeiro'] },
        },
        { sequence: 88, description: 'Roteamento interno', kind: 'routing' },
    ],
} as const)
// Tipo de ModuleId inferido: 'solicitante' | 'juridico' | 'financeiro'

ActivityKind — controla o comportamento na barra de progresso:

| Valor | Comportamento | | ----------- | ------------------------------------------------------------------- | | 'human' | Ação de usuário — estágio atual destacado na barra | | 'system' | Aguardando retorno externo (webhook) — exibe spinner | | 'support' | Suporte transversal — sobrepõe banner de alerta; não avança a barra | | 'routing' | Roteamento interno do motor BPM — invisível na barra |


extractCompletedStages / extractCurrentStage — Histórico do processo

Parseia o histórico bruto retornado por parent.ECM.workflowView.processDefinition.urlHistory e produz um ProcessHistory para consumo pelo ScreenContext.

import { extractCompletedStages, extractCurrentStage } from 'jsegd-bpm'
import type { BpmHistoryMap, ProcessHistory } from 'jsegd-bpm'

const rawHistory = parent.ECM.workflowView.processDefinition.urlHistory as BpmHistoryMap
const currentSequence: number = parent.ECM.workflowView.processDefinition.cardIndex
const historyType: string | null = parent.ECM.workflowView.processDefinition.historyType ?? null

const completedStages = extractCompletedStages(rawHistory, workflowConfig.activities)
// Ex: ['solicitacao', 'juridico']

const currentStage = extractCurrentStage(currentSequence, historyType, workflowConfig.activities)
// Ex: { stage: 'financeiro', status: 'current' }

const processHistory: ProcessHistory = { completedStages, currentStage }

resolveWorkflowScreen + ScreenContext — Estado da tela

Cruza a configuração com o histórico para produzir um ScreenContext — o único objeto que os Presenters precisam consultar.

import { resolveWorkflowScreen } from 'jsegd-bpm'

const screen = resolveWorkflowScreen(workflowConfig, currentSequence, processHistory)

// Visibilidade e editabilidade
screen.isVisible('juridico') // true
screen.isEditable('financeiro') // false
screen.isActive('juridico') // true

// Estado da atividade
screen.isAwaitingSystem() // true quando kind === 'system' ou status === 'waiting'
screen.isInSupport() // true para kind === 'support'

// Barra de progresso
const stages = screen.getProgressBarStages()
// [
//   { stage: 'solicitacao', status: 'done' },
//   { stage: 'juridico',    status: 'done' },
//   { stage: 'financeiro',  status: 'current' },
// ]

// Módulos
const visiveis = screen.getVisibleModules() // ResolvedModule[] — apenas isVisible = true
const navegacao = screen.getNavigationModules() // ResolvedModule[] — apenas showInNavigation = true e visível

registerStores — Alpine stores tipados

Registra múltiplos Alpine stores em uma única chamada e retorna um proxy tipado para acesso direto sem casting manual.

import Alpine from 'alpinejs'
import { registerStores } from 'jsegd-bpm'

type PerfilId = 'admin' | 'analista' | 'visualizador'

const stores = registerStores(Alpine, {
    usuario: { nome: '', perfil: '' as PerfilId, matricula: '' },
    ui: { carregando: false, erro: null as string | null },
})

Alpine.start()

// Acesso tipado — sem Alpine.store('usuario') as UsuarioStore
stores.usuario.nome // string
stores.usuario.perfil // PerfilId
stores.ui.carregando // boolean

registerStores aceita Pick<Alpine, 'store'> — compatível com qualquer mock em testes unitários.


Uso típico em um formulário EGD BPM

import Alpine from 'alpinejs'
import {
    AttachButton,
    AttachmentsTable,
    WorkflowViewPatcher,
    BpmFormRepository,
    extractCompletedStages,
    extractCurrentStage,
    resolveWorkflowScreen,
    registerStores,
} from 'jsegd-bpm'
import type { BpmHistoryMap } from 'jsegd-bpm'
import { workflowConfig } from './workflow.config'

// Registrar Custom Elements
customElements.define('attachment-button', AttachButton)
customElements.define('attachments-table', AttachmentsTable)

// Alpine stores
const stores = registerStores(Alpine, {
    solicitante: { nome: '', departamento: '' },
    ui: { carregando: false },
})

// Histórico e tela
const rawHistory = parent.ECM.workflowView.processDefinition.urlHistory as BpmHistoryMap
const seq: number = parent.ECM.workflowView.processDefinition.cardIndex
const histType: string | null = parent.ECM.workflowView.processDefinition.historyType ?? null

const processHistory = {
    completedStages: extractCompletedStages(rawHistory, workflowConfig.activities),
    currentStage: extractCurrentStage(seq, histType, workflowConfig.activities),
}

const screen = resolveWorkflowScreen(workflowConfig, seq, processHistory)

// Patcher
await WorkflowViewPatcher.init()
WorkflowViewPatcher.patchAll()
WorkflowViewPatcher.addBeforeValidate(async () => {
    const repo = new BpmFormRepository()
    const dados = repo.load<{ nome: string }>('solicitante')
    if (!dados.nome) throw new Error('Informe o nome do solicitante')
})

Alpine.start()

Licença

Proprietária — EGD Tecnologia. Uso restrito a projetos autorizados.