@rescript-tauri/schema¶
@rescript-tauri/core 向けの Layer 3 型付き IPC です。エンコーダ・デコーダを 手書きする代わりに、rescript-schema のスキーマ 1 ペアから Tauri コマンドを宣言できます。
注釈
本パッケージは main で機能完備済みです。初回 npm 公開(schema-v0.1.0)は他のパッケージと合わせて予定されています。それまでは、ソースリポジトリ経由かワークスペースリンクで @rescript-tauri/schema を利用してください。
インストール¶
pnpm add @rescript-tauri/schema rescript-schema
@rescript-tauri/schema は @rescript-tauri/core と rescript-schema の両方を peerDependencies として宣言します。rescript.json に追加してください:
{
"dependencies": [
"@rescript-tauri/core",
"@rescript-tauri/schema",
"rescript-schema"
]
}
Rust 側の変更は不要です。schema は純粋にフロントエンド側のヘルパーです。
なぜ Layer 3 が必要か¶
Layer 2(Core.Command.make)はコマンド名を明示的なエンコーダ・デコーダとともに ラップします:
let greet = Core.Command.make(
~name="greet",
~encodeArgs=(name: string) => JSON.Encode.object(
Dict.fromArray([("name", JSON.Encode.string(name))])
),
~decodeResult=json =>
switch json->JSON.Decode.string {
| Some(s) => Ok(s)
| None => Error("expected string")
},
)
Layer 3 では同じコマンドを 1 つの宣言にまとめられます:
open RescriptTauriSchema
let greet = Schema.fromSchemas(
~name="greet",
~args=Schema.S.object(s => {name: s.field("name", Schema.S.string)}),
~result=Schema.S.string,
)
両方の Layer とも Core.Command.t<'args, 'result> を返すため、Core.Command.invoke の呼び出し側はコマンドがどちらの Layer で宣言されたかを 意識する必要はありません。
最小例¶
open RescriptTauriCore.Tauri
open RescriptTauriSchema
type greetArgs = {name: string}
let greet = Schema.fromSchemas(
~name="greet",
~args=Schema.S.object(s => {name: s.field("name", Schema.S.string)}),
~result=Schema.S.string,
)
switch await greet->Core.Command.invoke({name: "ReScript"}) {
| Ok(message) => Console.log(message)
| Error(DecodeError(msg)) => Console.error("decode failed: " ++ msg)
| Error(RustError(json)) => Console.error2("rust error:", json)
}
S.parseJsonOrThrow の失敗は toDecoder 内で捕捉され、既存の Core.Command.invoke のエラー variant に揃えて Error(DecodeError(message)) として表面化されます。
公開 API¶
エントリポイント |
用途 |
|---|---|
|
|
|
スキーマでデコードする |
|
スキーマでデコードする |
|
内部で利用される |
Schema.S は RescriptSchema.S を再エクスポートするため、利用者は @rescript-tauri/schema だけをインポートすればスキーマ DSL に 1 経路で アクセスできます。
Channel の例¶
Tauri の Channel<u32> の受信側は 1 行で書けるようになります:
let countChannel = Schema.channelFromSchema(~message=Schema.S.int)
Core.Channel.onMessage(countChannel, result =>
switch result {
| Ok(n) => Console.log2("recv", n)
| Error(_msg) => () // ignore decode failures
}
)
Channel を開くコマンドは依然として手書きのエンコーダが必要です。Core.Channel.t は スキーマから見て不透明なためです。完全な手順は examples/ipc-typed-with-schema を参照してください。
rescript-schema DSL の落とし穴¶
field はトップレベル関数ではなくメソッド¶
rescript-schema 9.x ではフィールドビルダを Object.s 引数のメソッドとして公開しています。ドット記法で呼び出してください:
// ✅
let s1 = Schema.S.object(s => {
name: s.field("name", Schema.S.string),
})
// ❌ compile error: `field` not in `Schema.S`
let s2 = Schema.S.object(s => {
name: s->Schema.S.field("name", Schema.S.string),
})
Tauri コマンド引数のフラット化¶
Tauri 2.x の tauri::command は、単一レコード引数を args オブジェクトの トップレベルキーにフラット化します。次のような Rust シグネチャでは:
#[tauri::command]
fn summarize(title: &str, items: Vec<String>) -> Summary { /* … */ }
args の JSON は {"title": ..., "items": ...} を期待し、{"args": {"title": ...}} のようなネストではありません。S.object スキーマは このフラット形状に合わせて記述してください。
互換性¶
コンポーネント |
サポート範囲 |
|---|---|
上流の |
|
|
|
ReScript |
|
|
|
rescript-struct は 非対応 です。上流のパッケージは rescript-schema への 置き換え方針で deprecated 済みです(2026-05-09 確認、RFC-0002 §2.1 に記録)。
関連情報¶
動作デモ:
examples/ipc-typed-with-schema。examples/ipc-typed/と対にして、同じコマンドを Layer 2 と Layer 3 の両方で 表現する例を示しています。ソース:
packages/schemaRFC-0002: Schema 統合設計