Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/mobile-eas-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ name: Mobile EAS Production
# Store stays a manual App Store Connect step.
# 2. OTA: publish a production-channel update for each platform where at
# least one finished production build matches the current native
# fingerprint. Old-version binaries with a matching fingerprint receive
# it too. When native drift means no binary could install the update,
# fingerprint. Older binaries of the same major version with a matching
# fingerprint receive it too; the major version is part of the
# fingerprint (apps/mobile/fingerprint.config.js), so a new major never
# reaches the previous major's store binaries over the air. When native
# drift means no binary could install the update,
# it is skipped and flagged in the job summary instead of published
# into the void.
# workflow_dispatch remains as a manual override for both modes (e.g. to
Expand Down
18 changes: 18 additions & 0 deletions apps/mobile/fingerprint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @ts-check
const fs = require("node:fs");
const path = require("node:path");

// Expo's fingerprint ignores the app version, so binaries of different majors
// share a runtime version whenever native code is unchanged, and a production
// OTA from main would reach every older store binary. Hashing the major
// version keeps each major's OTAs on its own binaries: a new major reaches
// users only once its store build is promoted.
const appConfig = fs.readFileSync(path.join(__dirname, "app.config.ts"), "utf8");
const majorVersion = appConfig.match(/^ {2}version: "(\d+)\./m)?.[1];
if (!majorVersion) {
throw new Error("fingerprint.config.js could not read the app version from app.config.ts");
}

module.exports = {
extraSources: [{ type: "contents", id: "appMajorVersion", contents: majorVersion }],
};
3 changes: 2 additions & 1 deletion knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@
"ignoreIssues": { "src/components/ui/*.tsx": ["exports", "nsExports", "duplicates"] },
},
"apps/mobile": {
// Expo loads plugins by string; Metro embeds the browser entry in the native WebView.
// Expo loads plugins and the fingerprint config by string; Metro embeds the browser entry in the native WebView.
"entry": [
"index.ts!",
"fingerprint.config.js",
"plugins/*.cjs",
"scripts/generate-device-stream.mts",
"src/features/devices/device-stream.browser.ts!",
Expand Down
Loading