@absolutejs/absolute 0.20.0-beta.69 → 0.20.0-beta.70

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.
@@ -25502,6 +25502,8 @@ var resolveAbsoluteMobileUpdateRuntime = (config, projectRoot) => {
25502
25502
  import { join as join14 } from "path";
25503
25503
  var HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
25504
25504
  `;
25505
+ var XML_HEADER = `<!-- Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync. -->
25506
+ `;
25505
25507
  var moduleConfig = `${JSON.stringify({
25506
25508
  android: {
25507
25509
  modules: [
@@ -25640,13 +25642,16 @@ android {
25640
25642
  lintOptions { abortOnError false }
25641
25643
  }
25642
25644
  `;
25643
- var androidManifest = `${HEADER}<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
25645
+ var androidManifest = `${XML_HEADER}<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
25644
25646
  `;
25645
25647
  var androidModule = `${HEADER}package expo.modules.absolutemobileobservability
25646
25648
 
25647
25649
  import android.app.ActivityManager
25648
25650
  import android.app.ApplicationExitInfo
25651
+ import android.content.pm.ApplicationInfo
25649
25652
  import android.os.Build
25653
+ import android.os.Handler
25654
+ import android.os.Looper
25650
25655
  import android.util.Base64
25651
25656
  import expo.modules.kotlin.modules.Module
25652
25657
  import expo.modules.kotlin.modules.ModuleDefinition
@@ -25665,6 +25670,7 @@ class AbsoluteMobileObservabilityModule : Module() {
25665
25670
  private const val MAX_REPORTS = 8
25666
25671
  private const val MAX_TRACE_BYTES = 32 * 1024
25667
25672
  private const val ACKNOWLEDGED_KEY = "acknowledged"
25673
+ private const val CRASH_TEST_KEY = "crash-test-id"
25668
25674
  private const val PREFERENCES = "AbsoluteMobileObservability"
25669
25675
  }
25670
25676
 
@@ -25689,6 +25695,25 @@ class AbsoluteMobileObservabilityModule : Module() {
25689
25695
  }
25690
25696
  writeAcknowledged(acknowledged)
25691
25697
  }
25698
+
25699
+ AsyncFunction("crashForTesting") { options: Map<String, String> ->
25700
+ val context = context() ?: return@AsyncFunction false
25701
+ if (context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE == 0) {
25702
+ throw IllegalStateException("Native observability crash injection requires a debuggable build.")
25703
+ }
25704
+ val testId = options["testId"]
25705
+ ?.takeIf { it.matches(Regex("[A-Za-z0-9._:-]{1,128}")) }
25706
+ ?: throw IllegalArgumentException("Native observability crash injection requires a valid testId.")
25707
+ val preferences = context.getSharedPreferences(PREFERENCES, 0)
25708
+ if (preferences.getString(CRASH_TEST_KEY, null) == testId) {
25709
+ return@AsyncFunction false
25710
+ }
25711
+ preferences.edit().putString(CRASH_TEST_KEY, testId).commit()
25712
+ Handler(Looper.getMainLooper()).post {
25713
+ throw RuntimeException("AbsoluteJS native observability acceptance crash: $testId")
25714
+ }
25715
+ true
25716
+ }
25692
25717
  }
25693
25718
 
25694
25719
  private fun context() = appContext.reactContext
@@ -25823,6 +25848,7 @@ import { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';
25823
25848
 
25824
25849
  type NativeObservabilityModule = {
25825
25850
  acknowledge(options: { ids: string[] }): Promise<void>;
25851
+ crashForTesting(options: { testId: string }): Promise<boolean>;
25826
25852
  pending(): Promise<{ reports: unknown[] }>;
25827
25853
  };
25828
25854
  type NativeReport = { details: Record<string, unknown>; id: string; kind: string; occurredAt: number; platform: 'android' | 'ios' };
@@ -25883,6 +25909,7 @@ export const startAbsoluteExpoNativeObservability = () => {
25883
25909
  }
25884
25910
  return drain();
25885
25911
  };
25912
+ export const crashAbsoluteExpoNativeObservabilityForTesting = (testId: string) => native.crashForTesting({ testId });
25886
25913
  `;
25887
25914
  var absoluteExpoNativeObservabilityFiles = (project) => new Map([
25888
25915
  [
@@ -27887,11 +27914,160 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
27887
27914
  // src/mobile/expoDevController.ts
27888
27915
  import { spawn } from "child_process";
27889
27916
  import { access as access11 } from "fs/promises";
27890
- import { join as join17 } from "path";
27917
+ import { join as join17, resolve as resolvePath4 } from "path";
27891
27918
  var METRO_READY_TIMEOUT_MS = 60000;
27892
27919
  var PROCESS_CLOSE_TIMEOUT_MS = 2000;
27920
+ var preserveWindowsSubstRealpaths = `
27921
+ const fs = require('node:fs');
27922
+ const path = require('node:path');
27923
+ const physicalRoot = process.env.ABSOLUTE_EXPO_PHYSICAL_ROOT;
27924
+ const mappedRoot = process.env.ABSOLUTE_EXPO_MAPPED_ROOT;
27925
+ const remap = (value) => {
27926
+ if (typeof value !== 'string' || !physicalRoot || !mappedRoot) return value;
27927
+ const normalizedValue = path.resolve(value);
27928
+ const normalizedRoot = path.resolve(physicalRoot);
27929
+ if (normalizedValue.toLowerCase() === normalizedRoot.toLowerCase()) return mappedRoot;
27930
+ const prefix = normalizedRoot.endsWith(path.sep) ? normalizedRoot : normalizedRoot + path.sep;
27931
+ return normalizedValue.toLowerCase().startsWith(prefix.toLowerCase())
27932
+ ? path.join(mappedRoot, normalizedValue.slice(prefix.length))
27933
+ : value;
27934
+ };
27935
+ const realpath = fs.realpath.bind(fs);
27936
+ const realpathSync = fs.realpathSync.bind(fs);
27937
+ const realpathNative = fs.realpathSync.native?.bind(fs.realpathSync);
27938
+ fs.realpath = (value, options, callback) => {
27939
+ const done = typeof options === 'function' ? options : callback;
27940
+ const encoding = typeof options === 'function' ? undefined : options;
27941
+ return realpath(value, encoding, (error, result) => done(error, remap(result)));
27942
+ };
27943
+ fs.realpathSync = (value, options) => remap(realpathSync(value, options));
27944
+ if (realpathNative) fs.realpathSync.native = (value, options) => remap(realpathNative(value, options));
27945
+ const promiseRealpath = fs.promises.realpath.bind(fs.promises);
27946
+ fs.promises.realpath = async (value, options) => remap(await promiseRealpath(value, options));
27947
+ `;
27948
+ var expoDevelopmentClientScheme = (appId) => `exp+${appId.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-")}`;
27949
+ var expoDevelopmentClientUrl = (appId, host3, port) => `${expoDevelopmentClientScheme(appId)}://expo-development-client/?url=${encodeURIComponent(`http://${host3}:${port}`)}`;
27950
+ var captureCommand4 = (command) => {
27951
+ const result = Bun.spawnSync(command, {
27952
+ stderr: "ignore",
27953
+ stdout: "pipe"
27954
+ });
27955
+ return { exitCode: result.exitCode, stdout: result.stdout.toString() };
27956
+ };
27957
+ var windowsPathFromWsl2 = (path, capture) => {
27958
+ const result = capture(["wslpath", "-w", path]);
27959
+ if (result.exitCode !== 0 || !result.stdout.trim()) {
27960
+ throw new Error(`Could not translate WSL path for Windows: ${path}`);
27961
+ }
27962
+ return result.stdout.trim();
27963
+ };
27964
+ var connectLocalExpoAndroid = (adb, appId, metroPort, capture, preferredDevice) => {
27965
+ const devices = capture([adb, "devices"]);
27966
+ if (devices.exitCode !== 0)
27967
+ throw new Error("Could not inspect devices after the Expo Android build.");
27968
+ const ready = devices.stdout.split(/\r?\n/u).flatMap((line) => {
27969
+ const match = /^(\S+)\s+device$/u.exec(line.trim());
27970
+ return match?.[1] ? [match[1]] : [];
27971
+ });
27972
+ const serial = preferredDevice ? ready.find((value) => value === preferredDevice) : ready.find((value) => value.startsWith("emulator-")) ?? ready[0];
27973
+ if (!serial)
27974
+ throw new Error(preferredDevice ? "The selected Expo Android device is not connected after build." : "Expo Android build completed but no ready device was found.");
27975
+ const run = (args, message) => {
27976
+ if (capture([adb, "-s", serial, ...args]).exitCode !== 0)
27977
+ throw new Error(message);
27978
+ };
27979
+ run(["reverse", `tcp:${metroPort}`, `tcp:${metroPort}`], "Expo Android Metro forwarding failed.");
27980
+ run(["shell", "am", "force-stop", appId], "Expo Android development-client reset failed.");
27981
+ run([
27982
+ "shell",
27983
+ "am",
27984
+ "start",
27985
+ "-W",
27986
+ "-a",
27987
+ "android.intent.action.VIEW",
27988
+ "-d",
27989
+ expoDevelopmentClientUrl(appId, "localhost", metroPort),
27990
+ appId
27991
+ ], "Expo Android development-client launch failed.");
27992
+ return serial;
27993
+ };
27994
+ var encodedWindowsExpoAndroidCommand = (project, androidRoot, appId, args, capture, metroPort, preferredDevice) => {
27995
+ const windowsSource = windowsPathFromWsl2(project, capture);
27996
+ const buildId = Bun.hash(resolvePath4(project)).toString(16);
27997
+ const buildDirectory = resolvePath4(androidRoot, "..", "..", "ExpoBuilds", buildId.slice(0, 10));
27998
+ const windowsDirectory = windowsPathFromWsl2(buildDirectory, capture);
27999
+ const windowsAndroidRoot = windowsPathFromWsl2(androidRoot, capture);
28000
+ const encode = (value) => Buffer.from(value, "utf8").toString("base64");
28001
+ const developmentScheme = expoDevelopmentClientScheme(appId);
28002
+ const realpathHook = encode(preserveWindowsSubstRealpaths);
28003
+ const mappedBuild = [
28004
+ "$mappedProject = Join-Path ($drive + '\\') (Split-Path -Leaf $directory)",
28005
+ "Set-Location $mappedProject",
28006
+ "$hook = Join-Path $mappedProject '.absolutejs-preserve-subst.cjs'",
28007
+ `[IO.File]::WriteAllText($hook, [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${realpathHook}')))`,
28008
+ "$env:ABSOLUTE_EXPO_PHYSICAL_ROOT = $directory",
28009
+ "$env:ABSOLUTE_EXPO_MAPPED_ROOT = $mappedProject",
28010
+ '$env:NODE_OPTIONS = "--require=$hook"',
28011
+ "$autolinkingCache = Join-Path $mappedProject 'android\\build\\generated\\autolinking'",
28012
+ "if ([IO.Directory]::Exists($autolinkingCache)) { [IO.Directory]::Delete($autolinkingCache, $true) }",
28013
+ "$expo = Join-Path $mappedProject 'node_modules\\.bin\\expo.exe'",
28014
+ "& $expo @expoArguments",
28015
+ "if ($LASTEXITCODE -ne 0) { throw 'Expo Android native build failed.' }",
28016
+ "$adb = Join-Path $androidHome 'platform-tools\\adb.exe'",
28017
+ "$readyDevices = @(& $adb devices) | Where-Object { $_ -match '\\tdevice$' } | ForEach-Object { ($_ -split '\\s+')[0] }",
28018
+ ...preferredDevice ? [
28019
+ `$serial = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encode(preferredDevice)}'))`,
28020
+ "if ($readyDevices -notcontains $serial) { throw 'The selected Expo Android device is not connected after build.' }"
28021
+ ] : [
28022
+ "$serial = $readyDevices | Where-Object { $_ -like 'emulator-*' } | Select-Object -First 1",
28023
+ "if (-not $serial) { $serial = $readyDevices | Select-Object -First 1 }"
28024
+ ],
28025
+ "if (-not $serial) { throw 'Expo Android build completed but no ready device was found.' }",
28026
+ `& $adb -s $serial reverse 'tcp:${metroPort}' 'tcp:${metroPort}'`,
28027
+ "if ($LASTEXITCODE -ne 0) { throw 'Expo Android Metro forwarding failed.' }",
28028
+ `& $adb -s $serial shell am force-stop '${appId}'`,
28029
+ "if ($LASTEXITCODE -ne 0) { throw 'Expo Android development-client reset failed.' }",
28030
+ `$developmentUrl = '${developmentScheme}://expo-development-client/?url=' + [Uri]::EscapeDataString('http://localhost:${metroPort}')`,
28031
+ `& $adb -s $serial shell am start -W -a android.intent.action.VIEW -d $developmentUrl '${appId}'`,
28032
+ "if ($LASTEXITCODE -ne 0) { throw 'Expo Android development-client launch failed.' }"
28033
+ ].join("; ");
28034
+ const source = [
28035
+ "$ErrorActionPreference = 'Stop'",
28036
+ "$ProgressPreference = 'SilentlyContinue'",
28037
+ `$source = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encode(windowsSource)}'))`,
28038
+ `$directory = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encode(windowsDirectory)}'))`,
28039
+ `$androidHome = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encode(windowsAndroidRoot)}'))`,
28040
+ `$expoArguments = @([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encode(JSON.stringify(args))}')) | ConvertFrom-Json)`,
28041
+ "$env:ANDROID_HOME = $androidHome",
28042
+ "$env:ANDROID_SDK_ROOT = $androidHome",
28043
+ "$env:NODE_ENV = 'development'",
28044
+ ...preferredDevice ? [] : ["$env:ORG_GRADLE_PROJECT_reactNativeArchitectures = 'x86_64'"],
28045
+ "New-Item -ItemType Directory -Force -Path $directory | Out-Null",
28046
+ "& robocopy.exe $source $directory /MIR /XD node_modules .expo .git .gradle .cxx .kotlin build /XF bun.lock bun.lockb .absolutejs-preserve-subst.cjs /NFL /NDL /NJH /NJS /NP",
28047
+ "$copyExit = $LASTEXITCODE",
28048
+ "if ($copyExit -ge 8) { exit $copyExit }",
28049
+ "Set-Location $directory",
28050
+ "$bun = (Get-Command bun.exe -ErrorAction Stop).Source",
28051
+ "& $bun install",
28052
+ "if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }",
28053
+ "$drive = @('Z:', 'Y:', 'X:', 'W:', 'V:', 'U:', 'T:') | Where-Object { -not (Test-Path ($_ + '\\')) } | Select-Object -First 1",
28054
+ "if (-not $drive) { throw 'AbsoluteJS could not reserve a temporary drive letter for the Expo Android build.' }",
28055
+ "$mirrorRoot = Split-Path -Parent $directory",
28056
+ "& subst.exe $drive $mirrorRoot",
28057
+ "if ($LASTEXITCODE -ne 0) { throw 'AbsoluteJS could not create the short Expo Android build path.' }",
28058
+ `try { ${mappedBuild} } finally { Set-Location ($env:SystemDrive + '\\'); & subst.exe $drive /D | Out-Null }`,
28059
+ "exit 0"
28060
+ ].join("; ");
28061
+ return [
28062
+ "powershell.exe",
28063
+ "-NoProfile",
28064
+ "-EncodedCommand",
28065
+ Buffer.from(source, "utf16le").toString("base64")
28066
+ ];
28067
+ };
27893
28068
  var commandEnvironment = (options) => ({
27894
28069
  ABSOLUTE_EXPO_DEVELOPMENT: "1",
28070
+ NODE_ENV: "development",
27895
28071
  ...options.certificateAuthorityPath ? {
27896
28072
  ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH: options.certificateAuthorityPath
27897
28073
  } : {},
@@ -27946,8 +28122,6 @@ var planAbsoluteExpoDevSession = (config, options) => {
27946
28122
  args: [
27947
28123
  `run:${platform2}`,
27948
28124
  "--no-bundler",
27949
- "--port",
27950
- String(options.metroPort),
27951
28125
  ...device ? ["--device", device] : []
27952
28126
  ],
27953
28127
  env,
@@ -28028,6 +28202,8 @@ var startAbsoluteExpoDevSession = async (options) => {
28028
28202
  const plan = planAbsoluteExpoDevSession(options.config, options);
28029
28203
  const executable = options.executable ?? await absoluteExpoExecutable(plan.project);
28030
28204
  const run = options.spawnProcess ?? spawn;
28205
+ const host3 = options.host ?? detectAbsoluteMobileHost();
28206
+ const capture = options.capture ?? captureCommand4;
28031
28207
  const log = options.log ?? (() => {
28032
28208
  return;
28033
28209
  });
@@ -28129,7 +28305,14 @@ var startAbsoluteExpoDevSession = async (options) => {
28129
28305
  const state = platform2 === "android" ? "building-android" : "building-ios";
28130
28306
  setState(state);
28131
28307
  const started = performance.now();
28132
- const child = run(executable, command.args, {
28308
+ const invocation = platform2 === "android" && host3 === "wsl" ? encodedWindowsExpoAndroidCommand(plan.project, options.androidRoot ?? absoluteManagedAndroidSdkRoot(host3), options.config.appId, command.args, capture, options.metroPort, options.androidDevice) : [executable, ...command.args];
28309
+ if (platform2 === "android" && host3 === "wsl") {
28310
+ log("[android] Mirroring native inputs to the Windows host for accelerated Expo build and launch.");
28311
+ }
28312
+ const [nativeExecutable, ...nativeArguments] = invocation;
28313
+ if (!nativeExecutable)
28314
+ throw new Error("Expo native build command is empty.");
28315
+ const child = run(nativeExecutable, nativeArguments, {
28133
28316
  cwd: plan.project,
28134
28317
  env: { ...process.env, ...command.env },
28135
28318
  stdio: ["ignore", "pipe", "pipe"]
@@ -28147,6 +28330,12 @@ var startAbsoluteExpoDevSession = async (options) => {
28147
28330
  if (exitCode !== 0) {
28148
28331
  throw new Error(`Expo ${platform2} development build exited with status ${exitCode}.`);
28149
28332
  }
28333
+ if (platform2 === "android" && host3 !== "wsl") {
28334
+ const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host3);
28335
+ const adb = options.androidAdb ?? join17(androidRoot, "platform-tools", host3 === "windows" ? "adb.exe" : "adb");
28336
+ connectLocalExpoAndroid(adb, options.config.appId, options.metroPort, capture, options.androidDevice);
28337
+ log("Connected the Expo Android development client to Metro.");
28338
+ }
28150
28339
  if (platform2 === "ios" && options.certificateAuthorityPath && options.iosOrigin && new URL(options.iosOrigin).protocol === "https:" && !options.iosDevice) {
28151
28340
  setState("enrolling-trust");
28152
28341
  const trustStarted = performance.now();
@@ -28171,6 +28360,23 @@ var startAbsoluteExpoDevSession = async (options) => {
28171
28360
  log("Installed the AbsoluteJS development CA into the Expo iOS Simulator and relaunched the app.");
28172
28361
  publishTiming("enrolling-trust", performance.now() - trustStarted);
28173
28362
  }
28363
+ if (platform2 === "ios" && !options.iosDevice) {
28364
+ const utilityOptions = {
28365
+ cwd: plan.project,
28366
+ signal: options.signal,
28367
+ log: (line) => line && log(`[ios-connect] ${line}`)
28368
+ };
28369
+ await runUtilityCommand(run, "xcrun", ["simctl", "terminate", "booted", options.config.appId], utilityOptions);
28370
+ const connectExit = await runUtilityCommand(run, "xcrun", [
28371
+ "simctl",
28372
+ "openurl",
28373
+ "booted",
28374
+ expoDevelopmentClientUrl(options.config.appId, options.metroHost ?? "localhost", options.metroPort)
28375
+ ], utilityOptions);
28376
+ if (connectExit !== 0)
28377
+ throw new Error(`Expo iOS Simulator Metro connection exited with status ${connectExit}.`);
28378
+ log("Connected the Expo iOS Simulator development client to Metro.");
28379
+ }
28174
28380
  const durationMs = performance.now() - started;
28175
28381
  timings[state] = durationMs;
28176
28382
  options.onPhaseTiming?.({ durationMs, phase: state });
@@ -37606,5 +37812,5 @@ export {
37606
37812
  writeAbsoluteMobileGithubWorkflow
37607
37813
  };
37608
37814
 
37609
- //# debugId=E4E383CA64D4F3BE64756E2164756E21
37815
+ //# debugId=35A5FB460BBC263E64756E2164756E21
37610
37816
  //# sourceMappingURL=index.js.map