Skip to content

Drift & cross-repo delivery

In a real deployment the JS bundle and the native binaries ship independently — the bundle is often renovate-ignored. Skew is the steady state, not an error condition. BridgeKit treats it as a first-class concern.

A 32-bit hash over the normalized descriptor is baked into both the generated native binding and the JS descriptor. At bind / first-resolution time the router diffs member sets:

  • Missing members → one structured warning naming the missing members and both hashes.
  • Full hash mismatch on identical member sets → tolerated (this is additive evolution).
  • Calls to a removed member → fail with METHOD_NOT_FOUND carrying the diff context.

So a newer bundle talking to an older native descriptor degrades gracefully and loudly, never silently.

A generated contract id → hash map, committed next to the generated bindings in the consuming repo. It lets the native repo’s CI verify internal consistency without a Node toolchain — no need to run the TypeScript generator on the native CI.

The lock carries a platform field recording which emitter produced it:

{
"descriptorVersion": 1,
"platform": "kotlin", // or "swift"
"contracts": {
"axion.host": {
"hash": "8e552bd7",
"members": {
"methods.getAppVersion": "71ff3fa0",
"methods.getCountryAndLanguage": "27aee930",
"methods.getLiteral": "494175a7",
"methods.openUrl": "fb545690",
"methods.trackEvent": "99cf4370"
}
}
}
}

Each platform (Kotlin, Swift) has its own lock file in its own output directory.

--into <path> — tool-owned cross-repo copy

Section titled “--into <path> — tool-owned cross-repo copy”

When the contracts live in one repo and the generated bindings must land in another (e.g. Android.Application/features/lia/bridgekit/), --into makes that copy tool-owned rather than a manual cp:

Terminal window
axion bridgekit generate \
--contracts 'src/**/*.contract.ts' \
--out-dir bridgekit/generated \
--into ../Android.Application/features/lia/bridgekit

The same applies to Swift:

Terminal window
axion bridgekit generate \
--platform swift \
--out-dir ios/contracts/generated \
--into ../iOS.Application/lia/contracts

The documented, --check-enforced rule:

Additive only. New optional fields, new methods, new streams, new state keys are fine. Removals and renames require a new contract id.

--check compares against the last generated descriptors and fails CI on a non-additive change. This is what lets two independently-deployed artifacts evolve without a lockstep release.

When you genuinely need to branch on whether a member exists across a skew boundary, use the readiness/provision APIs rather than catching errors:

  • JS: useBridgeReady(Contract) / isProvided(Contract)
  • Kotlin: isProvided(contract) / awaitProvided(contract, timeout)
  • Swift: BridgeKitRuntime.default.isProvided(Contract()) / awaitProvided(Contract(), timeoutMs:)