miaoda-expo-devkit 0.1.1-beta.98 → 0.1.1-dev.development-build.1
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/README.md +154 -110
- package/dist/babel/plugin-lucide-react-native.js +184 -184
- package/dist/cli/lint.js +317 -309
- package/dist/index.d.mts +1 -110
- package/dist/index.d.ts +1 -110
- package/dist/index.js +0 -159
- package/dist/index.mjs +0 -132
- package/dist/metro.d.mts +25 -5
- package/dist/metro.d.ts +25 -5
- package/dist/metro.js +49 -18
- package/dist/metro.mjs +50 -20
- package/dist/rules/no-expo-audio-compat.js +2041 -0
- package/dist/rules/no-expo-video-compat.js +90 -90
- package/dist/stubs/entry-inject.js +0 -2
- package/dist/stubs/expo-native-wechat-stub.js +116 -0
- package/dist/stubs/expo-router-entry-native-stub.js +4 -0
- package/dist/stubs/i18n/en.js +16 -1
- package/dist/stubs/i18n/zh.js +16 -1
- package/dist/stubs/logbox-control.js +9 -0
- package/dist/stubs/screenshot-control.js +1 -1
- package/dist/stubs/sentry-react-native-stub.js +15 -180
- package/oxlint-config.json +11 -4
- package/package.json +60 -5
- package/pnpm-patches/@expo__cli@55.0.16-55.0.22.patch +627 -0
- package/pnpm-patches/@expo__cli@55.0.16.patch +218 -0
- package/pnpm-patches/@expo__cli@55.0.17.patch +218 -0
- package/pnpm-patches/@expo__cli@55.0.18.patch +218 -0
- package/pnpm-patches/@expo__cli@55.0.19.patch +218 -0
- package/pnpm-patches/@expo__cli@55.0.20.patch +218 -0
- package/pnpm-patches/@expo__cli@55.0.21.patch +218 -0
- package/pnpm-patches/@expo__cli@55.0.22.patch +218 -0
- package/pnpm-patches/@shopify__react-native-skia@2.4.18.patch +14 -0
- package/pnpm-patches/expo-modules-core@55.0.15.patch +21 -0
- package/pnpm-patches/expo@55.0.6.patch +235 -0
- package/pnpm-patches/metro-file-map@0.83.3.patch +24 -0
- package/pnpm-patches/metro-runtime@0.83.3.patch +13 -0
- package/pnpm-patches/react-native-css-interop@0.2.6.patch +12 -0
- package/pnpm-patches/react-native-reanimated@4.2.1.patch +53 -0
- package/pnpm-patches/react-native-worklets@0.7.2.patch +91 -0
- package/pnpm-patches/react-native@0.83.2.patch +384 -0
- package/pnpmfile.cjs +168 -0
- package/dist/stubs/preview-control.js +0 -60
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
diff --git a/build/src/start/server/metro/instantiateMetro.js b/build/src/start/server/metro/instantiateMetro.js
|
|
2
|
+
--- a/build/src/start/server/metro/instantiateMetro.js
|
|
3
|
+
+++ b/build/src/start/server/metro/instantiateMetro.js
|
|
4
|
+
@@ -90,6 +90,7 @@
|
|
5
|
+
const _attachAtlas = require("./debugging/attachAtlas");
|
|
6
|
+
const _createDebugMiddleware = require("./debugging/createDebugMiddleware");
|
|
7
|
+
const _createMetroMiddleware = require("./dev-server/createMetroMiddleware");
|
|
8
|
+
+const _aiErrorCollector = require("./aiErrorCollector");
|
|
9
|
+
const _runServerfork = require("./runServer-fork");
|
|
10
|
+
const _withMetroMultiPlatform = require("./withMetroMultiPlatform");
|
|
11
|
+
const _events = require("../../../events");
|
|
12
|
+
@@ -274,6 +275,7 @@
|
|
13
|
+
const { middleware, messagesSocket, eventsSocket, websocketEndpoints } = (0, _createMetroMiddleware.createMetroMiddleware)(metroConfig, {
|
|
14
|
+
getMetroBundler
|
|
15
|
+
});
|
|
16
|
+
+ const aiErrorCollector = !isExporting ? (0, _aiErrorCollector.createAiErrorCollector)(projectRoot) : null;
|
|
17
|
+
// Get local URL to Metro bundler server (typically configured as 127.0.0.1:8081)
|
|
18
|
+
const serverBaseUrl = metroBundler.getUrlCreator().constructUrl({
|
|
19
|
+
scheme: 'http',
|
|
20
|
+
@@ -348,7 +350,10 @@
|
|
21
|
+
}
|
|
22
|
+
}), fileBuffer);
|
|
23
|
+
};
|
|
24
|
+
- setEventReporter(eventsSocket.reportMetroEvent);
|
|
25
|
+
+ setEventReporter((event)=>{
|
|
26
|
+
+ eventsSocket.reportMetroEvent(event);
|
|
27
|
+
+ aiErrorCollector == null ? void 0 : aiErrorCollector.handleMetroEvent(event);
|
|
28
|
+
+ });
|
|
29
|
+
// This function ensures that modules in source maps are sorted in the same
|
|
30
|
+
// order as in a plain JS bundle.
|
|
31
|
+
metro._getSortedModules = function(graph) {
|
|
32
|
+
@@ -493,1 +498,1 @@
|
|
33
|
+
-//# sourceMappingURL=instantiateMetro.js.map
|
|
34
|
+
|
|
35
|
+
+//# sourceMappingURL=instantiateMetro.js.map
|
|
36
|
+
diff --git a/build/src/start/server/metro/aiErrorCollector.js b/build/src/start/server/metro/aiErrorCollector.js
|
|
37
|
+
new file mode 100644
|
|
38
|
+
--- /dev/null
|
|
39
|
+
+++ b/build/src/start/server/metro/aiErrorCollector.js
|
|
40
|
+
@@ -0,0 +1,178 @@
|
|
41
|
+
+"use strict";
|
|
42
|
+
+Object.defineProperty(exports, "__esModule", {
|
|
43
|
+
+ value: true
|
|
44
|
+
+});
|
|
45
|
+
+Object.defineProperty(exports, "createAiErrorCollector", {
|
|
46
|
+
+ enumerable: true,
|
|
47
|
+
+ get: function() {
|
|
48
|
+
+ return createAiErrorCollector;
|
|
49
|
+
+ }
|
|
50
|
+
+});
|
|
51
|
+
+const fs = require("fs");
|
|
52
|
+
+const os = require("os");
|
|
53
|
+
+const path = require("path");
|
|
54
|
+
+
|
|
55
|
+
+const MAX_VALUE_DEPTH = 4;
|
|
56
|
+
+const MAX_STRING_LENGTH = 20000;
|
|
57
|
+
+
|
|
58
|
+
+function isEnabled() {
|
|
59
|
+
+ return process.env.EXPO_AI_ERROR_COLLECTOR === '1';
|
|
60
|
+
+}
|
|
61
|
+
+
|
|
62
|
+
+function getOutputPath(projectRoot) {
|
|
63
|
+
+ const configured = process.env.EXPO_AI_ERROR_FILE;
|
|
64
|
+
+ if (!configured) return path.join(projectRoot, 'node_modules', '.miaoda-expo', 'ai-error.json');
|
|
65
|
+
+ return path.isAbsolute(configured) ? configured : path.resolve(projectRoot, configured);
|
|
66
|
+
+}
|
|
67
|
+
+
|
|
68
|
+
+function toSerializable(value, depth = 0, seen = new Set()) {
|
|
69
|
+
+ if (value == null || typeof value === 'boolean' || typeof value === 'number') return value;
|
|
70
|
+
+ if (typeof value === 'string') return value.length > MAX_STRING_LENGTH ? value.slice(0, MAX_STRING_LENGTH) + '...[truncated]' : value;
|
|
71
|
+
+ if (depth >= MAX_VALUE_DEPTH) return '[truncated]';
|
|
72
|
+
+ if (typeof value === 'function' || typeof value === 'symbol') return String(value);
|
|
73
|
+
+ if (seen.has(value)) return '[circular]';
|
|
74
|
+
+ seen.add(value);
|
|
75
|
+
+ if (value instanceof Error) {
|
|
76
|
+
+ const error = {
|
|
77
|
+
+ name: value.name,
|
|
78
|
+
+ message: value.message,
|
|
79
|
+
+ stack: value.stack
|
|
80
|
+
+ };
|
|
81
|
+
+ for (const key of Object.keys(value)) error[key] = toSerializable(value[key], depth + 1, seen);
|
|
82
|
+
+ seen.delete(value);
|
|
83
|
+
+ return error;
|
|
84
|
+
+ }
|
|
85
|
+
+ if (Array.isArray(value)) {
|
|
86
|
+
+ const result = value.map((item)=>toSerializable(item, depth + 1, seen));
|
|
87
|
+
+ seen.delete(value);
|
|
88
|
+
+ return result;
|
|
89
|
+
+ }
|
|
90
|
+
+ if (typeof value === 'object') {
|
|
91
|
+
+ const result = {};
|
|
92
|
+
+ for (const key of Object.keys(value)) result[key] = toSerializable(value[key], depth + 1, seen);
|
|
93
|
+
+ seen.delete(value);
|
|
94
|
+
+ return result;
|
|
95
|
+
+ }
|
|
96
|
+
+ return String(value);
|
|
97
|
+
+}
|
|
98
|
+
+
|
|
99
|
+
+function normalizeError(error, projectRoot, buildID) {
|
|
100
|
+
+ const raw = error && typeof error === 'object' ? error : {
|
|
101
|
+
+ message: String(error ?? 'Metro bundling failed')
|
|
102
|
+
+ };
|
|
103
|
+
+ const message = String(raw.message ?? raw.reason ?? error ?? 'Metro bundling failed');
|
|
104
|
+
+ const record = {
|
|
105
|
+
+ schemaVersion: 1,
|
|
106
|
+
+ id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,
|
|
107
|
+
+ timestamp: new Date().toISOString(),
|
|
108
|
+
+ source: 'metro',
|
|
109
|
+
+ eventType: 'bundling_error',
|
|
110
|
+
+ buildID: buildID ?? undefined,
|
|
111
|
+
+ projectRoot,
|
|
112
|
+
+ type: String(raw.type ?? raw.name ?? 'MetroError'),
|
|
113
|
+
+ name: raw.name == null ? undefined : String(raw.name),
|
|
114
|
+
+ message,
|
|
115
|
+
+ filename: raw.filename == null ? undefined : String(raw.filename),
|
|
116
|
+
+ lineNumber: typeof raw.lineNumber === 'number' ? raw.lineNumber : undefined,
|
|
117
|
+
+ column: typeof raw.column === 'number' ? raw.column : undefined,
|
|
118
|
+
+ errors: Array.isArray(raw.errors) ? toSerializable(raw.errors) : [],
|
|
119
|
+
+ stack: raw.stack == null ? undefined : String(raw.stack),
|
|
120
|
+
+ cause: raw.cause == null ? undefined : toSerializable(raw.cause)
|
|
121
|
+
+ };
|
|
122
|
+
+ const extra = {};
|
|
123
|
+
+ for (const key of Object.keys(raw)) {
|
|
124
|
+
+ if (!['type', 'name', 'message', 'filename', 'lineNumber', 'column', 'errors', 'stack', 'cause'].includes(key)) {
|
|
125
|
+
+ extra[key] = toSerializable(raw[key]);
|
|
126
|
+
+ }
|
|
127
|
+
+ }
|
|
128
|
+
+ if (Object.keys(extra).length) record.extra = extra;
|
|
129
|
+
+ return omitUndefined(record);
|
|
130
|
+
+}
|
|
131
|
+
+
|
|
132
|
+
+function omitUndefined(value) {
|
|
133
|
+
+ if (!value || typeof value !== 'object') return value;
|
|
134
|
+
+ if (Array.isArray(value)) return value.map(omitUndefined);
|
|
135
|
+
+ const result = {};
|
|
136
|
+
+ for (const [key, item] of Object.entries(value)) {
|
|
137
|
+
+ if (item !== undefined) result[key] = omitUndefined(item);
|
|
138
|
+
+ }
|
|
139
|
+
+ return result;
|
|
140
|
+
+}
|
|
141
|
+
+
|
|
142
|
+
+function createAiErrorCollector(projectRoot) {
|
|
143
|
+
+ if (!isEnabled()) return null;
|
|
144
|
+
+ const outputFile = getOutputPath(projectRoot);
|
|
145
|
+
+ let activeBuildID = null;
|
|
146
|
+
+ let lastFailedBuildID = null;
|
|
147
|
+
+ let state = {
|
|
148
|
+
+ schemaVersion: 1,
|
|
149
|
+
+ status: 'compiling',
|
|
150
|
+
+ buildID: null,
|
|
151
|
+
+ updatedAt: new Date().toISOString(),
|
|
152
|
+
+ error: null
|
|
153
|
+
+ };
|
|
154
|
+
+ let warned = false;
|
|
155
|
+
+ const publish = (nextState)=>{
|
|
156
|
+
+ state = omitUndefined({ ...nextState, updatedAt: new Date().toISOString() });
|
|
157
|
+
+ let temporaryFile;
|
|
158
|
+
+ try {
|
|
159
|
+
+ fs.mkdirSync(path.dirname(outputFile), { recursive: true });
|
|
160
|
+
+ temporaryFile = `${outputFile}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
161
|
+
+ fs.writeFileSync(temporaryFile, JSON.stringify(state, null, 2) + os.EOL, 'utf8');
|
|
162
|
+
+ fs.renameSync(temporaryFile, outputFile);
|
|
163
|
+
+ } catch (error) {
|
|
164
|
+
+ try {
|
|
165
|
+
+ if (temporaryFile) fs.rmSync(temporaryFile, { force: true });
|
|
166
|
+
+ } catch {}
|
|
167
|
+
+ if (!warned) {
|
|
168
|
+
+ warned = true;
|
|
169
|
+
+ console.warn(`[expo-ai-error] Could not write ${outputFile}: ${error.message}`);
|
|
170
|
+
+ }
|
|
171
|
+
+ }
|
|
172
|
+
+ };
|
|
173
|
+
+ const isCurrentBuild = (buildID, allowMissing = false)=>buildID == null ? allowMissing || activeBuildID == null : activeBuildID == null || buildID === activeBuildID;
|
|
174
|
+
+ return {
|
|
175
|
+
+ getState() {
|
|
176
|
+
+ return state;
|
|
177
|
+
+ },
|
|
178
|
+
+ handleMetroEvent(event) {
|
|
179
|
+
+ if (!event || typeof event !== 'object') return;
|
|
180
|
+
+ const type = event.type;
|
|
181
|
+
+ const buildID = event.buildID ?? event.bundleDetails?.buildID ?? null;
|
|
182
|
+
+ if (type === 'bundle_build_started') {
|
|
183
|
+
+ activeBuildID = buildID;
|
|
184
|
+
+ lastFailedBuildID = null;
|
|
185
|
+
+ publish({ schemaVersion: 1, status: 'compiling', buildID, error: null });
|
|
186
|
+
+ return;
|
|
187
|
+
+ }
|
|
188
|
+
+ if (type === 'bundle_build_failed') {
|
|
189
|
+
+ if (!isCurrentBuild(buildID)) return;
|
|
190
|
+
+ lastFailedBuildID = buildID ?? activeBuildID;
|
|
191
|
+
+ publish({
|
|
192
|
+
+ schemaVersion: 1,
|
|
193
|
+
+ status: 'failed',
|
|
194
|
+
+ buildID: lastFailedBuildID,
|
|
195
|
+
+ error: normalizeError(event.error ?? { type: 'MetroBundleError', message: 'Metro bundling failed' }, projectRoot, lastFailedBuildID)
|
|
196
|
+
+ });
|
|
197
|
+
+ return;
|
|
198
|
+
+ }
|
|
199
|
+
+ if (type === 'bundling_error') {
|
|
200
|
+
+ const errorBuildID = buildID ?? lastFailedBuildID ?? activeBuildID;
|
|
201
|
+
+ if (!isCurrentBuild(errorBuildID, true)) return;
|
|
202
|
+
+ publish({
|
|
203
|
+
+ schemaVersion: 1,
|
|
204
|
+
+ status: 'failed',
|
|
205
|
+
+ buildID: errorBuildID,
|
|
206
|
+
+ error: normalizeError(event.error, projectRoot, errorBuildID)
|
|
207
|
+
+ });
|
|
208
|
+
+ return;
|
|
209
|
+
+ }
|
|
210
|
+
+ if (type === 'bundle_build_done') {
|
|
211
|
+
+ if (!isCurrentBuild(buildID)) return;
|
|
212
|
+
+ publish({ schemaVersion: 1, status: 'succeeded', buildID: buildID ?? activeBuildID, error: null });
|
|
213
|
+
+ }
|
|
214
|
+
+ }
|
|
215
|
+
+ };
|
|
216
|
+
+}
|
|
217
|
+
+
|
|
218
|
+
+//# sourceMappingURL=aiErrorCollector.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
diff --git a/scripts/install-skia.mjs b/scripts/install-skia.mjs
|
|
2
|
+
index ac4e945f9acb611c43f60a38aaada1ca2b695bb2..d502637ac0e09d8016b2b174c08265237bf4085f 100644
|
|
3
|
+
--- a/scripts/install-skia.mjs
|
|
4
|
+
+++ b/scripts/install-skia.mjs
|
|
5
|
+
@@ -484,7 +484,8 @@ const main = async () => {
|
|
6
|
+
for (const artifactName of names) {
|
|
7
|
+
const assetName = `${artifactName}-${releaseTag}.tar.gz`;
|
|
8
|
+
const extractDir = path.join(artifactsDir, artifactName);
|
|
9
|
+
- const downloadUrl = `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`;
|
|
10
|
+
+ const baseUrl = process.env.SKIA_DOWNLOAD_BASE_URL || `https://github.com/${repo}/releases/download`;
|
|
11
|
+
+ const downloadUrl = `${baseUrl}/${releaseTag}/${assetName}`;
|
|
12
|
+
|
|
13
|
+
console.log(` Downloading ${assetName}...`);
|
|
14
|
+
try {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
--- a/android/cmake/main.cmake
|
|
2
|
+
+++ b/android/cmake/main.cmake
|
|
3
|
+
@@ -73,15 +73,17 @@
|
|
4
|
+
|
|
5
|
+
if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
|
6
|
+
set(BUILD_TYPE "debug")
|
|
7
|
+
+ set(MERGE_NATIVE_LIBS_DIR "mergeDebugNativeLibs")
|
|
8
|
+
else ()
|
|
9
|
+
set(BUILD_TYPE "release")
|
|
10
|
+
+ set(MERGE_NATIVE_LIBS_DIR "mergeReleaseNativeLibs")
|
|
11
|
+
endif ()
|
|
12
|
+
|
|
13
|
+
set_target_properties(
|
|
14
|
+
worklets
|
|
15
|
+
PROPERTIES
|
|
16
|
+
IMPORTED_LOCATION
|
|
17
|
+
- "${REACT_NATIVE_WORKLETS_DIR}/android/build/intermediates/cmake/${BUILD_TYPE}/obj/${ANDROID_ABI}/libworklets.so"
|
|
18
|
+
+ "${REACT_NATIVE_WORKLETS_DIR}/android/build/intermediates/merged_native_libs/${BUILD_TYPE}/${MERGE_NATIVE_LIBS_DIR}/out/lib/${ANDROID_ABI}/libworklets.so"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
target_link_libraries(
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
diff --git a/bundledNativeModules.json b/bundledNativeModules.json
|
|
2
|
+
index e2b8941923b274b1c5c9bda2269d28cf574aff7f..355deae878b654e1e1d9db114ee88c1e7e504276 100644
|
|
3
|
+
--- a/bundledNativeModules.json
|
|
4
|
+
+++ b/bundledNativeModules.json
|
|
5
|
+
@@ -19,7 +19,7 @@
|
|
6
|
+
"expo-apple-authentication": "~55.0.8",
|
|
7
|
+
"expo-application": "~55.0.9",
|
|
8
|
+
"expo-asset": "~55.0.8",
|
|
9
|
+
- "expo-audio": "~55.0.8",
|
|
10
|
+
+ "expo-audio": "55.0.6",
|
|
11
|
+
"expo-auth-session": "~55.0.8",
|
|
12
|
+
"expo-background-fetch": "~55.0.9",
|
|
13
|
+
"expo-background-task": "~55.0.9",
|
|
14
|
+
@@ -90,7 +90,7 @@
|
|
15
|
+
"expo-tracking-transparency": "~55.0.8",
|
|
16
|
+
"expo-updates": "~55.0.13",
|
|
17
|
+
"expo-video-thumbnails": "~55.0.10",
|
|
18
|
+
- "expo-video": "~55.0.10",
|
|
19
|
+
+ "expo-video": "55.0.5",
|
|
20
|
+
"expo-web-browser": "~55.0.9",
|
|
21
|
+
"jest-expo": "~55.0.9",
|
|
22
|
+
"lottie-react-native": "~7.3.4",
|
|
23
|
+
diff --git a/src/async-require/hmr.ts b/src/async-require/hmr.ts
|
|
24
|
+
--- a/src/async-require/hmr.ts
|
|
25
|
+
+++ b/src/async-require/hmr.ts
|
|
26
|
+
@@ -17,6 +17,7 @@
|
|
27
|
+
handleCompileError,
|
|
28
|
+
hideLoading,
|
|
29
|
+
resetErrorOverlay,
|
|
30
|
+
+ reload,
|
|
31
|
+
showLoading,
|
|
32
|
+
} from './hmrUtils';
|
|
33
|
+
|
|
34
|
+
@@ -29,6 +30,20 @@
|
|
35
|
+
let hmrUnavailableReason: string | null = null;
|
|
36
|
+
const buildErrorQueue = new Set<unknown>();
|
|
37
|
+
let didConnect: boolean = false;
|
|
38
|
+
+// Agent pause is separate from the user's native Fast Refresh preference.
|
|
39
|
+
+let miaodaPaused = false;
|
|
40
|
+
+let fastRefreshRequested = false;
|
|
41
|
+
+const MIAODA_HMR_POLL_INTERVAL_MS = 2000;
|
|
42
|
+
+type MiaodaStatusProtocol = 'http' | 'https';
|
|
43
|
+
+let miaodaStatusHost: string | null = null;
|
|
44
|
+
+let miaodaStatusInitialProtocol: MiaodaStatusProtocol = 'http';
|
|
45
|
+
+let miaodaStatusProtocol: MiaodaStatusProtocol | null = null;
|
|
46
|
+
+let miaodaStatusPollingStopped = false;
|
|
47
|
+
+let miaodaPollTimer: ReturnType<typeof setTimeout> | null = null;
|
|
48
|
+
+let miaodaStateVersion: number | null = null;
|
|
49
|
+
+let miaodaLastControlVersion: number | null = null;
|
|
50
|
+
+let miaodaObservedPaused = false;
|
|
51
|
+
+let miaodaWebSocketDisconnected = false;
|
|
52
|
+
const pendingLogs: [LogLevel, any[]][] = [];
|
|
53
|
+
|
|
54
|
+
type LogLevel =
|
|
55
|
+
@@ -42,6 +57,86 @@
|
|
56
|
+
| 'groupEnd'
|
|
57
|
+
| 'debug';
|
|
58
|
+
|
|
59
|
+
+function scheduleMiaodaStatusPoll() {
|
|
60
|
+
+ if (process.env.EXPO_OS === 'web' || !miaodaStatusHost || miaodaStatusPollingStopped || miaodaPollTimer != null) return;
|
|
61
|
+
+ miaodaPollTimer = setTimeout(() => {
|
|
62
|
+
+ miaodaPollTimer = null;
|
|
63
|
+
+ void pollMiaodaStatus();
|
|
64
|
+
+ }, MIAODA_HMR_POLL_INTERVAL_MS);
|
|
65
|
+
+ (miaodaPollTimer as any).unref?.();
|
|
66
|
+
+}
|
|
67
|
+
+
|
|
68
|
+
+function miaodaStatusUrl(protocol: MiaodaStatusProtocol) {
|
|
69
|
+
+ return `${protocol}://${miaodaStatusHost}/innerapi/v1/sourcecode/__hmr_status`;
|
|
70
|
+
+}
|
|
71
|
+
+
|
|
72
|
+
+function alternateMiaodaStatusProtocol(protocol: MiaodaStatusProtocol): MiaodaStatusProtocol {
|
|
73
|
+
+ return protocol === 'https' ? 'http' : 'https';
|
|
74
|
+
+}
|
|
75
|
+
+
|
|
76
|
+
+async function pollMiaodaStatus() {
|
|
77
|
+
+ if (process.env.EXPO_OS === 'web' || !miaodaStatusHost || miaodaStatusPollingStopped) return;
|
|
78
|
+
+ let protocol = miaodaStatusProtocol ?? miaodaStatusInitialProtocol;
|
|
79
|
+
+ try {
|
|
80
|
+
+ let response;
|
|
81
|
+
+ try {
|
|
82
|
+
+ response = await fetch(miaodaStatusUrl(protocol), {headers: {'Cache-Control': 'no-cache'}});
|
|
83
|
+
+ } catch {
|
|
84
|
+
+ // Devices may reject development certificates and need HTTP, while other
|
|
85
|
+
+ // environments expose HTTPS only. Switch only after a network/SSL failure.
|
|
86
|
+
+ protocol = alternateMiaodaStatusProtocol(protocol);
|
|
87
|
+
+ response = await fetch(miaodaStatusUrl(protocol), {headers: {'Cache-Control': 'no-cache'}});
|
|
88
|
+
+ }
|
|
89
|
+
+
|
|
90
|
+
+ if (response.status === 404) {
|
|
91
|
+
+ // A 404 is a definitive signal that this Metro instance has no control route.
|
|
92
|
+
+ // Stop probing until the WebSocket reconnects, which may point at a new server.
|
|
93
|
+
+ miaodaStatusPollingStopped = true;
|
|
94
|
+
+ if (miaodaPollTimer != null) {
|
|
95
|
+
+ clearTimeout(miaodaPollTimer);
|
|
96
|
+
+ miaodaPollTimer = null;
|
|
97
|
+
+ }
|
|
98
|
+
+ return;
|
|
99
|
+
+ }
|
|
100
|
+
+ if (!response.ok) {
|
|
101
|
+
+ // 5xx and other temporary HTTP failures are retried on the next interval.
|
|
102
|
+
+ return;
|
|
103
|
+
+ }
|
|
104
|
+
+
|
|
105
|
+
+ // Remember the protocol that reached the server for subsequent polls.
|
|
106
|
+
+ miaodaStatusProtocol = protocol;
|
|
107
|
+
+ const state = (await response.json()) as {
|
|
108
|
+
+ paused?: boolean; reloadPending?: boolean; stateVersion?: number; lastMode?: string | null;
|
|
109
|
+
+ };
|
|
110
|
+
+ const version = Number.isInteger(state.stateVersion) ? state.stateVersion : null;
|
|
111
|
+
+ const firstObservation = miaodaStateVersion === null;
|
|
112
|
+
+ miaodaStateVersion = version;
|
|
113
|
+
+ if (state.paused) {
|
|
114
|
+
+ miaodaObservedPaused = true;
|
|
115
|
+
+ miaodaPaused = true;
|
|
116
|
+
+ hmrClient?.disable();
|
|
117
|
+
+ // The observed pause is now our local baseline. A later version without a
|
|
118
|
+
+ // matching WebSocket message requires a full Bundle reload.
|
|
119
|
+
+ miaodaLastControlVersion = version;
|
|
120
|
+
+ } else {
|
|
121
|
+
+ const missedControl = !firstObservation && version !== null && version !== miaodaLastControlVersion;
|
|
122
|
+
+ const shouldReload = !firstObservation && (state.lastMode === 'reload' || (missedControl && (miaodaObservedPaused || miaodaWebSocketDisconnected)));
|
|
123
|
+
+ miaodaObservedPaused = false;
|
|
124
|
+
+ miaodaPaused = false;
|
|
125
|
+
+ miaodaLastControlVersion = version;
|
|
126
|
+
+ if (shouldReload) {
|
|
127
|
+
+ reload();
|
|
128
|
+
+ return;
|
|
129
|
+
+ }
|
|
130
|
+
+ if (fastRefreshRequested) HMRClient.enable();
|
|
131
|
+
+ }
|
|
132
|
+
+ } catch {
|
|
133
|
+
+ // Network, timeout and invalid-response failures must not release the edit gate.
|
|
134
|
+
+ } finally {
|
|
135
|
+
+ scheduleMiaodaStatusPoll();
|
|
136
|
+
+ }
|
|
137
|
+
+}
|
|
138
|
+
+
|
|
139
|
+
function assert(foo: any, msg: string): asserts foo {
|
|
140
|
+
if (!foo) throw new Error(msg);
|
|
141
|
+
}
|
|
142
|
+
@@ -52,6 +147,8 @@
|
|
143
|
+
*/
|
|
144
|
+
const HMRClient = {
|
|
145
|
+
enable() {
|
|
146
|
+
+ fastRefreshRequested = true;
|
|
147
|
+
+ if (miaodaPaused) return;
|
|
148
|
+
if (hmrUnavailableReason !== null) {
|
|
149
|
+
// If HMR became unavailable while you weren't using it,
|
|
150
|
+
// explain why when you try to turn it on.
|
|
151
|
+
@@ -87,6 +184,7 @@
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
disable() {
|
|
155
|
+
+ fastRefreshRequested = false;
|
|
156
|
+
assert(hmrClient, 'Expected HMRClient.setup() call at startup.');
|
|
157
|
+
hmrClient.disable();
|
|
158
|
+
},
|
|
159
|
+
@@ -180,6 +278,13 @@
|
|
160
|
+
const origin = `${serverScheme}://${serverHost}`;
|
|
161
|
+
const client = new MetroHMRClient(`${origin}/hot`);
|
|
162
|
+
hmrClient = client;
|
|
163
|
+
+ if (process.env.EXPO_OS !== 'web') {
|
|
164
|
+
+ // Native clients may receive HTTPS bundle URLs with invalid development certificates,
|
|
165
|
+
+ // while some deployments expose only HTTPS. Probe the bundle protocol first, then
|
|
166
|
+
+ // remember the protocol that succeeds for subsequent polls.
|
|
167
|
+
+ miaodaStatusHost = serverHost;
|
|
168
|
+
+ miaodaStatusInitialProtocol = serverScheme === 'https' || serverScheme === 'wss' ? 'https' : 'http';
|
|
169
|
+
+ }
|
|
170
|
+
|
|
171
|
+
pendingEntryPoints.push(
|
|
172
|
+
// HMRServer understands regular bundle URLs, so prefer that in case
|
|
173
|
+
@@ -192,6 +297,45 @@
|
|
174
|
+
platform: typeof platformOrOptions === 'string' ? platformOrOptions : undefined,
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
+
|
|
178
|
+
+ client.on('open', () => {
|
|
179
|
+
+ miaodaWebSocketDisconnected = false;
|
|
180
|
+
+ // A reconnect may target a Metro process with HMR control enabled.
|
|
181
|
+
+ miaodaStatusPollingStopped = false;
|
|
182
|
+
+ scheduleMiaodaStatusPoll();
|
|
183
|
+
+ });
|
|
184
|
+
+
|
|
185
|
+
+ client.on('miaoda-hmr-control', (message: {
|
|
186
|
+
+ version: number; action: string; id?: number; error?: any; stateVersion?: number;
|
|
187
|
+
+ }) => {
|
|
188
|
+
+ if (message.version !== 1) return;
|
|
189
|
+
+ if (Number.isInteger(message.stateVersion)) {
|
|
190
|
+
+ miaodaStateVersion = message.stateVersion!;
|
|
191
|
+
+ miaodaLastControlVersion = message.stateVersion!;
|
|
192
|
+
+ }
|
|
193
|
+
+ switch (message.action) {
|
|
194
|
+
+ case 'pause':
|
|
195
|
+
+ miaodaPaused = true;
|
|
196
|
+
+ client.disable();
|
|
197
|
+
+ hideLoading();
|
|
198
|
+
+ client.send(JSON.stringify({type: 'miaoda-hmr-ack', version: 1, id: message.id}));
|
|
199
|
+
+ break;
|
|
200
|
+
+ case 'resume':
|
|
201
|
+
+ miaodaPaused = false;
|
|
202
|
+
+ if (fastRefreshRequested) HMRClient.enable();
|
|
203
|
+
+ break;
|
|
204
|
+
+ case 'reload':
|
|
205
|
+
+ miaodaPaused = true;
|
|
206
|
+
+ client.disable();
|
|
207
|
+
+ reload();
|
|
208
|
+
+ break;
|
|
209
|
+
+ case 'error':
|
|
210
|
+
+ // Final compilation failure is actionable even while the edit gate stays closed.
|
|
211
|
+
+ hideLoading();
|
|
212
|
+
+ handleCompileError(message.error);
|
|
213
|
+
+ break;
|
|
214
|
+
+ }
|
|
215
|
+
+ });
|
|
216
|
+
|
|
217
|
+
client.on('connection-error', (e: Error) => {
|
|
218
|
+
setHMRUnavailableReason(getConnectionError(serverHost, e));
|
|
219
|
+
@@ -234,6 +378,8 @@
|
|
220
|
+
client.on('error', (data) => this._onMetroError(data));
|
|
221
|
+
|
|
222
|
+
client.on('close', (closeEvent?: { code: number; reason: string }) => {
|
|
223
|
+
+ miaodaWebSocketDisconnected = true;
|
|
224
|
+
+ scheduleMiaodaStatusPoll();
|
|
225
|
+
hideLoading();
|
|
226
|
+
const reason = closeEvent?.reason;
|
|
227
|
+
const code = closeEvent?.code || 1000;
|
|
228
|
+
@@ -326,6 +472,7 @@
|
|
229
|
+
client?.send(
|
|
230
|
+
JSON.stringify({
|
|
231
|
+
type: 'register-entrypoints',
|
|
232
|
+
+ miaodaHmr: 1,
|
|
233
|
+
entryPoints: pendingEntryPoints,
|
|
234
|
+
})
|
|
235
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
diff --git a/src/index.js b/src/index.js
|
|
2
|
+
--- a/src/index.js
|
|
3
|
+
+++ b/src/index.js
|
|
4
|
+
@@ -670,6 +670,20 @@
|
|
5
|
+
);
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
+ // Miaoda edit-batch barrier. The cookie fences watcher delivery; drain file
|
|
9
|
+
+ // processing before emitting the changes used by DeltaCalculator.
|
|
10
|
+
+ this.miaodaFlushChanges = async (timeout = 5000) => {
|
|
11
|
+
+ const result = await this._watcher.checkHealth(timeout);
|
|
12
|
+
+ if (result.type !== "success") {
|
|
13
|
+
+ throw new Error("Metro watcher barrier failed: " + result.type);
|
|
14
|
+
+ }
|
|
15
|
+
+ let pending;
|
|
16
|
+
+ do {
|
|
17
|
+
+ pending = changeQueue;
|
|
18
|
+
+ await pending;
|
|
19
|
+
+ } while (pending !== changeQueue);
|
|
20
|
+
+ emitChange();
|
|
21
|
+
+ };
|
|
22
|
+
this._changeInterval = setInterval(emitChange, CHANGE_INTERVAL);
|
|
23
|
+
(0, _invariant.default)(
|
|
24
|
+
this._watcher != null,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
diff --git a/src/modules/HMRClient.js b/src/modules/HMRClient.js
|
|
2
|
+
--- a/src/modules/HMRClient.js
|
|
3
|
+
+++ b/src/modules/HMRClient.js
|
|
4
|
+
@@ -35,6 +35,9 @@
|
|
5
|
+
this._ws.onmessage = (message) => {
|
|
6
|
+
const data = JSON.parse(String(message.data));
|
|
7
|
+
switch (data.type) {
|
|
8
|
+
+ case "miaoda-hmr-control":
|
|
9
|
+
+ if (data.version === 1) this.emit("miaoda-hmr-control", data);
|
|
10
|
+
+ break;
|
|
11
|
+
case "bundle-registered":
|
|
12
|
+
this.emit("bundle-registered");
|
|
13
|
+
break;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
diff --git a/dist/css-to-rn/parseDeclaration.js b/dist/css-to-rn/parseDeclaration.js
|
|
2
|
+
index 59ea66e459dbf6922bcd80a6ac014408ca13c2af..088149d6f92dfb8f48bb979f5239c2a420f0dc2d 100644
|
|
3
|
+
--- a/dist/css-to-rn/parseDeclaration.js
|
|
4
|
+
+++ b/dist/css-to-rn/parseDeclaration.js
|
|
5
|
+
@@ -918,6 +918,7 @@ function parseDeclaration(declaration, options) {
|
|
6
|
+
return addStyleProp(declaration.property, parseTextAlign(declaration.value, parseOptions));
|
|
7
|
+
case "box-shadow": {
|
|
8
|
+
parseBoxShadow(declaration.value, parseOptions);
|
|
9
|
+
+ return;
|
|
10
|
+
}
|
|
11
|
+
case "aspect-ratio": {
|
|
12
|
+
return addStyleProp(declaration.property, parseAspectRatio(declaration.value));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
--- a/android/CMakeLists.txt
|
|
2
|
+
+++ b/android/CMakeLists.txt
|
|
3
|
+
@@ -76,8 +76,10 @@
|
|
4
|
+
|
|
5
|
+
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
|
6
|
+
set(BUILD_TYPE "debug")
|
|
7
|
+
+ set(MERGE_NATIVE_LIBS_DIR "mergeDebugNativeLibs")
|
|
8
|
+
else()
|
|
9
|
+
set(BUILD_TYPE "release")
|
|
10
|
+
+ set(MERGE_NATIVE_LIBS_DIR "mergeReleaseNativeLibs")
|
|
11
|
+
endif()
|
|
12
|
+
|
|
13
|
+
add_library(worklets SHARED IMPORTED)
|
|
14
|
+
@@ -86,7 +88,7 @@
|
|
15
|
+
worklets
|
|
16
|
+
PROPERTIES
|
|
17
|
+
IMPORTED_LOCATION
|
|
18
|
+
- "${REACT_NATIVE_WORKLETS_DIR}/android/build/intermediates/cmake/${BUILD_TYPE}/obj/${ANDROID_ABI}/libworklets.so"
|
|
19
|
+
+ "${REACT_NATIVE_WORKLETS_DIR}/android/build/intermediates/merged_native_libs/${BUILD_TYPE}/${MERGE_NATIVE_LIBS_DIR}/out/lib/${ANDROID_ABI}/libworklets.so"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
set_target_properties(reanimated PROPERTIES LINKER_LANGUAGE CXX)
|
|
23
|
+
--- a/android/build.gradle
|
|
24
|
+
+++ b/android/build.gradle
|
|
25
|
+
@@ -350,7 +350,26 @@
|
|
26
|
+
evaluationDependsOn(":react-native-worklets")
|
|
27
|
+
|
|
28
|
+
afterEvaluate {
|
|
29
|
+
- tasks.getByName("externalNativeBuildDebug").dependsOn(findProject(":react-native-worklets").tasks.getByName("externalNativeBuildDebug"))
|
|
30
|
+
- tasks.getByName("externalNativeBuildRelease").dependsOn(findProject(":react-native-worklets").tasks.getByName("externalNativeBuildRelease"))
|
|
31
|
+
+ def workletsTasks = findProject(":react-native-worklets").tasks
|
|
32
|
+
+ def workletsDebugNativeLibs = workletsTasks.getByName("mergeDebugNativeLibs")
|
|
33
|
+
+ def workletsReleaseNativeLibs = workletsTasks.getByName("mergeReleaseNativeLibs")
|
|
34
|
+
+
|
|
35
|
+
+ // CMakeLists.txt imports libworklets.so from the `merged_native_libs` output of
|
|
36
|
+
+ // `:react-native-worklets:merge<Variant>NativeLibs`. ninja resolves that file while the
|
|
37
|
+
+ // per-ABI `buildCMake<NativeBuildType>[<abi>][<target>]` tasks run, and those tasks are
|
|
38
|
+
+ // *upstream* of the `externalNativeBuild<Variant>` umbrella task, so ordering declared on
|
|
39
|
+
+ // the umbrella task alone lands too late and the link fails with
|
|
40
|
+
+ // "libworklets.so ... missing and no known rule to make it".
|
|
41
|
+
+ // Release variants build with CMAKE_BUILD_TYPE=RelWithDebInfo, so their task name is
|
|
42
|
+
+ // `buildCMakeRelWithDebInfo[...]`; match on "Debug" and treat every other build type as
|
|
43
|
+
+ // release, mirroring the CMAKE_BUILD_TYPE check in CMakeLists.txt.
|
|
44
|
+
+ tasks.matching { it.name.startsWith("buildCMake") }.configureEach { nativeBuildTask ->
|
|
45
|
+
+ nativeBuildTask.dependsOn(
|
|
46
|
+
+ nativeBuildTask.name.contains("Debug") ? workletsDebugNativeLibs : workletsReleaseNativeLibs
|
|
47
|
+
+ )
|
|
48
|
+
+ }
|
|
49
|
+
+
|
|
50
|
+
+ tasks.getByName("externalNativeBuildDebug").dependsOn(workletsDebugNativeLibs)
|
|
51
|
+
+ tasks.getByName("externalNativeBuildRelease").dependsOn(workletsReleaseNativeLibs)
|
|
52
|
+
}
|
|
53
|
+
}
|