Skip to content

Commit a577dee

Browse files
committed
fix(ota): include Expo config in manifests
1 parent e3e15fa commit a577dee

2 files changed

Lines changed: 124 additions & 3 deletions

File tree

apps/ota/src/__tests__/manifest.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,41 @@ describe("buildManifest", () => {
8585

8686
expect(first.id).toBe(second.id)
8787
})
88+
89+
it("includes the embedded Expo config needed by expo-constants after an OTA launch", () => {
90+
const manifest = buildManifest(createRelease(), {
91+
origin: "https://ota.folo.is",
92+
platform: "ios",
93+
})
94+
95+
expect(manifest.extra).toMatchObject({
96+
expoClient: {
97+
name: "Folo",
98+
slug: "follow",
99+
owner: "follow",
100+
scheme: ["follow", "folo"],
101+
version: "0.4.2",
102+
runtimeVersion: "0.4.1",
103+
updates: {
104+
url: "https://ota.folo.is/manifest",
105+
requestHeaders: {
106+
"expo-channel-name": "production",
107+
},
108+
},
109+
ios: {
110+
bundleIdentifier: "is.follow",
111+
},
112+
android: {
113+
package: "is.follow",
114+
},
115+
extra: {
116+
eas: {
117+
projectId: "a6335b14-fb84-45aa-ba80-6f6ab8926920",
118+
},
119+
},
120+
},
121+
})
122+
})
88123
})
89124

90125
describe("/manifest", () => {

apps/ota/src/lib/manifest.ts

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,43 @@ import type { OtaPlatform, OtaPlatformPayload, OtaProjectedPlatforms, OtaRelease
55

66
type PlatformPayload = OtaPlatformPayload
77
type PlatformAsset = PlatformPayload["launchAsset"] | PlatformPayload["assets"][number]
8+
type MobileExpoClientConfig = {
9+
name: string
10+
slug: string
11+
owner: string
12+
version: string
13+
runtimeVersion: string
14+
orientation: "portrait"
15+
scheme: string[]
16+
userInterfaceStyle: "automatic"
17+
updates: {
18+
url: string
19+
requestHeaders: {
20+
"expo-channel-name": string
21+
}
22+
codeSigningMetadata: {
23+
keyid: string
24+
alg: string
25+
}
26+
checkAutomatically: "NEVER"
27+
}
28+
ios: {
29+
bundleIdentifier: string
30+
supportsTablet: boolean
31+
usesAppleSignIn: boolean
32+
}
33+
android: {
34+
package: string
35+
}
36+
extra: {
37+
eas: {
38+
projectId: string
39+
}
40+
}
41+
}
42+
43+
const MOBILE_UPDATE_URL = "https://ota.folo.is/manifest"
44+
const MOBILE_EAS_PROJECT_ID = "a6335b14-fb84-45aa-ba80-6f6ab8926920"
845

946
export interface ManifestAsset {
1047
key: string
@@ -26,6 +63,7 @@ export interface OtaManifest {
2663
}
2764
extra: {
2865
product: OtaRelease["product"]
66+
expoClient?: MobileExpoClientConfig
2967
}
3068
}
3169

@@ -62,9 +100,7 @@ export function buildManifest(
62100
channel: release.channel,
63101
releaseVersion: release.releaseVersion,
64102
},
65-
extra: {
66-
product: release.product,
67-
},
103+
extra: buildManifestExtra(release),
68104
}
69105
}
70106

@@ -142,6 +178,56 @@ function toExpoAssetIdentity(path: string, contentType: string) {
142178
}
143179
}
144180

181+
function buildManifestExtra(release: OtaRelease): OtaManifest["extra"] {
182+
const extra: OtaManifest["extra"] = {
183+
product: release.product,
184+
}
185+
186+
if (release.product === "mobile") {
187+
// Expo Updates hydrates Constants.expoConfig from extra.expoClient after an OTA launch.
188+
extra.expoClient = buildMobileExpoClientConfig(release)
189+
}
190+
191+
return extra
192+
}
193+
194+
function buildMobileExpoClientConfig(release: Extract<OtaRelease, { product: "mobile" }>) {
195+
return {
196+
name: "Folo",
197+
slug: "follow",
198+
owner: "follow",
199+
version: release.releaseVersion,
200+
runtimeVersion: release.runtimeVersion,
201+
orientation: "portrait",
202+
scheme: ["follow", "folo"],
203+
userInterfaceStyle: "automatic",
204+
updates: {
205+
url: MOBILE_UPDATE_URL,
206+
requestHeaders: {
207+
"expo-channel-name": release.channel,
208+
},
209+
codeSigningMetadata: {
210+
keyid: "main",
211+
alg: "rsa-v1_5-sha256",
212+
},
213+
checkAutomatically: "NEVER",
214+
},
215+
ios: {
216+
bundleIdentifier: "is.follow",
217+
supportsTablet: true,
218+
usesAppleSignIn: true,
219+
},
220+
android: {
221+
package: "is.follow",
222+
},
223+
extra: {
224+
eas: {
225+
projectId: MOBILE_EAS_PROJECT_ID,
226+
},
227+
},
228+
} satisfies MobileExpoClientConfig
229+
}
230+
145231
function inferExtensionFromContentType(contentType: string) {
146232
switch (contentType) {
147233
case "application/javascript": {

0 commit comments

Comments
 (0)