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.
1. Header & imports
Section titled “1. Header & imports”// Generated by axion bridgekit. DO NOT EDIT.// Contract hash: 8e552bd7import BridgeKitThe 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.
2. Object types
Section titled “2. Object types”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 kind | Generated Swift signature |
|---|---|
fire | func m(_ params: P?) |
query | func m(_ params: P?) async throws -> R |
querySync | func m(_ params: P?) throws -> R |
stream | func 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.
5. The contract object
Section titled “5. The contract object”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 byOutboundCaller(used when this platform consumes a JS-provided contract).
Type mapping
Section titled “Type mapping”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 sanitize post-processing step
Section titled “The sanitize post-processing step”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.