- Início
- Documentation
- Nativos
- Contrato de Binding Nativo (Lado TypeScript)
Contrato de Binding Nativo (Lado TypeScript)
Este documento define o contrato do lado TypeScript que fica entre os chamadores de @f5-sales-demo/pi-natives e o addon N-API carregado.
Ele foca em três partes:
- formato do contrato (
NativeBindings+ augmentação de módulo), - comportamento do wrapper (
src/<module>/index.ts), - superfície de exportação pública (
src/index.ts).
Arquivos de implementação
Seção intitulada “Arquivos de implementação”packages/natives/src/bindings.tspackages/natives/src/native.tspackages/natives/src/index.tspackages/natives/src/clipboard/types.tspackages/natives/src/clipboard/index.tspackages/natives/src/glob/types.tspackages/natives/src/glob/index.tspackages/natives/src/grep/types.tspackages/natives/src/grep/index.tspackages/natives/src/highlight/types.tspackages/natives/src/highlight/index.tspackages/natives/src/html/types.tspackages/natives/src/html/index.tspackages/natives/src/image/types.tspackages/natives/src/image/index.tspackages/natives/src/keys/types.tspackages/natives/src/keys/index.tspackages/natives/src/ps/types.tspackages/natives/src/ps/index.tspackages/natives/src/pty/types.tspackages/natives/src/pty/index.tspackages/natives/src/shell/types.tspackages/natives/src/shell/index.tspackages/natives/src/system-info/types.tspackages/natives/src/system-info/index.tspackages/natives/src/text/types.tspackages/natives/src/text/index.tspackages/natives/src/work/types.tspackages/natives/src/work/index.ts
Modelo do contrato
Seção intitulada “Modelo do contrato”packages/natives/src/bindings.ts define o contrato base:
NativeBindings(interface base, atualmente incluicancelWork(id: number): void)Cancellable(timeoutMs?: number,signal?: AbortSignal)TsFunc<T>formato de callback usado por callbacks threadsafe do N-API
Cada módulo adiciona seus próprios campos por meio de declaration merging:
// packages/natives/src/<module>/types.tsdeclare module "../bindings" { interface NativeBindings { grep(options: GrepOptions, onMatch?: TsFunc<GrepMatch>): Promise<GrepResult>; }}Isso mantém uma interface de binding agregada sem um arquivo de tipos central monolítico.
Ciclo de vida do declaration-merging e transições de estado
Seção intitulada “Ciclo de vida do declaration-merging e transições de estado”1) Montagem de tipos em tempo de compilação
Seção intitulada “1) Montagem de tipos em tempo de compilação”bindings.tsfornece o símbolo baseNativeBindings.- Cada
src/<module>/types.tsestendeNativeBindingspor augmentação. src/native.tsimporta todos os arquivos./<module>/typespor efeitos colaterais, de modo que o contrato mesclado esteja no escopo ondeNativeBindingsé utilizado.
Transição de estado: Contrato base → Contrato mesclado.
2) Carregamento do addon em tempo de execução e validação
Seção intitulada “2) Carregamento do addon em tempo de execução e validação”src/native.tscarrega binários.nodecandidatos.- O objeto carregado é tratado como
NativeBindingse imediatamente passado porvalidateNative(...). validateNativeverifica as chaves de exportação necessárias usandotypeof bindings[name] === "function".
Transição de estado: Objeto addon não confiável → Objeto de binding nativo validado (ou falha crítica).
3) Invocação do wrapper
Seção intitulada “3) Invocação do wrapper”- Os wrappers de módulo em
src/<module>/index.tschamamnative.<export>. - Os wrappers adaptam valores padrão e formato de callback (
(err, value)para padrões de callback somente com valor nas APIs JS). src/index.tsre-exporta os wrappers/tipos dos módulos como a API pública do pacote.
Transição de estado: Bindings brutos validados → API pública ergonômica.
Responsabilidades dos wrappers
Seção intitulada “Responsabilidades dos wrappers”Os wrappers são intencionalmente finos; eles não reimplementam a lógica nativa.
Responsabilidades principais:
- Normalização/definição de valores padrão dos argumentos
glob()resolveoptions.pathpara caminho absoluto e define valores padrão parahidden,gitignore,recursive.hasMatch()preenche flags padrão (ignoreCase,multiline) antes da chamada nativa.
- Adaptação de callback
grep(),glob(),executeShell()convertemTsFunc<T>(error, value) em callback do usuário recebendo apenas valores bem-sucedidos.
- Comportamento de ambiente ou política em torno das chamadas nativas
- O wrapper de clipboard adiciona tratamento para OSC52/Termux/headless e trata copy como melhor esforço.
- Nomeação pública e curadoria de re-exportação
searchContent()mapeia para a exportação nativasearch.
Organização da superfície de exportação pública
Seção intitulada “Organização da superfície de exportação pública”packages/natives/src/index.ts é o barrel público canônico. Ele agrupa exportações por domínio de capacidade:
- Busca/texto:
grep,glob,text,highlight - Execução/processo/terminal:
shell,pty,ps,keys - Sistema/mídia/conversão:
image,html,clipboard,system-info,work
Regra para mantenedores: se um wrapper não é re-exportado de src/index.ts, ele não faz parte da superfície pública pretendida do pacote.
Mapeamento API JS ↔ exportação nativa (representativo)
Seção intitulada “Mapeamento API JS ↔ exportação nativa (representativo)”O lado Rust usa nomes de exportação N-API (tipicamente da conversão #[napi] snake_case -> camelCase, com aliases explícitos ocasionais) que devem corresponder a estas chaves de binding.
| Categoria | API JS pública (wrapper) | Chave de binding nativo | Tipo de retorno | Assíncrono? |
|---|---|---|---|---|
| Grep | grep(options, onMatch?) | grep | Promise<GrepResult> | Sim |
| Grep | searchContent(content, options) | search | SearchResult | Não |
| Grep | hasMatch(content, pattern, opts?) | hasMatch | boolean | Não |
| Grep | fuzzyFind(options) | fuzzyFind | Promise<FuzzyFindResult> | Sim |
| Glob | glob(options, onMatch?) | glob | Promise<GlobResult> | Sim |
| Glob | invalidateFsScanCache(path?) | invalidateFsScanCache | void | Não |
| Shell | executeShell(options, onChunk?) | executeShell | Promise<ShellExecuteResult> | Sim |
| Shell | Shell | Shell | construtor de classe | N/A |
| PTY | PtySession | PtySession | construtor de classe | N/A |
| Text | truncateToWidth(...) | truncateToWidth | string | Não |
| Text | sliceWithWidth(...) | sliceWithWidth | SliceWithWidthResult | Não |
| Text | visibleWidth(text) | visibleWidth | number | Não |
| Highlight | highlightCode(code, lang, colors) | highlightCode | string | Não |
| HTML | htmlToMarkdown(html, options?) | htmlToMarkdown | Promise<string> | Sim |
| System | getSystemInfo() | getSystemInfo | SystemInfo | Não |
| Work | getWorkProfile(lastSeconds) | getWorkProfile | WorkProfile | Não |
| Process | killTree(pid, signal) | killTree | number | Não |
| Process | listDescendants(pid) | listDescendants | number[] | Não |
| Clipboard | copyToClipboard(text) | copyToClipboard | Promise<void> (comportamento de melhor esforço do wrapper) | Sim |
| Clipboard | readImageFromClipboard() | readImageFromClipboard | Promise<ClipboardImage | null> | Sim |
| Keys | parseKey(data, kittyProtocolActive) | parseKey | string | null | Não |
Diferenças de contrato síncrono vs assíncrono
Seção intitulada “Diferenças de contrato síncrono vs assíncrono”O contrato mistura APIs síncronas e assíncronas; os wrappers preservam o estilo de chamada nativa em vez de forçar um único modelo:
- Exportações assíncronas baseadas em Promise para I/O ou trabalho de longa duração (
grep,glob,htmlToMarkdown,executeShell, clipboard, operações de imagem). - Exportações síncronas para transformações/parsers determinísticos em memória (
search,hasMatch, highlighting, largura/fatiamento de texto, parsing de teclas, consultas de processos). - Exportações de construtor para objetos de runtime com estado (
Shell,PtySession,PhotonImage).
Implicação para mantenedores: alterar síncrono ↔ assíncrono para uma exportação existente é uma mudança de API e contrato que quebra compatibilidade em wrappers e chamadores.
Padrões de tipagem de objetos e enums
Seção intitulada “Padrões de tipagem de objetos e enums”Padrões de objetos (objetos JS estilo #[napi(object)])
Seção intitulada “Padrões de objetos (objetos JS estilo #[napi(object)])”O TS modela valores nativos em formato de objeto como interfaces, por exemplo:
GrepResult,SearchResult,GlobResultSystemInfo,WorkProfileClipboardImage,ParsedKittyResult
Estes são contratos estruturais em tempo de compilação; a correção do formato em tempo de execução é de responsabilidade da implementação nativa.
Padrões de enum
Seção intitulada “Padrões de enum”Enums nativos numéricos são representados como valores const enum no TS:
FileType(1=file,2=dir,3=symlink)ImageFormat(0=PNG,1=JPEG,2=WEBP,3=GIF)SamplingFilter,Ellipsis,KeyEventType
Os chamadores veem membros nomeados do enum; a fronteira de binding passa números.
Como incompatibilidades são detectadas
Seção intitulada “Como incompatibilidades são detectadas”A detecção de incompatibilidades acontece em duas camadas:
-
Verificações de contrato TypeScript em tempo de compilação
- Os wrappers chamam
native.<name>contra oNativeBindingsmesclado. - Chaves de binding ausentes/renomeadas quebram a verificação de tipos do TS nos wrappers.
- Os wrappers chamam
-
Validação em tempo de execução em
validateNative- Após o carregamento,
native.tsverifica as exportações necessárias e lança erro se alguma estiver faltando. - A mensagem de erro inclui as chaves ausentes e instruções de rebuild.
- Após o carregamento,
Isso captura a comum divergência de binário desatualizado: wrapper/tipo existe mas o .node carregado não possui a exportação.
Comportamento de falha e ressalvas
Seção intitulada “Comportamento de falha e ressalvas”Falhas de carregamento/validação (falhas críticas)
Seção intitulada “Falhas de carregamento/validação (falhas críticas)”- Falha no carregamento do addon ou plataforma não suportada lança exceção durante a inicialização do módulo em
native.ts. - Exportações necessárias ausentes lançam exceção antes que os wrappers sejam utilizáveis.
Efeito: o pacote falha rapidamente em vez de postergar a falha para a primeira chamada.
Diferenças de comportamento no nível do wrapper
Seção intitulada “Diferenças de comportamento no nível do wrapper”- Alguns wrappers intencionalmente suavizam falhas (
copyToClipboardé melhor esforço e suprime falhas nativas). - Callbacks de streaming ignoram payloads de erro do callback e apenas encaminham eventos de valores bem-sucedidos.
Ressalvas no nível de tipos (runtime mais rigoroso que o TS)
Seção intitulada “Ressalvas no nível de tipos (runtime mais rigoroso que o TS)”- Campos opcionais do TS não garantem validade semântica; a camada nativa ainda pode rejeitar valores malformados.
- A tipagem
const enumnão impede que valores numéricos fora do intervalo sejam passados por chamadores não tipados em tempo de execução. validateNativeverifica apenas presença/natureza de função das exportações necessárias, não compatibilidade profunda de formato de argumentos/retorno.bindings.tsincluicancelWork(id)na interface base, mas a lista atual de validação em tempo de execução não impõe essa chave.
Checklist do mantenedor para alterações de binding
Seção intitulada “Checklist do mantenedor para alterações de binding”Ao adicionar/alterar uma exportação, atualize todos os seguintes:
src/<module>/types.ts(augmentação + tipos de contrato)src/<module>/index.ts(comportamento do wrapper)- Importações em
src/native.tspara os tipos do módulo (se for módulo novo) - Verificações de exportação necessária em
validateNative - Re-exportações públicas em
src/index.ts
Pular qualquer etapa cria divergência em tempo de compilação ou falha em tempo de carregamento no runtime.