- Accueil
- Documentation
- Natifs
- Contrat de liaison natif (côté TypeScript)
Contrat de liaison natif (côté TypeScript)
Ce document définit le contrat côté TypeScript qui se situe entre les appelants de @f5-sales-demo/pi-natives et l’addon N-API chargé.
Il se concentre sur trois éléments :
- la forme du contrat (
NativeBindings+ augmentation de module), - le comportement des wrappers (
src/<module>/index.ts), - la surface d’export publique (
src/index.ts).
Fichiers d’implémentation
Section intitulée « Fichiers d’implémentation »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
Modèle de contrat
Section intitulée « Modèle de contrat »packages/natives/src/bindings.ts définit le contrat de base :
NativeBindings(interface de base, inclut actuellementcancelWork(id: number): void)Cancellable(timeoutMs?: number,signal?: AbortSignal)TsFunc<T>forme de callback utilisée par les callbacks threadsafe N-API
Chaque module ajoute ses propres champs par fusion de déclarations :
// packages/natives/src/<module>/types.tsdeclare module "../bindings" { interface NativeBindings { grep(options: GrepOptions, onMatch?: TsFunc<GrepMatch>): Promise<GrepResult>; }}Cela maintient une interface de liaison agrégée unique sans fichier de types central monolithique.
Cycle de vie de la fusion de déclarations et transitions d’état
Section intitulée « Cycle de vie de la fusion de déclarations et transitions d’état »1) Assemblage des types à la compilation
Section intitulée « 1) Assemblage des types à la compilation »bindings.tsfournit le symboleNativeBindingsde base.- Chaque
src/<module>/types.tsaugmenteNativeBindings. src/native.tsimporte tous les fichiers./<module>/typespour leurs effets de bord afin que le contrat fusionné soit dans la portée oùNativeBindingsest utilisé.
Transition d’état : Contrat de base → Contrat fusionné.
2) Chargement de l’addon à l’exécution et porte de validation
Section intitulée « 2) Chargement de l’addon à l’exécution et porte de validation »src/native.tscharge les binaires.nodecandidats.- L’objet chargé est traité comme
NativeBindingset immédiatement passé à traversvalidateNative(...). validateNativevérifie les clés d’export requises viatypeof bindings[name] === "function".
Transition d’état : Objet addon non fiable → Objet de liaison natif validé (ou échec définitif).
3) Invocation des wrappers
Section intitulée « 3) Invocation des wrappers »- Les wrappers de module dans
src/<module>/index.tsappellentnative.<export>. - Les wrappers adaptent les valeurs par défaut et la forme des callbacks (
(err, value)vers des patterns de callback à valeur uniquement dans les API JS). src/index.tsré-exporte les wrappers/types de module comme API publique du package.
Transition d’état : Liaisons brutes validées → API publique ergonomique.
Responsabilités des wrappers
Section intitulée « Responsabilités des wrappers »Les wrappers sont intentionnellement minces ; ils ne ré-implémentent pas la logique native.
Responsabilités principales :
- Normalisation/valeurs par défaut des arguments
glob()résoutoptions.pathen chemin absolu et définit les valeurs par défaut pourhidden,gitignore,recursive.hasMatch()remplit les drapeaux par défaut (ignoreCase,multiline) avant l’appel natif.
- Adaptation des callbacks
grep(),glob(),executeShell()convertissentTsFunc<T>(error, value) en callback utilisateur recevant uniquement les valeurs réussies.
- Comportement d’environnement ou de politique autour des appels natifs
- Le wrapper du presse-papiers ajoute la gestion OSC52/Termux/headless et traite la copie comme un effort au mieux.
- Nommage public et curation des ré-exports
searchContent()correspond à l’export natifsearch.
Organisation de la surface d’export publique
Section intitulée « Organisation de la surface d’export publique »packages/natives/src/index.ts est le barrel public canonique. Il regroupe les exports par domaine de capacité :
- Recherche/texte :
grep,glob,text,highlight - Exécution/processus/terminal :
shell,pty,ps,keys - Système/média/conversion :
image,html,clipboard,system-info,work
Règle pour les mainteneurs : si un wrapper n’est pas ré-exporté depuis src/index.ts, il ne fait pas partie de la surface publique prévue du package.
Correspondance API JS ↔ export natif (représentatif)
Section intitulée « Correspondance API JS ↔ export natif (représentatif) »Le côté Rust utilise des noms d’export N-API (typiquement issus de la conversion #[napi] snake_case -> camelCase, avec des alias explicites occasionnels) qui doivent correspondre à ces clés de liaison.
| Catégorie | API JS publique (wrapper) | Clé de liaison native | Type de retour | Async ? |
|---|---|---|---|---|
| Grep | grep(options, onMatch?) | grep | Promise<GrepResult> | Oui |
| Grep | searchContent(content, options) | search | SearchResult | Non |
| Grep | hasMatch(content, pattern, opts?) | hasMatch | boolean | Non |
| Grep | fuzzyFind(options) | fuzzyFind | Promise<FuzzyFindResult> | Oui |
| Glob | glob(options, onMatch?) | glob | Promise<GlobResult> | Oui |
| Glob | invalidateFsScanCache(path?) | invalidateFsScanCache | void | Non |
| Shell | executeShell(options, onChunk?) | executeShell | Promise<ShellExecuteResult> | Oui |
| Shell | Shell | Shell | constructeur de classe | N/A |
| PTY | PtySession | PtySession | constructeur de classe | N/A |
| Text | truncateToWidth(...) | truncateToWidth | string | Non |
| Text | sliceWithWidth(...) | sliceWithWidth | SliceWithWidthResult | Non |
| Text | visibleWidth(text) | visibleWidth | number | Non |
| Highlight | highlightCode(code, lang, colors) | highlightCode | string | Non |
| HTML | htmlToMarkdown(html, options?) | htmlToMarkdown | Promise<string> | Oui |
| System | getSystemInfo() | getSystemInfo | SystemInfo | Non |
| Work | getWorkProfile(lastSeconds) | getWorkProfile | WorkProfile | Non |
| Process | killTree(pid, signal) | killTree | number | Non |
| Process | listDescendants(pid) | listDescendants | number[] | Non |
| Clipboard | copyToClipboard(text) | copyToClipboard | Promise<void> (comportement wrapper au mieux) | Oui |
| Clipboard | readImageFromClipboard() | readImageFromClipboard | Promise<ClipboardImage | null> | Oui |
| Keys | parseKey(data, kittyProtocolActive) | parseKey | string | null | Non |
Différences de contrat synchrone vs asynchrone
Section intitulée « Différences de contrat synchrone vs asynchrone »Le contrat mélange des API synchrones et asynchrones ; les wrappers préservent le style d’appel natif plutôt que de forcer un modèle unique :
- Exports asynchrones basés sur les Promise pour les E/S ou les travaux de longue durée (
grep,glob,htmlToMarkdown,executeShell, presse-papiers, opérations sur les images). - Exports synchrones pour les transformations/parseurs déterministes en mémoire (
search,hasMatch, coloration syntaxique, largeur/découpage de texte, analyse de touches, requêtes de processus). - Exports de constructeurs pour les objets runtime à état (
Shell,PtySession,PhotonImage).
Implication pour les mainteneurs : changer synchrone ↔ asynchrone pour un export existant constitue un changement d’API et de contrat cassant à travers les wrappers et les appelants.
Patterns de typage pour les objets et les enums
Section intitulée « Patterns de typage pour les objets et les enums »Patterns d’objets (objets JS style #[napi(object)])
Section intitulée « Patterns d’objets (objets JS style #[napi(object)]) »TS modélise les valeurs natives de forme objet comme des interfaces, par exemple :
GrepResult,SearchResult,GlobResultSystemInfo,WorkProfileClipboardImage,ParsedKittyResult
Ce sont des contrats structurels à la compilation ; la correction de la forme à l’exécution est de la responsabilité de l’implémentation native.
Patterns d’enums
Section intitulée « Patterns d’enums »Les enums natifs numériques sont représentés comme des valeurs const enum en TS :
FileType(1=file,2=dir,3=symlink)ImageFormat(0=PNG,1=JPEG,2=WEBP,3=GIF)SamplingFilter,Ellipsis,KeyEventType
Les appelants voient les membres nommés de l’enum ; la frontière de liaison transmet des nombres.
Comment les incohérences sont détectées
Section intitulée « Comment les incohérences sont détectées »La détection des incohérences se fait à deux niveaux :
-
Vérifications du contrat TypeScript à la compilation
- Les wrappers appellent
native.<name>contreNativeBindingsfusionné. - Les clés de liaison manquantes/renommées cassent la vérification de types TS dans les wrappers.
- Les wrappers appellent
-
Validation à l’exécution dans
validateNative- Après le chargement,
native.tsvérifie les exports requis et lève une exception si l’un d’eux est manquant. - Le message d’erreur inclut les clés manquantes et les instructions de reconstruction.
- Après le chargement,
Cela détecte la dérive courante de binaire obsolète : le wrapper/type existe mais le .node chargé ne possède pas l’export.
Comportement en cas d’échec et avertissements
Section intitulée « Comportement en cas d’échec et avertissements »Échecs de chargement/validation (échecs définitifs)
Section intitulée « Échecs de chargement/validation (échecs définitifs) »- L’échec de chargement de l’addon ou une plateforme non supportée lève une exception lors de l’initialisation du module dans
native.ts. - Les exports requis manquants lèvent une exception avant que les wrappers soient utilisables.
Effet : le package échoue rapidement plutôt que de différer l’échec au premier appel.
Différences de comportement au niveau des wrappers
Section intitulée « Différences de comportement au niveau des wrappers »- Certains wrappers adoucissent intentionnellement les échecs (
copyToClipboardfonctionne au mieux et absorbe les échecs natifs). - Les callbacks de streaming ignorent les charges d’erreur des callbacks et ne transmettent que les événements de valeurs réussies.
Avertissements au niveau des types (l’exécution est plus stricte que TS)
Section intitulée « Avertissements au niveau des types (l’exécution est plus stricte que TS) »- Les champs optionnels TS ne garantissent pas la validité sémantique ; la couche native peut toujours rejeter des valeurs malformées.
- Le typage
const enumn’empêche pas les valeurs numériques hors limites provenant d’appelants non typés à l’exécution. validateNativevérifie uniquement la présence/nature de fonction des exports requis, pas la compatibilité profonde des formes d’arguments/retours.bindings.tsinclutcancelWork(id)dans l’interface de base, mais la liste de validation à l’exécution actuelle n’impose pas cette clé.
Liste de contrôle pour les mainteneurs lors de changements de liaison
Section intitulée « Liste de contrôle pour les mainteneurs lors de changements de liaison »Lors de l’ajout/modification d’un export, mettez à jour tous les éléments suivants :
src/<module>/types.ts(augmentation + types de contrat)src/<module>/index.ts(comportement du wrapper)- Imports de
src/native.tspour les types du module (si nouveau module) - Vérifications des exports requis dans
validateNative - Ré-exports publics dans
src/index.ts
Sauter l’une de ces étapes crée soit une dérive à la compilation, soit un échec à l’exécution au moment du chargement.