Skip to content

Add offline-mode init via DITTO_OFFLINE_LICENSE_TOKEN across quickstarts#292

Closed
Brian Plattenburg (bplattenburg) wants to merge 8 commits into
mainfrom
add-offline-mode-license-token
Closed

Add offline-mode init via DITTO_OFFLINE_LICENSE_TOKEN across quickstarts#292
Brian Plattenburg (bplattenburg) wants to merge 8 commits into
mainfrom
add-offline-mode-license-token

Conversation

@bplattenburg
Copy link
Copy Markdown
Member

Summary

Every quickstart now reads DITTO_OFFLINE_LICENSE_TOKEN from the repo-root .env. When the value is non-empty (after trimming whitespace), the app initializes Ditto in offline-only mode (SmallPeersOnly on v5 SDKs, OfflinePlayground on v4) and calls setOfflineOnlyLicenseToken with the trimmed value. When empty/unset, the existing Online Playground flow runs unchanged.

Touched 17 apps (10 v5, 7 v4). v4 apps keep disableSyncWithV3() and the DQL strict-mode ALTER SYSTEM call in both branches; v5 SDKs no longer expose those. cpp-tui is intentionally skipped (handed off separately). android-cpp and java-spring have no committed source and are out of scope.

Unit tests for the mode-selection contract added in the 7 apps with a unit-test runner already wired up: android-java, android-kotlin, dotnet-tui, flutter_app, java-server, react-native, rust-tui. Tests cover null / empty / whitespace-only / non-empty token cases.

Follow-up & related

Test plan

  • All affected apps' build commands pass locally per their respective toolchains (see commit 78c2eaf notes for the offline-mode build fixes found during validation)
  • Unit tests pass for the 7 apps with test runners
  • Reviewer to spot-check at least one v4 and one v5 app end-to-end: set DITTO_OFFLINE_LICENSE_TOKEN in .env, run the app, confirm Ditto initializes offline-only and tasks sync against a second peer over LAN

Every quickstart now reads DITTO_OFFLINE_LICENSE_TOKEN from the repo-root
.env. When the value is non-empty (after trimming whitespace), the app
initializes Ditto in offline-only mode using the SDK's SmallPeersOnly /
OfflinePlayground identity and calls setOfflineOnlyLicenseToken with the
trimmed value. When empty/unset, the existing Online Playground flow
runs unchanged.

Touched 17 apps (10 v5, 7 v4). v4 apps keep disableSyncWithV3() and the
DQL strict-mode ALTER SYSTEM call in both branches; v5 SDKs no longer
expose those, so they don't appear. cpp-tui is intentionally skipped
(handed off separately). android-cpp and java-spring have no committed
source and are out of scope.

Unit tests for the mode-selection contract added in the 7 apps that
already have a unit-test runner wired up: android-java, android-kotlin,
dotnet-tui, flutter_app, java-server, react-native, rust-tui. Tests
exercise null / empty / whitespace-only / non-empty token cases. The
other 10 apps either have no test runner today or have integration / UI
test scaffolds rather than unit test ones; adding test infrastructure
for those is out of scope.

A docs/offline-mode-followup-for-v5-migration-prs.md note describes how
to re-apply this branch on top of @biozal's four open v5 migration PRs
(#239 Android Kotlin, #237 Flutter, #267 React Native, #242 Rust TUI),
since those PRs rewrite the init files this change touches.
Three follow-ups to the previous commit, surfaced by running the native
builds locally:

- java-server and kotlin-multiplatform's secrets generators emit
  DittoSecretsConfiguration fields from .env keys. If the user's local
  .env predates this PR and lacks DITTO_OFFLINE_LICENSE_TOKEN, the
  generated class is missing the field and the consuming code fails to
  compile. Both generators now default the key to "" when absent.

- swift/buildEnv.sh has the same shape: it generates Env.swift from .env
  lines, so a pre-existing .env without DITTO_OFFLINE_LICENSE_TOKEN
  produces an Env type without the property. The script now emits an
  empty default when the key is missing.

- The v5 Java SDK's Ditto.setOfflineOnlyLicenseToken(String) is declared
  to throw DittoException. java-server's call now wraps it and rethrows
  as RuntimeException to keep the Spring DittoService constructor
  signature unchanged.

Verified locally after these fixes: swift xcodebuild, java-server tests,
kotlin-multiplatform commonMain + Android target compile.
The DittoDotNetTasksConsole project has <Nullable>disable</Nullable>, so the
'string?' parameter triggered CS8632 on .NET 10. IsNullOrWhiteSpace handles
null safely; drop the '?' to keep the project's nullable mode consistent.
This is a transient planning doc; once all four migrations have the
offline branch re-applied, the file itself should be deleted in the
final follow-up PR. Document that explicitly so a future reader doesn't
take a stale plan as durable docs.
CI Lint runs `dotnet format --verify-no-changes` and flagged the indentation
of the LoginAsync arguments after the previous change wrapped the call in
an if/else. `dotnet format` reformats them; commit the result.
IntegrationTest.csproj pulls in TasksApp/TasksPeer.cs via a <Compile
Include> link. TasksPeer.cs now references DittoMode, which lives in
TasksApp/DittoMode.cs and wasn't being linked. The main TasksApp built
fine because it picks up everything in its own folder; only IntegrationTest
broke, and only on Windows (the only platform that builds the
net10.0-windows target).
…line-only builds

Two themes from the bot review on PR #282:

A) Online-mode init didn't validate that the playground/auth/websocket
   values were non-empty before using them, so a misconfigured online run
   would fail with an opaque UriFormatException or similar instead of a
   clear "DITTO_AUTH_URL is required" message. Added a validation block at
   the start of init in:
   - rust-tui  (anyhow::bail with the list of missing vars)
   - flutter_app  (Exception with the list of missing vars)
   - dotnet-tui, dotnet-winforms, dotnet-maui  (InvalidOperationException)
   The pattern mirrors what electron and dotnet-winforms-net48 already do.

B) The Android build.gradle.kts loadEnvProperties fallback (used when .env
   is absent) unconditionally required all playground vars from the
   process env, blocking offline-only build configurations. Both
   android-java and android-kotlin now only require DITTO_APP_ID, plus
   either DITTO_OFFLINE_LICENSE_TOKEN or the full playground trio.

Also picked up dotnet format whitespace on MauiProgram.cs after the
SetupDitto edit; auto-fixed.
Mirrors the same removal proposed against main. v5's serverConnect()
already derives the cloud-sync transport from the endpoint URL, and the
SDK enables LAN+mDNS by default — so the explicit websocketUrls() and
peerToPeer() blocks are dead weight. Re-enabling BLE on a server peer
is wrong regardless of online/offline mode.

This makes the offline-branch diff smaller: the updateTransportConfig()
call disappears entirely on both branches, leaving only the
serverConnect-vs-smallPeersOnlyConnect split as the offline-specific
change.
@bplattenburg
Copy link
Copy Markdown
Member Author

Opened in error — reverting. Offline branch stays pushed but isn't ready for review yet.

@bplattenburg Brian Plattenburg (bplattenburg) review requested due to automatic review settings May 27, 2026 20:36
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.

1 participant