Skip to content

Anatomy of generated Swift

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

axion.host
// Generated by axion 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 AxionHost: 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 AxionHostClient: 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 axion.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 AxionHostContract: BridgeContractDefinition<any AxionHost, any AxionHostClient> {
override var id: String { "axion.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 AxionHost) -> InboundContractAdapter {
AxionHostInboundAdapter(impl: impl)
}
override func outbound(_ caller: OutboundCaller) -> any AxionHostClient {
AxionHostOutboundProxy(caller: caller)
}
}

BridgeContractDefinition<P, C> is the open generic base class for all generated contract objects. The type parameters are protocol existentials (any AxionHost, any AxionHostClient) 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 raw axion bridgekit generate --platform swift output emits the protocol/func declarations shown above. The committed iOS file in packages/core/ios/contracts/generated/ is post-processed by sanitize-ios-public-module.py after the xcframework build, which injects clean public modifiers and synthesizes the .swiftinterface for the AxionContracts module.

This post-processing step runs once during the xcframework build, not on every codegen run. The generated .swift source file is what you commit; the sanitize script is part of the packaging pipeline. See Installation for how the xcframework packaging works.