Skip to content

Anatomy of generated Swift

Each contract produces a single <PascalName>Contract.swift. Here is the real output for the example.host contract, dissected piece by piece.

example.host
// Generated by bridgekit. DO NOT EDIT.
// Contract hash: 8e552bd7
import BridgeKit

The contract hash is embedded in the header. The only import is BridgeKit (the runtime module). Generated files never import NitroModules or any app-specific module.

public struct GetCountryAndLanguageResult {
public var country: String
public var language: String
public init(country: String, language: String) {
self.country = country
self.language = language
}
}
public struct GetLiteralParams {
public var key: String
public init(key: String) { self.key = key }
}
public struct TrackEventParams {
public var eventName: String
public init(eventName: String) { self.eventName = eventName }
}
public struct OpenUrlParams {
public var url: String
public init(url: String) { self.url = url }
}

Object schemas become public struct with stored properties and a memberwise public init. Discriminated unions become Swift enum with associated values. Literal unions become enum with a raw String value.

3. Provider protocol (the side that implements)

Section titled “3. Provider protocol (the side that implements)”
public protocol ExampleHost: AnyObject {
func getCountryAndLanguage() throws -> GetCountryAndLanguageResult
func getLiteral(_ params: GetLiteralParams) throws -> String
func getAppVersion() throws -> String
func trackEvent(_ params: TrackEventParams)
func openUrl(_ params: OpenUrlParams)
}

This is the protocol your implementation class conforms to. The method shapes follow the contract kind:

Contract kindGenerated Swift signature
firefunc m(_ params: P?)
queryfunc m(_ params: P?) async throws -> R
querySyncfunc m(_ params: P?) throws -> R
streamfunc m(_ params: P?) -> AsyncStream<T>
state (provider)var m: AsyncStream<T> { get }

AnyObject is required by the Nitro layer. throw on sync specs surfaces errors back to the caller rather than crashing.

4. Client protocol (the side that consumes)

Section titled “4. Client protocol (the side that consumes)”
public protocol ExampleHostClient: AnyObject {
func getCountryAndLanguage() throws -> GetCountryAndLanguageResult
func getLiteral(_ params: GetLiteralParams) throws -> String
func getAppVersion() throws -> String
func trackEvent(_ params: TrackEventParams)
func openUrl(_ params: OpenUrlParams)
}

For state members the client protocol wraps availability:

// state example — not in example.host but shown for completeness:
// provider: var connectivity: AsyncStream<Connectivity> { get }
// client: var connectivity: AsyncStream<BridgeValue<Connectivity>> { get }

Clients see AsyncStream<BridgeValue<T>> — availability is part of the value (Available / Initial / Replacing / Unprovided). See Using BridgeKit from Swift for how to iterate these streams.

class ExampleHostContract: BridgeContractDefinition<any ExampleHost, any ExampleHostClient> {
override var id: String { "example.host" }
override var contractHash: String { "8e552bd7" }
override var memberHashes: [String: String] {
[
"methods.getAppVersion": "71ff3fa0",
"methods.getCountryAndLanguage": "27aee930",
"methods.getLiteral": "494175a7",
"methods.openUrl": "fb545690",
"methods.trackEvent": "99cf4370",
]
}
override func inbound(_ impl: any ExampleHost) -> InboundContractAdapter {
ExampleHostInboundAdapter(impl: impl)
}
override func outbound(_ caller: OutboundCaller) -> any ExampleHostClient {
ExampleHostOutboundProxy(caller: caller)
}
}

BridgeContractDefinition<P, C> is the open generic base class for all generated contract objects. The type parameters are protocol existentials (any ExampleHost, any ExampleHostClient) because Swift protocol existentials do not satisfy AnyObject generic constraints directly.

Two halves, mirror images:

  • inbound(_:) routes engine calls into your typed provider (used when this platform provides the contract to JS).
  • outbound(_:) builds the typed proxy backed by OutboundCaller (used when this platform consumes a JS-provided contract).
DSL (t.*)Swift
t.string()String
t.number()Double
t.boolean()Bool
t.int64()Int64
t.date()Date
t.binary()Data
t.object({…})public struct
t.optional(T)T?
t.array(T)[T]
t.record(T)[String: T]
t.stream(T)AsyncStream<T>
t.state(T, init)provider: AsyncStream<T>, client: AsyncStream<BridgeValue<T>>
t.literals([…])enum with String raw value
t.enum([…])enum with Int raw value
t.union(…)enum with associated values

The .swift file bridgekit generate --platform swift writes is the final artifact — there is no post-processing step. Commit it and add it to your Xcode target’s Compile Sources; Xcode does not glob a directory.

Declarations carry no explicit access modifier, so they are internal to whichever target compiles them. That is deliberate: the generated code is part of your app, not a module you link against, which is why your own Swift only ever imports BridgeKit. See Installation for the target settings this requires.