Code generation
C# is the source of truth for every safe bridge operation. You declare native, JavaScript, and event contracts once; Vidra generates the APIs used on both sides.
flowchart LR
contracts["Annotated C# contracts"]
roslyn["Roslyn source generator"]
csharp["Typed C# tokens and clients"]
manifest["Contract manifest"]
codegen["vidra-codegen"]
typescript["Typed TypeScript proxies and handlers"]
fingerprint["Deterministic fingerprints"]
contracts --> roslyn
roslyn --> csharp
roslyn --> manifest
manifest --> codegen
codegen --> typescript
manifest --> fingerprint
Contract directions
| Direction | C# declaration | Generated JavaScript API | Generated C# API |
|---|---|---|---|
| JavaScript → C# | [BridgeModule], [BridgeMethod] | Typed proxy method | Module registration and codecs |
| C# → JavaScript | [JsContract], [JsMethod] | Typed handler registry | Bridge.Js() client |
| C# → JavaScript event | [BridgeEventContract], [BridgeEvent] | Typed on... subscription | Event token |
Generated user-facing APIs may use the dynamic transport internally, but callers
remain typed and manifest-backed. Use vidra.unsafe or Bridge.Unsafe only when
you intentionally need traffic that is not represented by a contract.
Where generated TypeScript goes
Scaffolded host projects configure:
<VidraTsOutputDir>$(MSBuildProjectDirectory)/../../ui/src/generated</VidraTsOutputDir>
Building the host writes one TypeScript file per contract plus:
index.ts, which exports proxies and handler registries.manifest.json, which describes methods, events, JavaScript methods, and payload schemas.
Generated files are deterministic. Commit them so the web development server can start before the first native build and reviewers can see contract changes. Do not edit them by hand.
Type mapping
| C# | TypeScript |
|---|---|
record or class with properties | interface |
string, Guid, DateTime | string |
| Numeric types | number |
bool | boolean |
T[], List<T>, IReadOnlyList<T> | T[] |
Dictionary<string, T> | Record<string, T> |
enum | camel-case string-literal union |
Nullable<T> | optional T | null |
| Nullable reference | optional T | null |
Enums cross the bridge by their camel-case string names, not numeric values.
Unsupported shapes, cycles, duplicate contract/member names, and invalid method
signatures fail generation instead of falling back to unknown.
Manifests and fingerprints
Vidra produces separate fingerprints for:
- Core contracts shipped by the matched Vidra SDK and native packages.
- App contracts declared by your application and opted-in libraries.
The WebView startup handshake compares both fingerprints before accepting bridge traffic. If a web bundle and installed native host disagree, startup reports the mismatch rather than allowing a method call to fail later.
Any public contract change changes its fingerprint. A native rebuild that does not alter contracts keeps the same fingerprint.
Build and verify
Generate app contracts:
dotnet build src/MyApp.Host/MyApp.Host.csproj
Verify that committed output is current in CI:
dotnet msbuild src/MyApp.Host/MyApp.Host.csproj -t:VidraCodeGenCheck
If startup reports a fingerprint mismatch, rebuild the host and regenerate and commit the TypeScript output. Clearing package caches does not repair stale generated contracts.