peachsim 0.1.628 → 0.1.630
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 +8 -4
- package/cli/bridge-flow-runner.ts +10 -3
- package/cli/cli-update.ts +2 -7
- package/cli/cloud-test-tunnel.ts +16 -3
- package/cli/commands/config.ts +1 -1
- package/cli/commands/control.ts +28 -3
- package/cli/commands/daemon-mac-app.ts +4 -2
- package/cli/commands/daemon.ts +4 -4
- package/cli/commands/device.ts +2 -3
- package/cli/commands/inspect/actions.ts +125 -90
- package/cli/commands/inspect/core.ts +5 -0
- package/cli/commands/inspect.ts +27 -13
- package/cli/commands/platform.ts +1 -1
- package/cli/commands/screenshot-layers.ts +1 -1
- package/cli/commands/screenshot.ts +1 -1
- package/cli/commands/skills.ts +0 -31
- package/cli/drivers/playwright-provisioning.ts +3 -2
- package/cli/drivers/playwright-sim-host.ts +25 -9
- package/cli/main.ts +8 -2
- package/cli/outbound-endpoints.ts +0 -4
- package/detox/index.ts +74 -43
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +129 -27
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +290 -315
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +253 -121
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/{vite-kotlin.cjs → kotlin-host.cjs} +130 -19
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +132 -9
- package/dist-lib/native-app-identity.cjs +278 -0
- package/dist-lib/native-app-identity.mjs +245 -0
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +110 -87
- package/dist-lib/sdk.mjs +110 -87
- package/dist-lib/skills.cjs +841 -643
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +282 -177
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +11 -28
- package/kotlin/README.md +32 -4
- package/kotlin/fixtures/counter/Counter.kt +26 -0
- package/kotlin/fixtures/counter/CounterScreen.kt +40 -0
- package/kotlin/fixtures/headless-counter/Headless.kt +228 -0
- package/kotlin/fixtures/runtime-state/RuntimeState.kt +200 -0
- package/kotlin/fork/LICENSE +178 -0
- package/kotlin/fork/NOTICE +25 -0
- package/kotlin/fork/README.md +59 -0
- package/kotlin/fork/build.sh +128 -0
- package/kotlin/fork/compose-worker-globals.patch +96 -0
- package/kotlin/fork/fork.json +33 -0
- package/kotlin/fork/publish.ts +77 -0
- package/kotlin/fork/skiko-worker-clock.patch +33 -0
- package/kotlin/toolchain.json +288 -0
- package/package.json +12 -5
- package/src/automatic-update-policy.ts +17 -0
- package/src/host/bridge-host.ts +3 -1
- package/src/{vite-plugin-kotlin.ts → kotlin-host.ts} +155 -12
- package/src/metro-plugin.ts +18 -0
- package/src/native-app-identity.ts +376 -0
- package/src/native-firebase-config.ts +90 -0
- package/src/screenshots/frame-compose.ts +5 -2
- package/src/screenshots/registry.ts +1 -1
- package/src/screenshots/schema.ts +2 -2
- package/src/vite-plugin-one.ts +11 -28
- package/src/vite-plugin.ts +6 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
|
+
"use strict";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/native-app-identity.ts
|
|
23
|
+
var native_app_identity_exports = {};
|
|
24
|
+
__export(native_app_identity_exports, {
|
|
25
|
+
applyNativeAppIdentity: () => applyNativeAppIdentity,
|
|
26
|
+
createNativeAppIdentityFooter: () => createNativeAppIdentityFooter,
|
|
27
|
+
detachNativeAppIdentityFooter: () => detachNativeAppIdentityFooter,
|
|
28
|
+
extractNativeAppIdentityFromFiles: () => extractNativeAppIdentityFromFiles,
|
|
29
|
+
getAppliedNativeAppIdentity: () => getAppliedNativeAppIdentity,
|
|
30
|
+
insertNativeAppIdentityFooter: () => insertNativeAppIdentityFooter,
|
|
31
|
+
isNativeAppIdentity: () => isNativeAppIdentity,
|
|
32
|
+
readNativeAppIdentity: () => readNativeAppIdentity,
|
|
33
|
+
readNativeAppIdentityFooter: () => readNativeAppIdentityFooter
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(native_app_identity_exports);
|
|
36
|
+
var NATIVE_APP_IDENTITY_PREFIX = "globalThis.__sootsimNativeAppIdentity=";
|
|
37
|
+
var METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
|
|
38
|
+
function isRecord(value) {
|
|
39
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
function nonEmptyString(value) {
|
|
42
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
43
|
+
}
|
|
44
|
+
function isNativeAppIdentity(value) {
|
|
45
|
+
if (!isRecord(value)) return false;
|
|
46
|
+
const platform = value.platform;
|
|
47
|
+
if (platform !== "ios" && platform !== "android") return false;
|
|
48
|
+
const applicationName = value.applicationName;
|
|
49
|
+
if (applicationName !== null && nonEmptyString(applicationName) === null) return false;
|
|
50
|
+
if (nonEmptyString(value.appVersion) === null) return false;
|
|
51
|
+
if (nonEmptyString(value.bundleIdentifier) === null) return false;
|
|
52
|
+
const buildVersion = nonEmptyString(value.buildVersion);
|
|
53
|
+
if (buildVersion === null) return false;
|
|
54
|
+
if (platform === "android" && !/^[1-9][0-9]*$/.test(buildVersion)) return false;
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
function readNativeAppIdentity(value) {
|
|
58
|
+
if (value === void 0 || value === null) return null;
|
|
59
|
+
if (!isNativeAppIdentity(value)) {
|
|
60
|
+
throw new Error("native app identity is malformed");
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
applicationName: value.applicationName,
|
|
64
|
+
appVersion: value.appVersion,
|
|
65
|
+
buildVersion: value.buildVersion,
|
|
66
|
+
bundleIdentifier: value.bundleIdentifier,
|
|
67
|
+
platform: value.platform
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function applyNativeAppIdentity(identity) {
|
|
71
|
+
const globals = globalThis;
|
|
72
|
+
if (identity) globals.__sootsim_native_app_identity = identity;
|
|
73
|
+
else delete globals.__sootsim_native_app_identity;
|
|
74
|
+
}
|
|
75
|
+
function getAppliedNativeAppIdentity() {
|
|
76
|
+
const value = globalThis.__sootsim_native_app_identity;
|
|
77
|
+
return isNativeAppIdentity(value) ? value : null;
|
|
78
|
+
}
|
|
79
|
+
function createNativeAppIdentityFooter(identity) {
|
|
80
|
+
const payload = JSON.stringify(identity).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/<\//g, "<\\/");
|
|
81
|
+
return `
|
|
82
|
+
${NATIVE_APP_IDENTITY_PREFIX}${payload};`;
|
|
83
|
+
}
|
|
84
|
+
function nativeAppIdentityFooterStart(source) {
|
|
85
|
+
return source.lastIndexOf(`
|
|
86
|
+
${NATIVE_APP_IDENTITY_PREFIX}`);
|
|
87
|
+
}
|
|
88
|
+
function readNativeAppIdentityFooter(source) {
|
|
89
|
+
const start = nativeAppIdentityFooterStart(source);
|
|
90
|
+
if (start < 0) return null;
|
|
91
|
+
const lineEnd = source.indexOf("\n", start + 1);
|
|
92
|
+
const line = source.slice(start + 1, lineEnd < 0 ? void 0 : lineEnd);
|
|
93
|
+
if (!line.endsWith(";")) {
|
|
94
|
+
throw new Error("native app identity footer is truncated");
|
|
95
|
+
}
|
|
96
|
+
let parsed;
|
|
97
|
+
try {
|
|
98
|
+
parsed = JSON.parse(line.slice(NATIVE_APP_IDENTITY_PREFIX.length, -1));
|
|
99
|
+
} catch {
|
|
100
|
+
throw new Error("native app identity footer is not valid JSON");
|
|
101
|
+
}
|
|
102
|
+
if (!isNativeAppIdentity(parsed)) {
|
|
103
|
+
throw new Error("native app identity footer is malformed");
|
|
104
|
+
}
|
|
105
|
+
return parsed;
|
|
106
|
+
}
|
|
107
|
+
function detachNativeAppIdentityFooter(source) {
|
|
108
|
+
const start = nativeAppIdentityFooterStart(source);
|
|
109
|
+
if (start < 0) return { source, identity: null };
|
|
110
|
+
const identity = readNativeAppIdentityFooter(source);
|
|
111
|
+
const lineEnd = source.indexOf("\n", start + 1);
|
|
112
|
+
const end = lineEnd < 0 ? source.length : lineEnd;
|
|
113
|
+
return { source: source.slice(0, start) + source.slice(end), identity };
|
|
114
|
+
}
|
|
115
|
+
function insertNativeAppIdentityFooter(source, identity) {
|
|
116
|
+
const existing = nativeAppIdentityFooterStart(source);
|
|
117
|
+
const existingEnd = existing < 0 ? -1 : source.includes("\n", existing + 1) ? source.indexOf("\n", existing + 1) : -1;
|
|
118
|
+
const withoutExisting = existing < 0 ? source : source.slice(0, existing) + source.slice(existingEnd < 0 ? source.length : existingEnd);
|
|
119
|
+
const moduleFooter = withoutExisting.lastIndexOf(`
|
|
120
|
+
${METRO_MODULE_PATHS_PREFIX}`);
|
|
121
|
+
const footer = createNativeAppIdentityFooter(identity);
|
|
122
|
+
if (moduleFooter < 0) return withoutExisting + footer;
|
|
123
|
+
return withoutExisting.slice(0, moduleFooter) + footer + withoutExisting.slice(moduleFooter);
|
|
124
|
+
}
|
|
125
|
+
function plistString(plist, key) {
|
|
126
|
+
const match = plist.match(new RegExp(`<key>${key}</key>\\s*<string>([^<]*)</string>`));
|
|
127
|
+
return match ? match[1].trim() : null;
|
|
128
|
+
}
|
|
129
|
+
function resolveBuildSetting(value, settings, depth = 0) {
|
|
130
|
+
if (depth > 8) return null;
|
|
131
|
+
let unresolved = false;
|
|
132
|
+
const resolved = value.replace(/\$\(([^()]+)\)/g, (_match, reference) => {
|
|
133
|
+
const separator = reference.indexOf(":");
|
|
134
|
+
if (separator >= 0) {
|
|
135
|
+
unresolved = true;
|
|
136
|
+
return "";
|
|
137
|
+
}
|
|
138
|
+
const replacement = settings[reference];
|
|
139
|
+
if (replacement === void 0) {
|
|
140
|
+
unresolved = true;
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
return replacement;
|
|
144
|
+
});
|
|
145
|
+
if (unresolved) return null;
|
|
146
|
+
if (resolved.includes("$(")) return resolveBuildSetting(resolved, settings, depth + 1);
|
|
147
|
+
return resolved;
|
|
148
|
+
}
|
|
149
|
+
function resolvedIdentityField(value) {
|
|
150
|
+
const trimmed = value?.trim() ?? "";
|
|
151
|
+
if (!trimmed || trimmed.includes("$(")) return null;
|
|
152
|
+
return trimmed;
|
|
153
|
+
}
|
|
154
|
+
function identityFieldFrom(settings, raw, fallbackSetting) {
|
|
155
|
+
if (raw !== null) return resolvedIdentityField(resolveBuildSetting(raw, settings));
|
|
156
|
+
return resolvedIdentityField(nonEmptyString(fallbackSetting ?? null));
|
|
157
|
+
}
|
|
158
|
+
function readBuildSettingsBlock(source, start) {
|
|
159
|
+
let depth = 0;
|
|
160
|
+
for (let index = start; index < source.length; index++) {
|
|
161
|
+
const character = source[index];
|
|
162
|
+
if (character === "{") depth++;
|
|
163
|
+
else if (character === "}") {
|
|
164
|
+
depth--;
|
|
165
|
+
if (depth === 0) return source.slice(start, index + 1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return source.slice(start);
|
|
169
|
+
}
|
|
170
|
+
function parseBuildSettings(block) {
|
|
171
|
+
const settings = {};
|
|
172
|
+
const matchPattern = /([A-Z0-9_]+) = ("(?:[^"\\]|\\.)*"|[^;{}]*);/g;
|
|
173
|
+
let match;
|
|
174
|
+
while ((match = matchPattern.exec(block)) !== null) {
|
|
175
|
+
const raw = match[2].trim();
|
|
176
|
+
settings[match[1]] = raw.startsWith('"') ? raw.slice(1, -1) : raw.trim();
|
|
177
|
+
}
|
|
178
|
+
return settings;
|
|
179
|
+
}
|
|
180
|
+
function appTargetReleaseSettings(pbxproj, targetName, infoPlistRelativePath) {
|
|
181
|
+
const configurationPattern = /\/\* (Release|Debug) \*\/ = \{/g;
|
|
182
|
+
const candidates = [];
|
|
183
|
+
let match;
|
|
184
|
+
while ((match = configurationPattern.exec(pbxproj)) !== null) {
|
|
185
|
+
const blockStart = pbxproj.indexOf("{", match.index);
|
|
186
|
+
if (blockStart < 0) continue;
|
|
187
|
+
const block = readBuildSettingsBlock(pbxproj, blockStart);
|
|
188
|
+
const buildSettingsStart = block.indexOf("buildSettings = {");
|
|
189
|
+
if (buildSettingsStart < 0) continue;
|
|
190
|
+
const settings = parseBuildSettings(
|
|
191
|
+
readBuildSettingsBlock(block, block.indexOf("{", buildSettingsStart))
|
|
192
|
+
);
|
|
193
|
+
candidates.push({ name: match[1], settings });
|
|
194
|
+
}
|
|
195
|
+
const plistMatch = (settings) => {
|
|
196
|
+
const plist = settings.INFOPLIST_FILE;
|
|
197
|
+
if (!plist) return false;
|
|
198
|
+
const normalized = plist.replace(/^"|"$/g, "");
|
|
199
|
+
return normalized === infoPlistRelativePath || infoPlistRelativePath.endsWith(`/${normalized}`) || normalized.endsWith(`/${infoPlistRelativePath}`);
|
|
200
|
+
};
|
|
201
|
+
const named = (settings) => resolveBuildSetting(settings.PRODUCT_NAME ?? "", settings) === targetName;
|
|
202
|
+
return candidates.find(
|
|
203
|
+
(candidate) => candidate.name === "Release" && plistMatch(candidate.settings)
|
|
204
|
+
)?.settings ?? candidates.find(
|
|
205
|
+
(candidate) => candidate.name === "Release" && named(candidate.settings)
|
|
206
|
+
)?.settings ?? null;
|
|
207
|
+
}
|
|
208
|
+
function nativeAppIdentityFromIos(files) {
|
|
209
|
+
const appDelegatePattern = /(?:^|\/)ios\/([^/]+)\/AppDelegate\.(?:swift|mm|m)$/;
|
|
210
|
+
let targetName = null;
|
|
211
|
+
for (const path of Object.keys(files)) {
|
|
212
|
+
if (path.includes("/Pods/")) continue;
|
|
213
|
+
const match = path.match(appDelegatePattern);
|
|
214
|
+
if (match) {
|
|
215
|
+
targetName = match[1];
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!targetName) return null;
|
|
220
|
+
const plistPath = Object.keys(files).find(
|
|
221
|
+
(path) => path === `ios/${targetName}/Info.plist`
|
|
222
|
+
);
|
|
223
|
+
const plist = plistPath ? files[plistPath] : null;
|
|
224
|
+
if (!plist) return null;
|
|
225
|
+
const pbxprojPath = Object.keys(files).find(
|
|
226
|
+
(path) => /(?:^|\/)ios\/[^/]+\.xcodeproj\/project\.pbxproj$/.test(path)
|
|
227
|
+
);
|
|
228
|
+
const settings = pbxprojPath ? appTargetReleaseSettings(files[pbxprojPath], targetName, `${targetName}/Info.plist`) : null;
|
|
229
|
+
if (!settings) return null;
|
|
230
|
+
const bundleIdentifier = identityFieldFrom(
|
|
231
|
+
settings,
|
|
232
|
+
plistString(plist, "CFBundleIdentifier"),
|
|
233
|
+
settings.PRODUCT_BUNDLE_IDENTIFIER
|
|
234
|
+
);
|
|
235
|
+
if (!bundleIdentifier) return null;
|
|
236
|
+
const appVersion = identityFieldFrom(
|
|
237
|
+
settings,
|
|
238
|
+
plistString(plist, "CFBundleShortVersionString"),
|
|
239
|
+
settings.MARKETING_VERSION
|
|
240
|
+
);
|
|
241
|
+
const buildVersion = identityFieldFrom(
|
|
242
|
+
settings,
|
|
243
|
+
plistString(plist, "CFBundleVersion"),
|
|
244
|
+
settings.CURRENT_PROJECT_VERSION
|
|
245
|
+
);
|
|
246
|
+
if (!appVersion || !buildVersion) return null;
|
|
247
|
+
const applicationName = identityFieldFrom(settings, plistString(plist, "CFBundleDisplayName"), void 0) ?? identityFieldFrom(
|
|
248
|
+
settings,
|
|
249
|
+
plistString(plist, "CFBundleName"),
|
|
250
|
+
settings.PRODUCT_NAME
|
|
251
|
+
) ?? resolvedIdentityField(resolveBuildSetting(settings.PRODUCT_NAME ?? "", settings)) ?? resolvedIdentityField(targetName);
|
|
252
|
+
if (!applicationName) return null;
|
|
253
|
+
return {
|
|
254
|
+
applicationName,
|
|
255
|
+
appVersion,
|
|
256
|
+
buildVersion,
|
|
257
|
+
bundleIdentifier,
|
|
258
|
+
platform: "ios"
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function nativeAppIdentityFromAndroid() {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
function extractNativeAppIdentityFromFiles(files, platform) {
|
|
265
|
+
return platform === "android" ? nativeAppIdentityFromAndroid() : nativeAppIdentityFromIos(files);
|
|
266
|
+
}
|
|
267
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
268
|
+
0 && (module.exports = {
|
|
269
|
+
applyNativeAppIdentity,
|
|
270
|
+
createNativeAppIdentityFooter,
|
|
271
|
+
detachNativeAppIdentityFooter,
|
|
272
|
+
extractNativeAppIdentityFromFiles,
|
|
273
|
+
getAppliedNativeAppIdentity,
|
|
274
|
+
insertNativeAppIdentityFooter,
|
|
275
|
+
isNativeAppIdentity,
|
|
276
|
+
readNativeAppIdentity,
|
|
277
|
+
readNativeAppIdentityFooter
|
|
278
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
|
|
3
|
+
// src/native-app-identity.ts
|
|
4
|
+
var NATIVE_APP_IDENTITY_PREFIX = "globalThis.__sootsimNativeAppIdentity=";
|
|
5
|
+
var METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function nonEmptyString(value) {
|
|
10
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
11
|
+
}
|
|
12
|
+
function isNativeAppIdentity(value) {
|
|
13
|
+
if (!isRecord(value)) return false;
|
|
14
|
+
const platform = value.platform;
|
|
15
|
+
if (platform !== "ios" && platform !== "android") return false;
|
|
16
|
+
const applicationName = value.applicationName;
|
|
17
|
+
if (applicationName !== null && nonEmptyString(applicationName) === null) return false;
|
|
18
|
+
if (nonEmptyString(value.appVersion) === null) return false;
|
|
19
|
+
if (nonEmptyString(value.bundleIdentifier) === null) return false;
|
|
20
|
+
const buildVersion = nonEmptyString(value.buildVersion);
|
|
21
|
+
if (buildVersion === null) return false;
|
|
22
|
+
if (platform === "android" && !/^[1-9][0-9]*$/.test(buildVersion)) return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
function readNativeAppIdentity(value) {
|
|
26
|
+
if (value === void 0 || value === null) return null;
|
|
27
|
+
if (!isNativeAppIdentity(value)) {
|
|
28
|
+
throw new Error("native app identity is malformed");
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
applicationName: value.applicationName,
|
|
32
|
+
appVersion: value.appVersion,
|
|
33
|
+
buildVersion: value.buildVersion,
|
|
34
|
+
bundleIdentifier: value.bundleIdentifier,
|
|
35
|
+
platform: value.platform
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function applyNativeAppIdentity(identity) {
|
|
39
|
+
const globals = globalThis;
|
|
40
|
+
if (identity) globals.__sootsim_native_app_identity = identity;
|
|
41
|
+
else delete globals.__sootsim_native_app_identity;
|
|
42
|
+
}
|
|
43
|
+
function getAppliedNativeAppIdentity() {
|
|
44
|
+
const value = globalThis.__sootsim_native_app_identity;
|
|
45
|
+
return isNativeAppIdentity(value) ? value : null;
|
|
46
|
+
}
|
|
47
|
+
function createNativeAppIdentityFooter(identity) {
|
|
48
|
+
const payload = JSON.stringify(identity).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/<\//g, "<\\/");
|
|
49
|
+
return `
|
|
50
|
+
${NATIVE_APP_IDENTITY_PREFIX}${payload};`;
|
|
51
|
+
}
|
|
52
|
+
function nativeAppIdentityFooterStart(source) {
|
|
53
|
+
return source.lastIndexOf(`
|
|
54
|
+
${NATIVE_APP_IDENTITY_PREFIX}`);
|
|
55
|
+
}
|
|
56
|
+
function readNativeAppIdentityFooter(source) {
|
|
57
|
+
const start = nativeAppIdentityFooterStart(source);
|
|
58
|
+
if (start < 0) return null;
|
|
59
|
+
const lineEnd = source.indexOf("\n", start + 1);
|
|
60
|
+
const line = source.slice(start + 1, lineEnd < 0 ? void 0 : lineEnd);
|
|
61
|
+
if (!line.endsWith(";")) {
|
|
62
|
+
throw new Error("native app identity footer is truncated");
|
|
63
|
+
}
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(line.slice(NATIVE_APP_IDENTITY_PREFIX.length, -1));
|
|
67
|
+
} catch {
|
|
68
|
+
throw new Error("native app identity footer is not valid JSON");
|
|
69
|
+
}
|
|
70
|
+
if (!isNativeAppIdentity(parsed)) {
|
|
71
|
+
throw new Error("native app identity footer is malformed");
|
|
72
|
+
}
|
|
73
|
+
return parsed;
|
|
74
|
+
}
|
|
75
|
+
function detachNativeAppIdentityFooter(source) {
|
|
76
|
+
const start = nativeAppIdentityFooterStart(source);
|
|
77
|
+
if (start < 0) return { source, identity: null };
|
|
78
|
+
const identity = readNativeAppIdentityFooter(source);
|
|
79
|
+
const lineEnd = source.indexOf("\n", start + 1);
|
|
80
|
+
const end = lineEnd < 0 ? source.length : lineEnd;
|
|
81
|
+
return { source: source.slice(0, start) + source.slice(end), identity };
|
|
82
|
+
}
|
|
83
|
+
function insertNativeAppIdentityFooter(source, identity) {
|
|
84
|
+
const existing = nativeAppIdentityFooterStart(source);
|
|
85
|
+
const existingEnd = existing < 0 ? -1 : source.includes("\n", existing + 1) ? source.indexOf("\n", existing + 1) : -1;
|
|
86
|
+
const withoutExisting = existing < 0 ? source : source.slice(0, existing) + source.slice(existingEnd < 0 ? source.length : existingEnd);
|
|
87
|
+
const moduleFooter = withoutExisting.lastIndexOf(`
|
|
88
|
+
${METRO_MODULE_PATHS_PREFIX}`);
|
|
89
|
+
const footer = createNativeAppIdentityFooter(identity);
|
|
90
|
+
if (moduleFooter < 0) return withoutExisting + footer;
|
|
91
|
+
return withoutExisting.slice(0, moduleFooter) + footer + withoutExisting.slice(moduleFooter);
|
|
92
|
+
}
|
|
93
|
+
function plistString(plist, key) {
|
|
94
|
+
const match = plist.match(new RegExp(`<key>${key}</key>\\s*<string>([^<]*)</string>`));
|
|
95
|
+
return match ? match[1].trim() : null;
|
|
96
|
+
}
|
|
97
|
+
function resolveBuildSetting(value, settings, depth = 0) {
|
|
98
|
+
if (depth > 8) return null;
|
|
99
|
+
let unresolved = false;
|
|
100
|
+
const resolved = value.replace(/\$\(([^()]+)\)/g, (_match, reference) => {
|
|
101
|
+
const separator = reference.indexOf(":");
|
|
102
|
+
if (separator >= 0) {
|
|
103
|
+
unresolved = true;
|
|
104
|
+
return "";
|
|
105
|
+
}
|
|
106
|
+
const replacement = settings[reference];
|
|
107
|
+
if (replacement === void 0) {
|
|
108
|
+
unresolved = true;
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
return replacement;
|
|
112
|
+
});
|
|
113
|
+
if (unresolved) return null;
|
|
114
|
+
if (resolved.includes("$(")) return resolveBuildSetting(resolved, settings, depth + 1);
|
|
115
|
+
return resolved;
|
|
116
|
+
}
|
|
117
|
+
function resolvedIdentityField(value) {
|
|
118
|
+
const trimmed = value?.trim() ?? "";
|
|
119
|
+
if (!trimmed || trimmed.includes("$(")) return null;
|
|
120
|
+
return trimmed;
|
|
121
|
+
}
|
|
122
|
+
function identityFieldFrom(settings, raw, fallbackSetting) {
|
|
123
|
+
if (raw !== null) return resolvedIdentityField(resolveBuildSetting(raw, settings));
|
|
124
|
+
return resolvedIdentityField(nonEmptyString(fallbackSetting ?? null));
|
|
125
|
+
}
|
|
126
|
+
function readBuildSettingsBlock(source, start) {
|
|
127
|
+
let depth = 0;
|
|
128
|
+
for (let index = start; index < source.length; index++) {
|
|
129
|
+
const character = source[index];
|
|
130
|
+
if (character === "{") depth++;
|
|
131
|
+
else if (character === "}") {
|
|
132
|
+
depth--;
|
|
133
|
+
if (depth === 0) return source.slice(start, index + 1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return source.slice(start);
|
|
137
|
+
}
|
|
138
|
+
function parseBuildSettings(block) {
|
|
139
|
+
const settings = {};
|
|
140
|
+
const matchPattern = /([A-Z0-9_]+) = ("(?:[^"\\]|\\.)*"|[^;{}]*);/g;
|
|
141
|
+
let match;
|
|
142
|
+
while ((match = matchPattern.exec(block)) !== null) {
|
|
143
|
+
const raw = match[2].trim();
|
|
144
|
+
settings[match[1]] = raw.startsWith('"') ? raw.slice(1, -1) : raw.trim();
|
|
145
|
+
}
|
|
146
|
+
return settings;
|
|
147
|
+
}
|
|
148
|
+
function appTargetReleaseSettings(pbxproj, targetName, infoPlistRelativePath) {
|
|
149
|
+
const configurationPattern = /\/\* (Release|Debug) \*\/ = \{/g;
|
|
150
|
+
const candidates = [];
|
|
151
|
+
let match;
|
|
152
|
+
while ((match = configurationPattern.exec(pbxproj)) !== null) {
|
|
153
|
+
const blockStart = pbxproj.indexOf("{", match.index);
|
|
154
|
+
if (blockStart < 0) continue;
|
|
155
|
+
const block = readBuildSettingsBlock(pbxproj, blockStart);
|
|
156
|
+
const buildSettingsStart = block.indexOf("buildSettings = {");
|
|
157
|
+
if (buildSettingsStart < 0) continue;
|
|
158
|
+
const settings = parseBuildSettings(
|
|
159
|
+
readBuildSettingsBlock(block, block.indexOf("{", buildSettingsStart))
|
|
160
|
+
);
|
|
161
|
+
candidates.push({ name: match[1], settings });
|
|
162
|
+
}
|
|
163
|
+
const plistMatch = (settings) => {
|
|
164
|
+
const plist = settings.INFOPLIST_FILE;
|
|
165
|
+
if (!plist) return false;
|
|
166
|
+
const normalized = plist.replace(/^"|"$/g, "");
|
|
167
|
+
return normalized === infoPlistRelativePath || infoPlistRelativePath.endsWith(`/${normalized}`) || normalized.endsWith(`/${infoPlistRelativePath}`);
|
|
168
|
+
};
|
|
169
|
+
const named = (settings) => resolveBuildSetting(settings.PRODUCT_NAME ?? "", settings) === targetName;
|
|
170
|
+
return candidates.find(
|
|
171
|
+
(candidate) => candidate.name === "Release" && plistMatch(candidate.settings)
|
|
172
|
+
)?.settings ?? candidates.find(
|
|
173
|
+
(candidate) => candidate.name === "Release" && named(candidate.settings)
|
|
174
|
+
)?.settings ?? null;
|
|
175
|
+
}
|
|
176
|
+
function nativeAppIdentityFromIos(files) {
|
|
177
|
+
const appDelegatePattern = /(?:^|\/)ios\/([^/]+)\/AppDelegate\.(?:swift|mm|m)$/;
|
|
178
|
+
let targetName = null;
|
|
179
|
+
for (const path of Object.keys(files)) {
|
|
180
|
+
if (path.includes("/Pods/")) continue;
|
|
181
|
+
const match = path.match(appDelegatePattern);
|
|
182
|
+
if (match) {
|
|
183
|
+
targetName = match[1];
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (!targetName) return null;
|
|
188
|
+
const plistPath = Object.keys(files).find(
|
|
189
|
+
(path) => path === `ios/${targetName}/Info.plist`
|
|
190
|
+
);
|
|
191
|
+
const plist = plistPath ? files[plistPath] : null;
|
|
192
|
+
if (!plist) return null;
|
|
193
|
+
const pbxprojPath = Object.keys(files).find(
|
|
194
|
+
(path) => /(?:^|\/)ios\/[^/]+\.xcodeproj\/project\.pbxproj$/.test(path)
|
|
195
|
+
);
|
|
196
|
+
const settings = pbxprojPath ? appTargetReleaseSettings(files[pbxprojPath], targetName, `${targetName}/Info.plist`) : null;
|
|
197
|
+
if (!settings) return null;
|
|
198
|
+
const bundleIdentifier = identityFieldFrom(
|
|
199
|
+
settings,
|
|
200
|
+
plistString(plist, "CFBundleIdentifier"),
|
|
201
|
+
settings.PRODUCT_BUNDLE_IDENTIFIER
|
|
202
|
+
);
|
|
203
|
+
if (!bundleIdentifier) return null;
|
|
204
|
+
const appVersion = identityFieldFrom(
|
|
205
|
+
settings,
|
|
206
|
+
plistString(plist, "CFBundleShortVersionString"),
|
|
207
|
+
settings.MARKETING_VERSION
|
|
208
|
+
);
|
|
209
|
+
const buildVersion = identityFieldFrom(
|
|
210
|
+
settings,
|
|
211
|
+
plistString(plist, "CFBundleVersion"),
|
|
212
|
+
settings.CURRENT_PROJECT_VERSION
|
|
213
|
+
);
|
|
214
|
+
if (!appVersion || !buildVersion) return null;
|
|
215
|
+
const applicationName = identityFieldFrom(settings, plistString(plist, "CFBundleDisplayName"), void 0) ?? identityFieldFrom(
|
|
216
|
+
settings,
|
|
217
|
+
plistString(plist, "CFBundleName"),
|
|
218
|
+
settings.PRODUCT_NAME
|
|
219
|
+
) ?? resolvedIdentityField(resolveBuildSetting(settings.PRODUCT_NAME ?? "", settings)) ?? resolvedIdentityField(targetName);
|
|
220
|
+
if (!applicationName) return null;
|
|
221
|
+
return {
|
|
222
|
+
applicationName,
|
|
223
|
+
appVersion,
|
|
224
|
+
buildVersion,
|
|
225
|
+
bundleIdentifier,
|
|
226
|
+
platform: "ios"
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function nativeAppIdentityFromAndroid() {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
function extractNativeAppIdentityFromFiles(files, platform) {
|
|
233
|
+
return platform === "android" ? nativeAppIdentityFromAndroid() : nativeAppIdentityFromIos(files);
|
|
234
|
+
}
|
|
235
|
+
export {
|
|
236
|
+
applyNativeAppIdentity,
|
|
237
|
+
createNativeAppIdentityFooter,
|
|
238
|
+
detachNativeAppIdentityFooter,
|
|
239
|
+
extractNativeAppIdentityFromFiles,
|
|
240
|
+
getAppliedNativeAppIdentity,
|
|
241
|
+
insertNativeAppIdentityFooter,
|
|
242
|
+
isNativeAppIdentity,
|
|
243
|
+
readNativeAppIdentity,
|
|
244
|
+
readNativeAppIdentityFooter
|
|
245
|
+
};
|
package/dist-lib/profiles.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
package/dist-lib/render-mode.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.630 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|