expo 58.0.0-preview.4 → 58.0.0-preview.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +2 -2
- package/build/winter/runtime.js +6 -0
- package/build/winter/runtime.js.map +1 -1
- package/build/winter/runtime.native.d.ts +1 -1
- package/build/winter/runtime.native.js +1 -1
- package/build/winter/runtime.native.js.map +1 -1
- package/build/winter/setupReactNativeEnvironment.d.ts +1 -0
- package/build/winter/setupReactNativeEnvironment.js +5 -0
- package/build/winter/setupReactNativeEnvironment.js.map +1 -0
- package/build/winter/setupReactNativeEnvironment.macos.d.ts +1 -0
- package/build/winter/setupReactNativeEnvironment.macos.js +4 -0
- package/build/winter/setupReactNativeEnvironment.macos.js.map +1 -0
- package/bundledNativeModules.json +39 -39
- package/package.json +9 -9
- package/scripts/spm/__tests__/flavored-frameworks.test.js +161 -11
- package/scripts/spm/flavored-frameworks.js +28 -2
- package/scripts/spm/manifests.js +1 -1
- package/src/winter/__tests__/runtime.test.web.ts +35 -1
- package/src/winter/runtime.native.ts +1 -1
- package/src/winter/runtime.ts +7 -0
- package/src/winter/setupReactNativeEnvironment.macos.ts +2 -0
- package/src/winter/setupReactNativeEnvironment.ts +3 -0
- package/template.tgz +0 -0
package/android/build.gradle
CHANGED
|
@@ -10,7 +10,7 @@ buildscript {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
group = 'host.exp.exponent'
|
|
13
|
-
version = '58.0.0-preview.
|
|
13
|
+
version = '58.0.0-preview.6'
|
|
14
14
|
|
|
15
15
|
expoModule {
|
|
16
16
|
// We can't prebuild the module because it depends on the generated files.
|
|
@@ -21,7 +21,7 @@ android {
|
|
|
21
21
|
namespace "expo.core"
|
|
22
22
|
defaultConfig {
|
|
23
23
|
versionCode 1
|
|
24
|
-
versionName "58.0.0-preview.
|
|
24
|
+
versionName "58.0.0-preview.6"
|
|
25
25
|
consumerProguardFiles("proguard-rules.pro")
|
|
26
26
|
}
|
|
27
27
|
testOptions {
|
package/build/winter/runtime.js
CHANGED
|
@@ -7,5 +7,11 @@ Object.defineProperty(globalThis, '__ExpoImportMetaRegistry', {
|
|
|
7
7
|
enumerable: false,
|
|
8
8
|
writable: true
|
|
9
9
|
});
|
|
10
|
+
// Server rendering has no animation frames, but we need to stub these *temporarily* to work around
|
|
11
|
+
// react-native-worklets, see: https://github.com/software-mansion/react-native-reanimated/pull/10667
|
|
12
|
+
if (process.env.EXPO_SERVER && typeof globalThis.requestAnimationFrame !== 'function') {
|
|
13
|
+
globalThis.requestAnimationFrame = ()=>0;
|
|
14
|
+
globalThis.cancelAnimationFrame = ()=>{};
|
|
15
|
+
}
|
|
10
16
|
|
|
11
17
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["winter/runtime.ts"],"sourcesContent":[null],"names":["Object","defineProperty","globalThis","value","require","ImportMetaRegistry","enumerable","writable"],"mappings":"AAAA,OAAO,yBAAyB;AAChC,iGAAiG;AACjG,sFAAsF;AACtF,OAAO,wBAAwB;AAE/BA,OAAOC,cAAc,CAACC,YAAY,4BAA4B;IAC5DC,OAAOC,QAAQ,wBAAwBC,kBAAkB;IACzDC,YAAY;IACZC,UAAU;AACZ"}
|
|
1
|
+
{"version":3,"sources":["winter/runtime.ts"],"sourcesContent":[null],"names":["Object","defineProperty","globalThis","value","require","ImportMetaRegistry","enumerable","writable","process","env","EXPO_SERVER","requestAnimationFrame","cancelAnimationFrame"],"mappings":"AAAA,OAAO,yBAAyB;AAChC,iGAAiG;AACjG,sFAAsF;AACtF,OAAO,wBAAwB;AAE/BA,OAAOC,cAAc,CAACC,YAAY,4BAA4B;IAC5DC,OAAOC,QAAQ,wBAAwBC,kBAAkB;IACzDC,YAAY;IACZC,UAAU;AACZ;AAEA,mGAAmG;AACnG,qGAAqG;AACrG,IAAIC,QAAQC,GAAG,CAACC,WAAW,IAAI,OAAOR,WAAWS,qBAAqB,KAAK,YAAY;IACrFT,WAAWS,qBAAqB,GAAG,IAAM;IACzCT,WAAWU,oBAAoB,GAAG,KAAO;AAC3C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import '
|
|
1
|
+
import './setupReactNativeEnvironment';
|
|
2
2
|
import '../../types';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// https://wintercg.org/
|
|
3
3
|
// WARN(@kitten): We must ensure that the core react-native globals are initialized before ours
|
|
4
4
|
// Otherwise we're relying on `getModulesRunBeforeMainModule` which is unstable or can be missing
|
|
5
|
-
import '
|
|
5
|
+
import './setupReactNativeEnvironment';
|
|
6
6
|
import '../../types';
|
|
7
7
|
import { installAbortSignalPatch } from './AbortSignal';
|
|
8
8
|
import { installFormDataPatch } from './FormData';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["winter/runtime.native.ts"],"sourcesContent":[null],"names":["installAbortSignalPatch","installFormDataPatch","installGlobal","install","require","TextDecoder","TextDecoderStream","TextEncoderStream","URL","URLSearchParams","DOMException","ImportMetaRegistry","default","FormData","AbortSignal","Symbol","asyncIterator","for","useRnFetch","process","env","EXPO_PUBLIC_USE_RN_FETCH","globalThis","Headers","Error","fetch"],"mappings":"AAAA,wFAAwF;AACxF,wBAAwB;AAExB,+FAA+F;AAC/F,iGAAiG;AACjG,OAAO,
|
|
1
|
+
{"version":3,"sources":["winter/runtime.native.ts"],"sourcesContent":[null],"names":["installAbortSignalPatch","installFormDataPatch","installGlobal","install","require","TextDecoder","TextDecoderStream","TextEncoderStream","URL","URLSearchParams","DOMException","ImportMetaRegistry","default","FormData","AbortSignal","Symbol","asyncIterator","for","useRnFetch","process","env","EXPO_PUBLIC_USE_RN_FETCH","globalThis","Headers","Error","fetch"],"mappings":"AAAA,wFAAwF;AACxF,wBAAwB;AAExB,+FAA+F;AAC/F,iGAAiG;AACjG,OAAO,gCAAgC;AACvC,OAAO,cAAc;AACrB,SAASA,uBAAuB,QAAQ,gBAAgB;AACxD,SAASC,oBAAoB,QAAQ,aAAa;AAClD,SAASC,iBAAiBC,OAAO,QAAQ,kBAAkB;AAE3D,gDAAgD;AAChDA,QAAQ,eAAe,IAAMC,QAAQ,iBAAiBC,WAAW;AACjE,gEAAgE;AAChEF,QAAQ,qBAAqB,IAAMC,QAAQ,uBAAuBE,iBAAiB;AACnF,gEAAgE;AAChEH,QAAQ,qBAAqB,IAAMC,QAAQ,uBAAuBG,iBAAiB;AACnF,mCAAmC;AACnCJ,QAAQ,OAAO,IAAMC,QAAQ,SAASI,GAAG;AACzC,+CAA+C;AAC/CL,QAAQ,mBAAmB,IAAMC,QAAQ,SAASK,eAAe;AACjE,mDAAmD;AACnDN,QAAQ,gBAAgB,IAAMC,QAAQ,kBAAkBM,YAAY;AACpE,sCAAsC;AACtC,kDAAkD;AAElDP,QAAQ,4BAA4B,IAAMC,QAAQ,wBAAwBO,kBAAkB;AAE5F,8EAA8E;AAC9ER,QAAQ,mBAAmB,IAAMC,QAAQ,2BAA2BQ,OAAO;AAE3EX,qBAAqBY;AACrBb,wBAAwBc;AAExB,6CAA6C;AAC7C,+EAA+E;AAC/EC,OAAOC,aAAa,KAAKD,OAAOE,GAAG,CAAC;AAEpC,MAAMC,aACJC,QAAQC,GAAG,CAACC,wBAAwB,KAAK,OAAOF,QAAQC,GAAG,CAACC,wBAAwB,KAAK;AAE3F,IAAI,CAACH,YAAY;IACf,sEAAsE;IACtE,sEAAsE;IACtE,IAAI,CAACI,WAAWC,OAAO,EAAE;QACvB,MAAM,IAAIC,MACR;IAEJ;IACArB,QAAQ,SAAS,IAAMC,QAAQ,WAAWqB,KAAK;AACjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'react-native/setup-env';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["winter/setupReactNativeEnvironment.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA,gDAAgD;AAChD,8DAA8D;AAC9D,OAAO,yBAAyB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["winter/setupReactNativeEnvironment.macos.ts"],"sourcesContent":[null],"names":["require"],"mappings":"AAAA,oGAAoG;AACpGA,QAAQ"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"@expo/dom-webview": "~58.0.1",
|
|
3
3
|
"@expo/fingerprint": "~0.21.1",
|
|
4
|
-
"@expo/metro-runtime": "~58.0.
|
|
4
|
+
"@expo/metro-runtime": "~58.0.6",
|
|
5
5
|
"@expo/vector-icons": "^15.0.2",
|
|
6
|
-
"@expo/ui": "~58.0.
|
|
6
|
+
"@expo/ui": "~58.0.6",
|
|
7
7
|
"@react-native-async-storage/async-storage": "2.2.0",
|
|
8
8
|
"@react-native-community/datetimepicker": "9.2.1",
|
|
9
9
|
"@react-native-masked-view/masked-view": "0.3.2",
|
|
@@ -16,87 +16,87 @@
|
|
|
16
16
|
"eslint-config-expo": "~58.0.2",
|
|
17
17
|
"expo-analytics-amplitude": "~11.3.0",
|
|
18
18
|
"expo-app-auth": "~11.1.0",
|
|
19
|
-
"expo-app-intents": "~0.4.
|
|
19
|
+
"expo-app-intents": "~0.4.4",
|
|
20
20
|
"expo-app-loader-provider": "~8.0.0",
|
|
21
|
-
"expo-app-metrics": "~58.0.
|
|
21
|
+
"expo-app-metrics": "~58.0.6",
|
|
22
22
|
"expo-apple-authentication": "~58.0.1",
|
|
23
23
|
"expo-application": "~58.0.1",
|
|
24
|
-
"expo-asset": "~58.0.
|
|
25
|
-
"expo-audio": "~58.0.
|
|
26
|
-
"expo-auth-session": "~58.0.
|
|
27
|
-
"expo-background-fetch": "~58.0.
|
|
28
|
-
"expo-background-task": "~58.0.
|
|
24
|
+
"expo-asset": "~58.0.6",
|
|
25
|
+
"expo-audio": "~58.0.2",
|
|
26
|
+
"expo-auth-session": "~58.0.4",
|
|
27
|
+
"expo-background-fetch": "~58.0.6",
|
|
28
|
+
"expo-background-task": "~58.0.6",
|
|
29
29
|
"expo-battery": "~58.0.1",
|
|
30
30
|
"expo-blur": "~58.0.1",
|
|
31
31
|
"expo-brightness": "~58.0.0",
|
|
32
|
-
"expo-brownfield": "~58.0.
|
|
33
|
-
"expo-build-properties": "~58.0.
|
|
32
|
+
"expo-brownfield": "~58.0.6",
|
|
33
|
+
"expo-build-properties": "~58.0.6",
|
|
34
34
|
"expo-calendar": "~58.0.2",
|
|
35
|
-
"expo-camera": "~58.0.
|
|
35
|
+
"expo-camera": "~58.0.3",
|
|
36
36
|
"expo-cellular": "~58.0.0",
|
|
37
37
|
"expo-checkbox": "~58.0.1",
|
|
38
38
|
"expo-clipboard": "~58.0.1",
|
|
39
|
-
"expo-constants": "~58.0.
|
|
39
|
+
"expo-constants": "~58.0.6",
|
|
40
40
|
"expo-contacts": "~58.0.2",
|
|
41
41
|
"expo-crypto": "~58.0.2",
|
|
42
|
-
"expo-dev-client": "~58.0.
|
|
43
|
-
"expo-device": "~58.0.
|
|
44
|
-
"expo-document-picker": "~58.0.
|
|
42
|
+
"expo-dev-client": "~58.0.6",
|
|
43
|
+
"expo-device": "~58.0.2",
|
|
44
|
+
"expo-document-picker": "~58.0.1",
|
|
45
45
|
"expo-eas-client": "~58.0.0",
|
|
46
|
-
"expo-file-system": "~58.0.
|
|
46
|
+
"expo-file-system": "~58.0.1",
|
|
47
47
|
"expo-font": "~58.0.2",
|
|
48
48
|
"expo-gl": "~58.0.1",
|
|
49
|
-
"expo-glass-effect": "~58.0.
|
|
49
|
+
"expo-glass-effect": "~58.0.2",
|
|
50
50
|
"expo-google-app-auth": "~8.3.0",
|
|
51
51
|
"expo-haptics": "~58.0.1",
|
|
52
|
-
"expo-image": "~58.0.
|
|
52
|
+
"expo-image": "~58.0.5",
|
|
53
53
|
"expo-image-loader": "~58.0.1",
|
|
54
|
-
"expo-image-manipulator": "~58.0.
|
|
55
|
-
"expo-image-picker": "~58.0.
|
|
54
|
+
"expo-image-manipulator": "~58.0.7",
|
|
55
|
+
"expo-image-picker": "~58.0.6",
|
|
56
56
|
"expo-intent-launcher": "~58.0.0",
|
|
57
|
-
"expo-insights": "~58.0.
|
|
57
|
+
"expo-insights": "~58.0.6",
|
|
58
58
|
"expo-keep-awake": "~58.0.1",
|
|
59
59
|
"expo-linear-gradient": "~58.0.1",
|
|
60
|
-
"expo-linking": "~58.0.
|
|
60
|
+
"expo-linking": "~58.0.6",
|
|
61
61
|
"expo-local-authentication": "~58.0.0",
|
|
62
62
|
"expo-localization": "~58.0.1",
|
|
63
|
-
"expo-location": "~58.0.
|
|
63
|
+
"expo-location": "~58.0.6",
|
|
64
64
|
"expo-mail-composer": "~58.0.0",
|
|
65
65
|
"expo-manifests": "~58.0.0",
|
|
66
66
|
"expo-maps": "~58.0.2",
|
|
67
67
|
"expo-mcp": "~0.2.1",
|
|
68
|
-
"expo-media-library": "~58.0.
|
|
68
|
+
"expo-media-library": "~58.0.1",
|
|
69
69
|
"expo-mesh-gradient": "~58.0.1",
|
|
70
|
-
"expo-module-template": "~58.0.
|
|
71
|
-
"expo-modules-core": "~58.0.
|
|
70
|
+
"expo-module-template": "~58.0.3",
|
|
71
|
+
"expo-modules-core": "~58.0.6",
|
|
72
72
|
"expo-navigation-bar": "~58.0.1",
|
|
73
73
|
"expo-network": "~58.0.1",
|
|
74
|
-
"expo-notifications": "~58.0.
|
|
75
|
-
"expo-observe": "~58.0.
|
|
76
|
-
"expo-print": "~58.0.
|
|
74
|
+
"expo-notifications": "~58.0.6",
|
|
75
|
+
"expo-observe": "~58.0.8",
|
|
76
|
+
"expo-print": "~58.0.2",
|
|
77
77
|
"expo-live-photo": "~58.0.1",
|
|
78
|
-
"expo-router": "~58.0.
|
|
79
|
-
"expo-screen-capture": "~58.0.
|
|
78
|
+
"expo-router": "~58.0.7",
|
|
79
|
+
"expo-screen-capture": "~58.0.2",
|
|
80
80
|
"expo-screen-orientation": "~58.0.0",
|
|
81
81
|
"expo-secure-store": "~58.0.0",
|
|
82
82
|
"expo-sensors": "~58.0.0",
|
|
83
83
|
"expo-server": "~58.0.1",
|
|
84
|
-
"expo-sharing": "~58.0.
|
|
84
|
+
"expo-sharing": "~58.0.9",
|
|
85
85
|
"expo-sms": "~58.0.0",
|
|
86
86
|
"expo-speech": "~58.0.0",
|
|
87
87
|
"expo-splash-screen": "~58.0.1",
|
|
88
|
-
"expo-sqlite": "~58.0.
|
|
88
|
+
"expo-sqlite": "~58.0.5",
|
|
89
89
|
"expo-status-bar": "~58.0.1",
|
|
90
90
|
"expo-store-review": "~58.0.0",
|
|
91
91
|
"expo-symbols": "~58.0.2",
|
|
92
92
|
"expo-system-ui": "~58.0.2",
|
|
93
|
-
"expo-task-manager": "~58.0.
|
|
93
|
+
"expo-task-manager": "~58.0.7",
|
|
94
94
|
"expo-tracking-transparency": "~58.0.0",
|
|
95
|
-
"expo-updates": "~58.0.
|
|
95
|
+
"expo-updates": "~58.0.8",
|
|
96
96
|
"expo-video-thumbnails": "~58.0.0",
|
|
97
|
-
"expo-video": "~58.0.
|
|
98
|
-
"expo-web-browser": "~58.0.
|
|
99
|
-
"expo-widgets": "~58.0.
|
|
97
|
+
"expo-video": "~58.0.3",
|
|
98
|
+
"expo-web-browser": "~58.0.2",
|
|
99
|
+
"expo-widgets": "~58.0.6",
|
|
100
100
|
"jest-expo": "~58.0.3",
|
|
101
101
|
"lottie-react-native": "~7.5.0",
|
|
102
102
|
"react": "19.3.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo",
|
|
3
|
-
"version": "58.0.0-preview.
|
|
3
|
+
"version": "58.0.0-preview.6",
|
|
4
4
|
"description": "The Expo SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"expo"
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
},
|
|
201
201
|
"dependencies": {
|
|
202
202
|
"@babel/runtime": "^7.20.0",
|
|
203
|
-
"@expo/cli": "^58.0.
|
|
203
|
+
"@expo/cli": "^58.0.6",
|
|
204
204
|
"@expo/config": "~58.0.0",
|
|
205
205
|
"@expo/config-plugins": "~58.0.2",
|
|
206
206
|
"@expo/devtools": "~58.0.1",
|
|
@@ -213,23 +213,23 @@
|
|
|
213
213
|
"@expo/metro-config": "~58.0.4",
|
|
214
214
|
"@ungap/structured-clone": "^1.3.0",
|
|
215
215
|
"babel-preset-expo": "~58.0.4",
|
|
216
|
-
"expo-asset": "~58.0.
|
|
217
|
-
"expo-constants": "~58.0.
|
|
218
|
-
"expo-file-system": "~58.0.
|
|
216
|
+
"expo-asset": "~58.0.6",
|
|
217
|
+
"expo-constants": "~58.0.6",
|
|
218
|
+
"expo-file-system": "~58.0.1",
|
|
219
219
|
"expo-font": "~58.0.2",
|
|
220
220
|
"expo-keep-awake": "~58.0.1",
|
|
221
221
|
"expo-modules-autolinking": "~58.0.3",
|
|
222
|
-
"expo-modules-core": "~58.0.
|
|
222
|
+
"expo-modules-core": "~58.0.6",
|
|
223
223
|
"pretty-format": "^29.7.0",
|
|
224
224
|
"react-refresh": "^0.14.2",
|
|
225
225
|
"whatwg-url-minimum": "^0.2.0"
|
|
226
226
|
},
|
|
227
227
|
"devDependencies": {
|
|
228
228
|
"@expo/dom-webview": "58.0.1",
|
|
229
|
-
"@expo/metro-runtime": "58.0.
|
|
229
|
+
"@expo/metro-runtime": "58.0.6",
|
|
230
230
|
"@types/node": "^22.14.0",
|
|
231
231
|
"@types/react": "~19.3.0",
|
|
232
|
-
"expo-updates": "58.0.
|
|
232
|
+
"expo-updates": "58.0.8",
|
|
233
233
|
"npm-run-all2": "^8.0.4",
|
|
234
234
|
"react": "19.3.0",
|
|
235
235
|
"react-dom": "19.3.0",
|
|
@@ -269,7 +269,7 @@
|
|
|
269
269
|
"engines": {
|
|
270
270
|
"node": "^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0"
|
|
271
271
|
},
|
|
272
|
-
"gitHead": "
|
|
272
|
+
"gitHead": "8aeb4368d396d2d71a2fc8c652c4d1d4d53ed858",
|
|
273
273
|
"scripts": {
|
|
274
274
|
"build": "../expo-module-scripts/bin/expo-build src",
|
|
275
275
|
"clean": "rimraf build",
|
|
@@ -6,12 +6,16 @@ const os = require('os');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
|
+
FLAVORS,
|
|
9
10
|
prepareCompileInterfaces,
|
|
10
11
|
resolveFlavoredFramework,
|
|
11
12
|
stableFrameworkId,
|
|
12
13
|
validateFlavoredFramework,
|
|
13
14
|
} = require('../flavored-frameworks');
|
|
14
15
|
|
|
16
|
+
// GNU tar reads the `C:` in a Windows path as a remote hostname and fails to connect.
|
|
17
|
+
const itNotWindows = process.platform === 'win32' ? it.skip : it;
|
|
18
|
+
|
|
15
19
|
function makeXcframework(root, frameworkName, flavor, contents = flavor) {
|
|
16
20
|
const xcframework = path.join(root, flavor, `${frameworkName}.xcframework`);
|
|
17
21
|
const framework = path.join(xcframework, 'ios-arm64', `${frameworkName}.framework`);
|
|
@@ -33,6 +37,13 @@ function makeXcframework(root, frameworkName, flavor, contents = flavor) {
|
|
|
33
37
|
return xcframework;
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
function packTarball(sourceDir, tarballPath, entries, { preservePaths = false } = {}) {
|
|
41
|
+
fs.mkdirSync(path.dirname(tarballPath), { recursive: true });
|
|
42
|
+
const flags = preservePaths ? ['-czPf'] : ['-czf'];
|
|
43
|
+
execFileSync('tar', [...flags, tarballPath, '-C', sourceDir, ...entries]);
|
|
44
|
+
return tarballPath;
|
|
45
|
+
}
|
|
46
|
+
|
|
36
47
|
function declaration(frameworkName, debug, release, overrides = {}) {
|
|
37
48
|
return {
|
|
38
49
|
id: stableFrameworkId(frameworkName),
|
|
@@ -131,21 +142,16 @@ describe('artifact preparation', () => {
|
|
|
131
142
|
).toThrow('missing release');
|
|
132
143
|
});
|
|
133
144
|
|
|
134
|
-
|
|
145
|
+
itNotWindows('expands both bundled tarballs before returning absolute flavor paths', () => {
|
|
135
146
|
const output = path.join(root, 'test-package', 'output');
|
|
136
147
|
for (const flavor of ['debug', 'release']) {
|
|
137
148
|
const source = path.join(root, `source-${flavor}`);
|
|
138
149
|
makeXcframework(source, 'ExpoPair', flavor);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
path.join(tarballDir, 'ExpoPair.tar.gz'),
|
|
145
|
-
'-C',
|
|
146
|
-
sourceDir,
|
|
147
|
-
'ExpoPair.xcframework',
|
|
148
|
-
]);
|
|
150
|
+
packTarball(
|
|
151
|
+
path.join(source, flavor),
|
|
152
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
153
|
+
['ExpoPair.xcframework']
|
|
154
|
+
);
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
const result = resolveFlavoredFramework({
|
|
@@ -167,6 +173,150 @@ describe('artifact preparation', () => {
|
|
|
167
173
|
expect(fs.existsSync(path.join(result.flavors.release, 'Info.plist'))).toBe(true);
|
|
168
174
|
});
|
|
169
175
|
|
|
176
|
+
it('accepts a tarball that also bundles a SwiftPM dependency xcframework', () => {
|
|
177
|
+
const output = path.join(root, 'test-package', 'output');
|
|
178
|
+
for (const flavor of FLAVORS) {
|
|
179
|
+
const source = path.join(root, `source-${flavor}`);
|
|
180
|
+
makeXcframework(source, 'ExpoPair', flavor);
|
|
181
|
+
makeXcframework(source, 'Lottie', flavor);
|
|
182
|
+
packTarball(
|
|
183
|
+
path.join(source, flavor),
|
|
184
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
185
|
+
['ExpoPair.xcframework', 'Lottie.xcframework']
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const result = resolveFlavoredFramework({
|
|
190
|
+
packageName: 'test-package',
|
|
191
|
+
moduleRoot: path.join(root, 'module'),
|
|
192
|
+
frameworkName: 'ExpoPair',
|
|
193
|
+
cacheDir: path.join(root, 'cache'),
|
|
194
|
+
});
|
|
195
|
+
expect(result.flavors).toEqual({
|
|
196
|
+
debug: path.join(root, 'cache', 'expo-pair', 'debug', 'ExpoPair.xcframework'),
|
|
197
|
+
release: path.join(root, 'cache', 'expo-pair', 'release', 'ExpoPair.xcframework'),
|
|
198
|
+
});
|
|
199
|
+
expect(fs.existsSync(path.join(result.flavors.debug, 'Info.plist'))).toBe(true);
|
|
200
|
+
expect(
|
|
201
|
+
fs.existsSync(path.join(root, 'cache', 'expo-pair', 'debug', 'Lottie.xcframework'))
|
|
202
|
+
).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('rejects a tarball holding an entry outside an xcframework root', () => {
|
|
206
|
+
const output = path.join(root, 'test-package', 'output');
|
|
207
|
+
for (const flavor of FLAVORS) {
|
|
208
|
+
const source = path.join(root, `source-${flavor}`);
|
|
209
|
+
makeXcframework(source, 'ExpoPair', flavor);
|
|
210
|
+
fs.writeFileSync(path.join(source, flavor, 'README.md'), 'stray');
|
|
211
|
+
packTarball(
|
|
212
|
+
path.join(source, flavor),
|
|
213
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
214
|
+
['ExpoPair.xcframework', 'README.md']
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
expect(() =>
|
|
219
|
+
resolveFlavoredFramework({
|
|
220
|
+
packageName: 'test-package',
|
|
221
|
+
moduleRoot: path.join(root, 'module'),
|
|
222
|
+
frameworkName: 'ExpoPair',
|
|
223
|
+
cacheDir: path.join(root, 'cache'),
|
|
224
|
+
})
|
|
225
|
+
).toThrow("'README.md' is not part of an .xcframework");
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('rejects a tarball that never contains the requested framework', () => {
|
|
229
|
+
const output = path.join(root, 'test-package', 'output');
|
|
230
|
+
for (const flavor of FLAVORS) {
|
|
231
|
+
const source = path.join(root, `source-${flavor}`);
|
|
232
|
+
makeXcframework(source, 'Lottie', flavor);
|
|
233
|
+
packTarball(
|
|
234
|
+
path.join(source, flavor),
|
|
235
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
236
|
+
['Lottie.xcframework']
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
expect(() =>
|
|
241
|
+
resolveFlavoredFramework({
|
|
242
|
+
packageName: 'test-package',
|
|
243
|
+
moduleRoot: path.join(root, 'module'),
|
|
244
|
+
frameworkName: 'ExpoPair',
|
|
245
|
+
cacheDir: path.join(root, 'cache'),
|
|
246
|
+
})
|
|
247
|
+
).toThrow('does not contain ExpoPair.xcframework');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('rejects a tarball whose member escapes through an absolute path', () => {
|
|
251
|
+
const output = path.join(root, 'test-package', 'output');
|
|
252
|
+
for (const flavor of FLAVORS) {
|
|
253
|
+
const source = path.join(root, `source-${flavor}`);
|
|
254
|
+
const xcframework = makeXcframework(source, 'ExpoPair', flavor);
|
|
255
|
+
packTarball(
|
|
256
|
+
path.join(source, flavor),
|
|
257
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
258
|
+
[xcframework],
|
|
259
|
+
{ preservePaths: true }
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
expect(() =>
|
|
264
|
+
resolveFlavoredFramework({
|
|
265
|
+
packageName: 'test-package',
|
|
266
|
+
moduleRoot: path.join(root, 'module'),
|
|
267
|
+
frameworkName: 'ExpoPair',
|
|
268
|
+
cacheDir: path.join(root, 'cache'),
|
|
269
|
+
})
|
|
270
|
+
).toThrow(/holds the unsafe path '\/.*ExpoPair\.xcframework/);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("rejects a tarball whose member escapes through '..'", () => {
|
|
274
|
+
const output = path.join(root, 'test-package', 'output');
|
|
275
|
+
for (const flavor of FLAVORS) {
|
|
276
|
+
const source = path.join(root, `source-${flavor}`);
|
|
277
|
+
const xcframework = makeXcframework(source, 'ExpoPair', flavor);
|
|
278
|
+
packTarball(
|
|
279
|
+
xcframework,
|
|
280
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
281
|
+
['../ExpoPair.xcframework'],
|
|
282
|
+
{ preservePaths: true }
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
expect(() =>
|
|
287
|
+
resolveFlavoredFramework({
|
|
288
|
+
packageName: 'test-package',
|
|
289
|
+
moduleRoot: path.join(root, 'module'),
|
|
290
|
+
frameworkName: 'ExpoPair',
|
|
291
|
+
cacheDir: path.join(root, 'cache'),
|
|
292
|
+
})
|
|
293
|
+
).toThrow("holds the unsafe path '../ExpoPair.xcframework");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('rejects a root named only .xcframework', () => {
|
|
297
|
+
const output = path.join(root, 'test-package', 'output');
|
|
298
|
+
for (const flavor of FLAVORS) {
|
|
299
|
+
const source = path.join(root, `source-${flavor}`);
|
|
300
|
+
makeXcframework(source, 'ExpoPair', flavor);
|
|
301
|
+
fs.mkdirSync(path.join(source, flavor, '.xcframework'), { recursive: true });
|
|
302
|
+
fs.writeFileSync(path.join(source, flavor, '.xcframework', 'Info.plist'), '<plist/>');
|
|
303
|
+
packTarball(
|
|
304
|
+
path.join(source, flavor),
|
|
305
|
+
path.join(output, flavor, 'xcframeworks', 'ExpoPair.tar.gz'),
|
|
306
|
+
['ExpoPair.xcframework', '.xcframework']
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
expect(() =>
|
|
311
|
+
resolveFlavoredFramework({
|
|
312
|
+
packageName: 'test-package',
|
|
313
|
+
moduleRoot: path.join(root, 'module'),
|
|
314
|
+
frameworkName: 'ExpoPair',
|
|
315
|
+
cacheDir: path.join(root, 'cache'),
|
|
316
|
+
})
|
|
317
|
+
).toThrow('is not part of an .xcframework');
|
|
318
|
+
});
|
|
319
|
+
|
|
170
320
|
it('produces byte-identical compile interfaces regardless of declaration order', () => {
|
|
171
321
|
const aDebug = makeXcframework(root, 'ExpoA', 'a-debug', 'a');
|
|
172
322
|
const aRelease = makeXcframework(root, 'ExpoA', 'a-release', 'a');
|
|
@@ -57,6 +57,12 @@ function artifactBaseDirs(packageName, moduleRoot) {
|
|
|
57
57
|
return Array.from(new Set(bases));
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* A flavor tarball holds one xcframework root per product the prebuild packed:
|
|
62
|
+
* the module itself plus any SwiftPM dependency bundled with it (for example
|
|
63
|
+
* Lottie.xcframework inside lottie-react-native). Anything else is either an
|
|
64
|
+
* unrelated archive or an extraction escape.
|
|
65
|
+
*/
|
|
60
66
|
function validateTarEntries(tarballPath, frameworkName) {
|
|
61
67
|
const expectedRoot = `${frameworkName}.xcframework`;
|
|
62
68
|
const listing = execFileSync('tar', ['-tzf', tarballPath], {
|
|
@@ -70,13 +76,33 @@ function validateTarEntries(tarballPath, frameworkName) {
|
|
|
70
76
|
if (entries.length === 0) {
|
|
71
77
|
throw new Error(`[expo-spm-plugin] ${tarballPath} is empty`);
|
|
72
78
|
}
|
|
79
|
+
const roots = new Set();
|
|
73
80
|
for (const entry of entries) {
|
|
74
81
|
const parts = entry.split('/');
|
|
75
|
-
if (path.isAbsolute(entry) || parts.includes('..')
|
|
82
|
+
if (path.isAbsolute(entry) || parts.includes('..')) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`[expo-spm-plugin] ${tarballPath} holds the unsafe path '${entry}'. Extracting it would ` +
|
|
85
|
+
'write outside the plugin cache, so the archive is not a precompiled Expo artifact. ' +
|
|
86
|
+
'Delete it and rebuild or re-download the precompiled module.'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (!/.+\.xcframework$/.test(parts[0])) {
|
|
76
90
|
throw new Error(
|
|
77
|
-
`[expo-spm-plugin] ${tarballPath}
|
|
91
|
+
`[expo-spm-plugin] in ${tarballPath}, '${entry}' is not part of an .xcframework. ` +
|
|
92
|
+
'A flavor tarball holds only XCFramework directories, so this archive was packed by ' +
|
|
93
|
+
'something other than the Expo prebuild pipeline. Delete it and rebuild or ' +
|
|
94
|
+
're-download the precompiled module.'
|
|
78
95
|
);
|
|
79
96
|
}
|
|
97
|
+
roots.add(parts[0]);
|
|
98
|
+
}
|
|
99
|
+
if (!roots.has(expectedRoot)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`[expo-spm-plugin] ${tarballPath} does not contain ${expectedRoot}; it holds ` +
|
|
102
|
+
`${Array.from(roots).sort().join(', ')}. The tarball belongs to a different product or ` +
|
|
103
|
+
'the prebuild for this one did not finish. Rebuild the module with the Expo prebuild ' +
|
|
104
|
+
'pipeline, or re-download its precompiled artifacts.'
|
|
105
|
+
);
|
|
80
106
|
}
|
|
81
107
|
}
|
|
82
108
|
|
package/scripts/spm/manifests.js
CHANGED
|
@@ -496,7 +496,7 @@ function resolveTargetPaths(targets, moduleRoot) {
|
|
|
496
496
|
continue;
|
|
497
497
|
}
|
|
498
498
|
const inferred =
|
|
499
|
-
PREDEFINED_SOURCE_DIRS.map((dir) => path.join(dir, target.name)).find((rel) =>
|
|
499
|
+
PREDEFINED_SOURCE_DIRS.map((dir) => path.posix.join(dir, target.name)).find((rel) =>
|
|
500
500
|
fs.existsSync(path.join(moduleRoot, rel))
|
|
501
501
|
) ??
|
|
502
502
|
(singleTarget
|
|
@@ -18,7 +18,41 @@ function setCurrentScript(src: string | null) {
|
|
|
18
18
|
// The web test project runs this file in jsdom, the node project on the server.
|
|
19
19
|
// `getBundleUrl` reads `document.currentScript`, so only assert in the browser.
|
|
20
20
|
if (typeof window === 'undefined') {
|
|
21
|
-
|
|
21
|
+
// The jsdom environment provides animation frames, which a server environment such as Node.js
|
|
22
|
+
// does not, so remove them for each test.
|
|
23
|
+
const jsdomRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
24
|
+
const jsdomCancelAnimationFrame = globalThis.cancelAnimationFrame;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
// @ts-expect-error Simulates a server environment without animation frames.
|
|
28
|
+
delete globalThis.requestAnimationFrame;
|
|
29
|
+
// @ts-expect-error Simulates a server environment without animation frames.
|
|
30
|
+
delete globalThis.cancelAnimationFrame;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
globalThis.requestAnimationFrame = jsdomRequestAnimationFrame;
|
|
35
|
+
globalThis.cancelAnimationFrame = jsdomCancelAnimationFrame;
|
|
36
|
+
jest.resetModules();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('stubs requestAnimationFrame on the server, never running callbacks', async () => {
|
|
40
|
+
require('../runtime');
|
|
41
|
+
|
|
42
|
+
const callback = jest.fn();
|
|
43
|
+
globalThis.requestAnimationFrame(callback);
|
|
44
|
+
globalThis.cancelAnimationFrame(0);
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
46
|
+
expect(callback).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('keeps an existing requestAnimationFrame on the server', () => {
|
|
50
|
+
const existingRequestAnimationFrame = jest.fn();
|
|
51
|
+
globalThis.requestAnimationFrame = existingRequestAnimationFrame;
|
|
52
|
+
require('../runtime');
|
|
53
|
+
|
|
54
|
+
expect(globalThis.requestAnimationFrame).toBe(existingRequestAnimationFrame);
|
|
55
|
+
});
|
|
22
56
|
} else {
|
|
23
57
|
afterEach(() => {
|
|
24
58
|
setCurrentScript(null);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// WARN(@kitten): We must ensure that the core react-native globals are initialized before ours
|
|
5
5
|
// Otherwise we're relying on `getModulesRunBeforeMainModule` which is unstable or can be missing
|
|
6
|
-
import '
|
|
6
|
+
import './setupReactNativeEnvironment';
|
|
7
7
|
import '../../types';
|
|
8
8
|
import { installAbortSignalPatch } from './AbortSignal';
|
|
9
9
|
import { installFormDataPatch } from './FormData';
|
package/src/winter/runtime.ts
CHANGED
|
@@ -8,3 +8,10 @@ Object.defineProperty(globalThis, '__ExpoImportMetaRegistry', {
|
|
|
8
8
|
enumerable: false,
|
|
9
9
|
writable: true,
|
|
10
10
|
});
|
|
11
|
+
|
|
12
|
+
// Server rendering has no animation frames, but we need to stub these *temporarily* to work around
|
|
13
|
+
// react-native-worklets, see: https://github.com/software-mansion/react-native-reanimated/pull/10667
|
|
14
|
+
if (process.env.EXPO_SERVER && typeof globalThis.requestAnimationFrame !== 'function') {
|
|
15
|
+
globalThis.requestAnimationFrame = () => 0;
|
|
16
|
+
globalThis.cancelAnimationFrame = () => {};
|
|
17
|
+
}
|
package/template.tgz
CHANGED
|
Binary file
|