- Inicio
- Documentation
- Nativos
- Contrato de Binding Nativo (Lado TypeScript)
Contrato de Binding Nativo (Lado TypeScript)
Este documento define el contrato del lado TypeScript que se sitúa entre los consumidores de @f5-sales-demo/pi-natives y el addon N-API cargado.
Se centra en tres piezas:
- forma del contrato (
NativeBindings+ augmentación de módulo), - comportamiento del wrapper (
src/<module>/index.ts), - superficie de exportación pública (
src/index.ts).
Archivos de implementación
Sección titulada «Archivos de implementación»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 del contrato
Sección titulada «Modelo del contrato»packages/natives/src/bindings.ts define el contrato base:
NativeBindings(interfaz base, actualmente incluyecancelWork(id: number): void)Cancellable(timeoutMs?: number,signal?: AbortSignal)TsFunc<T>forma de callback utilizada por los callbacks threadsafe de N-API
Cada módulo agrega sus propios campos mediante fusión de declaraciones (declaration merging):
// packages/natives/src/<module>/types.tsdeclare module "../bindings" { interface NativeBindings { grep(options: GrepOptions, onMatch?: TsFunc<GrepMatch>): Promise<GrepResult>; }}Esto mantiene una única interfaz de binding agregada sin un archivo de tipos monolítico central.
Ciclo de vida de la fusión de declaraciones y transiciones de estado
Sección titulada «Ciclo de vida de la fusión de declaraciones y transiciones de estado»1) Ensamblaje de tipos en tiempo de compilación
Sección titulada «1) Ensamblaje de tipos en tiempo de compilación»bindings.tsproporciona el símbolo baseNativeBindings.- Cada
src/<module>/types.tsaugmentaNativeBindings. src/native.tsimporta todos los archivos./<module>/typespor sus efectos secundarios para que el contrato fusionado esté en alcance donde se utilizaNativeBindings.
Transición de estado: Contrato base → Contrato fusionado.
2) Carga del addon en tiempo de ejecución y puerta de validación
Sección titulada «2) Carga del addon en tiempo de ejecución y puerta de validación»src/native.tscarga los binarios.nodecandidatos.- El objeto cargado se trata como
NativeBindingsy se pasa inmediatamente a través devalidateNative(...). validateNativeverifica las claves de exportación requeridas mediantetypeof bindings[name] === "function".
Transición de estado: Objeto addon no confiable → Objeto de binding nativo validado (o fallo definitivo).
3) Invocación del wrapper
Sección titulada «3) Invocación del wrapper»- Los wrappers de módulo en
src/<module>/index.tsllaman anative.<export>. - Los wrappers adaptan valores por defecto y la forma del callback (de
(err, value)a patrones de callback solo con valor en las APIs de JS). src/index.tsreexporta los wrappers/tipos de módulo como la API pública del paquete.
Transición de estado: Bindings crudos validados → API pública ergonómica.
Responsabilidades del wrapper
Sección titulada «Responsabilidades del wrapper»Los wrappers son intencionalmente delgados; no reimplementan la lógica nativa.
Responsabilidades principales:
- Normalización/valores por defecto de argumentos
glob()resuelveoptions.patha una ruta absoluta y establece valores por defecto parahidden,gitignore,recursive.hasMatch()completa los flags por defecto (ignoreCase,multiline) antes de la llamada nativa.
- Adaptación de callbacks
grep(),glob(),executeShell()conviertenTsFunc<T>(error, value) en un callback de usuario que recibe solo valores exitosos.
- Comportamiento de entorno o política alrededor de las llamadas nativas
- El wrapper del portapapeles agrega manejo de OSC52/Termux/headless y trata la copia como mejor esfuerzo.
- Nombrado público y curación de reexportaciones
searchContent()se mapea a la exportación nativasearch.
Organización de la superficie de exportación pública
Sección titulada «Organización de la superficie de exportación pública»packages/natives/src/index.ts es el barrel público canónico. Agrupa las exportaciones por dominio de capacidad:
- Búsqueda/texto:
grep,glob,text,highlight - Ejecución/proceso/terminal:
shell,pty,ps,keys - Sistema/medios/conversión:
image,html,clipboard,system-info,work
Regla para mantenedores: si un wrapper no se reexporta desde src/index.ts, no forma parte de la superficie pública intencionada del paquete.
Mapeo de API JS ↔ exportación nativa (representativo)
Sección titulada «Mapeo de API JS ↔ exportación nativa (representativo)»El lado Rust utiliza nombres de exportación N-API (típicamente de la conversión #[napi] snake_case -> camelCase, con alias explícitos ocasionales) que deben coincidir con estas claves de binding.
| Categoría | API JS pública (wrapper) | Clave de binding nativo | Tipo de retorno | ¿Async? |
|---|---|---|---|---|
| Grep | grep(options, onMatch?) | grep | Promise<GrepResult> | Sí |
| Grep | searchContent(content, options) | search | SearchResult | No |
| Grep | hasMatch(content, pattern, opts?) | hasMatch | boolean | No |
| Grep | fuzzyFind(options) | fuzzyFind | Promise<FuzzyFindResult> | Sí |
| Glob | glob(options, onMatch?) | glob | Promise<GlobResult> | Sí |
| Glob | invalidateFsScanCache(path?) | invalidateFsScanCache | void | No |
| Shell | executeShell(options, onChunk?) | executeShell | Promise<ShellExecuteResult> | Sí |
| Shell | Shell | Shell | constructor de clase | N/A |
| PTY | PtySession | PtySession | constructor de clase | N/A |
| Text | truncateToWidth(...) | truncateToWidth | string | No |
| Text | sliceWithWidth(...) | sliceWithWidth | SliceWithWidthResult | No |
| Text | visibleWidth(text) | visibleWidth | number | No |
| Highlight | highlightCode(code, lang, colors) | highlightCode | string | No |
| HTML | htmlToMarkdown(html, options?) | htmlToMarkdown | Promise<string> | Sí |
| System | getSystemInfo() | getSystemInfo | SystemInfo | No |
| Work | getWorkProfile(lastSeconds) | getWorkProfile | WorkProfile | No |
| Process | killTree(pid, signal) | killTree | number | No |
| Process | listDescendants(pid) | listDescendants | number[] | No |
| Clipboard | copyToClipboard(text) | copyToClipboard | Promise<void> (comportamiento de mejor esfuerzo del wrapper) | Sí |
| Clipboard | readImageFromClipboard() | readImageFromClipboard | Promise<ClipboardImage | null> | Sí |
| Keys | parseKey(data, kittyProtocolActive) | parseKey | string | null | No |
Diferencias del contrato entre sync y async
Sección titulada «Diferencias del contrato entre sync y async»El contrato mezcla APIs síncronas y asíncronas; los wrappers preservan el estilo de llamada nativo en lugar de forzar un solo modelo:
- Exportaciones async basadas en Promise para I/O o trabajo de larga duración (
grep,glob,htmlToMarkdown,executeShell, portapapeles, operaciones de imagen). - Exportaciones síncronas para transformaciones/parsers determinísticos en memoria (
search,hasMatch, resaltado de sintaxis, ancho/segmentación de texto, parseo de teclas, consultas de procesos). - Exportaciones de constructores para objetos con estado en tiempo de ejecución (
Shell,PtySession,PhotonImage).
Implicación para mantenedores: cambiar sync ↔ async para una exportación existente es un cambio de API y contrato que rompe compatibilidad a través de wrappers y consumidores.
Patrones de tipado de objetos y enums
Sección titulada «Patrones de tipado de objetos y enums»Patrones de objetos (objetos JS estilo #[napi(object)])
Sección titulada «Patrones de objetos (objetos JS estilo #[napi(object)])»TS modela los valores nativos con forma de objeto como interfaces, por ejemplo:
GrepResult,SearchResult,GlobResultSystemInfo,WorkProfileClipboardImage,ParsedKittyResult
Estos son contratos estructurales en tiempo de compilación; la corrección de la forma en tiempo de ejecución es responsabilidad de la implementación nativa.
Patrones de enums
Sección titulada «Patrones de enums»Los enums nativos numéricos se representan como valores const enum en TS:
FileType(1=file,2=dir,3=symlink)ImageFormat(0=PNG,1=JPEG,2=WEBP,3=GIF)SamplingFilter,Ellipsis,KeyEventType
Los consumidores ven miembros nombrados del enum; la frontera del binding pasa números.
Cómo se detectan las inconsistencias
Sección titulada «Cómo se detectan las inconsistencias»La detección de inconsistencias ocurre en dos capas:
-
Verificaciones del contrato TypeScript en tiempo de compilación
- Los wrappers llaman a
native.<name>contraNativeBindingsfusionado. - Las claves de binding faltantes/renombradas rompen la verificación de tipos TS en los wrappers.
- Los wrappers llaman a
-
Validación en tiempo de ejecución en
validateNative- Después de la carga,
native.tsverifica las exportaciones requeridas y lanza una excepción si alguna falta. - El mensaje de error incluye las claves faltantes e instrucciones de reconstrucción.
- Después de la carga,
Esto detecta la deriva común de binarios obsoletos: el wrapper/tipo existe pero el .node cargado carece de la exportación.
Comportamiento de fallos y advertencias
Sección titulada «Comportamiento de fallos y advertencias»Fallos de carga/validación (fallos definitivos)
Sección titulada «Fallos de carga/validación (fallos definitivos)»- El fallo de carga del addon o una plataforma no soportada lanza una excepción durante la inicialización del módulo en
native.ts. - Las exportaciones requeridas faltantes lanzan una excepción antes de que los wrappers sean utilizables.
Efecto: el paquete falla rápidamente en lugar de diferir el fallo a la primera llamada.
Diferencias de comportamiento a nivel de wrapper
Sección titulada «Diferencias de comportamiento a nivel de wrapper»- Algunos wrappers intencionalmente suavizan los fallos (
copyToClipboardes de mejor esfuerzo y absorbe el fallo nativo). - Los callbacks de streaming ignoran los payloads de error del callback y solo reenvían eventos de valor exitosos.
Advertencias a nivel de tipos (el runtime es más estricto que TS)
Sección titulada «Advertencias a nivel de tipos (el runtime es más estricto que TS)»- Los campos opcionales en TS no garantizan validez semántica; la capa nativa aún puede rechazar valores malformados.
- El tipado
const enumno previene que valores numéricos fuera de rango sean pasados por consumidores sin tipado en tiempo de ejecución. validateNativeverifica solo la presencia y que sean funciones las exportaciones requeridas, no la compatibilidad profunda de forma de argumentos/retorno.bindings.tsincluyecancelWork(id)en la interfaz base, pero la lista de validación en tiempo de ejecución actual no aplica esa clave.
Lista de verificación para mantenedores ante cambios de binding
Sección titulada «Lista de verificación para mantenedores ante cambios de binding»Al agregar/cambiar una exportación, actualice todos los siguientes:
src/<module>/types.ts(augmentación + tipos del contrato)src/<module>/index.ts(comportamiento del wrapper)- Importaciones de
src/native.tspara los tipos del módulo (si es un módulo nuevo) - Verificaciones de exportaciones requeridas en
validateNative - Reexportaciones públicas en
src/index.ts
Omitir cualquier paso crea ya sea deriva en tiempo de compilación o fallo en tiempo de ejecución durante la carga.