Skip to content

feat(merraria/mobile): iOS and Android on Calimero 1.0 - #702

Open
frdomovic wants to merge 4 commits into
mainfrom
feat/merraria-ios-core-1.0
Open

frdomovic wants to merge 4 commits into
mainfrom
feat/merraria-ios-core-1.0

Conversation

@frdomovic

@frdomovic frdomovic commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

What and why

Calimero core 1.0 removed /admin-api, /jsonrpc, relays, delegated execution and mero-auth. Clients talk to attested cluster nodes over the sealed channel and sign in with passkeys. This PR moves both native apps (apps/merraria/mobile/ios and apps/merraria/mobile/android) onto the 1.0 SDKs, and they now call the contract's component ABI as ported in #710. Both apps keep the same screens, flows and copy. Only apps/merraria/mobile/** changes.

SDK pins (they move when the SDK PRs merge)

  • iOS: swift-sdk 37c09f3f96e7d98440f6618eef8a0e83ddee8ebd, the head of swift-sdk#85. It's set in ios/project.yml, ios/MerrariaCore/Package.swift and Package.resolved.
  • Android: kotlin-sdk 61b65e9c0c87db8fbb2d3b2ce827603b0c84d5f9, the head of kotlin-sdk#68. It's set in android/kotlin-sdk.ref, using the same composite build as before.
  • Both pins move to the merge commits once swift-sdk#85 and kotlin-sdk#68 land.

Contract surface (#710)

  • Typed client: MerrariaClient is now typed by hand on both platforms (Contract/MerrariaClient.swift, contract/MerrariaClient.kt) and mirrors the web app's app/src/net/merraria.ts. abi-codegen can't read a component ABI yet, so the generated clients and scripts/regenerate.sh are gone.
    • Calls: createWorld, setTiles, join, heartbeat, leave.
    • Views: worldMeta, getOverrides, getPlayers.
  • Number types: seed, createdAt and every now are u32 seconds.
  • Paging: getOverrides is paged ({items, next}), and allOverrides() reads page by page.
  • Creating a world follows the web app's steps:
    1. Create an organization.
    2. Create the app instance in it. The component init() takes no arguments.
    3. Call createWorld(name, seed, now), which only the creator may run.
    • The old extra open team is gone, so mobile-made and web-made worlds have the same shape. Worlds an earlier build put in a team are still listed and opened.
  • Errors: APP_ERROR codes show as plain sentences: NoWorld, WorldExists, WorldFull {max} and TooManyEdits {max}.
  • Game page: unchanged. As feat(merraria): move to the component SDK, merod local and CalimeroClient #710 keeps it (host.ts V1_METHOD), the page still sends v1 names (get_overrides, set_tiles, world_meta, get_players).
    • BridgeDispatcher is the one place that maps those names to the component methods.
    • get_overrides reads every page and answers v1's single array.
    • now from the page is clamped to u32.
    • No game bundle rebuild was needed.
  • ABI check: ContractTests / ContractTest compare the method lists with logic/res/abi.json. They skip until feat(merraria): move to the component SDK, merod local and CalimeroClient #710 is on main, because the ABI there is still v1. I ran them against feat(merraria): move to the component SDK, merod local and CalimeroClient #710's abi.json locally and they pass.

Sign-in, invites, approvals

  • Sign in with Calimero Cloud: you enter the cluster's name (nodes come from the node directory, with failover) or a node URL, then a passkey: "Sign in with a passkey" or "Create an account".
  • Development node: you enter a merod local URL. The app sets allowMock and keeps a soft passkey per node, and the first sign-in creates the account. Android allows cleartext http to localhost, 127.0.0.1 and 10.0.2.2 in debug builds only.
  • Presets:
    • iOS: MeroNodeURL, MeroNodes and MeroAllowMock.
    • Android: -PmeroCluster, -PmeroNodeUrl and -PmeroAllowMock.
    • The wallet, registry and enrol settings are gone.
  • Android session: MeroAppSession is rebuilt for each cluster chosen. The activity sets session.passkey = PlatformPasskey(activity) in onCreate and clears it in onDestroy, so invite step-ups work.
  • Invites are org invite links. The payload is the SDKs' OrgInvitation, plus groupId for a world that lives in a team, and is the same on iOS and Android. Pre-1.0 links are refused (tested).
  • Approvals: the worlds list has a "Needs your approval" section. "Review" asks the node and shows the confirmation code first. It then opens the node's consent page in the system browser (a Custom Tab on Android), which returns to merraria://consent.
  • Errors in words: LoginRequired, WrongNode, Unavailable, ReleaseDeadline, ConsentStale, a cancelled passkey, a missing step-up passkey and failed attestation.
  • Vocabulary: "Organization", "Team" and "World (app instance)" appear behind Details.
  • Test backend: the in-memory backend (InMemoryAppBackend, RecordingContextContract) still backs every model and bridge test.

Verification (build-only)

  • iOS unit tests: swift test --package-path MerrariaCore ran 47 tests with 0 failures. One test is skipped: the ABI comparison, until feat(merraria): move to the component SDK, merod local and CalimeroClient #710 lands.
  • iOS build: xcodegen generate, then xcodebuild build -destination 'generic/platform=iOS' CODE_SIGNING_ALLOWED=NO: BUILD SUCCEEDED.
  • Android: ./gradlew ktlintCheck detekt testDebugUnitTest lint assembleDebug against the pinned kotlin-sdk all pass. That covers 43 JVM tests, 0 failures, with the same ABI comparison skipped.
  • Not run: no simulator or emulator, nothing against a live cluster, and no end-to-end run.

Gaps

  • Web invite links: the web app's invite links (<frontend>/?invite=<token>, a bare token) aren't accepted by the apps. Links the apps make use links.calimero.network, which the web launcher doesn't read either. Invites cross between iOS and Android, but not with the web yet.
  • Associated Domain and asset links: a real cluster's passkeys need iOS webcredentials:<rp-id> and Android Digital Asset Links for that cluster's rp-id. Neither is set yet.
  • Committed game bundle: game/www is still the last v1 build. It works through the bridge's name mapping. Rebuilding it from feat(merraria): move to the component SDK, merod local and CalimeroClient #710 is optional.

🤖 Generated with Claude Code

Pin swift-sdk to the head of its Calimero 1.0 branch (6c5f116, PR #85)
and adapt the iOS app: passkey sign-in and account creation with a
node-URL path (mock attestation for merod local), orgs/teams/app
instances in place of namespaces/groups/contexts, org invite tokens in
invitation links, pending releases and upgrades approved on the node's
consent page in the system browser, and the typed 1.0 errors in words.
Tests and README updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frdomovic frdomovic changed the title feat(merraria-ios): run on Calimero 1.0 feat(merraria/mobile-ios): native iOS app on Calimero 1.0 (mobile only, web app untouched) Oct 30, 2026
frdomovic and others added 2 commits November 2, 2026 11:10
- Both apps call the contract's component ABI (apps#710) through a
  hand-typed MerrariaClient per platform: camelCase methods, u32 seconds,
  paged getOverrides, and a world created as the web does (organization,
  app instance, then createWorld). The game page keeps its v1 method
  names; the bridge maps them. APP_ERROR codes read as words.
- Android moves from 0.x (relay, wallet) to kotlin-sdk#68: Calimero Cloud
  cluster by name or URL, or a development node with a soft passkey;
  passkey sign-in / create account; org invite links; approvals on the
  node's consent page with the confirmation code first.
- iOS moves to swift-sdk#85 at 37c09f3 with the same sign-in choices and
  the confirmation code before the consent page.
- Pins: swift-sdk 37c09f3f96e7d98440f6618eef8a0e83ddee8ebd,
  kotlin-sdk 61b65e9c0c87db8fbb2d3b2ce827603b0c84d5f9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frdomovic frdomovic changed the title feat(merraria/mobile-ios): native iOS app on Calimero 1.0 (mobile only, web app untouched) feat(merraria/mobile): iOS and Android on Calimero 1.0 Nov 2, 2026
iOS takes the swift-sdk release (exactVersion 0.5.0) instead of the
swift-sdk#85 head; Android's kotlin-sdk.ref moves to the v0.2.0 tag
commit (still a composite build: the release is on GitHub Packages,
not Maven Central).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chefsale pushed a commit that referenced this pull request Nov 2, 2026
The iOS/Android apps are ported to Calimero 1.0 and this component ABI
in their own PR, #702, which owns apps/merraria/mobile/ and depends on
this one. So mobile/README.md is restored to main's (the only mobile
file this PR had touched), and the app README, the root README row and
the native-host comments say the apps move in #702 instead of "not
ported". The bridge keeps v1 method names (V1_METHOD), which #702's
BridgeDispatcher maps onto the component ABI.

notReadyYet also matches `NoWorld` in an error's text, the shape a
bridged error arrives in, so the game waits for a just-founded world in
the apps as it does on the web.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D7MHpFosvnuf8dbWwRPVQi

chefsale commented Nov 2, 2026

Copy link
Copy Markdown
Member

Compatibility note from the merraria web port (#710), which this PR depends on: the contract methods, parameters, answer fields and error codes all match the clients here.

One thing to check on this side. The bundled game page (main.ts, notReadyYet) retries while the world is still being created, and it recognises that case by finding NoWorld in the error text. This PR's bridge turns that error into a user-facing message ("This world is still being created"). If the text the page receives no longer contains NoWorld, the page shows an error instead of waiting. Either keep the code NoWorld in the error text the bridge hands to the page, or pass the code separately.

Minor: Edit.t and Transform.sel are u8 in the contract but UInt32/UInt in the clients. A value above 255 would be rejected as BadArgs. The game never sends one.


Generated by Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants