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

@innleaders/documents

v0.7.0

Published

Gerador de documentos Office no padrão InnLeaders — .docx, .pptx e .xlsx tematizados pela marca, sem dependência de runtime

Readme

@innleaders/documents

Gera .docx, .pptx e .xlsx no padrão InnLeaders a partir de um spec de conteúdo — ou a partir de um arquivo cru que alguém mandou. Irmão nativo do caminho HTML→PDF (templates/documents/ + scripts/render_pdf.py): mesma anatomia, mesmos tokens, mesma marca.

As regras de forma estão em brand/documents.md. Este pacote é a implementação delas para os formatos Office — quando a política e o código divergirem, a política vence e o código é corrigido.


Por que existe

Um documento da família é reconhecível: capa com faixa na cor da marca, seções 01 —, tabela com cabeçalho colorido, rodapé com © e paginação. Reproduzir isso à mão em cada proposta é retrabalho — e todo mundo erra um detalhe diferente. Aqui quem escreve descreve o conteúdo; a forma é decisão de marca e vem pronta.

Trocar capa.marca re-tematiza o arquivo inteiro — é o data-brand do lado Office.

Instalação

pnpm add @innleaders/documents

Zero dependências de runtime. Os três formatos são OOXML — ZIP de XMLs — escritos direto com node:zlib. Ganhamos ausência de cadeia de suprimentos e controle total da fidelidade à marca; abrimos mão da conveniência de uma biblioteca pronta (o custo aparece quando o formato precisar de um recurso novo, como gráfico nativo ou imagem).

Uso — API

import { gerar, type DocumentoSpec } from '@innleaders/documents';
import { writeFileSync } from 'node:fs';

const spec: DocumentoSpec = {
  formato: 'documento',
  capa: { marca: 'innmarketing', tipo: 'Proposta comercial', titulo: 'Título da proposta', cliente: 'Cliente Ltda.' },
  sumario: true,
  blocos: [
    { tipo: 'secao', titulo: 'Contexto e objetivo' },
    { tipo: 'paragrafo', texto: 'Texto com **ênfase** onde importa.' },
    { tipo: 'investimento', valor: 'R$ 8.940', condicoes: 'parcelável em 3× sem juros' },
  ],
};

writeFileSync('proposta.docx', gerar(spec));

Uso — CLI

# spec de referência de cada formato (é o melhor jeito de aprender o vocabulário)
npx innleaders-doc exemplo documento > proposta.json

# validar contra a política de estrutura (o gerar roda isto sozinho)
npx innleaders-doc validar proposta.json

# gerar — spec fora da política NÃO vira arquivo (--force para ignorar, com os avisos)
npx innleaders-doc gerar proposta.json proposta.docx

# reformatar um arquivo cru no padrão da marca
npx innleaders-doc formatar entrada.xlsx saida.xlsx --marca inndata --titulo "Base de contratos"

O ciclo completo para IA: document_scaffold (MCP) entrega o esqueleto conforme → preencher → document_validate/validar reprova o que ficou fora da política ou com «placeholder» → gerar escreve o binário. A API expõe validar(spec) para o mesmo gate em código.

Imagens: foto/retrato (deck) e figura (documento) aceitam imagem — caminho de arquivo PNG/JPEG ou data URI base64 — com recorte de cobertura automático (nunca esticada). Sem imagem, sai o espaço reservado padronizado. Gráficos desenhados carregam a série completa como alt-text (descr): leitor de tela e máquina leem os dados.

Iconografia: icone: 'trending-up' nos blocos icones e kpis desenha o ícone da biblioteca oficial (assets/icons/, a mesma que o PDF resolve em {{ICON:nome}}) como vetorcustGeom no PowerPoint, VML no Word. Vetor e não PNG porque o ícone herda a cor da marca: rasterizar exigiria ~1.500 arquivos (9 marcas × 2 tintas × 83 ícones). pnpm icones regera a partir dos SVG, e o gate de CI (scripts/conferir-icones.mjs) quebra o build se um SVG mudar sem regerar.

Logotipo: a capa usa o logo oficial da marca quando o asset existe, e o lockup textual sancionado quando não — agente nunca desenha logo. Os PNG em logos/ são derivados dos SVG oficiais (assets/logos/) por pnpm logos, com o sha256 da origem no manifesto e gate de CI que quebra o build se o SVG mudar sem regenerar. $INNLEADERS_ASSETS/logos/<marca>/<variante>.png sobrepõe o embutido — quem tem o repositório usa sempre o logo mais recente. Arquitetura completa (banco de imagens, cache, geração por IA) no ADR 0006.

O que cada formato entrega

| Formato | Página | O que é nativo (não é imitação) | |---|---|---| | .docx | A4 retrato | numeração de seção 01 — (decimalZero), sumário nativo com número de página (campo TOC com resultado em cache e âncoras PAGEREF; abre sem o diálogo de campos externos — INNLEADERS_DOC_TOC_DIRTY=1 troca isso por recálculo automático ao abrir), paginação no rodapé (PAGE/NUMPAGES), marca-d'água de rascunho, propriedades do arquivo preenchidas | | .pptx | 16:9 (12192000×6858000 EMU) | masters da família como shapes posicionados, tabela OOXML de verdade | | .xlsx | — | formatos numéricos reais (moeda/percentual/data), painel congelado, autofiltro, SUBTOTAL na linha de total |

Os três formatos carregam o theme1.xml da marca (cores + Montserrat): o seletor de cores/fontes do Word, PowerPoint e Excel abre na paleta do design system — o que o cliente criar depois de receber o arquivo continua na marca.

O documento sai editável: o cliente abre no Word e continua trabalhando sem quebrar o padrão.

Vocabulário do spec

Definido em src/spec.ts — os blocos espelham os componentes do print.css, então o mesmo conteúdo rende nos dois caminhos:

  • Documento: secao · subtitulo · paragrafo · lista · tabela · destaque (marca/info/atenção/risco/sucesso) · sumarioExecutivo · kpis · investimento · passos · fases · escopo · planos · riscos · citacao · faq · glossario · assinaturas · aprovacoes · versoes · nota · legal · cronograma (barras) · contato (card do especialista) · selos · raci · antesDepois · duasColunas · figura · anexo (numeração Anexo A — própria)
  • Apresentação: capa · capaClara · agenda · divisor · conteudo (com escuro) · kpis · dashboard · bignum · grafico · linha · funil · waterfall · stack · donut · duascol · timeline · tabela · processo · matriz · piramide · arquitetura · icones · planos · risco · equipe · citacao · retrato · case · logos · foto · checklist · cta · fim
  • Planilha: abas com colunas tipadas (texto · numero · moeda · percentual · data · inteiro), kpis, totais, congelar

Ênfase inline: **negrito** no texto de qualquer bloco. O catálogo de masters do PDF tem paridade total no .pptx.

Estrutura de conteúdo por tipo de documento (o que é obrigatório numa proposta, num relatório, num parecer): policies/documents/exemplo-estrutura-proposta.v1.md. A tool document_scaffold do @innleaders/mcp devolve um spec inicial já conforme.

Slides de foto/retrato sem asset — ou com asset que não resolveu — saem com o espaço reservado padronizado (listras diagonais + etiqueta); binário de imagem vive no bucket, nunca no pacote (ver Imagens do acervo, abaixo). Os gráficos do deck (funil, donut, linha, cascata) são desenhados com geometria própria, ponto a ponto: os presets do formato somem ou deformam fora do PowerPoint.

Imagens do acervo (banco://, ilustracao://, ia://)

O spec carrega identificador lógico, nunca bytes e nunca URL de storage (ADR 0006 §8). Um deck de 30 fotos em base64 seria um JSON de ~120 MB; e apontar para o bucket amarraria todo o sistema ao caminho físico.

{ "tipo": "foto",   "imagem": "banco://convencao-2026/abertura" }
{ "tipo": "figura", "imagem": "ilustracao://especialidades/gestao-de-leads" }
{ "tipo": "foto",   "imagem": "ia://cidade-sao-paulo-aerea" }

Resolver é passo assíncrono (tem rede no meio); gerar() continua síncrono. Rode a hidratação antes:

import { gerar, hidratarAcervo } from '@innleaders/documents';

const { spec: pronto, relatorio } = await hidratarAcervo(spec);
writeFileSync('deck.pptx', gerar(pronto));

if (relatorio.reservados) console.warn(`${relatorio.reservados} imagem(ns) caíram no espaço reservado`);

A cadeia, na ordem: cache local por conteúdo (<cache>/<sha256>, o que torna o build offline e reprodutível) → $INNLEADERS_ASSETS/acervo/…catálogo → bucketespaço reservado. Sem rede, sem cache e sem asset, o documento sai igual, com o espaço reservado padronizado no lugar da imagem: documento nunca quebra por falta de imagem (decisão 5).

| variável | para quê | |---|---| | INNLEADERS_ACERVO_URL | endereço do catálogo (ex.: https://mcp.innleaders.com/api/acervo) | | INNLEADERS_ACERVO_TOKEN | Bearer de serviço (ilsvc_…) com escopo de leitura | | INNLEADERS_ACERVO_CACHE | onde fica o cache (default ~/.cache/innleaders/acervo) |

Sem as duas primeiras, tudo resolve para espaço reservado — que é o comportamento correto do CI e de quem acabou de clonar o repo.

A imagem chega já reduzida ao tamanho do slot (decisão 4). A largura sai do tipo do bloco — foto/capa/divisor 1920 px · figura/anexo 1600 · retrato/equipe 800 · contato/logos 600, e 1920 para tipo desconhecido. Quem redimensiona é o storage, na entrega: o pacote continua sem rasterizador. Só encolhe — imagem menor que o alvo vem como está. Para forçar, passe larguraAlvo (0 traz o original). E a mesma imagem usada N vezes entra uma vez no arquivo, endereçada pelo sha256.

ia:// é pedido de criação, não referência: ele primeiro busca no acervo (§3, "buscar antes de criar") e só aciona a esteira de geração no vazio, via o gancho opcoes.gerar. Enquanto a esteira (R3·S9) não estiver ligada, ia:// que não encontra nada no acervo cai no espaço reservado.

logo:// e icone:// não passam por aqui: conjunto fechado e crítico, vivem no Git → pacote → CDN (§6/§7). Publicar no acervo: pnpm acervo:publicar (ver scripts/acervo-publicar.mjs).

Reformatar arquivo cru

documentoDeArquivo() e planilhaDeArquivo() leem o arquivo, extraem a estrutura (títulos, listas, tabelas, tipos de coluna) e descartam a formatação de origem — de propósito: o resultado tem que sair com a forma da marca, não com a de quem mandou.

Limites conhecidos: não interpretamos imagens, campos, notas de rodapé, células mescladas nem fórmulas do arquivo de origem; .pptx de terceiro não é reformatado (monte o spec e use gerar).

Tipografia

Montserrat (fonte pública sancionada — Mont e Gotham são comerciais e nunca entram neste pipeline). A fonte vai embutida no .docx (Regular, Bold e Light como .odttf) e no .pptx (.fntdata): o documento renderiza igual em qualquer máquina, mesmo sem a Montserrat instalada. Custo: ~0,6 MB por arquivo; fontes: false no spec gera a versão leve (usa a substituta do sistema onde a fonte faltar). Os TTF vendorizados vivem em fontes/ com a licença OFL junto — ela permite embutir e redistribuir. O .xlsx não tem mecanismo de embed no formato.

Verificação

pnpm --filter @innleaders/documents build
pnpm --filter @innleaders/documents test:smoke

O smoke gera os três exemplos e confere: ZIP legível, XML bem formado em todas as partes, partes declaradas no [Content_Types].xml, tema da marca em todo pacote, as 9 marcas × 3 formatos, gate de contraste WCAG (os pares oficiais do ADR 0003, os estados semânticos e as rampas tingidas, nas 9 marcas), lint de layout (todo shape do deck dentro do palco; sangria só por allowlist), idempotência (mesmo spec → mesmos bytes, graças à data fixa do ZIP), guarda de hex local (cor literal em src/*.ts fora de tema.ts reprova — o gate global do repo não cobre OOXML, que escreve cor sem #), casos de borda (spec vazio, tabela sem linhas, texto hostil escapado, nomes de aba duplicados/longos), imagem embutida (mídia + rel + content type), o validador da política (exemplos passam; proposta sem escopo, slide com 6 bullets e «placeholder» reprovam), ida e volta do caminho "arquivo cru → padrão" com fidelidade numérica e — no macOS — que o parser OOXML do próprio sistema abre os arquivos (qlmanage). Tudo isso roda no CI a cada push.