- ホーム
- Documentation
- ネイティブ
- ネイティブバインディングコントラクト(TypeScript側)
ネイティブバインディングコントラクト(TypeScript側)
このドキュメントでは、@f5-sales-demo/pi-natives の呼び出し元とロードされたN-APIアドオンの間に位置するTypeScript側のコントラクトを定義します。
以下の3つの要素に焦点を当てます:
- コントラクトの形状(
NativeBindings+ モジュール拡張) - ラッパーの振る舞い(
src/<module>/index.ts) - パブリックエクスポートサーフェス(
src/index.ts)
実装ファイル
Section titled “実装ファイル”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
コントラクトモデル
Section titled “コントラクトモデル”packages/natives/src/bindings.ts はベースコントラクトを定義します:
NativeBindings(ベースインターフェース、現在はcancelWork(id: number): voidを含む)Cancellable(timeoutMs?: number、signal?: AbortSignal)TsFunc<T>N-APIスレッドセーフコールバックで使用されるコールバック形状
各モジュールは宣言マージによって独自のフィールドを追加します:
// packages/natives/src/<module>/types.tsdeclare module "../bindings" { interface NativeBindings { grep(options: GrepOptions, onMatch?: TsFunc<GrepMatch>): Promise<GrepResult>; }}これにより、モノリシックな中央型ファイルを必要とせず、1つの集約されたバインディングインターフェースを維持できます。
宣言マージのライフサイクルと状態遷移
Section titled “宣言マージのライフサイクルと状態遷移”1) コンパイル時の型アセンブリ
Section titled “1) コンパイル時の型アセンブリ”bindings.tsがベースとなるNativeBindingsシンボルを提供します。- すべての
src/<module>/types.tsがNativeBindingsを拡張します。 src/native.tsがすべての./<module>/typesファイルを副作用のためにインポートし、NativeBindingsが使用される場所でマージされたコントラクトがスコープ内に入るようにします。
状態遷移: ベースコントラクト → マージ済みコントラクト
2) ランタイムでのアドオンロードとバリデーションゲート
Section titled “2) ランタイムでのアドオンロードとバリデーションゲート”src/native.tsが候補の.nodeバイナリをロードします。- ロードされたオブジェクトは
NativeBindingsとして扱われ、直ちにvalidateNative(...)に渡されます。 validateNativeはtypeof bindings[name] === "function"により必要なエクスポートキーを検証します。
状態遷移: 信頼されていないアドオンオブジェクト → 検証済みネイティブバインディングオブジェクト(またはハードフェイラー)
3) ラッパー呼び出し
Section titled “3) ラッパー呼び出し”src/<module>/index.tsのモジュールラッパーがnative.<export>を呼び出します。- ラッパーはデフォルト値とコールバック形状を適応させます(
(err, value)をJS APIでの値のみのコールバックパターンに変換)。 src/index.tsがモジュールラッパー/型をパブリックパッケージAPIとして再エクスポートします。
状態遷移: 検証済みの生バインディング → 人間工学的なパブリックAPI
ラッパーの責務
Section titled “ラッパーの責務”ラッパーは意図的に薄く設計されており、ネイティブロジックを再実装しません。
主な責務:
- 引数の正規化/デフォルト設定
glob()はoptions.pathを絶対パスに解決し、hidden、gitignore、recursiveのデフォルト値を設定します。hasMatch()はネイティブ呼び出し前にデフォルトフラグ(ignoreCase、multiline)を設定します。
- コールバックの適応
grep()、glob()、executeShell()はTsFunc<T>(error, value)を成功した値のみを受け取るユーザーコールバックに変換します。
- ネイティブ呼び出しに関する環境またはポリシーの振る舞い
- クリップボードラッパーはOSC52/Termux/ヘッドレス処理を追加し、コピーをベストエフォートとして扱います。
- パブリック命名と再エクスポートの管理
searchContent()はネイティブエクスポートsearchにマッピングされます。
パブリックエクスポートサーフェスの構成
Section titled “パブリックエクスポートサーフェスの構成”packages/natives/src/index.ts は正規のパブリックバレルファイルです。機能ドメインごとにエクスポートをグループ化しています:
- 検索/テキスト:
grep、glob、text、highlight - 実行/プロセス/ターミナル:
shell、pty、ps、keys - システム/メディア/変換:
image、html、clipboard、system-info、work
メンテナールール: ラッパーが src/index.ts から再エクスポートされていない場合、それは意図されたパブリックパッケージサーフェスの一部ではありません。
JS API ↔ ネイティブエクスポートマッピング(代表例)
Section titled “JS API ↔ ネイティブエクスポートマッピング(代表例)”Rust側はN-APIエクスポート名(通常は #[napi] のsnake_case → camelCase変換から、時折明示的なエイリアスを使用)を使用し、これらのバインディングキーと一致する必要があります。
| カテゴリ | パブリックJS API(ラッパー) | ネイティブバインディングキー | 戻り値の型 | 非同期? |
|---|---|---|---|---|
| Grep | grep(options, onMatch?) | grep | Promise<GrepResult> | はい |
| Grep | searchContent(content, options) | search | SearchResult | いいえ |
| Grep | hasMatch(content, pattern, opts?) | hasMatch | boolean | いいえ |
| Grep | fuzzyFind(options) | fuzzyFind | Promise<FuzzyFindResult> | はい |
| Glob | glob(options, onMatch?) | glob | Promise<GlobResult> | はい |
| Glob | invalidateFsScanCache(path?) | invalidateFsScanCache | void | いいえ |
| Shell | executeShell(options, onChunk?) | executeShell | Promise<ShellExecuteResult> | はい |
| Shell | Shell | Shell | クラスコンストラクタ | N/A |
| PTY | PtySession | PtySession | クラスコンストラクタ | N/A |
| Text | truncateToWidth(...) | truncateToWidth | string | いいえ |
| Text | sliceWithWidth(...) | sliceWithWidth | SliceWithWidthResult | いいえ |
| Text | visibleWidth(text) | visibleWidth | number | いいえ |
| Highlight | highlightCode(code, lang, colors) | highlightCode | string | いいえ |
| HTML | htmlToMarkdown(html, options?) | htmlToMarkdown | Promise<string> | はい |
| System | getSystemInfo() | getSystemInfo | SystemInfo | いいえ |
| Work | getWorkProfile(lastSeconds) | getWorkProfile | WorkProfile | いいえ |
| Process | killTree(pid, signal) | killTree | number | いいえ |
| Process | listDescendants(pid) | listDescendants | number[] | いいえ |
| Clipboard | copyToClipboard(text) | copyToClipboard | Promise<void>(ベストエフォートラッパー動作) | はい |
| Clipboard | readImageFromClipboard() | readImageFromClipboard | Promise<ClipboardImage | null> | はい |
| Keys | parseKey(data, kittyProtocolActive) | parseKey | string | null | いいえ |
同期 vs 非同期のコントラクトの違い
Section titled “同期 vs 非同期のコントラクトの違い”コントラクトは同期と非同期のAPIを混在させています。ラッパーは1つのモデルを強制するのではなく、ネイティブの呼び出しスタイルを維持します:
- Promiseベースの非同期エクスポート — I/Oまたは長時間実行の処理向け(
grep、glob、htmlToMarkdown、executeShell、クリップボード、画像操作)。 - 同期エクスポート — 決定論的なインメモリ変換/パーサー向け(
search、hasMatch、ハイライト、テキスト幅/スライス、キーパース、プロセスクエリ)。 - コンストラクタエクスポート — ステートフルなランタイムオブジェクト向け(
Shell、PtySession、PhotonImage)。
メンテナーへの注意: 既存のエクスポートの同期↔非同期を変更することは、ラッパーと呼び出し元全体にわたる破壊的なAPIおよびコントラクトの変更となります。
オブジェクトと列挙型の型付けパターン
Section titled “オブジェクトと列挙型の型付けパターン”オブジェクトパターン(#[napi(object)] スタイルのJSオブジェクト)
Section titled “オブジェクトパターン(#[napi(object)] スタイルのJSオブジェクト)”TSはオブジェクト形状のネイティブ値をインターフェースとしてモデル化します。例:
GrepResult、SearchResult、GlobResultSystemInfo、WorkProfileClipboardImage、ParsedKittyResult
これらはコンパイル時の構造的コントラクトであり、ランタイムの形状の正しさはネイティブ実装が担保します。
列挙型パターン
Section titled “列挙型パターン”数値のネイティブ列挙型はTSでは const enum 値として表現されます:
FileType(1=file、2=dir、3=symlink)ImageFormat(0=PNG、1=JPEG、2=WEBP、3=GIF)SamplingFilter、Ellipsis、KeyEventType
呼び出し元は名前付きの列挙型メンバーを参照しますが、バインディング境界では数値が渡されます。
不一致の検出方法
Section titled “不一致の検出方法”不一致の検出は2つのレイヤーで行われます:
-
コンパイル時のTypeScriptコントラクトチェック
- ラッパーはマージ済みの
NativeBindingsに対してnative.<name>を呼び出します。 - バインディングキーが欠落/名前変更されるとラッパーのTS型チェックが失敗します。
- ラッパーはマージ済みの
-
validateNativeによるランタイムバリデーション- ロード後、
native.tsが必要なエクスポートをチェックし、欠落があればスローします。 - エラーメッセージには欠落しているキーとリビルド手順が含まれます。
- ロード後、
これにより、ラッパー/型は存在するがロードされた .node にエクスポートがないという、よくある古いバイナリのドリフトを検出できます。
失敗時の振る舞いと注意事項
Section titled “失敗時の振る舞いと注意事項”ロード/バリデーション失敗(ハードフェイラー)
Section titled “ロード/バリデーション失敗(ハードフェイラー)”- アドオンのロード失敗またはサポートされていないプラットフォームの場合、
native.tsのモジュール初期化時にスローされます。 - 必要なエクスポートの欠落は、ラッパーが使用可能になる前にスローされます。
効果: パッケージは最初の呼び出しまで失敗を遅延させるのではなく、即座に失敗します。
ラッパーレベルの動作の違い
Section titled “ラッパーレベルの動作の違い”- 一部のラッパーは意図的に失敗を軽減します(
copyToClipboardはベストエフォートであり、ネイティブの失敗を握りつぶします)。 - ストリーミングコールバックはコールバックのエラーペイロードを無視し、成功した値イベントのみを転送します。
型レベルの注意事項(ランタイムはTSより厳格)
Section titled “型レベルの注意事項(ランタイムはTSより厳格)”- TSのオプショナルフィールドはセマンティックな妥当性を保証しません。ネイティブレイヤーは不正な値を拒否する可能性があります。
const enumの型付けは、ランタイムで型付けされていない呼び出し元からの範囲外の数値を防止しません。validateNativeは必要なエクスポートの存在/関数であることのみをチェックし、引数/戻り値の形状の深い互換性はチェックしません。bindings.tsはベースインターフェースにcancelWork(id)を含んでいますが、現在のランタイムバリデーションリストはそのキーを強制していません。
バインディング変更時のメンテナーチェックリスト
Section titled “バインディング変更時のメンテナーチェックリスト”エクスポートを追加/変更する際は、以下のすべてを更新してください:
src/<module>/types.ts(拡張 + コントラクト型)src/<module>/index.ts(ラッパーの振る舞い)src/native.tsのモジュール型のインポート(新規モジュールの場合)validateNativeの必要なエクスポートチェックsrc/index.tsのパブリック再エクスポート
いずれかのステップをスキップすると、コンパイル時のドリフトまたはランタイムのロード時失敗が発生します。