@tamagui/native-ci 3.0.0-beta.669.1 → 3.0.0-beta.728.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/dist/android-utils.mjs.map +1 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/detox.mjs.map +1 -1
- package/dist/fingerprint.mjs.map +1 -1
- package/dist/ios-utils.mjs.map +1 -1
- package/dist/metro.mjs.map +1 -1
- package/dist/runner.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"android-utils.js","names":[],"sources":["android-utils.js"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { $ } from \"bun\";\nimport { METRO_PORT, DETOX_SERVER_PORT } from \"./constants\";\nasync function waitForDevice() {\n console.info(\"\\n--- Waiting for device ---\");\n try {\n const result = await $`adb devices`.quiet();\n const lines = result.stdout.toString().split(\"\\n\").filter((line) => line.includes(\"\tdevice\"));\n if (lines.length === 0) {\n throw new Error(\n \"No Android device/emulator connected. Please start an emulator first.\"\n );\n }\n } catch (error) {\n const err = error;\n throw new Error(`No Android device available: ${err.message}`);\n }\n try {\n await $`timeout 30 adb wait-for-device`.quiet();\n await $`timeout 60 adb shell 'while [ -z \"$(getprop sys.boot_completed)\" ]; do sleep 1; done'`.quiet();\n console.info(\"Device is ready!\");\n } catch (error) {\n const err = error;\n throw new Error(`Failed to wait for Android device: ${err.message}`);\n }\n}\nasync function setupAdbReverse() {\n console.info(\"\\n--- Setting up ADB reverse ---\");\n try {\n await $`adb reverse tcp:${METRO_PORT} tcp:${METRO_PORT}`;\n console.info(`Reversed port ${METRO_PORT} (Metro)`);\n await $`adb reverse tcp:${DETOX_SERVER_PORT} tcp:${DETOX_SERVER_PORT}`;\n console.info(`Reversed port ${DETOX_SERVER_PORT} (Detox)`);\n } catch (error) {\n const err = error;\n throw new Error(\n `Failed to setup ADB reverse ports: ${err.message}\nMake sure the Android emulator is running and adb is available.`\n );\n }\n}\nasync function setupAndroidDevice() {\n await waitForDevice();\n await setupAdbReverse();\n}\nasync function ensureAndroidFolder() {\n const buildGradlePath = join(process.cwd(), \"android\", \"build.gradle\");\n if (existsSync(buildGradlePath)) {\n console.info(\"Android folder already exists (build.gradle found)\");\n return;\n }\n console.info(\"\\n--- Generating android/ folder (for Metro) ---\");\n console.info(\"Note: android/build.gradle not found, running expo prebuild\");\n try {\n await $`npx expo prebuild --platform android`;\n console.info(\"Android folder generated!\");\n } catch (error) {\n const err = error;\n throw new Error(`Failed to generate android folder: ${err.message}`);\n }\n}\nexport {\n ensureAndroidFolder,\n setupAdbReverse,\n setupAndroidDevice,\n waitForDevice\n};\n//# sourceMappingURL=android-utils.js.map\n"],"mappings":";;;;;;AAIA,eAAe,gBAAgB;CAC7B,QAAQ,KAAK,8BAA8B;CAC3C,IAAI;EACF,MAAM,SAAS,MAAM,CAAC,cAAc,MAAM;EAC1C,MAAM,QAAQ,OAAO,OAAO,SAAS,
|
|
1
|
+
{"version":3,"file":"android-utils.js","names":[],"sources":["android-utils.js"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { $ } from \"bun\";\nimport { METRO_PORT, DETOX_SERVER_PORT } from \"./constants\";\nasync function waitForDevice() {\n console.info(\"\\n--- Waiting for device ---\");\n try {\n const result = await $`adb devices`.quiet();\n const lines = result.stdout.toString().split(\"\\n\").filter((line) => line.includes(\"\tdevice\"));\n if (lines.length === 0) {\n throw new Error(\n \"No Android device/emulator connected. Please start an emulator first.\"\n );\n }\n } catch (error) {\n const err = error;\n throw new Error(`No Android device available: ${err.message}`);\n }\n try {\n await $`timeout 30 adb wait-for-device`.quiet();\n await $`timeout 60 adb shell 'while [ -z \"$(getprop sys.boot_completed)\" ]; do sleep 1; done'`.quiet();\n console.info(\"Device is ready!\");\n } catch (error) {\n const err = error;\n throw new Error(`Failed to wait for Android device: ${err.message}`);\n }\n}\nasync function setupAdbReverse() {\n console.info(\"\\n--- Setting up ADB reverse ---\");\n try {\n await $`adb reverse tcp:${METRO_PORT} tcp:${METRO_PORT}`;\n console.info(`Reversed port ${METRO_PORT} (Metro)`);\n await $`adb reverse tcp:${DETOX_SERVER_PORT} tcp:${DETOX_SERVER_PORT}`;\n console.info(`Reversed port ${DETOX_SERVER_PORT} (Detox)`);\n } catch (error) {\n const err = error;\n throw new Error(\n `Failed to setup ADB reverse ports: ${err.message}\nMake sure the Android emulator is running and adb is available.`\n );\n }\n}\nasync function setupAndroidDevice() {\n await waitForDevice();\n await setupAdbReverse();\n}\nasync function ensureAndroidFolder() {\n const buildGradlePath = join(process.cwd(), \"android\", \"build.gradle\");\n if (existsSync(buildGradlePath)) {\n console.info(\"Android folder already exists (build.gradle found)\");\n return;\n }\n console.info(\"\\n--- Generating android/ folder (for Metro) ---\");\n console.info(\"Note: android/build.gradle not found, running expo prebuild\");\n try {\n await $`npx expo prebuild --platform android`;\n console.info(\"Android folder generated!\");\n } catch (error) {\n const err = error;\n throw new Error(`Failed to generate android folder: ${err.message}`);\n }\n}\nexport {\n ensureAndroidFolder,\n setupAdbReverse,\n setupAndroidDevice,\n waitForDevice\n};\n//# sourceMappingURL=android-utils.js.map\n"],"mappings":";;;;;;AAIA,eAAe,gBAAgB;CAC7B,QAAQ,KAAK,8BAA8B;CAC3C,IAAI;EACF,MAAM,SAAS,MAAM,CAAC,cAAc,MAAM;EAC1C,MAAM,QAAQ,OAAO,OAAO,SAAS,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,SAAS,SAAS,CAAC;EAC5F,IAAI,MAAM,WAAW,GAAG;GACtB,MAAM,IAAI,MACR,uEACF;EACF;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MAAM,gCAAgC,IAAI,SAAS;CAC/D;CACA,IAAI;EACF,MAAM,CAAC,iCAAiC,MAAM;EAC9C,MAAM,CAAC,wFAAwF,MAAM;EACrG,QAAQ,KAAK,kBAAkB;CACjC,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MAAM,sCAAsC,IAAI,SAAS;CACrE;AACF;AACA,eAAe,kBAAkB;CAC/B,QAAQ,KAAK,kCAAkC;CAC/C,IAAI;EACF,MAAM,CAAC,mBAAmB,WAAW,OAAO;EAC5C,QAAQ,KAAK,iBAAiB,WAAW,SAAS;EAClD,MAAM,CAAC,mBAAmB,kBAAkB,OAAO;EACnD,QAAQ,KAAK,iBAAiB,kBAAkB,SAAS;CAC3D,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MACR,sCAAsC,IAAI,QAAQ;gEAEpD;CACF;AACF;AACA,eAAe,qBAAqB;CAClC,MAAM,cAAc;CACpB,MAAM,gBAAgB;AACxB;AACA,eAAe,sBAAsB;CACnC,MAAM,kBAAkB,KAAK,QAAQ,IAAI,GAAG,WAAW,cAAc;CACrE,IAAI,WAAW,eAAe,GAAG;EAC/B,QAAQ,KAAK,oDAAoD;EACjE;CACF;CACA,QAAQ,KAAK,kDAAkD;CAC/D,QAAQ,KAAK,6DAA6D;CAC1E,IAAI;EACF,MAAM,CAAC;EACP,QAAQ,KAAK,2BAA2B;CAC1C,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MAAM,sCAAsC,IAAI,SAAS;CACrE;AACF"}
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["cli.js"],"sourcesContent":["#!/usr/bin/env bun\nimport { generateFingerprint, generatePreFingerprintHash } from \"./fingerprint\";\nimport {\n createCacheKey,\n saveFingerprintToKV,\n getFingerprintFromKV,\n saveCache,\n loadCache\n} from \"./cache\";\nimport { setGitHubOutput, isGitHubActions, isCI } from \"./runner\";\nimport {\n ensureIosDeps,\n ensureAndroidDeps,\n ensureMaestro,\n printDepsStatus\n} from \"./deps\";\nimport { withMetro } from \"./metro\";\nimport { runDetoxTests } from \"./detox\";\nimport {\n ensureIOSFolder,\n ensureIOSApp,\n ensureBootedSimulator,\n ensureAppInstalled,\n getBootedSimulatorUDID,\n getMaestroBundleId\n} from \"./ios-utils\";\nimport { setupAndroidDevice, ensureAndroidFolder } from \"./android-utils\";\nimport { chmodSync, mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nconst HELP = `\nnative-ci - Native CI/CD helpers for Expo apps\n\nCOMMANDS:\n\n Test Commands:\n test ios [options] Run iOS Detox tests\n test android [options] Run Android Detox tests\n test maestro [flow] Run Maestro tests\n test all Run all tests (iOS + Android)\n\n Dependency Commands:\n deps Show dependency status\n deps install Install missing dependencies\n deps install-ios Install iOS dependencies (macOS only)\n deps install-android Install Android dependencies\n deps install-maestro Install Maestro\n\n Fingerprint Commands:\n fingerprint <platform> Generate native build fingerprint\n fingerprint-test Test fingerprint caching locally\n pre-hash <files...> Generate quick pre-fingerprint hash\n cache-key <platform> <fp> Generate cache key from fingerprint\n\n KV Store Commands:\n kv-get <key> Get value from KV store\n kv-set <key> <value> Set value in KV store\n\nOPTIONS:\n --project-root <path> Project root directory (default: cwd)\n --config <name> Detox configuration name\n --record-logs <mode> Record logs: none, failing, all (default: all)\n --retries <n> Number of retries for flaky tests (default: 0)\n --headless Run in headless mode (Android only)\n --prefix <prefix> Cache key prefix (default: native-build)\n --github-output Output results for GitHub Actions\n --json Output as JSON\n --help Show this help message\n\nENVIRONMENT:\n KV_STORE_REDIS_REST_URL Redis REST API URL for fingerprint caching\n KV_STORE_REDIS_REST_TOKEN Redis REST API token\n\nEXAMPLES:\n native-ci test ios\n native-ci test android --headless\n native-ci test maestro\n native-ci deps\n native-ci deps install\n native-ci fingerprint ios\n native-ci fingerprint-test\n`;\nfunction createMaestroXcrunShim() {\n const binDir = mkdtempSync(join(tmpdir(), \"native-ci-maestro-\"));\n const xcrunPath = join(binDir, \"xcrun\");\n writeFileSync(\n xcrunPath,\n `#!/bin/sh\nif [ \"$1\" = \"devicectl\" ] && [ \"$2\" = \"--json-output\" ] && [ \"$4\" = \"list\" ] && [ \"$5\" = \"devices\" ]; then\n printf '{\"result\":{\"devices\":[]}}\\\\n' > \"$3\"\n exit 0\nfi\n\nexec /usr/bin/xcrun \"$@\"\n`\n );\n chmodSync(xcrunPath, 493);\n return binDir;\n}\nfunction parseArgs(argv) {\n const args2 = [];\n const options2 = {\n projectRoot: process.cwd(),\n config: \"\",\n recordLogs: \"all\",\n retries: 0,\n headless: false,\n prefix: \"native-build\",\n githubOutput: false,\n json: false,\n help: false\n };\n let i = 0;\n while (i < argv.length) {\n const arg = argv[i];\n if (arg === \"--project-root\" && argv[i + 1]) {\n options2.projectRoot = argv[++i];\n } else if (arg === \"--config\" && argv[i + 1]) {\n options2.config = argv[++i];\n } else if (arg === \"--record-logs\" && argv[i + 1]) {\n options2.recordLogs = argv[++i];\n } else if (arg === \"--retries\" && argv[i + 1]) {\n const val = Number.parseInt(argv[++i], 10);\n if (!Number.isNaN(val) && val >= 0) {\n options2.retries = val;\n }\n } else if (arg === \"--prefix\" && argv[i + 1]) {\n options2.prefix = argv[++i];\n } else if (arg === \"--github-output\") {\n options2.githubOutput = true;\n } else if (arg === \"--json\") {\n options2.json = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n options2.help = true;\n } else if (!arg.startsWith(\"-\")) {\n args2.push(arg);\n }\n i++;\n }\n return {\n command: args2[0] || \"\",\n subcommand: args2[1] || \"\",\n args: args2.slice(2),\n options: options2\n };\n}\nfunction validatePlatform(value) {\n if (value !== \"ios\" && value !== \"android\") {\n console.error('Error: platform must be \"ios\" or \"android\"');\n process.exit(1);\n }\n return value;\n}\nfunction getKVCredentials() {\n const url = process.env.KV_STORE_REDIS_REST_URL;\n const token = process.env.KV_STORE_REDIS_REST_TOKEN;\n if (!url || !token) {\n console.error(\"Error: KV_STORE_REDIS_REST_URL and KV_STORE_REDIS_REST_TOKEN required\");\n process.exit(1);\n }\n return { url, token };\n}\nconst { command, subcommand, args, options } = parseArgs(process.argv.slice(2));\nif (options.help || !command) {\n console.info(HELP);\n process.exit(options.help ? 0 : 1);\n}\ntry {\n switch (command) {\n // ========================================\n // Test Commands\n // ========================================\n case \"test\": {\n if (isCI() && !process.env.NATIVE_CI_FORCE_RUN) {\n console.info(\"Skipping native tests in CI (handled by separate workflow)\");\n console.info(\"Set NATIVE_CI_FORCE_RUN=1 to force run\");\n process.exit(0);\n }\n const platform = subcommand || \"ios\";\n if (platform === \"ios\") {\n ensureBootedSimulator();\n await ensureIosDeps();\n const config = options.config || \"ios.sim.debug\";\n console.info(\"=== iOS Detox Test Runner ===\");\n console.info(`Config: ${config}`);\n console.info(`Project root: ${options.projectRoot}`);\n process.chdir(options.projectRoot);\n await ensureIOSFolder();\n await ensureIOSApp(config);\n const exitCode = await withMetro(\"ios\", async () => {\n return runDetoxTests({\n config,\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries,\n testFiles: args.length > 0 ? args : void 0\n });\n });\n process.exit(exitCode);\n } else if (platform === \"android\") {\n await ensureAndroidDeps();\n const config = options.config || \"android.emu.debug\";\n console.info(\"=== Android Detox Test Runner ===\");\n console.info(`Config: ${config}`);\n console.info(`Project root: ${options.projectRoot}`);\n console.info(`Headless: ${options.headless}`);\n process.chdir(options.projectRoot);\n await ensureAndroidFolder();\n await setupAndroidDevice();\n const exitCode = await withMetro(\"android\", async () => {\n return runDetoxTests({\n config,\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries,\n headless: options.headless,\n testFiles: args.length > 0 ? args : void 0\n });\n });\n process.exit(exitCode);\n } else if (platform === \"maestro\") {\n ensureBootedSimulator();\n await ensureMaestro();\n const flow = args[0] || \"\";\n console.info(\"=== Maestro Test Runner ===\");\n console.info(`Flow: ${flow || \"all\"}`);\n console.info(`Project root: ${options.projectRoot}`);\n process.chdir(options.projectRoot);\n const udid = getBootedSimulatorUDID();\n const bundleId = getMaestroBundleId(options.projectRoot);\n await ensureAppInstalled({ projectRoot: options.projectRoot, bundleId, udid });\n const exitCode = await withMetro(\"ios\", async () => {\n const { $ } = await import(\"bun\");\n const flowArg = flow ? `./flows/${flow}` : \"./flows\";\n const udidArgs = [\"--udid\", udid];\n const debugDir = `${options.projectRoot}/.maestro-debug`;\n const xcrunShimDir = createMaestroXcrunShim();\n const previousPath = process.env.PATH;\n try {\n process.env.PATH = `${xcrunShimDir}:${previousPath ?? \"\"}`;\n const result = await $`maestro test ${flowArg} --exclude-tags=util --no-ansi --debug-output=${debugDir} ${udidArgs}`.nothrow();\n return result.exitCode;\n } finally {\n if (previousPath === void 0) {\n delete process.env.PATH;\n } else {\n process.env.PATH = previousPath;\n }\n rmSync(xcrunShimDir, { recursive: true, force: true });\n }\n });\n process.exit(exitCode);\n } else if (platform === \"all\") {\n ensureBootedSimulator();\n console.info(\"=== Running All Native Tests ===\\n\");\n await ensureIosDeps();\n console.info(\"\\n--- iOS Tests ---\\n\");\n process.chdir(options.projectRoot);\n await ensureIOSFolder();\n await ensureIOSApp(options.config || \"ios.sim.debug\");\n let iosExit = 0;\n try {\n iosExit = await withMetro(\"ios\", async () => {\n return runDetoxTests({\n config: options.config || \"ios.sim.debug\",\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries\n });\n });\n } catch (err) {\n console.error(\"iOS tests failed:\", err);\n iosExit = 1;\n }\n await ensureAndroidDeps();\n console.info(\"\\n--- Android Tests ---\\n\");\n await ensureAndroidFolder();\n await setupAndroidDevice();\n let androidExit = 0;\n try {\n androidExit = await withMetro(\"android\", async () => {\n return runDetoxTests({\n config: options.config || \"android.emu.debug\",\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries,\n headless: options.headless\n });\n });\n } catch (err) {\n console.error(\"Android tests failed:\", err);\n androidExit = 1;\n }\n const success = iosExit === 0 && androidExit === 0;\n console.info(`\n=== Test Results ===`);\n console.info(`iOS: ${iosExit === 0 ? \"PASSED\" : \"FAILED\"}`);\n console.info(`Android: ${androidExit === 0 ? \"PASSED\" : \"FAILED\"}`);\n process.exit(success ? 0 : 1);\n } else {\n console.error(`Unknown test platform: ${platform}`);\n console.info(\"Usage: native-ci test [ios|android|maestro|all]\");\n process.exit(1);\n }\n break;\n }\n // ========================================\n // Dependency Commands\n // ========================================\n case \"deps\": {\n if (!subcommand || subcommand === \"status\") {\n printDepsStatus();\n } else if (subcommand === \"install\") {\n console.info(\"Installing all dependencies...\\n\");\n await ensureIosDeps();\n await ensureMaestro();\n console.info(\"\\nAll dependencies installed!\");\n } else if (subcommand === \"install-ios\") {\n await ensureIosDeps();\n } else if (subcommand === \"install-android\") {\n await ensureAndroidDeps();\n } else if (subcommand === \"install-maestro\") {\n await ensureMaestro();\n } else {\n console.error(`Unknown deps subcommand: ${subcommand}`);\n process.exit(1);\n }\n break;\n }\n // ========================================\n // Fingerprint Commands\n // ========================================\n case \"fingerprint\": {\n const platform = validatePlatform(subcommand);\n const result = await generateFingerprint({\n platform,\n projectRoot: options.projectRoot\n });\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"fingerprint\", result.hash);\n setGitHubOutput(\n \"cache-key\",\n createCacheKey({\n platform,\n fingerprint: result.hash,\n prefix: options.prefix\n })\n );\n }\n if (options.json) {\n console.info(JSON.stringify(result, null, 2));\n } else {\n console.info(result.hash);\n }\n break;\n }\n case \"fingerprint-test\": {\n const CACHE_FILE = \".fingerprint-cache.json\";\n console.info(\"Generating fingerprints...\\n\");\n const iosResult = await generateFingerprint({\n platform: \"ios\",\n projectRoot: options.projectRoot\n });\n const androidResult = await generateFingerprint({\n platform: \"android\",\n projectRoot: options.projectRoot\n });\n const iosFingerprint = iosResult.hash;\n const androidFingerprint = androidResult.hash;\n console.info(\"Current fingerprints:\");\n console.info(` iOS: ${iosFingerprint}`);\n console.info(` Android: ${androidFingerprint}`);\n console.info(\"\");\n const cache = loadCache(CACHE_FILE);\n if (cache?.ios && cache?.android) {\n console.info(\"Previous fingerprints (from cache):\");\n console.info(` iOS: ${cache.ios}`);\n console.info(` Android: ${cache.android}`);\n console.info(\"\");\n const iosChanged = cache.ios !== iosFingerprint;\n const androidChanged = cache.android !== androidFingerprint;\n if (iosChanged || androidChanged) {\n console.info(\"Fingerprints changed!\");\n if (iosChanged)\n console.info(\" - iOS fingerprint changed (would trigger iOS rebuild)\");\n if (androidChanged)\n console.info(\n \" - Android fingerprint changed (would trigger Android rebuild)\"\n );\n } else {\n console.info(\"Fingerprints match - no rebuild needed\");\n }\n } else {\n console.info(\"No previous fingerprints cached.\");\n }\n saveCache(CACHE_FILE, {\n ios: iosFingerprint,\n android: androidFingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n console.info(`\nSaved fingerprints to ${CACHE_FILE}`);\n console.info(`\nTo test cache invalidation:\n 1. Add a native dependency: yarn add react-native-mmkv\n 2. Run this script again: native-ci fingerprint-test\n 3. Fingerprints should change!\n 4. Remove the dependency: yarn remove react-native-mmkv\n 5. Run this script again - fingerprints should match original\n`);\n break;\n }\n case \"pre-hash\": {\n const files = [subcommand, ...args].filter(Boolean);\n if (files.length === 0) {\n console.error(\"Error: at least one file required\");\n process.exit(1);\n }\n const hash = generatePreFingerprintHash(files, options.projectRoot);\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"pre-fingerprint-hash\", hash);\n }\n if (options.json) {\n console.info(JSON.stringify({ hash, files }, null, 2));\n } else {\n console.info(hash);\n }\n break;\n }\n case \"cache-key\": {\n const platform = validatePlatform(subcommand);\n const fingerprint = args[0];\n if (!fingerprint) {\n console.error(\"Error: fingerprint is required\");\n process.exit(1);\n }\n const cacheKey = createCacheKey({\n platform,\n fingerprint,\n prefix: options.prefix\n });\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"cache-key\", cacheKey);\n }\n console.info(cacheKey);\n break;\n }\n // ========================================\n // KV Store Commands\n // ========================================\n case \"kv-get\": {\n const key = subcommand;\n if (!key) {\n console.error(\"Error: key is required\");\n process.exit(1);\n }\n const kv = getKVCredentials();\n const value = await getFingerprintFromKV(kv, key);\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"value\", value || \"\");\n setGitHubOutput(\"found\", value ? \"true\" : \"false\");\n }\n if (value) {\n console.info(value);\n } else {\n process.exit(1);\n }\n break;\n }\n case \"kv-set\": {\n const key = subcommand;\n const value = args[0];\n if (!key || !value) {\n console.error(\"Error: key and value are required\");\n process.exit(1);\n }\n const kv = getKVCredentials();\n await saveFingerprintToKV(kv, key, value);\n console.info(\"OK\");\n break;\n }\n default:\n console.error(`Unknown command: ${command}`);\n console.info(HELP);\n process.exit(1);\n }\n} catch (error) {\n console.error(\"Error:\", error.message);\n process.exit(1);\n}\n//# sourceMappingURL=cli.js.map\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["cli.js"],"sourcesContent":["#!/usr/bin/env bun\nimport { generateFingerprint, generatePreFingerprintHash } from \"./fingerprint\";\nimport {\n createCacheKey,\n saveFingerprintToKV,\n getFingerprintFromKV,\n saveCache,\n loadCache\n} from \"./cache\";\nimport { setGitHubOutput, isGitHubActions, isCI } from \"./runner\";\nimport {\n ensureIosDeps,\n ensureAndroidDeps,\n ensureMaestro,\n printDepsStatus\n} from \"./deps\";\nimport { withMetro } from \"./metro\";\nimport { runDetoxTests } from \"./detox\";\nimport {\n ensureIOSFolder,\n ensureIOSApp,\n ensureBootedSimulator,\n ensureAppInstalled,\n getBootedSimulatorUDID,\n getMaestroBundleId\n} from \"./ios-utils\";\nimport { setupAndroidDevice, ensureAndroidFolder } from \"./android-utils\";\nimport { chmodSync, mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nconst HELP = `\nnative-ci - Native CI/CD helpers for Expo apps\n\nCOMMANDS:\n\n Test Commands:\n test ios [options] Run iOS Detox tests\n test android [options] Run Android Detox tests\n test maestro [flow] Run Maestro tests\n test all Run all tests (iOS + Android)\n\n Dependency Commands:\n deps Show dependency status\n deps install Install missing dependencies\n deps install-ios Install iOS dependencies (macOS only)\n deps install-android Install Android dependencies\n deps install-maestro Install Maestro\n\n Fingerprint Commands:\n fingerprint <platform> Generate native build fingerprint\n fingerprint-test Test fingerprint caching locally\n pre-hash <files...> Generate quick pre-fingerprint hash\n cache-key <platform> <fp> Generate cache key from fingerprint\n\n KV Store Commands:\n kv-get <key> Get value from KV store\n kv-set <key> <value> Set value in KV store\n\nOPTIONS:\n --project-root <path> Project root directory (default: cwd)\n --config <name> Detox configuration name\n --record-logs <mode> Record logs: none, failing, all (default: all)\n --retries <n> Number of retries for flaky tests (default: 0)\n --headless Run in headless mode (Android only)\n --prefix <prefix> Cache key prefix (default: native-build)\n --github-output Output results for GitHub Actions\n --json Output as JSON\n --help Show this help message\n\nENVIRONMENT:\n KV_STORE_REDIS_REST_URL Redis REST API URL for fingerprint caching\n KV_STORE_REDIS_REST_TOKEN Redis REST API token\n\nEXAMPLES:\n native-ci test ios\n native-ci test android --headless\n native-ci test maestro\n native-ci deps\n native-ci deps install\n native-ci fingerprint ios\n native-ci fingerprint-test\n`;\nfunction createMaestroXcrunShim() {\n const binDir = mkdtempSync(join(tmpdir(), \"native-ci-maestro-\"));\n const xcrunPath = join(binDir, \"xcrun\");\n writeFileSync(\n xcrunPath,\n `#!/bin/sh\nif [ \"$1\" = \"devicectl\" ] && [ \"$2\" = \"--json-output\" ] && [ \"$4\" = \"list\" ] && [ \"$5\" = \"devices\" ]; then\n printf '{\"result\":{\"devices\":[]}}\\\\n' > \"$3\"\n exit 0\nfi\n\nexec /usr/bin/xcrun \"$@\"\n`\n );\n chmodSync(xcrunPath, 493);\n return binDir;\n}\nfunction parseArgs(argv) {\n const args2 = [];\n const options2 = {\n projectRoot: process.cwd(),\n config: \"\",\n recordLogs: \"all\",\n retries: 0,\n headless: false,\n prefix: \"native-build\",\n githubOutput: false,\n json: false,\n help: false\n };\n let i = 0;\n while (i < argv.length) {\n const arg = argv[i];\n if (arg === \"--project-root\" && argv[i + 1]) {\n options2.projectRoot = argv[++i];\n } else if (arg === \"--config\" && argv[i + 1]) {\n options2.config = argv[++i];\n } else if (arg === \"--record-logs\" && argv[i + 1]) {\n options2.recordLogs = argv[++i];\n } else if (arg === \"--retries\" && argv[i + 1]) {\n const val = Number.parseInt(argv[++i], 10);\n if (!Number.isNaN(val) && val >= 0) {\n options2.retries = val;\n }\n } else if (arg === \"--prefix\" && argv[i + 1]) {\n options2.prefix = argv[++i];\n } else if (arg === \"--github-output\") {\n options2.githubOutput = true;\n } else if (arg === \"--json\") {\n options2.json = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n options2.help = true;\n } else if (!arg.startsWith(\"-\")) {\n args2.push(arg);\n }\n i++;\n }\n return {\n command: args2[0] || \"\",\n subcommand: args2[1] || \"\",\n args: args2.slice(2),\n options: options2\n };\n}\nfunction validatePlatform(value) {\n if (value !== \"ios\" && value !== \"android\") {\n console.error('Error: platform must be \"ios\" or \"android\"');\n process.exit(1);\n }\n return value;\n}\nfunction getKVCredentials() {\n const url = process.env.KV_STORE_REDIS_REST_URL;\n const token = process.env.KV_STORE_REDIS_REST_TOKEN;\n if (!url || !token) {\n console.error(\"Error: KV_STORE_REDIS_REST_URL and KV_STORE_REDIS_REST_TOKEN required\");\n process.exit(1);\n }\n return { url, token };\n}\nconst { command, subcommand, args, options } = parseArgs(process.argv.slice(2));\nif (options.help || !command) {\n console.info(HELP);\n process.exit(options.help ? 0 : 1);\n}\ntry {\n switch (command) {\n // ========================================\n // Test Commands\n // ========================================\n case \"test\": {\n if (isCI() && !process.env.NATIVE_CI_FORCE_RUN) {\n console.info(\"Skipping native tests in CI (handled by separate workflow)\");\n console.info(\"Set NATIVE_CI_FORCE_RUN=1 to force run\");\n process.exit(0);\n }\n const platform = subcommand || \"ios\";\n if (platform === \"ios\") {\n ensureBootedSimulator();\n await ensureIosDeps();\n const config = options.config || \"ios.sim.debug\";\n console.info(\"=== iOS Detox Test Runner ===\");\n console.info(`Config: ${config}`);\n console.info(`Project root: ${options.projectRoot}`);\n process.chdir(options.projectRoot);\n await ensureIOSFolder();\n await ensureIOSApp(config);\n const exitCode = await withMetro(\"ios\", async () => {\n return runDetoxTests({\n config,\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries,\n testFiles: args.length > 0 ? args : void 0\n });\n });\n process.exit(exitCode);\n } else if (platform === \"android\") {\n await ensureAndroidDeps();\n const config = options.config || \"android.emu.debug\";\n console.info(\"=== Android Detox Test Runner ===\");\n console.info(`Config: ${config}`);\n console.info(`Project root: ${options.projectRoot}`);\n console.info(`Headless: ${options.headless}`);\n process.chdir(options.projectRoot);\n await ensureAndroidFolder();\n await setupAndroidDevice();\n const exitCode = await withMetro(\"android\", async () => {\n return runDetoxTests({\n config,\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries,\n headless: options.headless,\n testFiles: args.length > 0 ? args : void 0\n });\n });\n process.exit(exitCode);\n } else if (platform === \"maestro\") {\n ensureBootedSimulator();\n await ensureMaestro();\n const flow = args[0] || \"\";\n console.info(\"=== Maestro Test Runner ===\");\n console.info(`Flow: ${flow || \"all\"}`);\n console.info(`Project root: ${options.projectRoot}`);\n process.chdir(options.projectRoot);\n const udid = getBootedSimulatorUDID();\n const bundleId = getMaestroBundleId(options.projectRoot);\n await ensureAppInstalled({ projectRoot: options.projectRoot, bundleId, udid });\n const exitCode = await withMetro(\"ios\", async () => {\n const { $ } = await import(\"bun\");\n const flowArg = flow ? `./flows/${flow}` : \"./flows\";\n const udidArgs = [\"--udid\", udid];\n const debugDir = `${options.projectRoot}/.maestro-debug`;\n const xcrunShimDir = createMaestroXcrunShim();\n const previousPath = process.env.PATH;\n try {\n process.env.PATH = `${xcrunShimDir}:${previousPath ?? \"\"}`;\n const result = await $`maestro test ${flowArg} --exclude-tags=util --no-ansi --debug-output=${debugDir} ${udidArgs}`.nothrow();\n return result.exitCode;\n } finally {\n if (previousPath === void 0) {\n delete process.env.PATH;\n } else {\n process.env.PATH = previousPath;\n }\n rmSync(xcrunShimDir, { recursive: true, force: true });\n }\n });\n process.exit(exitCode);\n } else if (platform === \"all\") {\n ensureBootedSimulator();\n console.info(\"=== Running All Native Tests ===\\n\");\n await ensureIosDeps();\n console.info(\"\\n--- iOS Tests ---\\n\");\n process.chdir(options.projectRoot);\n await ensureIOSFolder();\n await ensureIOSApp(options.config || \"ios.sim.debug\");\n let iosExit = 0;\n try {\n iosExit = await withMetro(\"ios\", async () => {\n return runDetoxTests({\n config: options.config || \"ios.sim.debug\",\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries\n });\n });\n } catch (err) {\n console.error(\"iOS tests failed:\", err);\n iosExit = 1;\n }\n await ensureAndroidDeps();\n console.info(\"\\n--- Android Tests ---\\n\");\n await ensureAndroidFolder();\n await setupAndroidDevice();\n let androidExit = 0;\n try {\n androidExit = await withMetro(\"android\", async () => {\n return runDetoxTests({\n config: options.config || \"android.emu.debug\",\n projectRoot: options.projectRoot,\n recordLogs: options.recordLogs,\n retries: options.retries,\n headless: options.headless\n });\n });\n } catch (err) {\n console.error(\"Android tests failed:\", err);\n androidExit = 1;\n }\n const success = iosExit === 0 && androidExit === 0;\n console.info(`\n=== Test Results ===`);\n console.info(`iOS: ${iosExit === 0 ? \"PASSED\" : \"FAILED\"}`);\n console.info(`Android: ${androidExit === 0 ? \"PASSED\" : \"FAILED\"}`);\n process.exit(success ? 0 : 1);\n } else {\n console.error(`Unknown test platform: ${platform}`);\n console.info(\"Usage: native-ci test [ios|android|maestro|all]\");\n process.exit(1);\n }\n break;\n }\n // ========================================\n // Dependency Commands\n // ========================================\n case \"deps\": {\n if (!subcommand || subcommand === \"status\") {\n printDepsStatus();\n } else if (subcommand === \"install\") {\n console.info(\"Installing all dependencies...\\n\");\n await ensureIosDeps();\n await ensureMaestro();\n console.info(\"\\nAll dependencies installed!\");\n } else if (subcommand === \"install-ios\") {\n await ensureIosDeps();\n } else if (subcommand === \"install-android\") {\n await ensureAndroidDeps();\n } else if (subcommand === \"install-maestro\") {\n await ensureMaestro();\n } else {\n console.error(`Unknown deps subcommand: ${subcommand}`);\n process.exit(1);\n }\n break;\n }\n // ========================================\n // Fingerprint Commands\n // ========================================\n case \"fingerprint\": {\n const platform = validatePlatform(subcommand);\n const result = await generateFingerprint({\n platform,\n projectRoot: options.projectRoot\n });\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"fingerprint\", result.hash);\n setGitHubOutput(\n \"cache-key\",\n createCacheKey({\n platform,\n fingerprint: result.hash,\n prefix: options.prefix\n })\n );\n }\n if (options.json) {\n console.info(JSON.stringify(result, null, 2));\n } else {\n console.info(result.hash);\n }\n break;\n }\n case \"fingerprint-test\": {\n const CACHE_FILE = \".fingerprint-cache.json\";\n console.info(\"Generating fingerprints...\\n\");\n const iosResult = await generateFingerprint({\n platform: \"ios\",\n projectRoot: options.projectRoot\n });\n const androidResult = await generateFingerprint({\n platform: \"android\",\n projectRoot: options.projectRoot\n });\n const iosFingerprint = iosResult.hash;\n const androidFingerprint = androidResult.hash;\n console.info(\"Current fingerprints:\");\n console.info(` iOS: ${iosFingerprint}`);\n console.info(` Android: ${androidFingerprint}`);\n console.info(\"\");\n const cache = loadCache(CACHE_FILE);\n if (cache?.ios && cache?.android) {\n console.info(\"Previous fingerprints (from cache):\");\n console.info(` iOS: ${cache.ios}`);\n console.info(` Android: ${cache.android}`);\n console.info(\"\");\n const iosChanged = cache.ios !== iosFingerprint;\n const androidChanged = cache.android !== androidFingerprint;\n if (iosChanged || androidChanged) {\n console.info(\"Fingerprints changed!\");\n if (iosChanged)\n console.info(\" - iOS fingerprint changed (would trigger iOS rebuild)\");\n if (androidChanged)\n console.info(\n \" - Android fingerprint changed (would trigger Android rebuild)\"\n );\n } else {\n console.info(\"Fingerprints match - no rebuild needed\");\n }\n } else {\n console.info(\"No previous fingerprints cached.\");\n }\n saveCache(CACHE_FILE, {\n ios: iosFingerprint,\n android: androidFingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\n });\n console.info(`\nSaved fingerprints to ${CACHE_FILE}`);\n console.info(`\nTo test cache invalidation:\n 1. Add a native dependency: yarn add react-native-mmkv\n 2. Run this script again: native-ci fingerprint-test\n 3. Fingerprints should change!\n 4. Remove the dependency: yarn remove react-native-mmkv\n 5. Run this script again - fingerprints should match original\n`);\n break;\n }\n case \"pre-hash\": {\n const files = [subcommand, ...args].filter(Boolean);\n if (files.length === 0) {\n console.error(\"Error: at least one file required\");\n process.exit(1);\n }\n const hash = generatePreFingerprintHash(files, options.projectRoot);\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"pre-fingerprint-hash\", hash);\n }\n if (options.json) {\n console.info(JSON.stringify({ hash, files }, null, 2));\n } else {\n console.info(hash);\n }\n break;\n }\n case \"cache-key\": {\n const platform = validatePlatform(subcommand);\n const fingerprint = args[0];\n if (!fingerprint) {\n console.error(\"Error: fingerprint is required\");\n process.exit(1);\n }\n const cacheKey = createCacheKey({\n platform,\n fingerprint,\n prefix: options.prefix\n });\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"cache-key\", cacheKey);\n }\n console.info(cacheKey);\n break;\n }\n // ========================================\n // KV Store Commands\n // ========================================\n case \"kv-get\": {\n const key = subcommand;\n if (!key) {\n console.error(\"Error: key is required\");\n process.exit(1);\n }\n const kv = getKVCredentials();\n const value = await getFingerprintFromKV(kv, key);\n if (options.githubOutput || isGitHubActions()) {\n setGitHubOutput(\"value\", value || \"\");\n setGitHubOutput(\"found\", value ? \"true\" : \"false\");\n }\n if (value) {\n console.info(value);\n } else {\n process.exit(1);\n }\n break;\n }\n case \"kv-set\": {\n const key = subcommand;\n const value = args[0];\n if (!key || !value) {\n console.error(\"Error: key and value are required\");\n process.exit(1);\n }\n const kv = getKVCredentials();\n await saveFingerprintToKV(kv, key, value);\n console.info(\"OK\");\n break;\n }\n default:\n console.error(`Unknown command: ${command}`);\n console.info(HELP);\n process.exit(1);\n }\n} catch (error) {\n console.error(\"Error:\", error.message);\n process.exit(1);\n}\n//# sourceMappingURL=cli.js.map\n"],"mappings":"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"}
|
package/dist/detox.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detox.js","names":[],"sources":["detox.js"],"sourcesContent":["import { parseArgs } from \"node:util\";\nimport { DETOX_SERVER_PORT } from \"./constants\";\nfunction parseDetoxArgs(platform) {\n const defaultConfig = platform === \"ios\" ? \"ios.sim.debug\" : \"android.emu.ci.debug\";\n const { values, positionals } = parseArgs({\n options: {\n config: { type: \"string\", default: defaultConfig },\n \"project-root\": { type: \"string\", default: process.cwd() },\n headless: { type: \"boolean\", default: false },\n \"record-logs\": { type: \"string\", default: \"all\" },\n retries: { type: \"string\", default: \"0\" },\n workers: { type: \"string\", default: \"1\" }\n },\n allowPositionals: true\n });\n const retriesNum = Number.parseInt(values.retries, 10);\n if (Number.isNaN(retriesNum) || retriesNum < 0) {\n console.error(\"Error: retries must be a non-negative integer\");\n process.exit(1);\n }\n const workersNum = Number.parseInt(values.workers, 10);\n if (Number.isNaN(workersNum) || workersNum < 1) {\n console.error(\"Error: workers must be a positive integer\");\n process.exit(1);\n }\n return {\n config: values.config,\n projectRoot: values[\"project-root\"],\n headless: values.headless,\n recordLogs: values[\"record-logs\"],\n retries: retriesNum,\n workers: workersNum,\n testFiles: positionals.length > 0 ? positionals : void 0\n };\n}\nfunction buildDetoxArgs(options) {\n const args = [\n \"detox\",\n \"test\",\n \"--configuration\",\n options.config,\n \"--record-logs\",\n options.recordLogs,\n \"--retries\",\n String(options.retries),\n // force jest to exit after tests complete (prevents hanging on open handles)\n \"--forceExit\"\n ];\n if (options.headless) {\n args.push(\"--headless\");\n }\n if (options.workers && options.workers > 1) {\n args.push(\"--workers\", String(options.workers));\n }\n if (options.testFiles && options.testFiles.length > 0) {\n args.push(...options.testFiles);\n }\n return args;\n}\nconst DETOX_TIMEOUT_MS = 60 * 60 * 1e3;\nconst MAX_CONNECT_FLAKE_RETRIES = 1;\nconst CONNECT_FLAKE_SIGNATURES = [\n /Exceeded timeout of \\d+ ?ms for a hook/,\n /Exceeded timeout of \\d+ ?ms while tearing down/,\n /Exceeded timeout of \\d+ ?ms while handling jest-circus/,\n /\\btimed out after \\d+ms/,\n /could not connect to Detox/,\n /launch recovery deadline exceeded/,\n /skipping launchApp:/,\n /skipping reload:/,\n /FBSOpenApplicationServiceErrorDomain/,\n /FBSOpenApplicationErrorDomain/,\n /Waited for the root of the view hierarchy to have window focus/,\n /Detox worker instance has not been installed/\n];\nconst REAL_FAILURE_SIGNATURES = [\n /Exceeded timeout of \\d+ ?ms while waiting for/,\n /expect\\([^)]+\\)\\.to/,\n /AssertionError:/,\n /(?<!Runtime)Error: (?!.*timed out after)/\n];\nconst ANSI_PATTERN = /\\x1b\\[[0-9;]*m/g;\nconst DETOX_DAEMON_LINE = /^.*\\bdetox\\[\\d+\\]\\s+[a-zA-Z]\\s/m;\nfunction classifyDetoxFailures(rawOutput) {\n const output = rawOutput.replace(ANSI_PATTERN, \"\");\n const delimiter = /(PASS|FAIL) (e2e\\/[^\\s):]+\\.test\\.ts)/g;\n const marks = [];\n for (const m of output.matchAll(delimiter)) {\n marks.push({ kind: m[1], file: m[2], index: m.index ?? 0 });\n }\n const failedFiles = [];\n const flakeFiles = [];\n const realFiles = [];\n for (let i = 0; i < marks.length; i++) {\n const mark = marks[i];\n if (mark.kind !== \"FAIL\") continue;\n const nextMark = i + 1 < marks.length ? marks[i + 1].index : output.length;\n const daemon = DETOX_DAEMON_LINE.exec(output.slice(mark.index, nextMark));\n const blockEnd = daemon ? mark.index + daemon.index : nextMark;\n const block = output.slice(mark.index, blockEnd);\n if (failedFiles.includes(mark.file)) continue;\n failedFiles.push(mark.file);\n const isReal = REAL_FAILURE_SIGNATURES.some((sig) => sig.test(block));\n if (isReal) {\n realFiles.push(mark.file);\n } else {\n const isFlake = CONNECT_FLAKE_SIGNATURES.some((sig) => sig.test(block));\n if (isFlake) {\n flakeFiles.push(mark.file);\n } else {\n realFiles.push(mark.file);\n }\n }\n }\n return { failedFiles, flakeFiles, realFiles };\n}\nasync function resetDetoxLockFile() {\n console.info(\"Resetting Detox lock file...\");\n const proc = Bun.spawn([\"npx\", \"detox\", \"reset-lock-file\"], {\n stdout: \"inherit\",\n stderr: \"inherit\"\n });\n await proc.exited;\n}\nasync function spawnDetoxOnce(detoxArgs, testFiles = []) {\n console.info(\"\\n--- Running Detox tests ---\");\n console.info(`Using fixed Detox server port: ${DETOX_SERVER_PORT}`);\n console.info(`Command: npx ${detoxArgs.join(\" \")}`);\n const proc = Bun.spawn([\"npx\", ...detoxArgs], {\n env: {\n ...process.env,\n DETOX_SERVER_PORT: String(DETOX_SERVER_PORT),\n TAMAGUI_DETOX_TEST_FILES: testFiles.join(\" \")\n },\n stdout: \"pipe\",\n stderr: \"pipe\"\n });\n const decoder = new TextDecoder();\n let output = \"\";\n const tee = async (stream, sink) => {\n const reader = stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n sink.write(value);\n output += decoder.decode(value, { stream: true });\n }\n };\n const pumps = Promise.all([\n tee(proc.stdout, process.stdout),\n tee(proc.stderr, process.stderr)\n ]);\n const timeoutPromise = new Promise((resolve) => {\n setTimeout(() => resolve(\"timeout\"), DETOX_TIMEOUT_MS);\n });\n const result = await Promise.race([proc.exited, timeoutPromise]);\n if (result === \"timeout\") {\n console.info(\"\\nDetox timed out, killing process...\");\n proc.kill(\"SIGKILL\");\n return { exitCode: 1, output };\n }\n await pumps;\n return { exitCode: result, output };\n}\nasync function runDetoxTests(options) {\n await resetDetoxLockFile();\n const detoxArgs = buildDetoxArgs(options);\n const { exitCode, output } = await spawnDetoxOnce(detoxArgs, options.testFiles ?? []);\n if (exitCode === 0) {\n console.info(\"\\nAll tests passed!\");\n return 0;\n }\n console.info(`\nTests failed with exit code: ${exitCode}`);\n const { flakeFiles, realFiles } = classifyDetoxFailures(output);\n if (flakeFiles.length === 0) {\n return exitCode;\n }\n if (realFiles.length > 0) {\n console.info(\n `\nReal test failure(s) present (${realFiles.join(\", \")}); not retrying the connect-flaked file(s).`\n );\n return exitCode;\n }\n for (let attempt = 1; attempt <= MAX_CONNECT_FLAKE_RETRIES; attempt++) {\n console.info(\n `\n::warning::Detox launch-connect flake detected (beforeAll could not connect to Detox). Retry ${attempt}/${MAX_CONNECT_FLAKE_RETRIES} of: ${flakeFiles.join(\", \")}`\n );\n await resetDetoxLockFile();\n const retryArgs = buildDetoxArgs({ ...options, testFiles: flakeFiles });\n const retry = await spawnDetoxOnce(retryArgs, flakeFiles);\n if (retry.exitCode === 0) {\n console.info(\n `\n\\u2713 Recovered ${flakeFiles.length} connect-flaked file(s) on retry ${attempt}.`\n );\n return 0;\n }\n const retryClass = classifyDetoxFailures(retry.output);\n if (retryClass.realFiles.length > 0 || retryClass.flakeFiles.length === 0) {\n console.info(\"\\nRetry surfaced a non-flake failure; surfacing it.\");\n return retry.exitCode;\n }\n flakeFiles.length = 0;\n flakeFiles.push(...retryClass.flakeFiles);\n }\n console.info(\"\\nConnect-flake retries exhausted; tests still failing.\");\n return 1;\n}\nexport {\n buildDetoxArgs,\n classifyDetoxFailures,\n parseDetoxArgs,\n resetDetoxLockFile,\n runDetoxTests\n};\n//# sourceMappingURL=detox.js.map\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"detox.js","names":[],"sources":["detox.js"],"sourcesContent":["import { parseArgs } from \"node:util\";\nimport { DETOX_SERVER_PORT } from \"./constants\";\nfunction parseDetoxArgs(platform) {\n const defaultConfig = platform === \"ios\" ? \"ios.sim.debug\" : \"android.emu.ci.debug\";\n const { values, positionals } = parseArgs({\n options: {\n config: { type: \"string\", default: defaultConfig },\n \"project-root\": { type: \"string\", default: process.cwd() },\n headless: { type: \"boolean\", default: false },\n \"record-logs\": { type: \"string\", default: \"all\" },\n retries: { type: \"string\", default: \"0\" },\n workers: { type: \"string\", default: \"1\" }\n },\n allowPositionals: true\n });\n const retriesNum = Number.parseInt(values.retries, 10);\n if (Number.isNaN(retriesNum) || retriesNum < 0) {\n console.error(\"Error: retries must be a non-negative integer\");\n process.exit(1);\n }\n const workersNum = Number.parseInt(values.workers, 10);\n if (Number.isNaN(workersNum) || workersNum < 1) {\n console.error(\"Error: workers must be a positive integer\");\n process.exit(1);\n }\n return {\n config: values.config,\n projectRoot: values[\"project-root\"],\n headless: values.headless,\n recordLogs: values[\"record-logs\"],\n retries: retriesNum,\n workers: workersNum,\n testFiles: positionals.length > 0 ? positionals : void 0\n };\n}\nfunction buildDetoxArgs(options) {\n const args = [\n \"detox\",\n \"test\",\n \"--configuration\",\n options.config,\n \"--record-logs\",\n options.recordLogs,\n \"--retries\",\n String(options.retries),\n // force jest to exit after tests complete (prevents hanging on open handles)\n \"--forceExit\"\n ];\n if (options.headless) {\n args.push(\"--headless\");\n }\n if (options.workers && options.workers > 1) {\n args.push(\"--workers\", String(options.workers));\n }\n if (options.testFiles && options.testFiles.length > 0) {\n args.push(...options.testFiles);\n }\n return args;\n}\nconst DETOX_TIMEOUT_MS = 60 * 60 * 1e3;\nconst MAX_CONNECT_FLAKE_RETRIES = 1;\nconst CONNECT_FLAKE_SIGNATURES = [\n /Exceeded timeout of \\d+ ?ms for a hook/,\n /Exceeded timeout of \\d+ ?ms while tearing down/,\n /Exceeded timeout of \\d+ ?ms while handling jest-circus/,\n /\\btimed out after \\d+ms/,\n /could not connect to Detox/,\n /launch recovery deadline exceeded/,\n /skipping launchApp:/,\n /skipping reload:/,\n /FBSOpenApplicationServiceErrorDomain/,\n /FBSOpenApplicationErrorDomain/,\n /Waited for the root of the view hierarchy to have window focus/,\n /Detox worker instance has not been installed/\n];\nconst REAL_FAILURE_SIGNATURES = [\n /Exceeded timeout of \\d+ ?ms while waiting for/,\n /expect\\([^)]+\\)\\.to/,\n /AssertionError:/,\n /(?<!Runtime)Error: (?!.*timed out after)/\n];\nconst ANSI_PATTERN = /\\x1b\\[[0-9;]*m/g;\nconst DETOX_DAEMON_LINE = /^.*\\bdetox\\[\\d+\\]\\s+[a-zA-Z]\\s/m;\nfunction classifyDetoxFailures(rawOutput) {\n const output = rawOutput.replace(ANSI_PATTERN, \"\");\n const delimiter = /(PASS|FAIL) (e2e\\/[^\\s):]+\\.test\\.ts)/g;\n const marks = [];\n for (const m of output.matchAll(delimiter)) {\n marks.push({ kind: m[1], file: m[2], index: m.index ?? 0 });\n }\n const failedFiles = [];\n const flakeFiles = [];\n const realFiles = [];\n for (let i = 0; i < marks.length; i++) {\n const mark = marks[i];\n if (mark.kind !== \"FAIL\") continue;\n const nextMark = i + 1 < marks.length ? marks[i + 1].index : output.length;\n const daemon = DETOX_DAEMON_LINE.exec(output.slice(mark.index, nextMark));\n const blockEnd = daemon ? mark.index + daemon.index : nextMark;\n const block = output.slice(mark.index, blockEnd);\n if (failedFiles.includes(mark.file)) continue;\n failedFiles.push(mark.file);\n const isReal = REAL_FAILURE_SIGNATURES.some((sig) => sig.test(block));\n if (isReal) {\n realFiles.push(mark.file);\n } else {\n const isFlake = CONNECT_FLAKE_SIGNATURES.some((sig) => sig.test(block));\n if (isFlake) {\n flakeFiles.push(mark.file);\n } else {\n realFiles.push(mark.file);\n }\n }\n }\n return { failedFiles, flakeFiles, realFiles };\n}\nasync function resetDetoxLockFile() {\n console.info(\"Resetting Detox lock file...\");\n const proc = Bun.spawn([\"npx\", \"detox\", \"reset-lock-file\"], {\n stdout: \"inherit\",\n stderr: \"inherit\"\n });\n await proc.exited;\n}\nasync function spawnDetoxOnce(detoxArgs, testFiles = []) {\n console.info(\"\\n--- Running Detox tests ---\");\n console.info(`Using fixed Detox server port: ${DETOX_SERVER_PORT}`);\n console.info(`Command: npx ${detoxArgs.join(\" \")}`);\n const proc = Bun.spawn([\"npx\", ...detoxArgs], {\n env: {\n ...process.env,\n DETOX_SERVER_PORT: String(DETOX_SERVER_PORT),\n TAMAGUI_DETOX_TEST_FILES: testFiles.join(\" \")\n },\n stdout: \"pipe\",\n stderr: \"pipe\"\n });\n const decoder = new TextDecoder();\n let output = \"\";\n const tee = async (stream, sink) => {\n const reader = stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n sink.write(value);\n output += decoder.decode(value, { stream: true });\n }\n };\n const pumps = Promise.all([\n tee(proc.stdout, process.stdout),\n tee(proc.stderr, process.stderr)\n ]);\n const timeoutPromise = new Promise((resolve) => {\n setTimeout(() => resolve(\"timeout\"), DETOX_TIMEOUT_MS);\n });\n const result = await Promise.race([proc.exited, timeoutPromise]);\n if (result === \"timeout\") {\n console.info(\"\\nDetox timed out, killing process...\");\n proc.kill(\"SIGKILL\");\n return { exitCode: 1, output };\n }\n await pumps;\n return { exitCode: result, output };\n}\nasync function runDetoxTests(options) {\n await resetDetoxLockFile();\n const detoxArgs = buildDetoxArgs(options);\n const { exitCode, output } = await spawnDetoxOnce(detoxArgs, options.testFiles ?? []);\n if (exitCode === 0) {\n console.info(\"\\nAll tests passed!\");\n return 0;\n }\n console.info(`\nTests failed with exit code: ${exitCode}`);\n const { flakeFiles, realFiles } = classifyDetoxFailures(output);\n if (flakeFiles.length === 0) {\n return exitCode;\n }\n if (realFiles.length > 0) {\n console.info(\n `\nReal test failure(s) present (${realFiles.join(\", \")}); not retrying the connect-flaked file(s).`\n );\n return exitCode;\n }\n for (let attempt = 1; attempt <= MAX_CONNECT_FLAKE_RETRIES; attempt++) {\n console.info(\n `\n::warning::Detox launch-connect flake detected (beforeAll could not connect to Detox). Retry ${attempt}/${MAX_CONNECT_FLAKE_RETRIES} of: ${flakeFiles.join(\", \")}`\n );\n await resetDetoxLockFile();\n const retryArgs = buildDetoxArgs({ ...options, testFiles: flakeFiles });\n const retry = await spawnDetoxOnce(retryArgs, flakeFiles);\n if (retry.exitCode === 0) {\n console.info(\n `\n\\u2713 Recovered ${flakeFiles.length} connect-flaked file(s) on retry ${attempt}.`\n );\n return 0;\n }\n const retryClass = classifyDetoxFailures(retry.output);\n if (retryClass.realFiles.length > 0 || retryClass.flakeFiles.length === 0) {\n console.info(\"\\nRetry surfaced a non-flake failure; surfacing it.\");\n return retry.exitCode;\n }\n flakeFiles.length = 0;\n flakeFiles.push(...retryClass.flakeFiles);\n }\n console.info(\"\\nConnect-flake retries exhausted; tests still failing.\");\n return 1;\n}\nexport {\n buildDetoxArgs,\n classifyDetoxFailures,\n parseDetoxArgs,\n resetDetoxLockFile,\n runDetoxTests\n};\n//# sourceMappingURL=detox.js.map\n"],"mappings":";;;;AAEA,SAAS,eAAe,UAAU;CAChC,MAAM,gBAAgB,aAAa,QAAQ,kBAAkB;CAC7D,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACxC,SAAS;GACP,QAAQ;IAAE,MAAM;IAAU,SAAS;GAAc;GACjD,gBAAgB;IAAE,MAAM;IAAU,SAAS,QAAQ,IAAI;GAAE;GACzD,UAAU;IAAE,MAAM;IAAW,SAAS;GAAM;GAC5C,eAAe;IAAE,MAAM;IAAU,SAAS;GAAM;GAChD,SAAS;IAAE,MAAM;IAAU,SAAS;GAAI;GACxC,SAAS;IAAE,MAAM;IAAU,SAAS;GAAI;EAC1C;EACA,kBAAkB;CACpB,CAAC;CACD,MAAM,aAAa,OAAO,SAAS,OAAO,SAAS,EAAE;CACrD,IAAI,OAAO,MAAM,UAAU,KAAK,aAAa,GAAG;EAC9C,QAAQ,MAAM,+CAA+C;EAC7D,QAAQ,KAAK,CAAC;CAChB;CACA,MAAM,aAAa,OAAO,SAAS,OAAO,SAAS,EAAE;CACrD,IAAI,OAAO,MAAM,UAAU,KAAK,aAAa,GAAG;EAC9C,QAAQ,MAAM,2CAA2C;EACzD,QAAQ,KAAK,CAAC;CAChB;CACA,OAAO;EACL,QAAQ,OAAO;EACf,aAAa,OAAO;EACpB,UAAU,OAAO;EACjB,YAAY,OAAO;EACnB,SAAS;EACT,SAAS;EACT,WAAW,YAAY,SAAS,IAAI,cAAc,KAAK;CACzD;AACF;AACA,SAAS,eAAe,SAAS;CAC/B,MAAM,OAAO;EACX;EACA;EACA;EACA,QAAQ;EACR;EACA,QAAQ;EACR;EACA,OAAO,QAAQ,OAAO;EAEtB;CACF;CACA,IAAI,QAAQ,UAAU;EACpB,KAAK,KAAK,YAAY;CACxB;CACA,IAAI,QAAQ,WAAW,QAAQ,UAAU,GAAG;EAC1C,KAAK,KAAK,aAAa,OAAO,QAAQ,OAAO,CAAC;CAChD;CACA,IAAI,QAAQ,aAAa,QAAQ,UAAU,SAAS,GAAG;EACrD,KAAK,KAAK,GAAG,QAAQ,SAAS;CAChC;CACA,OAAO;AACT;AACA,MAAM,mBAAmB,KAAK,KAAK;AACnC,MAAM,4BAA4B;AAClC,MAAM,2BAA2B;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AACA,MAAM,0BAA0B;CAC9B;CACA;CACA;CACA;AACF;AACA,MAAM,eAAe;AACrB,MAAM,oBAAoB;AAC1B,SAAS,sBAAsB,WAAW;CACxC,MAAM,SAAS,UAAU,QAAQ,cAAc,EAAE;CACjD,MAAM,YAAY;CAClB,MAAM,QAAQ,CAAC;CACf,KAAK,MAAM,KAAK,OAAO,SAAS,SAAS,GAAG;EAC1C,MAAM,KAAK;GAAE,MAAM,EAAE;GAAI,MAAM,EAAE;GAAI,OAAO,EAAE,SAAS;EAAE,CAAC;CAC5D;CACA,MAAM,cAAc,CAAC;CACrB,MAAM,aAAa,CAAC;CACpB,MAAM,YAAY,CAAC;CACnB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,SAAS,QAAQ;EAC1B,MAAM,WAAW,IAAI,IAAI,MAAM,SAAS,MAAM,IAAI,EAAE,CAAC,QAAQ,OAAO;EACpE,MAAM,SAAS,kBAAkB,KAAK,OAAO,MAAM,KAAK,OAAO,QAAQ,CAAC;EACxE,MAAM,WAAW,SAAS,KAAK,QAAQ,OAAO,QAAQ;EACtD,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,QAAQ;EAC/C,IAAI,YAAY,SAAS,KAAK,IAAI,GAAG;EACrC,YAAY,KAAK,KAAK,IAAI;EAC1B,MAAM,SAAS,wBAAwB,MAAM,QAAQ,IAAI,KAAK,KAAK,CAAC;EACpE,IAAI,QAAQ;GACV,UAAU,KAAK,KAAK,IAAI;EAC1B,OAAO;GACL,MAAM,UAAU,yBAAyB,MAAM,QAAQ,IAAI,KAAK,KAAK,CAAC;GACtE,IAAI,SAAS;IACX,WAAW,KAAK,KAAK,IAAI;GAC3B,OAAO;IACL,UAAU,KAAK,KAAK,IAAI;GAC1B;EACF;CACF;CACA,OAAO;EAAE;EAAa;EAAY;CAAU;AAC9C;AACA,eAAe,qBAAqB;CAClC,QAAQ,KAAK,8BAA8B;CAC3C,MAAM,OAAO,IAAI,MAAM;EAAC;EAAO;EAAS;CAAiB,GAAG;EAC1D,QAAQ;EACR,QAAQ;CACV,CAAC;CACD,MAAM,KAAK;AACb;AACA,eAAe,eAAe,WAAW,YAAY,CAAC,GAAG;CACvD,QAAQ,KAAK,+BAA+B;CAC5C,QAAQ,KAAK,kCAAkC,mBAAmB;CAClE,QAAQ,KAAK,gBAAgB,UAAU,KAAK,GAAG,GAAG;CAClD,MAAM,OAAO,IAAI,MAAM,CAAC,OAAO,GAAG,SAAS,GAAG;EAC5C,KAAK;GACH,GAAG,QAAQ;GACX,mBAAmB,OAAO,iBAAiB;GAC3C,0BAA0B,UAAU,KAAK,GAAG;EAC9C;EACA,QAAQ;EACR,QAAQ;CACV,CAAC;CACD,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CACb,MAAM,MAAM,OAAO,QAAQ,SAAS;EAClC,MAAM,SAAS,OAAO,UAAU;EAChC,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAC1C,IAAI,MAAM;GACV,KAAK,MAAM,KAAK;GAChB,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;EAClD;CACF;CACA,MAAM,QAAQ,QAAQ,IAAI,CACxB,IAAI,KAAK,QAAQ,QAAQ,MAAM,GAC/B,IAAI,KAAK,QAAQ,QAAQ,MAAM,CACjC,CAAC;CACD,MAAM,iBAAiB,IAAI,SAAS,YAAY;EAC9C,iBAAiB,QAAQ,SAAS,GAAG,gBAAgB;CACvD,CAAC;CACD,MAAM,SAAS,MAAM,QAAQ,KAAK,CAAC,KAAK,QAAQ,cAAc,CAAC;CAC/D,IAAI,WAAW,WAAW;EACxB,QAAQ,KAAK,uCAAuC;EACpD,KAAK,KAAK,SAAS;EACnB,OAAO;GAAE,UAAU;GAAG;EAAO;CAC/B;CACA,MAAM;CACN,OAAO;EAAE,UAAU;EAAQ;CAAO;AACpC;AACA,eAAe,cAAc,SAAS;CACpC,MAAM,mBAAmB;CACzB,MAAM,YAAY,eAAe,OAAO;CACxC,MAAM,EAAE,UAAU,WAAW,MAAM,eAAe,WAAW,QAAQ,aAAa,CAAC,CAAC;CACpF,IAAI,aAAa,GAAG;EAClB,QAAQ,KAAK,qBAAqB;EAClC,OAAO;CACT;CACA,QAAQ,KAAK;+BACgB,UAAU;CACvC,MAAM,EAAE,YAAY,cAAc,sBAAsB,MAAM;CAC9D,IAAI,WAAW,WAAW,GAAG;EAC3B,OAAO;CACT;CACA,IAAI,UAAU,SAAS,GAAG;EACxB,QAAQ,KACN;gCAC0B,UAAU,KAAK,IAAI,EAAE,4CACjD;EACA,OAAO;CACT;CACA,KAAK,IAAI,UAAU,GAAG,WAAW,2BAA2B,WAAW;EACrE,QAAQ,KACN;+FACyF,QAAQ,GAAG,0BAA0B,OAAO,WAAW,KAAK,IAAI,GAC3J;EACA,MAAM,mBAAmB;EACzB,MAAM,YAAY,eAAe;GAAE,GAAG;GAAS,WAAW;EAAW,CAAC;EACtE,MAAM,QAAQ,MAAM,eAAe,WAAW,UAAU;EACxD,IAAI,MAAM,aAAa,GAAG;GACxB,QAAQ,KACN;mBACW,WAAW,OAAO,mCAAmC,QAAQ,EAC1E;GACA,OAAO;EACT;EACA,MAAM,aAAa,sBAAsB,MAAM,MAAM;EACrD,IAAI,WAAW,UAAU,SAAS,KAAK,WAAW,WAAW,WAAW,GAAG;GACzE,QAAQ,KAAK,qDAAqD;GAClE,OAAO,MAAM;EACf;EACA,WAAW,SAAS;EACpB,WAAW,KAAK,GAAG,WAAW,UAAU;CAC1C;CACA,QAAQ,KAAK,yDAAyD;CACtE,OAAO;AACT"}
|
package/dist/fingerprint.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.js","names":[],"sources":["fingerprint.js"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nasync function generateFingerprint(options) {\n const { platform, projectRoot = process.cwd(), debug = false } = options;\n const appJsonPath = join(projectRoot, \"app.json\");\n if (!existsSync(appJsonPath)) {\n throw new Error(`No app.json found at ${projectRoot}. Is this an Expo project?`);\n }\n const execOptions = {\n cwd: projectRoot,\n encoding: \"utf-8\",\n stdio: debug ? \"inherit\" : [\"pipe\", \"pipe\", \"pipe\"]\n };\n try {\n const result = execSync(\n `npx @expo/fingerprint fingerprint:generate --platform ${platform}`,\n execOptions\n );\n const parsed = JSON.parse(result);\n return {\n hash: parsed.hash,\n sources: parsed.sources || []\n };\n } catch (error) {\n const err = error;\n throw new Error(\n `Failed to generate ${platform} fingerprint: ${err.message}${err.stderr ? `\n${err.stderr}` : \"\"}`\n );\n }\n}\nfunction generatePreFingerprintHash(files, projectRoot = process.cwd()) {\n const hash = createHash(\"sha256\");\n for (const file of files) {\n const filePath = join(projectRoot, file);\n if (existsSync(filePath)) {\n hash.update(readFileSync(filePath));\n }\n }\n return hash.digest(\"hex\").slice(0, 16);\n}\nexport {\n generateFingerprint,\n generatePreFingerprintHash\n};\n//# sourceMappingURL=fingerprint.js.map\n"],"mappings":";;;;;;AAIA,eAAe,oBAAoB,SAAS;CAC1C,MAAM,EAAE,UAAU,cAAc,QAAQ,IAAI,GAAG,QAAQ,UAAU;CACjE,MAAM,cAAc,KAAK,aAAa,UAAU;CAChD,IAAI,CAAC,WAAW,WAAW,GAAG;EAC5B,MAAM,IAAI,MAAM,wBAAwB,YAAY,2BAA2B;CACjF;CACA,MAAM,cAAc;EAClB,KAAK;EACL,UAAU;EACV,OAAO,QAAQ,YAAY;GAAC;GAAQ;GAAQ;EAAM;CACpD;CACA,IAAI;EACF,MAAM,SAAS,SACb,yDAAyD,YACzD,WACF;EACA,MAAM,SAAS,KAAK,MAAM,MAAM;EAChC,OAAO;GACL,MAAM,OAAO;GACb,SAAS,OAAO,WAAW,CAAC;EAC9B;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MACR,sBAAsB,SAAS,gBAAgB,IAAI,UAAU,IAAI,SAAS;EAC9E,IAAI,WAAW,IACb;CACF;AACF;AACA,SAAS,2BAA2B,OAAO,cAAc,QAAQ,IAAI,GAAG;CACtE,MAAM,OAAO,WAAW,QAAQ;CAChC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,aAAa,IAAI;EACvC,IAAI,WAAW,QAAQ,GAAG;GACxB,KAAK,OAAO,aAAa,QAAQ,CAAC;EACpC;CACF;CACA,OAAO,KAAK,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"fingerprint.js","names":[],"sources":["fingerprint.js"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nasync function generateFingerprint(options) {\n const { platform, projectRoot = process.cwd(), debug = false } = options;\n const appJsonPath = join(projectRoot, \"app.json\");\n if (!existsSync(appJsonPath)) {\n throw new Error(`No app.json found at ${projectRoot}. Is this an Expo project?`);\n }\n const execOptions = {\n cwd: projectRoot,\n encoding: \"utf-8\",\n stdio: debug ? \"inherit\" : [\"pipe\", \"pipe\", \"pipe\"]\n };\n try {\n const result = execSync(\n `npx @expo/fingerprint fingerprint:generate --platform ${platform}`,\n execOptions\n );\n const parsed = JSON.parse(result);\n return {\n hash: parsed.hash,\n sources: parsed.sources || []\n };\n } catch (error) {\n const err = error;\n throw new Error(\n `Failed to generate ${platform} fingerprint: ${err.message}${err.stderr ? `\n${err.stderr}` : \"\"}`\n );\n }\n}\nfunction generatePreFingerprintHash(files, projectRoot = process.cwd()) {\n const hash = createHash(\"sha256\");\n for (const file of files) {\n const filePath = join(projectRoot, file);\n if (existsSync(filePath)) {\n hash.update(readFileSync(filePath));\n }\n }\n return hash.digest(\"hex\").slice(0, 16);\n}\nexport {\n generateFingerprint,\n generatePreFingerprintHash\n};\n//# sourceMappingURL=fingerprint.js.map\n"],"mappings":";;;;;;AAIA,eAAe,oBAAoB,SAAS;CAC1C,MAAM,EAAE,UAAU,cAAc,QAAQ,IAAI,GAAG,QAAQ,UAAU;CACjE,MAAM,cAAc,KAAK,aAAa,UAAU;CAChD,IAAI,CAAC,WAAW,WAAW,GAAG;EAC5B,MAAM,IAAI,MAAM,wBAAwB,YAAY,2BAA2B;CACjF;CACA,MAAM,cAAc;EAClB,KAAK;EACL,UAAU;EACV,OAAO,QAAQ,YAAY;GAAC;GAAQ;GAAQ;EAAM;CACpD;CACA,IAAI;EACF,MAAM,SAAS,SACb,yDAAyD,YACzD,WACF;EACA,MAAM,SAAS,KAAK,MAAM,MAAM;EAChC,OAAO;GACL,MAAM,OAAO;GACb,SAAS,OAAO,WAAW,CAAC;EAC9B;CACF,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MACR,sBAAsB,SAAS,gBAAgB,IAAI,UAAU,IAAI,SAAS;EAC9E,IAAI,WAAW,IACb;CACF;AACF;AACA,SAAS,2BAA2B,OAAO,cAAc,QAAQ,IAAI,GAAG;CACtE,MAAM,OAAO,WAAW,QAAQ;CAChC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,aAAa,IAAI;EACvC,IAAI,WAAW,QAAQ,GAAG;GACxB,KAAK,OAAO,aAAa,QAAQ,CAAC;EACpC;CACF;CACA,OAAO,KAAK,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;AACvC"}
|
package/dist/ios-utils.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ios-utils.js","names":[],"sources":["ios-utils.js"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\nimport { execFileSync, execSync } from \"node:child_process\";\nimport { $ } from \"bun\";\nimport { isCI } from \"./runner\";\nimport { generateFingerprint } from \"./fingerprint\";\nfunction hasBootedSimulator() {\n return !!getBootedSimulatorUDID();\n}\nfunction getBootedSimulatorUDID() {\n try {\n const output = execSync(\"xcrun simctl list devices booted\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n const match = output.match(/\\(([A-F0-9-]{36})\\)/i);\n return match ? match[1] : null;\n } catch {\n return null;\n }\n}\nfunction ensureBootedSimulator() {\n if (hasBootedSimulator()) return;\n console.info(\"No booted iOS simulator found, booting one...\");\n try {\n const output = execSync(\"xcrun simctl list devices available\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n const match = output.match(/iPhone[^\\n]*\\(([A-F0-9-]{36})\\)/i);\n if (!match) {\n throw new Error(\"No available iPhone simulator found. Install one via Xcode.\");\n }\n const udid = match[1];\n console.info(`Booting simulator ${udid}...`);\n execSync(`xcrun simctl boot ${udid}`, { stdio: \"inherit\" });\n console.info(\"Simulator booted.\");\n } catch (err) {\n throw new Error(\n `Failed to boot iOS simulator: ${err instanceof Error ? err.message : err}`\n );\n }\n}\nfunction isAppInstalled(bundleId, udid) {\n try {\n execSync(`xcrun simctl get_app_container \"${udid}\" \"${bundleId}\"`, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n return true;\n } catch {\n return false;\n }\n}\nfunction getIOSProjectName(projectRoot) {\n const iosDir = join(projectRoot, \"ios\");\n const iosEntries = readdirSync(iosDir);\n const workspace = iosEntries.find((entry) => entry.endsWith(\".xcworkspace\"));\n if (workspace) return workspace.replace(/\\.xcworkspace$/, \"\");\n const project = iosEntries.find((entry) => entry.endsWith(\".xcodeproj\"));\n if (project) return project.replace(/\\.xcodeproj$/, \"\");\n throw new Error(`No iOS workspace or project found in ${iosDir}`);\n}\nfunction getIOSBuildConfiguration(config) {\n return config.toLowerCase().includes(\"release\") ? \"Release\" : \"Debug\";\n}\nfunction getIOSAppPath(projectRoot, config) {\n if (process.env.DETOX_IOS_APP_PATH) return process.env.DETOX_IOS_APP_PATH;\n const appName = getIOSProjectName(projectRoot);\n const buildConfiguration = getIOSBuildConfiguration(config);\n return `ios/build/Build/Products/${buildConfiguration}-iphonesimulator/${appName}.app`;\n}\nfunction getIOSFullAppPath(projectRoot, config) {\n const appPath = getIOSAppPath(projectRoot, config);\n return isAbsolute(appPath) ? appPath : join(projectRoot, appPath);\n}\nfunction getIOSPodTargetName(projectRoot) {\n const podfile = readFileSync(join(projectRoot, \"ios\", \"Podfile\"), \"utf-8\");\n const match = podfile.match(/^\\s*target ['\"]([^'\"]+)['\"] do/m);\n if (!match) {\n throw new Error(`No CocoaPods target found in ${join(projectRoot, \"ios\", \"Podfile\")}`);\n }\n return match[1];\n}\nfunction getIOSAppBundleId(fullAppPath) {\n const infoPlist = join(fullAppPath, \"Info.plist\");\n if (!existsSync(infoPlist)) return null;\n try {\n const bundleId = execFileSync(\n \"/usr/bin/plutil\",\n [\"-extract\", \"CFBundleIdentifier\", \"raw\", \"-o\", \"-\", infoPlist],\n {\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"]\n }\n ).trim();\n return bundleId || null;\n } catch {\n return null;\n }\n}\nfunction isIOSAppBundleReady(fullAppPath) {\n return existsSync(fullAppPath) && !!getIOSAppBundleId(fullAppPath);\n}\nasync function ensureAppInstalled(opts) {\n const { projectRoot, bundleId } = opts;\n const udid = opts.udid || getBootedSimulatorUDID() || \"booted\";\n if (isAppInstalled(bundleId, udid)) {\n console.info(`App ${bundleId} already installed on simulator ${udid}`);\n return;\n }\n if (bundleId === \"host.exp.Exponent\") {\n await installExpoGo(udid);\n return;\n }\n console.info(`App ${bundleId} not installed, building...`);\n await ensureIOSFolder();\n const appPath = getIOSAppPath(projectRoot, \"ios.sim.debug\");\n const fullAppPath = getIOSFullAppPath(projectRoot, \"ios.sim.debug\");\n if (!isIOSAppBundleReady(fullAppPath)) {\n await ensureIOSApp(\"ios.sim.debug\");\n }\n console.info(`Installing app on simulator ${udid}...`);\n execSync(`xcrun simctl install \"${udid}\" \"${fullAppPath}\"`, { stdio: \"inherit\" });\n console.info(\"App installed.\");\n}\nfunction getMaestroBundleId(projectRoot) {\n const flowsDir = join(projectRoot, \"flows\");\n if (existsSync(flowsDir)) {\n try {\n const files = require(\"fs\").readdirSync(flowsDir);\n for (const f of files) {\n if (!f.endsWith(\".yaml\")) continue;\n const content = readFileSync(join(flowsDir, f), \"utf-8\");\n const match = content.match(/^appId:\\s*(.+)$/m);\n if (match) return match[1].trim();\n }\n } catch {\n }\n }\n try {\n const appJson = JSON.parse(readFileSync(join(projectRoot, \"app.json\"), \"utf-8\"));\n return appJson.expo?.ios?.bundleIdentifier || \"host.exp.Exponent\";\n } catch {\n return \"host.exp.Exponent\";\n }\n}\nasync function installExpoGo(udid) {\n const tmpDir = join(require(\"os\").tmpdir(), \"expo-go-install\");\n const appPath = join(tmpDir, \"Expo Go.app\");\n if (existsSync(appPath)) {\n console.info(`Installing cached Expo Go on simulator ${udid}...`);\n execSync(`xcrun simctl install \"${udid}\" \"${appPath}\"`, { stdio: \"inherit\" });\n console.info(\"Expo Go installed.\");\n return;\n }\n console.info(\"Downloading Expo Go...\");\n mkdirSync(tmpDir, { recursive: true });\n const { getVersionsAsync } = (\n // @ts-ignore - no type declarations for internal expo module\n require(\"@expo/cli/build/src/api/getVersions\")\n );\n const versions = await getVersionsAsync();\n const sdkVersions = Object.entries(versions.sdkVersions || {}).filter(([, v]) => v.iosClientUrl).sort(([a], [b]) => b.localeCompare(a, void 0, { numeric: true }));\n const clientUrl = sdkVersions[0]?.[1]?.iosClientUrl;\n if (!clientUrl) {\n throw new Error(\"Could not find Expo Go download URL\");\n }\n execSync(`curl -fsSL \"${clientUrl}\" -o \"${tmpDir}/ExpoGo.tar.gz\"`, { stdio: \"inherit\" });\n mkdirSync(appPath, { recursive: true });\n execSync(`tar -xzf \"${tmpDir}/ExpoGo.tar.gz\" -C \"${appPath}\"`, { stdio: \"inherit\" });\n execSync(`xcrun simctl install \"${udid}\" \"${appPath}\"`, { stdio: \"inherit\" });\n console.info(\"Expo Go installed.\");\n}\nasync function cleanupSimulators() {\n console.info(\"\\n--- Cleaning up simulators ---\");\n try {\n execSync(\"xcrun simctl shutdown all 2>/dev/null || true\", { stdio: \"pipe\" });\n execSync('pkill -9 -f \"Simulator.app\" 2>/dev/null || true', { stdio: \"pipe\" });\n const booted = execSync(\"xcrun simctl list devices | grep -i booted | wc -l\", {\n encoding: \"utf-8\"\n }).trim();\n console.info(`Simulators cleaned up (${booted} still booted)`);\n } catch {\n console.info(\"Simulator cleanup completed (some commands may have failed)\");\n }\n}\nasync function ensureIOSFolder() {\n const podfilePath = join(process.cwd(), \"ios\", \"Podfile\");\n if (!existsSync(podfilePath)) {\n console.info(\"\\n--- Generating ios/ folder (for Metro) ---\");\n console.info(\"Note: ios/Podfile not found, running expo prebuild\");\n try {\n await $`npx expo prebuild --platform ios --no-install`;\n console.info(\"iOS folder generated!\");\n } catch (error) {\n const err = error;\n throw new Error(`Failed to generate ios folder: ${err.message}`);\n }\n } else {\n console.info(\"iOS folder already exists (Podfile found)\");\n }\n}\nconst IOS_FINGERPRINT_CACHE = \".ios-build-fingerprint.json\";\nfunction loadFingerprintCache(projectRoot) {\n const cachePath = join(projectRoot, IOS_FINGERPRINT_CACHE);\n if (!existsSync(cachePath)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(cachePath, \"utf-8\"));\n } catch {\n return null;\n }\n}\nfunction saveFingerprintCache(projectRoot, cache) {\n const cachePath = join(projectRoot, IOS_FINGERPRINT_CACHE);\n writeFileSync(cachePath, JSON.stringify(cache, null, 2));\n}\nasync function ensureIOSApp(config = \"ios.sim.debug\") {\n if (isCI()) {\n console.info(\"CI detected - skipping local build check\");\n return;\n }\n const projectRoot = process.cwd();\n const appPath = getIOSAppPath(projectRoot, config);\n const fullAppPath = getIOSFullAppPath(projectRoot, config);\n const appExists = isIOSAppBundleReady(fullAppPath);\n if (!appExists) {\n console.info(`\n--- iOS app not found at ${appPath}, building... ---`);\n await buildIOSApp(config, projectRoot, appPath, \"\");\n return;\n }\n let currentFingerprint;\n try {\n const result = await generateFingerprint({ platform: \"ios\", projectRoot });\n currentFingerprint = result.hash;\n } catch (err) {\n console.warn(\"Could not generate fingerprint, using existing app\");\n console.info(`iOS app found at ${appPath}`);\n return;\n }\n const cache = loadFingerprintCache(projectRoot);\n const fingerprintMatch = cache?.fingerprint === currentFingerprint && currentFingerprint !== \"\";\n if (fingerprintMatch) {\n console.info(`iOS app found at ${appPath} (fingerprint matches - no native changes)`);\n return;\n }\n if (cache?.fingerprint) {\n console.info(`\n--- iOS fingerprint changed ---`);\n console.info(`Previous: ${cache.fingerprint.slice(0, 16)}...`);\n console.info(`Current: ${currentFingerprint.slice(0, 16)}...`);\n if (process.env.SKIP_IOS_REBUILD) {\n console.info(\"SKIP_IOS_REBUILD set, using existing app\");\n saveFingerprintCache(projectRoot, {\n fingerprint: currentFingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n appPath\n });\n return;\n }\n console.info(\"Native dependencies changed, rebuilding...\");\n await buildIOSApp(config, projectRoot, appPath, currentFingerprint);\n return;\n }\n console.info(`iOS app found at ${appPath} (saving fingerprint)`);\n saveFingerprintCache(projectRoot, {\n fingerprint: currentFingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n appPath\n });\n}\nasync function buildIOSApp(config, projectRoot, appPath, fingerprint) {\n const podConfigPath = join(\n projectRoot,\n \"ios\",\n \"Pods\",\n \"Target Support Files\",\n `Pods-${getIOSPodTargetName(projectRoot)}`,\n `Pods-${getIOSPodTargetName(projectRoot)}.debug.xcconfig`\n );\n if (!existsSync(podConfigPath)) {\n console.info(\"Installing CocoaPods dependencies...\");\n await $`pod install --project-directory=ios`;\n }\n const scheme = getIOSProjectName(projectRoot);\n const buildConfiguration = getIOSBuildConfiguration(config);\n const workspace = join(\"ios\", `${scheme}.xcworkspace`);\n const symroot = join(projectRoot, \"ios\", \"build\", \"Build\", \"Products\");\n const objroot = join(projectRoot, \"ios\", \"build\", \"Build\", \"Intermediates.noindex\");\n console.info(`Building iOS app (config: ${config})...`);\n console.info(\"This may take a few minutes on first run.\");\n await $`xcodebuild -workspace ${workspace} -scheme ${scheme} -configuration ${buildConfiguration} -sdk iphonesimulator SYMROOT=${symroot} OBJROOT=${objroot}`;\n if (fingerprint) {\n saveFingerprintCache(projectRoot, {\n fingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n appPath\n });\n console.info(\"Saved build fingerprint to cache\");\n }\n console.info(\"iOS app built successfully!\");\n}\nexport {\n cleanupSimulators,\n ensureAppInstalled,\n ensureBootedSimulator,\n ensureIOSApp,\n ensureIOSFolder,\n getBootedSimulatorUDID,\n getMaestroBundleId,\n hasBootedSimulator\n};\n//# sourceMappingURL=ios-utils.js.map\n"],"mappings":";;;;;;;;;;;;;;;AAMA,SAAS,qBAAqB;CAC5B,OAAO,CAAC,CAAC,uBAAuB;AAClC;AACA,SAAS,yBAAyB;CAChC,IAAI;EACF,MAAM,SAAS,SAAS,oCAAoC;GAC1D,UAAU;GACV,OAAO;IAAC;IAAQ;IAAQ;GAAM;EAChC,CAAC;EACD,MAAM,QAAQ,OAAO,MAAM,sBAAsB;EACjD,OAAO,QAAQ,MAAM,KAAK;CAC5B,QAAQ;EACN,OAAO;CACT;AACF;AACA,SAAS,wBAAwB;CAC/B,IAAI,mBAAmB,GAAG;CAC1B,QAAQ,KAAK,+CAA+C;CAC5D,IAAI;EACF,MAAM,SAAS,SAAS,uCAAuC;GAC7D,UAAU;GACV,OAAO;IAAC;IAAQ;IAAQ;GAAM;EAChC,CAAC;EACD,MAAM,QAAQ,OAAO,MAAM,kCAAkC;EAC7D,IAAI,CAAC,OAAO;GACV,MAAM,IAAI,MAAM,6DAA6D;EAC/E;EACA,MAAM,OAAO,MAAM;EACnB,QAAQ,KAAK,qBAAqB,KAAK,IAAI;EAC3C,SAAS,qBAAqB,QAAQ,EAAE,OAAO,UAAU,CAAC;EAC1D,QAAQ,KAAK,mBAAmB;CAClC,SAAS,KAAK;EACZ,MAAM,IAAI,MACR,iCAAiC,eAAe,QAAQ,IAAI,UAAU,KACxE;CACF;AACF;AACA,SAAS,eAAe,UAAU,MAAM;CACtC,IAAI;EACF,SAAS,mCAAmC,KAAK,KAAK,SAAS,IAAI,EACjE,OAAO;GAAC;GAAQ;GAAQ;EAAM,EAChC,CAAC;EACD,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AACA,SAAS,kBAAkB,aAAa;CACtC,MAAM,SAAS,KAAK,aAAa,KAAK;CACtC,MAAM,aAAa,YAAY,MAAM;CACrC,MAAM,YAAY,WAAW,MAAM,UAAU,MAAM,SAAS,cAAc,CAAC;CAC3E,IAAI,WAAW,OAAO,UAAU,QAAQ,kBAAkB,EAAE;CAC5D,MAAM,UAAU,WAAW,MAAM,UAAU,MAAM,SAAS,YAAY,CAAC;CACvE,IAAI,SAAS,OAAO,QAAQ,QAAQ,gBAAgB,EAAE;CACtD,MAAM,IAAI,MAAM,wCAAwC,QAAQ;AAClE;AACA,SAAS,yBAAyB,QAAQ;CACxC,OAAO,OAAO,YAAY,EAAE,SAAS,SAAS,IAAI,YAAY;AAChE;AACA,SAAS,cAAc,aAAa,QAAQ;CAC1C,IAAI,QAAQ,IAAI,oBAAoB,OAAO,QAAQ,IAAI;CACvD,MAAM,UAAU,kBAAkB,WAAW;CAC7C,MAAM,qBAAqB,yBAAyB,MAAM;CAC1D,OAAO,4BAA4B,mBAAmB,mBAAmB,QAAQ;AACnF;AACA,SAAS,kBAAkB,aAAa,QAAQ;CAC9C,MAAM,UAAU,cAAc,aAAa,MAAM;CACjD,OAAO,WAAW,OAAO,IAAI,UAAU,KAAK,aAAa,OAAO;AAClE;AACA,SAAS,oBAAoB,aAAa;CACxC,MAAM,UAAU,aAAa,KAAK,aAAa,OAAO,SAAS,GAAG,OAAO;CACzE,MAAM,QAAQ,QAAQ,MAAM,iCAAiC;CAC7D,IAAI,CAAC,OAAO;EACV,MAAM,IAAI,MAAM,gCAAgC,KAAK,aAAa,OAAO,SAAS,GAAG;CACvF;CACA,OAAO,MAAM;AACf;AACA,SAAS,kBAAkB,aAAa;CACtC,MAAM,YAAY,KAAK,aAAa,YAAY;CAChD,IAAI,CAAC,WAAW,SAAS,GAAG,OAAO;CACnC,IAAI;EACF,MAAM,WAAW,aACf,mBACA;GAAC;GAAY;GAAsB;GAAO;GAAM;GAAK;EAAS,GAC9D;GACE,UAAU;GACV,OAAO;IAAC;IAAU;IAAQ;GAAM;EAClC,CACF,EAAE,KAAK;EACP,OAAO,YAAY;CACrB,QAAQ;EACN,OAAO;CACT;AACF;AACA,SAAS,oBAAoB,aAAa;CACxC,OAAO,WAAW,WAAW,KAAK,CAAC,CAAC,kBAAkB,WAAW;AACnE;AACA,eAAe,mBAAmB,MAAM;CACtC,MAAM,EAAE,aAAa,aAAa;CAClC,MAAM,OAAO,KAAK,QAAQ,uBAAuB,KAAK;CACtD,IAAI,eAAe,UAAU,IAAI,GAAG;EAClC,QAAQ,KAAK,OAAO,SAAS,kCAAkC,MAAM;EACrE;CACF;CACA,IAAI,aAAa,qBAAqB;EACpC,MAAM,cAAc,IAAI;EACxB;CACF;CACA,QAAQ,KAAK,OAAO,SAAS,4BAA4B;CACzD,MAAM,gBAAgB;CACtB,MAAM,UAAU,cAAc,aAAa,eAAe;CAC1D,MAAM,cAAc,kBAAkB,aAAa,eAAe;CAClE,IAAI,CAAC,oBAAoB,WAAW,GAAG;EACrC,MAAM,aAAa,eAAe;CACpC;CACA,QAAQ,KAAK,+BAA+B,KAAK,IAAI;CACrD,SAAS,yBAAyB,KAAK,KAAK,YAAY,IAAI,EAAE,OAAO,UAAU,CAAC;CAChF,QAAQ,KAAK,gBAAgB;AAC/B;AACA,SAAS,mBAAmB,aAAa;CACvC,MAAM,WAAW,KAAK,aAAa,OAAO;CAC1C,IAAI,WAAW,QAAQ,GAAG;EACxB,IAAI;GACF,MAAM,kBAAgB,IAAI,EAAE,YAAY,QAAQ;GAChD,KAAK,MAAM,KAAK,OAAO;IACrB,IAAI,CAAC,EAAE,SAAS,OAAO,GAAG;IAC1B,MAAM,UAAU,aAAa,KAAK,UAAU,CAAC,GAAG,OAAO;IACvD,MAAM,QAAQ,QAAQ,MAAM,kBAAkB;IAC9C,IAAI,OAAO,OAAO,MAAM,GAAG,KAAK;GAClC;EACF,QAAQ,CACR;CACF;CACA,IAAI;EACF,MAAM,UAAU,KAAK,MAAM,aAAa,KAAK,aAAa,UAAU,GAAG,OAAO,CAAC;EAC/E,OAAO,QAAQ,MAAM,KAAK,oBAAoB;CAChD,QAAQ;EACN,OAAO;CACT;AACF;AACA,eAAe,cAAc,MAAM;CACjC,MAAM,SAAS,eAAa,IAAI,EAAE,OAAO,GAAG,iBAAiB;CAC7D,MAAM,UAAU,KAAK,QAAQ,aAAa;CAC1C,IAAI,WAAW,OAAO,GAAG;EACvB,QAAQ,KAAK,0CAA0C,KAAK,IAAI;EAChE,SAAS,yBAAyB,KAAK,KAAK,QAAQ,IAAI,EAAE,OAAO,UAAU,CAAC;EAC5E,QAAQ,KAAK,oBAAoB;EACjC;CACF;CACA,QAAQ,KAAK,wBAAwB;CACrC,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;CACrC,MAAM,EAAE,+BAEE,qCAAqC;CAE/C,MAAM,WAAW,MAAM,iBAAiB;CACxC,MAAM,cAAc,OAAO,QAAQ,SAAS,eAAe,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,KAAK,GAAG,EAAE,SAAS,KAAK,CAAC,CAAC;CACjK,MAAM,YAAY,YAAY,KAAK,IAAI;CACvC,IAAI,CAAC,WAAW;EACd,MAAM,IAAI,MAAM,qCAAqC;CACvD;CACA,SAAS,eAAe,UAAU,QAAQ,OAAO,kBAAkB,EAAE,OAAO,UAAU,CAAC;CACvF,UAAU,SAAS,EAAE,WAAW,KAAK,CAAC;CACtC,SAAS,aAAa,OAAO,sBAAsB,QAAQ,IAAI,EAAE,OAAO,UAAU,CAAC;CACnF,SAAS,yBAAyB,KAAK,KAAK,QAAQ,IAAI,EAAE,OAAO,UAAU,CAAC;CAC5E,QAAQ,KAAK,oBAAoB;AACnC;AACA,eAAe,oBAAoB;CACjC,QAAQ,KAAK,kCAAkC;CAC/C,IAAI;EACF,SAAS,iDAAiD,EAAE,OAAO,OAAO,CAAC;EAC3E,SAAS,qDAAmD,EAAE,OAAO,OAAO,CAAC;EAC7E,MAAM,SAAS,SAAS,sDAAsD,EAC5E,UAAU,QACZ,CAAC,EAAE,KAAK;EACR,QAAQ,KAAK,0BAA0B,OAAO,eAAe;CAC/D,QAAQ;EACN,QAAQ,KAAK,6DAA6D;CAC5E;AACF;AACA,eAAe,kBAAkB;CAC/B,MAAM,cAAc,KAAK,QAAQ,IAAI,GAAG,OAAO,SAAS;CACxD,IAAI,CAAC,WAAW,WAAW,GAAG;EAC5B,QAAQ,KAAK,8CAA8C;EAC3D,QAAQ,KAAK,oDAAoD;EACjE,IAAI;GACF,MAAM,CAAC;GACP,QAAQ,KAAK,uBAAuB;EACtC,SAAS,OAAO;GACd,MAAM,MAAM;GACZ,MAAM,IAAI,MAAM,kCAAkC,IAAI,SAAS;EACjE;CACF,OAAO;EACL,QAAQ,KAAK,2CAA2C;CAC1D;AACF;AACA,MAAM,wBAAwB;AAC9B,SAAS,qBAAqB,aAAa;CACzC,MAAM,YAAY,KAAK,aAAa,qBAAqB;CACzD,IAAI,CAAC,WAAW,SAAS,GAAG;EAC1B,OAAO;CACT;CACA,IAAI;EACF,OAAO,KAAK,MAAM,aAAa,WAAW,OAAO,CAAC;CACpD,QAAQ;EACN,OAAO;CACT;AACF;AACA,SAAS,qBAAqB,aAAa,OAAO;CAChD,MAAM,YAAY,KAAK,aAAa,qBAAqB;CACzD,cAAc,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AACzD;AACA,eAAe,aAAa,SAAS,iBAAiB;CACpD,IAAI,KAAK,GAAG;EACV,QAAQ,KAAK,0CAA0C;EACvD;CACF;CACA,MAAM,cAAc,QAAQ,IAAI;CAChC,MAAM,UAAU,cAAc,aAAa,MAAM;CACjD,MAAM,cAAc,kBAAkB,aAAa,MAAM;CACzD,MAAM,YAAY,oBAAoB,WAAW;CACjD,IAAI,CAAC,WAAW;EACd,QAAQ,KAAK;2BACU,QAAQ,kBAAkB;EACjD,MAAM,YAAY,QAAQ,aAAa,SAAS,EAAE;EAClD;CACF;CACA,IAAI;CACJ,IAAI;EACF,MAAM,SAAS,MAAM,oBAAoB;GAAE,UAAU;GAAO;EAAY,CAAC;EACzE,qBAAqB,OAAO;CAC9B,SAAS,KAAK;EACZ,QAAQ,KAAK,oDAAoD;EACjE,QAAQ,KAAK,oBAAoB,SAAS;EAC1C;CACF;CACA,MAAM,QAAQ,qBAAqB,WAAW;CAC9C,MAAM,mBAAmB,OAAO,gBAAgB,sBAAsB,uBAAuB;CAC7F,IAAI,kBAAkB;EACpB,QAAQ,KAAK,oBAAoB,QAAQ,2CAA2C;EACpF;CACF;CACA,IAAI,OAAO,aAAa;EACtB,QAAQ,KAAK;gCACe;EAC5B,QAAQ,KAAK,aAAa,MAAM,YAAY,MAAM,GAAG,EAAE,EAAE,IAAI;EAC7D,QAAQ,KAAK,aAAa,mBAAmB,MAAM,GAAG,EAAE,EAAE,IAAI;EAC9D,IAAI,QAAQ,IAAI,kBAAkB;GAChC,QAAQ,KAAK,0CAA0C;GACvD,qBAAqB,aAAa;IAChC,aAAa;IACb,4BAA4B,IAAI,KAAK,GAAG,YAAY;IACpD;GACF,CAAC;GACD;EACF;EACA,QAAQ,KAAK,4CAA4C;EACzD,MAAM,YAAY,QAAQ,aAAa,SAAS,kBAAkB;EAClE;CACF;CACA,QAAQ,KAAK,oBAAoB,QAAQ,sBAAsB;CAC/D,qBAAqB,aAAa;EAChC,aAAa;EACb,4BAA4B,IAAI,KAAK,GAAG,YAAY;EACpD;CACF,CAAC;AACH;AACA,eAAe,YAAY,QAAQ,aAAa,SAAS,aAAa;CACpE,MAAM,gBAAgB,KACpB,aACA,OACA,QACA,wBACA,QAAQ,oBAAoB,WAAW,KACvC,QAAQ,oBAAoB,WAAW,EAAE,gBAC3C;CACA,IAAI,CAAC,WAAW,aAAa,GAAG;EAC9B,QAAQ,KAAK,sCAAsC;EACnD,MAAM,CAAC;CACT;CACA,MAAM,SAAS,kBAAkB,WAAW;CAC5C,MAAM,qBAAqB,yBAAyB,MAAM;CAC1D,MAAM,YAAY,KAAK,OAAO,GAAG,OAAO,aAAa;CACrD,MAAM,UAAU,KAAK,aAAa,OAAO,SAAS,SAAS,UAAU;CACrE,MAAM,UAAU,KAAK,aAAa,OAAO,SAAS,SAAS,uBAAuB;CAClF,QAAQ,KAAK,6BAA6B,OAAO,KAAK;CACtD,QAAQ,KAAK,2CAA2C;CACxD,MAAM,CAAC,yBAAyB,UAAU,WAAW,OAAO,kBAAkB,mBAAmB,gCAAgC,QAAQ,WAAW;CACpJ,IAAI,aAAa;EACf,qBAAqB,aAAa;GAChC;GACA,4BAA4B,IAAI,KAAK,GAAG,YAAY;GACpD;EACF,CAAC;EACD,QAAQ,KAAK,kCAAkC;CACjD;CACA,QAAQ,KAAK,6BAA6B;AAC5C"}
|
|
1
|
+
{"version":3,"file":"ios-utils.js","names":[],"sources":["ios-utils.js"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\nimport { execFileSync, execSync } from \"node:child_process\";\nimport { $ } from \"bun\";\nimport { isCI } from \"./runner\";\nimport { generateFingerprint } from \"./fingerprint\";\nfunction hasBootedSimulator() {\n return !!getBootedSimulatorUDID();\n}\nfunction getBootedSimulatorUDID() {\n try {\n const output = execSync(\"xcrun simctl list devices booted\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n const match = output.match(/\\(([A-F0-9-]{36})\\)/i);\n return match ? match[1] : null;\n } catch {\n return null;\n }\n}\nfunction ensureBootedSimulator() {\n if (hasBootedSimulator()) return;\n console.info(\"No booted iOS simulator found, booting one...\");\n try {\n const output = execSync(\"xcrun simctl list devices available\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n const match = output.match(/iPhone[^\\n]*\\(([A-F0-9-]{36})\\)/i);\n if (!match) {\n throw new Error(\"No available iPhone simulator found. Install one via Xcode.\");\n }\n const udid = match[1];\n console.info(`Booting simulator ${udid}...`);\n execSync(`xcrun simctl boot ${udid}`, { stdio: \"inherit\" });\n console.info(\"Simulator booted.\");\n } catch (err) {\n throw new Error(\n `Failed to boot iOS simulator: ${err instanceof Error ? err.message : err}`\n );\n }\n}\nfunction isAppInstalled(bundleId, udid) {\n try {\n execSync(`xcrun simctl get_app_container \"${udid}\" \"${bundleId}\"`, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"]\n });\n return true;\n } catch {\n return false;\n }\n}\nfunction getIOSProjectName(projectRoot) {\n const iosDir = join(projectRoot, \"ios\");\n const iosEntries = readdirSync(iosDir);\n const workspace = iosEntries.find((entry) => entry.endsWith(\".xcworkspace\"));\n if (workspace) return workspace.replace(/\\.xcworkspace$/, \"\");\n const project = iosEntries.find((entry) => entry.endsWith(\".xcodeproj\"));\n if (project) return project.replace(/\\.xcodeproj$/, \"\");\n throw new Error(`No iOS workspace or project found in ${iosDir}`);\n}\nfunction getIOSBuildConfiguration(config) {\n return config.toLowerCase().includes(\"release\") ? \"Release\" : \"Debug\";\n}\nfunction getIOSAppPath(projectRoot, config) {\n if (process.env.DETOX_IOS_APP_PATH) return process.env.DETOX_IOS_APP_PATH;\n const appName = getIOSProjectName(projectRoot);\n const buildConfiguration = getIOSBuildConfiguration(config);\n return `ios/build/Build/Products/${buildConfiguration}-iphonesimulator/${appName}.app`;\n}\nfunction getIOSFullAppPath(projectRoot, config) {\n const appPath = getIOSAppPath(projectRoot, config);\n return isAbsolute(appPath) ? appPath : join(projectRoot, appPath);\n}\nfunction getIOSPodTargetName(projectRoot) {\n const podfile = readFileSync(join(projectRoot, \"ios\", \"Podfile\"), \"utf-8\");\n const match = podfile.match(/^\\s*target ['\"]([^'\"]+)['\"] do/m);\n if (!match) {\n throw new Error(`No CocoaPods target found in ${join(projectRoot, \"ios\", \"Podfile\")}`);\n }\n return match[1];\n}\nfunction getIOSAppBundleId(fullAppPath) {\n const infoPlist = join(fullAppPath, \"Info.plist\");\n if (!existsSync(infoPlist)) return null;\n try {\n const bundleId = execFileSync(\n \"/usr/bin/plutil\",\n [\"-extract\", \"CFBundleIdentifier\", \"raw\", \"-o\", \"-\", infoPlist],\n {\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"]\n }\n ).trim();\n return bundleId || null;\n } catch {\n return null;\n }\n}\nfunction isIOSAppBundleReady(fullAppPath) {\n return existsSync(fullAppPath) && !!getIOSAppBundleId(fullAppPath);\n}\nasync function ensureAppInstalled(opts) {\n const { projectRoot, bundleId } = opts;\n const udid = opts.udid || getBootedSimulatorUDID() || \"booted\";\n if (isAppInstalled(bundleId, udid)) {\n console.info(`App ${bundleId} already installed on simulator ${udid}`);\n return;\n }\n if (bundleId === \"host.exp.Exponent\") {\n await installExpoGo(udid);\n return;\n }\n console.info(`App ${bundleId} not installed, building...`);\n await ensureIOSFolder();\n const appPath = getIOSAppPath(projectRoot, \"ios.sim.debug\");\n const fullAppPath = getIOSFullAppPath(projectRoot, \"ios.sim.debug\");\n if (!isIOSAppBundleReady(fullAppPath)) {\n await ensureIOSApp(\"ios.sim.debug\");\n }\n console.info(`Installing app on simulator ${udid}...`);\n execSync(`xcrun simctl install \"${udid}\" \"${fullAppPath}\"`, { stdio: \"inherit\" });\n console.info(\"App installed.\");\n}\nfunction getMaestroBundleId(projectRoot) {\n const flowsDir = join(projectRoot, \"flows\");\n if (existsSync(flowsDir)) {\n try {\n const files = require(\"fs\").readdirSync(flowsDir);\n for (const f of files) {\n if (!f.endsWith(\".yaml\")) continue;\n const content = readFileSync(join(flowsDir, f), \"utf-8\");\n const match = content.match(/^appId:\\s*(.+)$/m);\n if (match) return match[1].trim();\n }\n } catch {\n }\n }\n try {\n const appJson = JSON.parse(readFileSync(join(projectRoot, \"app.json\"), \"utf-8\"));\n return appJson.expo?.ios?.bundleIdentifier || \"host.exp.Exponent\";\n } catch {\n return \"host.exp.Exponent\";\n }\n}\nasync function installExpoGo(udid) {\n const tmpDir = join(require(\"os\").tmpdir(), \"expo-go-install\");\n const appPath = join(tmpDir, \"Expo Go.app\");\n if (existsSync(appPath)) {\n console.info(`Installing cached Expo Go on simulator ${udid}...`);\n execSync(`xcrun simctl install \"${udid}\" \"${appPath}\"`, { stdio: \"inherit\" });\n console.info(\"Expo Go installed.\");\n return;\n }\n console.info(\"Downloading Expo Go...\");\n mkdirSync(tmpDir, { recursive: true });\n const { getVersionsAsync } = (\n // @ts-ignore - no type declarations for internal expo module\n require(\"@expo/cli/build/src/api/getVersions\")\n );\n const versions = await getVersionsAsync();\n const sdkVersions = Object.entries(versions.sdkVersions || {}).filter(([, v]) => v.iosClientUrl).sort(([a], [b]) => b.localeCompare(a, void 0, { numeric: true }));\n const clientUrl = sdkVersions[0]?.[1]?.iosClientUrl;\n if (!clientUrl) {\n throw new Error(\"Could not find Expo Go download URL\");\n }\n execSync(`curl -fsSL \"${clientUrl}\" -o \"${tmpDir}/ExpoGo.tar.gz\"`, { stdio: \"inherit\" });\n mkdirSync(appPath, { recursive: true });\n execSync(`tar -xzf \"${tmpDir}/ExpoGo.tar.gz\" -C \"${appPath}\"`, { stdio: \"inherit\" });\n execSync(`xcrun simctl install \"${udid}\" \"${appPath}\"`, { stdio: \"inherit\" });\n console.info(\"Expo Go installed.\");\n}\nasync function cleanupSimulators() {\n console.info(\"\\n--- Cleaning up simulators ---\");\n try {\n execSync(\"xcrun simctl shutdown all 2>/dev/null || true\", { stdio: \"pipe\" });\n execSync('pkill -9 -f \"Simulator.app\" 2>/dev/null || true', { stdio: \"pipe\" });\n const booted = execSync(\"xcrun simctl list devices | grep -i booted | wc -l\", {\n encoding: \"utf-8\"\n }).trim();\n console.info(`Simulators cleaned up (${booted} still booted)`);\n } catch {\n console.info(\"Simulator cleanup completed (some commands may have failed)\");\n }\n}\nasync function ensureIOSFolder() {\n const podfilePath = join(process.cwd(), \"ios\", \"Podfile\");\n if (!existsSync(podfilePath)) {\n console.info(\"\\n--- Generating ios/ folder (for Metro) ---\");\n console.info(\"Note: ios/Podfile not found, running expo prebuild\");\n try {\n await $`npx expo prebuild --platform ios --no-install`;\n console.info(\"iOS folder generated!\");\n } catch (error) {\n const err = error;\n throw new Error(`Failed to generate ios folder: ${err.message}`);\n }\n } else {\n console.info(\"iOS folder already exists (Podfile found)\");\n }\n}\nconst IOS_FINGERPRINT_CACHE = \".ios-build-fingerprint.json\";\nfunction loadFingerprintCache(projectRoot) {\n const cachePath = join(projectRoot, IOS_FINGERPRINT_CACHE);\n if (!existsSync(cachePath)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(cachePath, \"utf-8\"));\n } catch {\n return null;\n }\n}\nfunction saveFingerprintCache(projectRoot, cache) {\n const cachePath = join(projectRoot, IOS_FINGERPRINT_CACHE);\n writeFileSync(cachePath, JSON.stringify(cache, null, 2));\n}\nasync function ensureIOSApp(config = \"ios.sim.debug\") {\n if (isCI()) {\n console.info(\"CI detected - skipping local build check\");\n return;\n }\n const projectRoot = process.cwd();\n const appPath = getIOSAppPath(projectRoot, config);\n const fullAppPath = getIOSFullAppPath(projectRoot, config);\n const appExists = isIOSAppBundleReady(fullAppPath);\n if (!appExists) {\n console.info(`\n--- iOS app not found at ${appPath}, building... ---`);\n await buildIOSApp(config, projectRoot, appPath, \"\");\n return;\n }\n let currentFingerprint;\n try {\n const result = await generateFingerprint({ platform: \"ios\", projectRoot });\n currentFingerprint = result.hash;\n } catch (err) {\n console.warn(\"Could not generate fingerprint, using existing app\");\n console.info(`iOS app found at ${appPath}`);\n return;\n }\n const cache = loadFingerprintCache(projectRoot);\n const fingerprintMatch = cache?.fingerprint === currentFingerprint && currentFingerprint !== \"\";\n if (fingerprintMatch) {\n console.info(`iOS app found at ${appPath} (fingerprint matches - no native changes)`);\n return;\n }\n if (cache?.fingerprint) {\n console.info(`\n--- iOS fingerprint changed ---`);\n console.info(`Previous: ${cache.fingerprint.slice(0, 16)}...`);\n console.info(`Current: ${currentFingerprint.slice(0, 16)}...`);\n if (process.env.SKIP_IOS_REBUILD) {\n console.info(\"SKIP_IOS_REBUILD set, using existing app\");\n saveFingerprintCache(projectRoot, {\n fingerprint: currentFingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n appPath\n });\n return;\n }\n console.info(\"Native dependencies changed, rebuilding...\");\n await buildIOSApp(config, projectRoot, appPath, currentFingerprint);\n return;\n }\n console.info(`iOS app found at ${appPath} (saving fingerprint)`);\n saveFingerprintCache(projectRoot, {\n fingerprint: currentFingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n appPath\n });\n}\nasync function buildIOSApp(config, projectRoot, appPath, fingerprint) {\n const podConfigPath = join(\n projectRoot,\n \"ios\",\n \"Pods\",\n \"Target Support Files\",\n `Pods-${getIOSPodTargetName(projectRoot)}`,\n `Pods-${getIOSPodTargetName(projectRoot)}.debug.xcconfig`\n );\n if (!existsSync(podConfigPath)) {\n console.info(\"Installing CocoaPods dependencies...\");\n await $`pod install --project-directory=ios`;\n }\n const scheme = getIOSProjectName(projectRoot);\n const buildConfiguration = getIOSBuildConfiguration(config);\n const workspace = join(\"ios\", `${scheme}.xcworkspace`);\n const symroot = join(projectRoot, \"ios\", \"build\", \"Build\", \"Products\");\n const objroot = join(projectRoot, \"ios\", \"build\", \"Build\", \"Intermediates.noindex\");\n console.info(`Building iOS app (config: ${config})...`);\n console.info(\"This may take a few minutes on first run.\");\n await $`xcodebuild -workspace ${workspace} -scheme ${scheme} -configuration ${buildConfiguration} -sdk iphonesimulator SYMROOT=${symroot} OBJROOT=${objroot}`;\n if (fingerprint) {\n saveFingerprintCache(projectRoot, {\n fingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n appPath\n });\n console.info(\"Saved build fingerprint to cache\");\n }\n console.info(\"iOS app built successfully!\");\n}\nexport {\n cleanupSimulators,\n ensureAppInstalled,\n ensureBootedSimulator,\n ensureIOSApp,\n ensureIOSFolder,\n getBootedSimulatorUDID,\n getMaestroBundleId,\n hasBootedSimulator\n};\n//# sourceMappingURL=ios-utils.js.map\n"],"mappings":"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"}
|
package/dist/metro.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metro.js","names":[],"sources":["metro.js"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport {\n METRO_URL,\n METRO_PORT,\n DEFAULT_METRO_WAIT_ATTEMPTS,\n DEFAULT_METRO_WAIT_INTERVAL_MS\n} from \"./constants\";\nasync function waitForMetro(options) {\n const {\n platform,\n maxAttempts = DEFAULT_METRO_WAIT_ATTEMPTS,\n intervalMs = DEFAULT_METRO_WAIT_INTERVAL_MS\n } = options;\n console.info(\"Waiting for Metro to start...\");\n for (let i = 1; i <= maxAttempts; i++) {\n try {\n const response = await fetch(`${METRO_URL}/`, {\n headers: { \"Expo-Platform\": platform }\n });\n if (response.ok) {\n console.info(\"Metro is responding!\");\n return true;\n }\n } catch {\n }\n console.info(`Waiting for Metro... (${i}/${maxAttempts})`);\n await Bun.sleep(intervalMs);\n }\n return false;\n}\nasync function prewarmBundle(platform) {\n console.info(\"Pre-warming bundle...\");\n try {\n const response = await fetch(`${METRO_URL}/`, {\n headers: { \"Expo-Platform\": platform }\n });\n if (response.ok) {\n const manifest = await response.json();\n const bundleUrl = manifest?.launchAsset?.url;\n if (bundleUrl) {\n console.info(`Fetching bundle from: ${bundleUrl}`);\n await fetch(bundleUrl);\n console.info(\"Bundle pre-warmed!\");\n } else {\n console.info(\"No bundle URL found in manifest, skipping pre-warm\");\n }\n }\n } catch (error) {\n console.info(\"Bundle pre-warm completed (with error, continuing)\");\n }\n}\nfunction projectUsesDevClient() {\n try {\n const pkg = JSON.parse(require(\"fs\").readFileSync(\"package.json\", \"utf-8\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps[\"expo-dev-client\"]) return true;\n if (typeof pkg.scripts?.start === \"string\" && pkg.scripts.start.includes(\"--dev-client\"))\n return true;\n return false;\n } catch {\n return false;\n }\n}\nfunction startMetro() {\n console.info(\"\\n--- Starting Metro bundler ---\");\n const isCI = !!process.env.CI;\n const useDevClient = projectUsesDevClient();\n const args = [\"bun\", \"expo\", \"start\", \"--offline\", \"--port\", String(METRO_PORT)];\n if (useDevClient) {\n args.splice(3, 0, \"--dev-client\");\n console.info(\"Dev client detected\");\n }\n if (isCI) {\n args.push(\"--clear\");\n console.info(\"CI detected: clearing Metro cache\");\n }\n const proc = Bun.spawn(args, {\n env: { ...process.env, EXPO_NO_TELEMETRY: \"true\" },\n stdout: \"inherit\",\n stderr: \"inherit\"\n });\n return {\n proc,\n kill: async () => {\n const pid = proc.pid;\n if (pid) {\n try {\n await Bun.spawn([\"pkill\", \"-P\", String(pid)], {\n stdout: \"ignore\",\n stderr: \"ignore\"\n }).exited;\n } catch {\n }\n }\n proc.kill(\"SIGKILL\");\n console.info(\"Metro stopped\");\n }\n };\n}\nfunction setupSignalHandlers(metro) {\n const cleanup = async (signal) => {\n console.info(`\nReceived ${signal}, cleaning up...`);\n await metro.kill();\n process.exit(signal === \"SIGINT\" ? 130 : 143);\n };\n process.on(\"SIGINT\", () => cleanup(\"SIGINT\"));\n process.on(\"SIGTERM\", () => cleanup(\"SIGTERM\"));\n}\nasync function isMetroRunning(platform) {\n try {\n const response = await fetch(`${METRO_URL}/`, {\n headers: { \"Expo-Platform\": platform }\n });\n return response.ok;\n } catch {\n return false;\n }\n}\nfunction killPortProcess() {\n try {\n const pid = execSync(`lsof -ti tcp:${METRO_PORT} -sTCP:LISTEN`, {\n encoding: \"utf-8\"\n }).trim();\n if (pid) {\n console.info(`Killing process ${pid} on port ${METRO_PORT}...`);\n process.kill(Number(pid), \"SIGTERM\");\n }\n } catch {\n }\n}\nasync function withMetro(platform, fn) {\n const alreadyRunning = await isMetroRunning(platform);\n if (alreadyRunning) {\n console.info(\"\\n--- Metro already running, reusing existing instance ---\");\n await prewarmBundle(platform);\n return await fn();\n }\n killPortProcess();\n const metro = startMetro();\n setupSignalHandlers(metro);\n try {\n const metroReady = await waitForMetro({ platform });\n if (!metroReady) {\n throw new Error(\"Metro failed to start within timeout\");\n }\n await prewarmBundle(platform);\n return await fn();\n } finally {\n await metro.kill();\n }\n}\nexport {\n prewarmBundle,\n setupSignalHandlers,\n startMetro,\n waitForMetro,\n withMetro\n};\n//# sourceMappingURL=metro.js.map\n"],"mappings":";;;;;;;;;;;AAOA,eAAe,aAAa,SAAS;CACnC,MAAM,EACJ,UACA,cAAc,6BACd,aAAa,mCACX;CACJ,QAAQ,KAAK,+BAA+B;CAC5C,KAAK,IAAI,IAAI,GAAG,KAAK,aAAa,KAAK;EACrC,IAAI;GACF,MAAM,WAAW,MAAM,MAAM,GAAG,UAAU,IAAI,EAC5C,SAAS,EAAE,iBAAiB,SAAS,EACvC,CAAC;GACD,IAAI,SAAS,IAAI;IACf,QAAQ,KAAK,sBAAsB;IACnC,OAAO;GACT;EACF,QAAQ,CACR;EACA,QAAQ,KAAK,yBAAyB,EAAE,GAAG,YAAY,EAAE;EACzD,MAAM,IAAI,MAAM,UAAU;CAC5B;CACA,OAAO;AACT;AACA,eAAe,cAAc,UAAU;CACrC,QAAQ,KAAK,uBAAuB;CACpC,IAAI;EACF,MAAM,WAAW,MAAM,MAAM,GAAG,UAAU,IAAI,EAC5C,SAAS,EAAE,iBAAiB,SAAS,EACvC,CAAC;EACD,IAAI,SAAS,IAAI;GACf,MAAM,WAAW,MAAM,SAAS,KAAK;GACrC,MAAM,YAAY,UAAU,aAAa;GACzC,IAAI,WAAW;IACb,QAAQ,KAAK,yBAAyB,WAAW;IACjD,MAAM,MAAM,SAAS;IACrB,QAAQ,KAAK,oBAAoB;GACnC,OAAO;IACL,QAAQ,KAAK,oDAAoD;GACnE;EACF;CACF,SAAS,OAAO;EACd,QAAQ,KAAK,oDAAoD;CACnE;AACF;AACA,SAAS,uBAAuB;CAC9B,IAAI;EACF,MAAM,MAAM,KAAK,gBAAc,IAAI,
|
|
1
|
+
{"version":3,"file":"metro.js","names":[],"sources":["metro.js"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport {\n METRO_URL,\n METRO_PORT,\n DEFAULT_METRO_WAIT_ATTEMPTS,\n DEFAULT_METRO_WAIT_INTERVAL_MS\n} from \"./constants\";\nasync function waitForMetro(options) {\n const {\n platform,\n maxAttempts = DEFAULT_METRO_WAIT_ATTEMPTS,\n intervalMs = DEFAULT_METRO_WAIT_INTERVAL_MS\n } = options;\n console.info(\"Waiting for Metro to start...\");\n for (let i = 1; i <= maxAttempts; i++) {\n try {\n const response = await fetch(`${METRO_URL}/`, {\n headers: { \"Expo-Platform\": platform }\n });\n if (response.ok) {\n console.info(\"Metro is responding!\");\n return true;\n }\n } catch {\n }\n console.info(`Waiting for Metro... (${i}/${maxAttempts})`);\n await Bun.sleep(intervalMs);\n }\n return false;\n}\nasync function prewarmBundle(platform) {\n console.info(\"Pre-warming bundle...\");\n try {\n const response = await fetch(`${METRO_URL}/`, {\n headers: { \"Expo-Platform\": platform }\n });\n if (response.ok) {\n const manifest = await response.json();\n const bundleUrl = manifest?.launchAsset?.url;\n if (bundleUrl) {\n console.info(`Fetching bundle from: ${bundleUrl}`);\n await fetch(bundleUrl);\n console.info(\"Bundle pre-warmed!\");\n } else {\n console.info(\"No bundle URL found in manifest, skipping pre-warm\");\n }\n }\n } catch (error) {\n console.info(\"Bundle pre-warm completed (with error, continuing)\");\n }\n}\nfunction projectUsesDevClient() {\n try {\n const pkg = JSON.parse(require(\"fs\").readFileSync(\"package.json\", \"utf-8\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps[\"expo-dev-client\"]) return true;\n if (typeof pkg.scripts?.start === \"string\" && pkg.scripts.start.includes(\"--dev-client\"))\n return true;\n return false;\n } catch {\n return false;\n }\n}\nfunction startMetro() {\n console.info(\"\\n--- Starting Metro bundler ---\");\n const isCI = !!process.env.CI;\n const useDevClient = projectUsesDevClient();\n const args = [\"bun\", \"expo\", \"start\", \"--offline\", \"--port\", String(METRO_PORT)];\n if (useDevClient) {\n args.splice(3, 0, \"--dev-client\");\n console.info(\"Dev client detected\");\n }\n if (isCI) {\n args.push(\"--clear\");\n console.info(\"CI detected: clearing Metro cache\");\n }\n const proc = Bun.spawn(args, {\n env: { ...process.env, EXPO_NO_TELEMETRY: \"true\" },\n stdout: \"inherit\",\n stderr: \"inherit\"\n });\n return {\n proc,\n kill: async () => {\n const pid = proc.pid;\n if (pid) {\n try {\n await Bun.spawn([\"pkill\", \"-P\", String(pid)], {\n stdout: \"ignore\",\n stderr: \"ignore\"\n }).exited;\n } catch {\n }\n }\n proc.kill(\"SIGKILL\");\n console.info(\"Metro stopped\");\n }\n };\n}\nfunction setupSignalHandlers(metro) {\n const cleanup = async (signal) => {\n console.info(`\nReceived ${signal}, cleaning up...`);\n await metro.kill();\n process.exit(signal === \"SIGINT\" ? 130 : 143);\n };\n process.on(\"SIGINT\", () => cleanup(\"SIGINT\"));\n process.on(\"SIGTERM\", () => cleanup(\"SIGTERM\"));\n}\nasync function isMetroRunning(platform) {\n try {\n const response = await fetch(`${METRO_URL}/`, {\n headers: { \"Expo-Platform\": platform }\n });\n return response.ok;\n } catch {\n return false;\n }\n}\nfunction killPortProcess() {\n try {\n const pid = execSync(`lsof -ti tcp:${METRO_PORT} -sTCP:LISTEN`, {\n encoding: \"utf-8\"\n }).trim();\n if (pid) {\n console.info(`Killing process ${pid} on port ${METRO_PORT}...`);\n process.kill(Number(pid), \"SIGTERM\");\n }\n } catch {\n }\n}\nasync function withMetro(platform, fn) {\n const alreadyRunning = await isMetroRunning(platform);\n if (alreadyRunning) {\n console.info(\"\\n--- Metro already running, reusing existing instance ---\");\n await prewarmBundle(platform);\n return await fn();\n }\n killPortProcess();\n const metro = startMetro();\n setupSignalHandlers(metro);\n try {\n const metroReady = await waitForMetro({ platform });\n if (!metroReady) {\n throw new Error(\"Metro failed to start within timeout\");\n }\n await prewarmBundle(platform);\n return await fn();\n } finally {\n await metro.kill();\n }\n}\nexport {\n prewarmBundle,\n setupSignalHandlers,\n startMetro,\n waitForMetro,\n withMetro\n};\n//# sourceMappingURL=metro.js.map\n"],"mappings":"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"}
|
package/dist/runner.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","names":[],"sources":["runner.js"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { appendFileSync } from \"node:fs\";\nimport { createCacheKey, loadCache, saveCache } from \"./cache\";\nimport { generateFingerprint } from \"./fingerprint\";\nasync function runWithCache(options) {\n const {\n platform,\n buildCommand,\n outputPaths,\n projectRoot = process.cwd(),\n cachePrefix = \"native-build\",\n debug = false\n } = options;\n const log = debug ? console.log : () => {\n };\n log(`Generating ${platform} fingerprint...`);\n const { hash: fingerprint } = await generateFingerprint({\n platform,\n projectRoot,\n debug\n });\n log(`Fingerprint: ${fingerprint}`);\n const cacheKey = createCacheKey({ platform, fingerprint, prefix: cachePrefix });\n log(`Cache key: ${cacheKey}`);\n const cached = loadCache(cacheKey);\n if (cached && cached.fingerprint === fingerprint) {\n log(\"Cache hit! Skipping build.\");\n return {\n cacheHit: true,\n fingerprint,\n cacheKey,\n outputPaths\n };\n }\n log(`Running build: ${buildCommand}`);\n const execOptions = {\n cwd: projectRoot,\n stdio: debug ? \"inherit\" : [\"pipe\", \"pipe\", \"pipe\"]\n };\n try {\n execSync(buildCommand, execOptions);\n } catch (error) {\n const err = error;\n throw new Error(`Build failed: ${err.message}${err.stderr ? `\n${err.stderr}` : \"\"}`);\n }\n saveCache(cacheKey, {\n fingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n platform,\n outputPaths\n });\n return {\n cacheHit: false,\n fingerprint,\n cacheKey,\n outputPaths\n };\n}\nfunction setGitHubOutput(name, value) {\n const outputFile = process.env.GITHUB_OUTPUT;\n if (outputFile) {\n appendFileSync(outputFile, `${name}=${value}\n`);\n } else {\n console.info(`[GitHub Output] ${name}=${value}`);\n }\n}\nfunction isGitHubActions() {\n return !!process.env.GITHUB_ACTIONS;\n}\nfunction isCI() {\n return !!process.env.CI;\n}\nexport {\n isCI,\n isGitHubActions,\n runWithCache,\n setGitHubOutput\n};\n//# sourceMappingURL=runner.js.map\n"],"mappings":";;;;;;AAIA,eAAe,aAAa,SAAS;CACnC,MAAM,EACJ,UACA,cACA,aACA,cAAc,QAAQ,IAAI,GAC1B,cAAc,gBACd,QAAQ,UACN;CACJ,MAAM,MAAM,QAAQ,QAAQ,YAAY,CACxC;CACA,IAAI,cAAc,SAAS,gBAAgB;CAC3C,MAAM,EAAE,MAAM,gBAAgB,MAAM,oBAAoB;EACtD;EACA;EACA;CACF,CAAC;CACD,IAAI,gBAAgB,aAAa;CACjC,MAAM,WAAW,eAAe;EAAE;EAAU;EAAa,QAAQ;CAAY,CAAC;CAC9E,IAAI,cAAc,UAAU;CAC5B,MAAM,SAAS,UAAU,QAAQ;CACjC,IAAI,UAAU,OAAO,gBAAgB,aAAa;EAChD,IAAI,4BAA4B;EAChC,OAAO;GACL,UAAU;GACV;GACA;GACA;EACF;CACF;CACA,IAAI,kBAAkB,cAAc;CACpC,MAAM,cAAc;EAClB,KAAK;EACL,OAAO,QAAQ,YAAY;GAAC;GAAQ;GAAQ;EAAM;CACpD;CACA,IAAI;EACF,SAAS,cAAc,WAAW;CACpC,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MAAM,iBAAiB,IAAI,UAAU,IAAI,SAAS;EAC9D,IAAI,WAAW,IAAI;CACnB;CACA,UAAU,UAAU;EAClB;EACA,4BAA4B,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"runner.js","names":[],"sources":["runner.js"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { appendFileSync } from \"node:fs\";\nimport { createCacheKey, loadCache, saveCache } from \"./cache\";\nimport { generateFingerprint } from \"./fingerprint\";\nasync function runWithCache(options) {\n const {\n platform,\n buildCommand,\n outputPaths,\n projectRoot = process.cwd(),\n cachePrefix = \"native-build\",\n debug = false\n } = options;\n const log = debug ? console.log : () => {\n };\n log(`Generating ${platform} fingerprint...`);\n const { hash: fingerprint } = await generateFingerprint({\n platform,\n projectRoot,\n debug\n });\n log(`Fingerprint: ${fingerprint}`);\n const cacheKey = createCacheKey({ platform, fingerprint, prefix: cachePrefix });\n log(`Cache key: ${cacheKey}`);\n const cached = loadCache(cacheKey);\n if (cached && cached.fingerprint === fingerprint) {\n log(\"Cache hit! Skipping build.\");\n return {\n cacheHit: true,\n fingerprint,\n cacheKey,\n outputPaths\n };\n }\n log(`Running build: ${buildCommand}`);\n const execOptions = {\n cwd: projectRoot,\n stdio: debug ? \"inherit\" : [\"pipe\", \"pipe\", \"pipe\"]\n };\n try {\n execSync(buildCommand, execOptions);\n } catch (error) {\n const err = error;\n throw new Error(`Build failed: ${err.message}${err.stderr ? `\n${err.stderr}` : \"\"}`);\n }\n saveCache(cacheKey, {\n fingerprint,\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\n platform,\n outputPaths\n });\n return {\n cacheHit: false,\n fingerprint,\n cacheKey,\n outputPaths\n };\n}\nfunction setGitHubOutput(name, value) {\n const outputFile = process.env.GITHUB_OUTPUT;\n if (outputFile) {\n appendFileSync(outputFile, `${name}=${value}\n`);\n } else {\n console.info(`[GitHub Output] ${name}=${value}`);\n }\n}\nfunction isGitHubActions() {\n return !!process.env.GITHUB_ACTIONS;\n}\nfunction isCI() {\n return !!process.env.CI;\n}\nexport {\n isCI,\n isGitHubActions,\n runWithCache,\n setGitHubOutput\n};\n//# sourceMappingURL=runner.js.map\n"],"mappings":";;;;;;AAIA,eAAe,aAAa,SAAS;CACnC,MAAM,EACJ,UACA,cACA,aACA,cAAc,QAAQ,IAAI,GAC1B,cAAc,gBACd,QAAQ,UACN;CACJ,MAAM,MAAM,QAAQ,QAAQ,YAAY,CACxC;CACA,IAAI,cAAc,SAAS,gBAAgB;CAC3C,MAAM,EAAE,MAAM,gBAAgB,MAAM,oBAAoB;EACtD;EACA;EACA;CACF,CAAC;CACD,IAAI,gBAAgB,aAAa;CACjC,MAAM,WAAW,eAAe;EAAE;EAAU;EAAa,QAAQ;CAAY,CAAC;CAC9E,IAAI,cAAc,UAAU;CAC5B,MAAM,SAAS,UAAU,QAAQ;CACjC,IAAI,UAAU,OAAO,gBAAgB,aAAa;EAChD,IAAI,4BAA4B;EAChC,OAAO;GACL,UAAU;GACV;GACA;GACA;EACF;CACF;CACA,IAAI,kBAAkB,cAAc;CACpC,MAAM,cAAc;EAClB,KAAK;EACL,OAAO,QAAQ,YAAY;GAAC;GAAQ;GAAQ;EAAM;CACpD;CACA,IAAI;EACF,SAAS,cAAc,WAAW;CACpC,SAAS,OAAO;EACd,MAAM,MAAM;EACZ,MAAM,IAAI,MAAM,iBAAiB,IAAI,UAAU,IAAI,SAAS;EAC9D,IAAI,WAAW,IAAI;CACnB;CACA,UAAU,UAAU;EAClB;EACA,4BAA4B,IAAI,KAAK,EAAC,CAAE,YAAY;EACpD;EACA;CACF,CAAC;CACD,OAAO;EACL,UAAU;EACV;EACA;EACA;CACF;AACF;AACA,SAAS,gBAAgB,MAAM,OAAO;CACpC,MAAM,aAAa,QAAQ,IAAI;CAC/B,IAAI,YAAY;EACd,eAAe,YAAY,GAAG,KAAK,GAAG,MAAM;CAC/C;CACC,OAAO;EACL,QAAQ,KAAK,mBAAmB,KAAK,GAAG,OAAO;CACjD;AACF;AACA,SAAS,kBAAkB;CACzB,OAAO,CAAC,CAAC,QAAQ,IAAI;AACvB;AACA,SAAS,OAAO;CACd,OAAO,CAAC,CAAC,QAAQ,IAAI;AACvB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/native-ci",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.728.1",
|
|
4
4
|
"description": "Native CI/CD helpers for React Native apps with Expo - fingerprinting, caching, and build optimization",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"clean:build": "tamagui-build clean:build"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@expo/fingerprint": "~0.20.
|
|
44
|
+
"@expo/fingerprint": "~0.20.6"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@tamagui/build": "3.0.0-beta.
|
|
47
|
+
"@tamagui/build": "3.0.0-beta.728.1",
|
|
48
48
|
"@types/bun": "^1.1.0",
|
|
49
49
|
"@types/node": "^22.1.0"
|
|
50
50
|
},
|