- Home
- Documentation
- Nativi
- Contratto di Binding Nativo (Lato TypeScript)
Contratto di Binding Nativo (Lato TypeScript)
Questo documento definisce il contratto lato TypeScript che si interpone tra i chiamanti di @f5-sales-demo/pi-natives e l’addon N-API caricato.
Si concentra su tre elementi:
- forma del contratto (
NativeBindings+ module augmentation), - comportamento dei wrapper (
src/<module>/index.ts), - superficie di esportazione pubblica (
src/index.ts).
File di implementazione
Sezione intitolata “File di implementazione”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
Modello del contratto
Sezione intitolata “Modello del contratto”packages/natives/src/bindings.ts definisce il contratto base:
NativeBindings(interfaccia base, attualmente includecancelWork(id: number): void)Cancellable(timeoutMs?: number,signal?: AbortSignal)TsFunc<T>forma della callback utilizzata dalle callback threadsafe di N-API
Ogni modulo aggiunge i propri campi tramite declaration merging:
// packages/natives/src/<module>/types.tsdeclare module "../bindings" { interface NativeBindings { grep(options: GrepOptions, onMatch?: TsFunc<GrepMatch>): Promise<GrepResult>; }}Questo mantiene un’unica interfaccia di binding aggregata senza un file di tipi centrale monolitico.
Ciclo di vita del declaration-merging e transizioni di stato
Sezione intitolata “Ciclo di vita del declaration-merging e transizioni di stato”1) Assemblaggio dei tipi a tempo di compilazione
Sezione intitolata “1) Assemblaggio dei tipi a tempo di compilazione”bindings.tsfornisce il simbolo baseNativeBindings.- Ogni
src/<module>/types.tsestendeNativeBindings. src/native.tsimporta tutti i file./<module>/typesper i side effect, così che il contratto unificato sia nello scope doveNativeBindingsviene utilizzato.
Transizione di stato: Contratto base → Contratto unificato.
2) Caricamento dell’addon a runtime e gate di validazione
Sezione intitolata “2) Caricamento dell’addon a runtime e gate di validazione”src/native.tscarica i binari.nodecandidati.- L’oggetto caricato viene trattato come
NativeBindingse immediatamente passato attraversovalidateNative(...). validateNativeverifica le chiavi di esportazione richieste tramitetypeof bindings[name] === "function".
Transizione di stato: Oggetto addon non attendibile → Oggetto di binding nativo validato (o fallimento critico).
3) Invocazione dei wrapper
Sezione intitolata “3) Invocazione dei wrapper”- I wrapper dei moduli in
src/<module>/index.tschiamanonative.<export>. - I wrapper adattano i valori predefiniti e la forma delle callback (da
(err, value)a pattern callback solo-valore nelle API JS). src/index.tsri-esporta wrapper/tipi dei moduli come API pubblica del pacchetto.
Transizione di stato: Binding grezzi validati → API pubblica ergonomica.
Responsabilità dei wrapper
Sezione intitolata “Responsabilità dei wrapper”I wrapper sono intenzionalmente sottili; non re-implementano la logica nativa.
Responsabilità principali:
- Normalizzazione/impostazione predefinita degli argomenti
glob()risolveoptions.pathin un percorso assoluto e imposta i valori predefiniti perhidden,gitignore,recursive.hasMatch()compila i flag predefiniti (ignoreCase,multiline) prima della chiamata nativa.
- Adattamento delle callback
grep(),glob(),executeShell()convertonoTsFunc<T>(error, value) in callback utente che ricevono solo valori di successo.
- Comportamento di ambiente o policy attorno alle chiamate native
- Il wrapper della clipboard aggiunge la gestione OSC52/Termux/headless e tratta la copia come best effort.
- Naming pubblico e curazione delle ri-esportazioni
searchContent()mappa all’esportazione nativasearch.
Organizzazione della superficie di esportazione pubblica
Sezione intitolata “Organizzazione della superficie di esportazione pubblica”packages/natives/src/index.ts è il barrel pubblico canonico. Raggruppa le esportazioni per dominio funzionale:
- Ricerca/testo:
grep,glob,text,highlight - Esecuzione/processi/terminale:
shell,pty,ps,keys - Sistema/media/conversione:
image,html,clipboard,system-info,work
Regola per i maintainer: se un wrapper non è ri-esportato da src/index.ts, non fa parte della superficie pubblica prevista del pacchetto.
Mappatura API JS ↔ esportazione nativa (rappresentativa)
Sezione intitolata “Mappatura API JS ↔ esportazione nativa (rappresentativa)”Il lato Rust utilizza nomi di esportazione N-API (tipicamente dalla conversione #[napi] snake_case -> camelCase, con occasionali alias espliciti) che devono corrispondere a queste chiavi di binding.
| Categoria | API JS pubblica (wrapper) | Chiave di binding nativa | Tipo di ritorno | Asincrona? |
|---|---|---|---|---|
| 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 | costruttore di classe | N/D |
| PTY | PtySession | PtySession | costruttore di classe | N/D |
| 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> (comportamento wrapper best effort) | Sì |
| Clipboard | readImageFromClipboard() | readImageFromClipboard | Promise<ClipboardImage | null> | Sì |
| Keys | parseKey(data, kittyProtocolActive) | parseKey | string | null | No |
Differenze contrattuali tra sincrono e asincrono
Sezione intitolata “Differenze contrattuali tra sincrono e asincrono”Il contratto mescola API sincrone e asincrone; i wrapper preservano lo stile di chiamata nativa piuttosto che forzare un unico modello:
- Esportazioni asincrone basate su Promise per I/O o lavori di lunga durata (
grep,glob,htmlToMarkdown,executeShell, clipboard, operazioni su immagini). - Esportazioni sincrone per trasformazioni/parser deterministici in memoria (
search,hasMatch, highlighting, larghezza/slicing del testo, parsing dei tasti, query sui processi). - Esportazioni di costruttori per oggetti runtime con stato (
Shell,PtySession,PhotonImage).
Implicazione per i maintainer: cambiare sincrono ↔ asincrono per un’esportazione esistente è un cambiamento breaking dell’API e del contratto attraverso wrapper e chiamanti.
Pattern di tipizzazione per oggetti ed enum
Sezione intitolata “Pattern di tipizzazione per oggetti ed enum”Pattern oggetto (oggetti JS in stile #[napi(object)])
Sezione intitolata “Pattern oggetto (oggetti JS in stile #[napi(object)])”I modelli TS rappresentano i valori nativi a forma di oggetto come interfacce, ad esempio:
GrepResult,SearchResult,GlobResultSystemInfo,WorkProfileClipboardImage,ParsedKittyResult
Questi sono contratti strutturali a tempo di compilazione; la correttezza della forma a runtime è di responsabilità dell’implementazione nativa.
Pattern enum
Sezione intitolata “Pattern enum”Gli enum nativi numerici sono rappresentati come valori const enum in TS:
FileType(1=file,2=dir,3=symlink)ImageFormat(0=PNG,1=JPEG,2=WEBP,3=GIF)SamplingFilter,Ellipsis,KeyEventType
I chiamanti vedono membri enum con nome; al confine del binding vengono passati numeri.
Come vengono rilevate le discrepanze
Sezione intitolata “Come vengono rilevate le discrepanze”Il rilevamento delle discrepanze avviene su due livelli:
-
Controlli del contratto TypeScript a tempo di compilazione
- I wrapper chiamano
native.<name>contro ilNativeBindingsunificato. - Chiavi di binding mancanti/rinominate interrompono il type-checking di TS nei wrapper.
- I wrapper chiamano
-
Validazione a runtime in
validateNative- Dopo il caricamento,
native.tsverifica le esportazioni richieste e lancia un’eccezione se ne mancano. - Il messaggio di errore include le chiavi mancanti e le istruzioni per la ricompilazione.
- Dopo il caricamento,
Questo intercetta il comune drift da binario obsoleto: il wrapper/tipo esiste ma il .node caricato non ha l’esportazione.
Comportamento in caso di fallimento e avvertenze
Sezione intitolata “Comportamento in caso di fallimento e avvertenze”Fallimenti di caricamento/validazione (fallimenti critici)
Sezione intitolata “Fallimenti di caricamento/validazione (fallimenti critici)”- Il fallimento del caricamento dell’addon o una piattaforma non supportata lanciano un’eccezione durante l’inizializzazione del modulo in
native.ts. - Esportazioni richieste mancanti lanciano un’eccezione prima che i wrapper siano utilizzabili.
Effetto: il pacchetto fallisce rapidamente piuttosto che rinviare il fallimento alla prima chiamata.
Differenze di comportamento a livello di wrapper
Sezione intitolata “Differenze di comportamento a livello di wrapper”- Alcuni wrapper attenuano intenzionalmente i fallimenti (
copyToClipboardè best effort e assorbe i fallimenti nativi). - Le callback di streaming ignorano i payload di errore delle callback e inoltrano solo eventi con valori di successo.
Avvertenze a livello di tipo (il runtime è più rigoroso del TS)
Sezione intitolata “Avvertenze a livello di tipo (il runtime è più rigoroso del TS)”- I campi opzionali in TS non garantiscono la validità semantica; il livello nativo può comunque rifiutare valori malformati.
- La tipizzazione
const enumnon impedisce valori numerici fuori range da chiamanti non tipizzati a runtime. validateNativecontrolla solo la presenza e la natura di funzione delle esportazioni richieste, non la compatibilità profonda della forma argomenti/ritorno.bindings.tsincludecancelWork(id)nell’interfaccia base, ma l’attuale lista di validazione a runtime non applica quella chiave.
Checklist per i maintainer per le modifiche ai binding
Sezione intitolata “Checklist per i maintainer per le modifiche ai binding”Quando si aggiunge/modifica un’esportazione, aggiornare tutti i seguenti:
src/<module>/types.ts(augmentation + tipi del contratto)src/<module>/index.ts(comportamento del wrapper)- Import di
src/native.tsper i tipi del modulo (se nuovo modulo) - Controlli delle esportazioni richieste in
validateNative - Ri-esportazioni pubbliche di
src/index.ts
Saltare qualsiasi passaggio crea drift a tempo di compilazione o fallimento a tempo di caricamento a runtime.