@absolutejs/absolute 0.20.0-beta.42 → 0.20.0-beta.43

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.
@@ -1,29 +1,350 @@
1
1
  // @bun
2
- import{mkdir as q$,readFile as z$,rm as sb,writeFile as y$}from"fs/promises";import{join as Ob}from"path";import{createInterface as R$}from"readline";import{resolve as Nb}from"path";var bw=/^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/,ww=/^[a-z][a-z0-9+.-]*$/,$w=/^[A-Z0-9]{10}$/,Aw=/^[0-9A-F]{64}$/,Sw=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/,v=(b,w,$)=>{let A=Nb(b),S=Nb(A,w);if(S!==A&&!S.startsWith(`${A}/`))throw TypeError(`${$} must remain inside the project root.`);return S},V=(b,w)=>{let $=b.trim();if(!$)throw TypeError(`${w} must not be empty.`);return $},Wb=(b)=>{let w=V(b??"/","mobile.entry");if(!w.startsWith("/")||w.startsWith("//"))throw TypeError("mobile.entry must be an absolute application path.");return w},Mw=(b)=>{let w=new URL(V(b,"mobile.server.productionOrigin")),$=w.protocol==="http:"&&(w.hostname==="localhost"||w.hostname==="127.0.0.1"||w.hostname==="[::1]");if(w.protocol!=="https:"&&!$)throw TypeError("mobile.server.productionOrigin must use HTTPS, except for a loopback development origin.");if(w.username||w.password||w.pathname!=="/"||w.search||w.hash)throw TypeError("mobile.server.productionOrigin must be an origin without credentials, path, query, or hash.");return w.origin},Ow=(b)=>{let w=[...new Set(b??["ios","android"])];if(w.length===0)throw TypeError("mobile.platforms must contain at least one platform.");return w},Cw=(b,w)=>{let $=(M)=>{let O=V(M,"mobile.deepLinks.hosts").toLowerCase();if(!Sw.test(O))throw TypeError("mobile.deepLinks.hosts entries must be valid hostnames without ports, wildcards, or paths.");return O},A=new URL(w).hostname,S=new Set(A==="[::1]"?[]:[$(A)]);for(let M of b??[])S.add($(M));return[...S].sort()},Dw=(b)=>{if(b===void 0)return;let w=V(b,"mobile.deepLinks.apple.appIdPrefix").toUpperCase();if(!$w.test(w))throw TypeError("mobile.deepLinks.apple.appIdPrefix must contain ten letters or digits.");return w},xw=(b)=>{if(b===void 0)return;let w=V(b,"mobile.ios.version");if(!/^\d+(?:\.\d+){0,2}$/u.test(w))throw TypeError("mobile.ios.version must contain one to three dot-separated integer components, for example 1.4.0.");return w},Jw=(b)=>[...new Set((b??[]).map((w)=>V(w,"mobile.deepLinks.android.sha256CertificateFingerprints").replaceAll(":","").toUpperCase()).map((w)=>{if(!Aw.test(w))throw TypeError("mobile.deepLinks.android.sha256CertificateFingerprints entries must be SHA-256 certificate fingerprints.");return w.match(/.{2}/g)?.join(":")??w}))].sort(),Nw=(b,w)=>{if(b.engine!=="expo")return{};let $=b.routes?.native??{},A={};for(let[S,M]of Object.entries($)){let O=Wb(S);if(O.includes("?")||O.includes("#")||O!=="/"&&O.endsWith("/"))throw TypeError(`mobile.routes.native route ${O} must be a canonical path without a query, fragment, or trailing slash.`);if(O==="/__absolute/native")throw TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");if(O.includes("*")||O.includes(":"))throw TypeError(`mobile.routes.native route ${O} must be static during the Expo experiment; parameters and wildcards are not supported yet.`);A[O]=v(w,V(M,`mobile.routes.native[${O}]`),`mobile.routes.native[${O}]`)}return Object.fromEntries(Object.entries(A).sort(([S],[M])=>S.localeCompare(M)))},Ub=(b,w)=>{let $=V(b.appId,"mobile.appId");if(!bw.test($))throw TypeError("mobile.appId must use reverse-domain notation, for example com.example.app.");let A=Mw(b.server.productionOrigin),S=(b.deepLinks?.scheme??$).trim().toLowerCase();if(S&&!ww.test(S))throw TypeError("mobile.deepLinks.scheme is not a valid URL scheme.");return{androidCertificateFingerprints:Jw(b.deepLinks?.android?.sha256CertificateFingerprints),appId:$,appleAppIdPrefix:Dw(b.deepLinks?.apple?.appIdPrefix),appName:V(b.appName,"mobile.appName"),bundleDirectory:v(w,b.bundleDirectory??".absolutejs/mobile/web","mobile.bundleDirectory"),deepLinkHosts:Cw(b.deepLinks?.hosts,A),deepLinkScheme:S,engine:b.engine??"capacitor",entry:Wb(b.entry),expoNativeRoutes:Nw(b,w),...b.engine==="expo"?{expoSdkVersion:b.expo?.sdkVersion??57}:{},iosVersion:xw(b.ios?.version),nativeProjectDirectory:v(w,b.nativeProject?.directory??(b.engine==="expo"?".absolutejs/mobile/expo":"mobile"),"mobile.nativeProject.directory"),platforms:Ow(b.platforms),productionOrigin:A,pushAndroidGoogleServicesFile:v(w,b.pushNotifications?.android?.googleServicesFile??"google-services.json","mobile.pushNotifications.android.googleServicesFile")}};import{createHash as hb,randomUUID as jw}from"crypto";import{access as uw,copyFile as qb,mkdir as z,readFile as r,rename as vw,rm as bb,writeFile as L}from"fs/promises";import{isIP as cw}from"net";import{dirname as gb,isAbsolute as aw,join as X,relative as rw,resolve as s,sep as sw}from"path";import{access as Uw}from"fs/promises";import{homedir as Xb}from"os";import{join as m}from"path";import{existsSync as p$,readFileSync as Ww}from"fs";var f=1000;var Kb=60000;var i=2;var l=(b)=>{let w;if(b<f)w=`${b.toFixed(i)}ms`;else if(b<Kb)w=`${(b/f).toFixed(i)}s`;else{let $=Math.round(b/f),A=Math.floor($/60),S=$%60;w=S===0?`${A}m`:`${A}m ${S}s`}return w};var Tb=()=>{try{let b=Ww("/proc/version","utf-8");return/microsoft|wsl/i.test(b)}catch{return!1}};var _b="AbsoluteJS_API_36",Kw=(b)=>{try{let w=Bun.spawnSync(b,{stderr:"ignore",stdout:"pipe"});return{exitCode:w.exitCode,stdout:w.stdout.toString()}}catch{return{exitCode:1,stdout:""}}},Tw=(b)=>{try{let w=JSON.parse(b);if(typeof w!=="object"||w===null)return!1;let $=Reflect.get(w,"runtimes");if(!Array.isArray($))return!1;return $.some((A)=>typeof A==="object"&&A!==null&&Reflect.get(A,"isAvailable")===!0&&typeof Reflect.get(A,"identifier")==="string"&&String(Reflect.get(A,"identifier")).includes("iOS"))}catch{return!1}},Xw=(b)=>{let w=/^([a-z]):[\\/](.*)$/i.exec(b.trim());if(!w)return b.trim().replaceAll("\\","/");return`/mnt/${w[1]?.toLowerCase()}/${w[2]?.replaceAll("\\","/")}`},_w=()=>{try{let b=Bun.spawnSync(["cmd.exe","/d","/c","echo","%LOCALAPPDATA%"],{stderr:"ignore",stdout:"pipe"});if(b.exitCode!==0)return;let w=b.stdout.toString().trim();if(!w||w==="%LOCALAPPDATA%")return;return Xw(w)}catch{return}},Bw=(b,w=process.env)=>{if(b==="windows")return m(w.LOCALAPPDATA??m(Xb(),"AppData","Local"),"AbsoluteJS","Android","Sdk");if(b==="wsl"){let $=_w();if($)return m($,"AbsoluteJS","Android","Sdk")}return m(Xb(),".absolutejs","android-sdk")},Fw=async(b)=>{try{return await Uw(b),!0}catch{return!1}},c=(b=process.platform,w=Tb())=>{if(b==="darwin")return"macos";if(b==="win32")return"windows";if(b==="linux"&&w)return"wsl";return"linux"},Gw=(b,w)=>{if(b==="wsl")return[`${w}.exe`,`${w}.bat`,w];if(b==="windows")return[w,`${w}.exe`,`${w}.bat`];return[w]},Z=async(b,w,$,A)=>{let M=(await Promise.all(w.map(async(O)=>await $.exists(O)?O:void 0))).find((O)=>O!==void 0);if(M)return M;for(let O of Gw(A,b)){let D=$.which(O);if(D)return D}return},E=(b,w,$,A,S)=>A?{id:b,label:w,path:A,platform:$,status:"pass"}:{id:b,label:w,platform:$,remediation:S,status:"fail"},Bb=async(b={})=>{let w=b.env??process.env,$=b.host??c(),A=b.exists??Fw,S=b.which??((T)=>Bun.which(T)),M=b.capture??Kw,O=b.androidRoot===null?void 0:b.androidRoot??w.ANDROID_HOME??w.ANDROID_SDK_ROOT??Bw($,w),D=$==="windows"||$==="wsl",C=(T)=>O?m(O,...T):void 0,J=(T)=>T.filter((K)=>Boolean(K)),_=await Z("adb",J([C(["platform-tools",D?"adb.exe":"adb"])]),{exists:A,which:S},$),W=await Z("emulator",J([C(["emulator",D?"emulator.exe":"emulator"])]),{exists:A,which:S},$),U=await Z("sdkmanager",J([C(["cmdline-tools","latest","bin",D?"sdkmanager.bat":"sdkmanager"])]),{exists:A,which:S},$),F=await Z("avdmanager",J([C(["cmdline-tools","latest","bin",D?"avdmanager.bat":"avdmanager"])]),{exists:A,which:S},$),x=await Z("java",[],{exists:A,which:S},$),N=[{id:"host",label:`Development host: ${$}`,platform:"host",status:"pass"},E("android.adb","Android Debug Bridge","android",_,"Install Android SDK Platform Tools or expose adb on PATH."),E("android.emulator","Android Emulator","android",W,"Install the Android Emulator from Android Studio SDK Manager."),E("android.sdkmanager","Android SDK Manager","android",U,"Install Android SDK Command-line Tools (latest)."),E("android.avdmanager","Android Virtual Device Manager","android",F,"Install Android SDK Command-line Tools (latest)."),E("android.java","Java runtime","android",x,"Install the JDK required by the configured Android Gradle plugin.")];if(W){let T=M([W,"-list-avds"]),K=T.exitCode===0&&T.stdout.split(/\r?\n/).includes(_b);N.push({id:"android.avd",label:`AbsoluteJS Android emulator (${_b})`,platform:"android",remediation:K?void 0:"Run absolute mobile doctor android --fix to provision the managed emulator.",status:K?"pass":"fail"})}if($==="wsl")N.push({id:"android.virtualization",label:_?.endsWith(".exe")?"Windows-host Android bridge available to WSL":"WSL requires a Windows-host emulator bridge or Linux KVM",platform:"android",remediation:_?.endsWith(".exe")?void 0:"Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",status:_?.endsWith(".exe")?"pass":"warn"});else if($==="linux"){let T=await A("/dev/kvm");N.push({id:"android.virtualization",label:"Linux KVM acceleration",platform:"android",remediation:T?void 0:"Enable KVM and grant the current user access to /dev/kvm.",status:T?"pass":"warn"})}if($!=="macos")return N.push({id:"ios.simulator",label:"iOS Simulator requires macOS and Xcode",platform:"ios",status:"skip"}),N;let B=await Z("xcrun",[],{exists:A,which:S},$),Q=await Z("xcodebuild",[],{exists:A,which:S},$);if(N.push(E("ios.xcrun","Xcode command runner","ios",B,"Install Xcode and select it with xcode-select."),E("ios.xcodebuild","Xcode build system","ios",Q,"Install Xcode and select it with xcode-select.")),B){let T=M([B,"simctl","list","runtimes","--json"]),K=T.exitCode===0&&Tw(T.stdout);N.push({id:"ios.runtime",label:"iOS Simulator runtime",platform:"ios",remediation:K?void 0:"Run absolute mobile doctor ios --fix to download an iOS Simulator runtime.",status:K?"pass":"fail"})}return N};import{access as Iw,readFile as Hw,rename as Vw,writeFile as Yw}from"fs/promises";import{relative as Qw,resolve as Fb}from"path";var Gb="capacitor.config.ts",p=(b,w)=>Qw(b,w).replaceAll("\\","/"),Zw=(b,w)=>`import type { CapacitorConfig } from '@capacitor/cli';
2
+ import{mkdir as ks,readFile as Rs,rm as Ie,writeFile as Cs}from"fs/promises";import{join as ue}from"path";import{createInterface as $r}from"readline";import{resolve as Ue}from"path";var Tr=/^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/,mr=/^[a-z][a-z0-9+.-]*$/,Dr=/^[A-Z0-9]{10}$/,Nr=/^[0-9A-F]{64}$/,Ir=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/,ee=(e,r,a)=>{let s=Ue(e),c=Ue(s,r);if(c!==s&&!c.startsWith(`${s}/`))throw TypeError(`${a} must remain inside the project root.`);return c},W=(e,r)=>{let a=e.trim();if(!a)throw TypeError(`${r} must not be empty.`);return a},Be=(e)=>{let r=W(e??"/","mobile.entry");if(!r.startsWith("/")||r.startsWith("//"))throw TypeError("mobile.entry must be an absolute application path.");return r},Mr=(e)=>{let r=new URL(W(e,"mobile.server.productionOrigin")),a=r.protocol==="http:"&&(r.hostname==="localhost"||r.hostname==="127.0.0.1"||r.hostname==="[::1]");if(r.protocol!=="https:"&&!a)throw TypeError("mobile.server.productionOrigin must use HTTPS, except for a loopback development origin.");if(r.username||r.password||r.pathname!=="/"||r.search||r.hash)throw TypeError("mobile.server.productionOrigin must be an origin without credentials, path, query, or hash.");return r.origin},kr=(e)=>{let r=[...new Set(e??["ios","android"])];if(r.length===0)throw TypeError("mobile.platforms must contain at least one platform.");return r},Rr=(e,r)=>{let a=(l)=>{let t=W(l,"mobile.deepLinks.hosts").toLowerCase();if(!Ir.test(t))throw TypeError("mobile.deepLinks.hosts entries must be valid hostnames without ports, wildcards, or paths.");return t},s=new URL(r).hostname,c=new Set(s==="[::1]"?[]:[a(s)]);for(let l of e??[])c.add(a(l));return[...c].sort()},Cr=(e)=>{if(e===void 0)return;let r=W(e,"mobile.deepLinks.apple.appIdPrefix").toUpperCase();if(!Dr.test(r))throw TypeError("mobile.deepLinks.apple.appIdPrefix must contain ten letters or digits.");return r},Wr=(e)=>{if(e===void 0)return;let r=W(e,"mobile.ios.version");if(!/^\d+(?:\.\d+){0,2}$/u.test(r))throw TypeError("mobile.ios.version must contain one to three dot-separated integer components, for example 1.4.0.");return r},Ur=(e)=>[...new Set((e??[]).map((r)=>W(r,"mobile.deepLinks.android.sha256CertificateFingerprints").replaceAll(":","").toUpperCase()).map((r)=>{if(!Nr.test(r))throw TypeError("mobile.deepLinks.android.sha256CertificateFingerprints entries must be SHA-256 certificate fingerprints.");return r.match(/.{2}/g)?.join(":")??r}))].sort(),Br=(e,r)=>{if(e.engine!=="expo")return{};let a=e.routes?.native??{},s={};for(let[c,l]of Object.entries(a)){let t=Be(c);if(t.includes("?")||t.includes("#")||t!=="/"&&t.endsWith("/"))throw TypeError(`mobile.routes.native route ${t} must be a canonical path without a query, fragment, or trailing slash.`);if(t==="/__absolute/native")throw TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");if(t.includes("*")||t.includes(":"))throw TypeError(`mobile.routes.native route ${t} must be static during the Expo experiment; parameters and wildcards are not supported yet.`);s[t]=ee(r,W(l,`mobile.routes.native[${t}]`),`mobile.routes.native[${t}]`)}return Object.fromEntries(Object.entries(s).sort(([c],[l])=>c.localeCompare(l)))},Je=(e,r)=>{let a=W(e.appId,"mobile.appId");if(!Tr.test(a))throw TypeError("mobile.appId must use reverse-domain notation, for example com.example.app.");let s=Mr(e.server.productionOrigin),c=(e.deepLinks?.scheme??a).trim().toLowerCase();if(c&&!mr.test(c))throw TypeError("mobile.deepLinks.scheme is not a valid URL scheme.");return{androidCertificateFingerprints:Ur(e.deepLinks?.android?.sha256CertificateFingerprints),appId:a,appleAppIdPrefix:Cr(e.deepLinks?.apple?.appIdPrefix),appName:W(e.appName,"mobile.appName"),bundleDirectory:ee(r,e.bundleDirectory??".absolutejs/mobile/web","mobile.bundleDirectory"),deepLinkHosts:Rr(e.deepLinks?.hosts,s),deepLinkScheme:c,engine:e.engine??"capacitor",entry:Be(e.entry),expoNativeRoutes:Br(e,r),...e.engine==="expo"?{expoSdkVersion:e.expo?.sdkVersion??57}:{},iosVersion:Wr(e.ios?.version),nativeProjectDirectory:ee(r,e.nativeProject?.directory??(e.engine==="expo"?".absolutejs/mobile/expo":"mobile"),"mobile.nativeProject.directory"),platforms:kr(e.platforms),productionOrigin:s,pushAndroidGoogleServicesFile:ee(r,e.pushNotifications?.android?.googleServicesFile??"google-services.json","mobile.pushNotifications.android.googleServicesFile")}};import{spawn as Pr}from"child_process";import{access as Yr}from"fs/promises";import{join as qr}from"path";import{randomUUID as Jr,X509Certificate as Hr}from"crypto";import{createServer as Lr}from"http";import{connect as Vr,createServer as He,isIP as Gr}from"net";import{readFile as Fr}from"fs/promises";var Ae=(e)=>new Promise((r,a)=>{e.close((s)=>{if(s)a(s);else r()})}),Le=(e,r)=>new Promise((a,s)=>{e.once("error",s),e.listen(r,"0.0.0.0",()=>{e.off("error",s);let c=e.address();if(!c||typeof c==="string"){s(Error("Could not determine the iOS device helper port."));return}a(c.port)})}),Xr=async()=>{let e=He(),r=await new Promise((a,s)=>{e.once("error",s),e.listen(0,"127.0.0.1",()=>{let c=e.address();if(!c||typeof c==="string"){s(Error("Could not allocate the iOS CA enrollment port."));return}a(c.port)})});return await Ae(e),r},ye=(e)=>{let r=e.trim();if(!r||r.length>253||/[\0\s/?#]/u.test(r))throw TypeError("Physical iOS development requires a valid LAN host.");return r},Ve=(e)=>{let r=e.trim();if(!r||r.length>256||/[\0\r\n]/u.test(r))throw TypeError("--ios-device requires a valid Xcode device identifier or name.");return r},Kr=(e,r,a)=>{let s=new URL(`${e}://localhost:${a}`),c=ye(r);return s.hostname=Gr(c)===6?`[${c}]`:c,s},re=async(e)=>{let a=new Hr(await Fr(e.certificateAuthorityPath)).raw,c=`/${Jr().replaceAll("-","")}/absolutejs-development-ca.cer`,l=Lr((w,b)=>{if(w.method!=="GET"||w.url!==c){b.writeHead(404,{"Cache-Control":"no-store","Content-Type":"text/plain; charset=utf-8"}),b.end("Not found.");return}b.writeHead(200,{"Cache-Control":"no-store","Content-Disposition":'attachment; filename="absolutejs-development-ca.cer"',"Content-Length":String(a.byteLength),"Content-Type":"application/x-x509-ca-cert","X-Content-Type-Options":"nosniff"}),b.end(a)}),t=await Xr();await Le(l,t);let u=Kr("http",e.displayHost,t);return u.pathname=c,{url:u.href,close:()=>Ae(l)}},ae=async(e)=>{let r=He((a)=>{let s=Vr({host:"127.0.0.1",port:e.targetPort});a.pipe(s),s.pipe(a);let c=()=>{a.destroy(),s.destroy()};a.once("error",c),s.once("error",c)});return await Le(r,e.listenPort),{close:()=>Ae(r)}};var Zr=60000,Qr=2000,zr=(e)=>({ABSOLUTE_EXPO_DEVELOPMENT:"1",...e.certificateAuthorityPath?{ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH:e.certificateAuthorityPath}:{},...e.androidOrigin?{EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN:e.androidOrigin}:{},...e.iosOrigin?{EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN:e.iosOrigin}:{},...e.metroHost?{REACT_NATIVE_PACKAGER_HOSTNAME:e.metroHost}:{}}),ge=async(e)=>{let r=qr(e,"node_modules",".bin","expo");try{return await Yr(r),r}catch{throw TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.")}},ir=(e,r)=>{if(e.engine!=="expo")throw TypeError("The Expo development controller requires Expo.");if(r.platforms.length===0&&r.metro==="external")throw TypeError("External Expo execution requires a target platform.");if([r.androidOrigin,r.iosOrigin].some((u)=>u&&new URL(u).protocol==="https:")&&!r.certificateAuthorityPath)throw TypeError("Expo HTTPS development requires the AbsoluteJS development CA certificate.");let s=zr(r),c={args:["start","--dev-client","--host","localhost","--port",String(r.metroPort)],env:s,role:"metro"},l=r.platforms.length===0?void 0:{args:["prebuild","--clean","--no-install","--platform",r.platforms.length===2?"all":r.platforms[0]??"all"],env:s,role:"native-prepare"},t=r.platforms.map((u)=>{let w=u==="android"?r.androidDevice:r.iosDevice;return{args:[`run:${u}`,"--no-bundler","--port",String(r.metroPort),...w?["--device",w]:[]],env:s,platform:u,role:"native-build"}});return{commands:[...l?[l]:[],...r.metro==="external"?[]:[c],...t],metroPort:r.metroPort,project:e.nativeProjectDirectory}},q=()=>new DOMException("Expo development aborted.","AbortError"),se=(e,r)=>{let a=(s)=>{if(!s)return;let c="";s.on("data",(l)=>{c+=l.toString("utf8");let t=c.indexOf(`
3
+ `);while(t>=0)r(c.slice(0,t).replace(/\r$/u,"")),c=c.slice(t+1),t=c.indexOf(`
4
+ `)}),s.on("end",()=>{if(c)r(c)})};a(e.stdout),a(e.stderr)},X=async(e)=>{if(e.exitCode!==null||e.killed)return;if(e.kill("SIGTERM"),await Promise.race([new Promise((r)=>e.once("exit",()=>r())),new Promise((r)=>setTimeout(r,Qr))]),e.exitCode===null)e.kill("SIGKILL")},Se=(e)=>new Promise((r)=>{if(e.exitCode!==null){r(e.exitCode);return}e.once("exit",(a)=>r(a??1))}),xe=async(e,r,a,s)=>{let c=e(r,a,{cwd:s.cwd,env:process.env,stdio:["ignore","pipe","pipe"]});se(c,s.log);let l=()=>void X(c);s.signal?.addEventListener("abort",l,{once:!0});let t=await Se(c);if(s.signal?.removeEventListener("abort",l),s.signal?.aborted)throw q();return t},Ge=async(e)=>{let r=ir(e.config,e),a=e.executable??await ge(r.project),s=e.spawnProcess??Pr,c=e.log??(()=>{return}),l={},t=null,u=async()=>{let d=t;t=null,await d?.close()},w=(d,E)=>{l[d]=(l[d]??0)+E,e.onPhaseTiming?.({durationMs:E,phase:d})},b=(d)=>{e.onStateChange?.(d)};if(e.signal?.aborted)throw q();let x=r.commands.find((d)=>d.role==="native-prepare"),A=r.commands.find((d)=>d.role==="metro"),f=r.commands.filter((d)=>d.role==="native-build"),O=async(d)=>{b("preparing-native");let E=performance.now(),m=s(a,d.args,{cwd:r.project,env:{...process.env,...d.env},stdio:["ignore","pipe","pipe"]});se(m,(U)=>{if(U)c(`[prebuild] ${U}`)});let M=()=>void X(m);e.signal?.addEventListener("abort",M,{once:!0});let N=await Se(m);if(e.signal?.removeEventListener("abort",M),e.signal?.aborted)throw q();if(N!==0)throw b("failed"),Error(`Expo native preparation exited with status ${N}.`);w("preparing-native",performance.now()-E)};if(x)await O(x);let n=A!==void 0;if(n)b("starting-metro");let y=performance.now(),S=A?s(a,A.args,{cwd:r.project,env:{...process.env,...A.env},stdio:["ignore","pipe","pipe"]}):void 0,D=!1,h,g=new Promise((d,E)=>{if(!S){d();return}let m=setTimeout(()=>{E(Error("Expo Metro did not become ready within 60 seconds."))},Zr);h=()=>{clearTimeout(m),d()},S.once("exit",(M)=>{if(!D)clearTimeout(m),E(Error(`Expo Metro exited with status ${M??1}.`))})});if(S)se(S,(d)=>{if(d)c(`[metro] ${d}`);if(!D&&/(?:Waiting on|Metro waiting on|Dev server ready)/iu.test(d))D=!0,h?.()});let C=()=>{if(S)X(S)};e.signal?.addEventListener("abort",C,{once:!0});let F=async(d)=>{if(e.signal?.aborted)throw q();let{platform:E}=d;if(!E)throw TypeError("Expo native build command is missing a platform.");let m=E==="android"?"building-android":"building-ios";b(m);let M=performance.now(),N=s(a,d.args,{cwd:r.project,env:{...process.env,...d.env},stdio:["ignore","pipe","pipe"]});se(N,(p)=>{if(p)c(`[${E}] ${p}`)});let U=()=>void X(N);e.signal?.addEventListener("abort",U,{once:!0});let B=await Se(N);if(e.signal?.removeEventListener("abort",U),e.signal?.aborted)throw q();if(B!==0)throw Error(`Expo ${E} development build exited with status ${B}.`);if(E==="ios"&&e.certificateAuthorityPath&&e.iosOrigin&&new URL(e.iosOrigin).protocol==="https:"&&!e.iosDevice){b("enrolling-trust");let p=performance.now(),fe={cwd:r.project,signal:e.signal,log:(We)=>We&&c(`[ios-trust] ${We}`)},Re=await xe(s,"xcrun",["simctl","keychain","booted","add-root-cert",e.certificateAuthorityPath],fe);if(Re!==0)throw Error(`Expo iOS Simulator development CA trust exited with status ${Re}.`);await xe(s,"xcrun",["simctl","terminate","booted",e.config.appId],fe);let Ce=await xe(s,"xcrun",["simctl","launch","booted",e.config.appId],fe);if(Ce!==0)throw Error(`Expo iOS Simulator relaunch exited with status ${Ce}.`);c("Installed the AbsoluteJS development CA into the Expo iOS Simulator and relaunched the app."),w("enrolling-trust",performance.now()-p)}let H=performance.now()-M;l[m]=H,e.onPhaseTiming?.({durationMs:H,phase:m})},o=async(d)=>{let[E,...m]=d;if(!E)return;await F(E),await o(m)},ne=async()=>{if(!e.iosDevice||!e.certificateAuthorityPath||!e.iosOrigin||new URL(e.iosOrigin).protocol!=="https:")return;b("enrolling-trust");let d=performance.now();t=await(e.startCaEnrollmentServer??re)({certificateAuthorityPath:e.certificateAuthorityPath,displayHost:new URL(e.iosOrigin).hostname}),c(`On the iOS device, open ${t.url}, install the AbsoluteJS development CA profile, then enable it under Settings > General > About > Certificate Trust Settings. This public CA endpoint exists only for this dev session.`),w("enrolling-trust",performance.now()-d)};try{if(await ne(),await g,n)w("starting-metro",performance.now()-y);return await o(f),b("ready"),{metroPort:r.metroPort,platforms:e.platforms,timings:l,close:async()=>{if(e.signal?.removeEventListener("abort",C),S)await X(S);await u(),b("closed")}}}catch(d){if(e.signal?.removeEventListener("abort",C),S)await X(S);throw await u(),b("failed"),d}};import{access as vr,cp as vs,mkdir as Fe,mkdtemp as js,readdir as jr,readFile as or,rename as pr,rm as os,writeFile as Xe}from"fs/promises";import{basename as ec,dirname as Ke,join as _,relative as ea,resolve as ra}from"path";var I=`// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
5
+ `;var aa=".absolutejs-expo-project",Z=async(e)=>{try{return await vr(e),!0}catch{return!1}},Pe=(e,r)=>{let a=ea(e,r).replaceAll("\\","/");return a.startsWith(".")?a:`./${a}`},sa=(e)=>e.split("/").filter(Boolean).map((r)=>{if(r.startsWith(":"))return`[${r.slice(1)}]`;if(r==="."||r===".."||!/^[A-Za-z0-9._~-]+$/u.test(r))throw TypeError(`Expo native route ${e} contains an unsupported segment ${r}.`);return r}),ca=(e,r)=>_(e,"app",...sa(r),"index.tsx"),la=()=>({dependencies:{expo:"~57.0.9","expo-asset":"~57.0.15","expo-constants":"~57.0.16","expo-dev-client":"~57.0.16","expo-file-system":"~57.0.6","expo-haptics":"~57.0.2","expo-linking":"~57.0.8","expo-router":"~57.0.17",react:"19.2.3","react-native":"0.86.3","react-native-safe-area-context":"~5.7.0","react-native-screens":"4.26.0","react-native-webview":"13.16.1"},devDependencies:{"@types/react":"~19.2.2",typescript:"~6.0.3"},main:"expo-router/entry",name:"absolutejs-expo-shell",private:!0,scripts:{android:"expo run:android",ios:"expo run:ios",start:"expo start --dev-client"},version:"0.0.0"}),ta=(e)=>({expo:{android:{intentFilters:e.deepLinkHosts.map((r)=>({action:"VIEW",autoVerify:!0,category:["BROWSABLE","DEFAULT"],data:[{host:r,pathPrefix:"/",scheme:"https"}]})),package:e.appId},experiments:{typedRoutes:!0},ios:{associatedDomains:e.deepLinkHosts.map((r)=>`applinks:${r}`),bundleIdentifier:e.appId,...e.iosVersion?{buildNumber:e.iosVersion}:{}},name:e.appName,plugins:["expo-router",["expo-dev-client",{launchMode:"most-recent"}]],runtimeVersion:{policy:"appVersion"},scheme:e.deepLinkScheme,slug:e.appId.toLowerCase().replaceAll(".","-"),version:e.iosVersion??"0.1.0"}}),wa=`${I}const config = require('./app.json');
6
+
7
+ if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
8
+ config.expo.plugins = [
9
+ ...config.expo.plugins,
10
+ './plugins/withAbsoluteDevelopmentCa'
11
+ ];
12
+ }
13
+
14
+ module.exports = config;
15
+ `,ba=`${I}const { AndroidConfig, withAndroidManifest, withDangerousMod } = require('expo/config-plugins');
16
+ const { copyFile, mkdir } = require('node:fs/promises');
17
+ const path = require('node:path');
18
+
19
+ const NETWORK_CONFIG = [
20
+ '<?xml version="1.0" encoding="utf-8"?>',
21
+ '<network-security-config>',
22
+ ' <debug-overrides>',
23
+ ' <trust-anchors>',
24
+ ' <certificates src="@raw/absolutejs_dev_ca" />',
25
+ ' </trust-anchors>',
26
+ ' </debug-overrides>',
27
+ '</network-security-config>',
28
+ ''
29
+ ].join('\\n');
30
+
31
+ const withAbsoluteDevelopmentCa = config => {
32
+ config = withAndroidManifest(config, value => {
33
+ const application = AndroidConfig.Manifest.getMainApplicationOrThrow(value.modResults);
34
+ application.$['android:networkSecurityConfig'] = '@xml/absolutejs_dev_network_security';
35
+ return value;
36
+ });
37
+ return withDangerousMod(config, ['android', async value => {
38
+ const certificate = process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH;
39
+ if (!certificate) throw new Error('AbsoluteJS Expo HTTPS development requires its development CA path.');
40
+ const resources = path.join(value.modRequest.platformProjectRoot, 'app', 'src', 'main', 'res');
41
+ await Promise.all([
42
+ mkdir(path.join(resources, 'raw'), { recursive: true }),
43
+ mkdir(path.join(resources, 'xml'), { recursive: true })
44
+ ]);
45
+ await Promise.all([
46
+ copyFile(certificate, path.join(resources, 'raw', 'absolutejs_dev_ca.pem')),
47
+ require('node:fs/promises').writeFile(path.join(resources, 'xml', 'absolutejs_dev_network_security.xml'), NETWORK_CONFIG)
48
+ ]);
49
+ return value;
50
+ }]);
51
+ };
52
+
53
+ module.exports = withAbsoluteDevelopmentCa;
54
+ `,ua=(e)=>`${I}const { getDefaultConfig } = require('expo/metro-config');
55
+ const path = require('node:path');
56
+
57
+ const projectRoot = __dirname;
58
+ const appRoot = ${JSON.stringify(e)};
59
+ const config = getDefaultConfig(projectRoot);
60
+ config.resolver.assetExts.push('absasset');
61
+ config.resolver.nodeModulesPaths = [
62
+ path.join(projectRoot, 'node_modules'),
63
+ path.join(appRoot, 'node_modules')
64
+ ];
65
+ config.watchFolders = [appRoot];
66
+
67
+ module.exports = config;
68
+ `,da=`${I}import { Stack } from 'expo-router';
69
+
70
+ export default function AbsoluteLayout() {
71
+ return <Stack screenOptions={{ headerShown: false }} />;
72
+ }
73
+ `,na=`${I}import * as Haptics from 'expo-haptics';
74
+ import { Link } from 'expo-router';
75
+ import { Pressable, SafeAreaView, StyleSheet, Text, View } from 'react-native';
76
+
77
+ export default function AbsoluteNativeDiagnostic() {
78
+ return (
79
+ <SafeAreaView style={styles.page}>
80
+ <View style={styles.card}>
81
+ <Text style={styles.eyebrow}>ABSOLUTEJS \xB7 EXPO EXPERIMENT</Text>
82
+ <Text style={styles.title}>This screen is native React UI.</Text>
83
+ <Text style={styles.body}>Ordinary AbsoluteJS routes remain embedded web routes. Only explicitly owned routes use React Native.</Text>
84
+ <Pressable style={styles.button} onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)}>
85
+ <Text style={styles.buttonText}>Test native haptics</Text>
86
+ </Pressable>
87
+ <Link href="/" style={styles.link}>Open the AbsoluteJS app</Link>
88
+ </View>
89
+ </SafeAreaView>
90
+ );
91
+ }
92
+
93
+ const styles = StyleSheet.create({
94
+ body: { color: '#cbd5e1', fontSize: 16, lineHeight: 24 },
95
+ button: { backgroundColor: '#f8fafc', borderRadius: 12, padding: 14 },
96
+ buttonText: { color: '#020617', fontSize: 16, fontWeight: '700', textAlign: 'center' },
97
+ card: { backgroundColor: '#0f172a', borderRadius: 24, gap: 20, maxWidth: 560, padding: 28, width: '100%' },
98
+ eyebrow: { color: '#38bdf8', fontSize: 12, fontWeight: '800', letterSpacing: 1.5 },
99
+ link: { color: '#7dd3fc', fontSize: 16, textAlign: 'center' },
100
+ page: { alignItems: 'center', backgroundColor: '#020617', flex: 1, justifyContent: 'center', padding: 20 },
101
+ title: { color: '#f8fafc', fontSize: 32, fontWeight: '800' }
102
+ });
103
+ `,fa=(e)=>{let r=["/__absolute/native",...Object.keys(e.expoNativeRoutes)];return`${I}import * as Haptics from 'expo-haptics';
104
+ import * as Linking from 'expo-linking';
105
+ import { router, usePathname } from 'expo-router';
106
+ import { useEffect, useRef, useState } from 'react';
107
+ import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'react-native';
108
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
109
+ import { materializeAbsoluteWebBundle } from './webAssets';
110
+
111
+ const BRIDGE_FORMAT = 1;
112
+ const MAX_MESSAGE_BYTES = 64 * 1024;
113
+ const MAX_HTTP_BODY_BYTES = 48 * 1024;
114
+ const NATIVE_ROUTES = new Set(${JSON.stringify(r)});
115
+ const PRODUCTION_ORIGIN = ${JSON.stringify(e.productionOrigin)};
116
+ const DEV_ORIGIN = Platform.OS === 'android'
117
+ ? process.env.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN
118
+ : process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
119
+ const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
120
+
121
+ const bridgeBootstrap = (path: string) => {
122
+ const initialPath = DEV_ORIGIN
123
+ ? 'location.pathname + location.search + location.hash'
124
+ : JSON.stringify(path);
125
+ return \`(() => {
126
+ const pending = new Map();
127
+ let sequence = 0;
128
+ let currentPath = \${initialPath};
129
+ const send = value => {
130
+ const source = JSON.stringify(value);
131
+ if (new TextEncoder().encode(source).byteLength > 65536) throw new Error('Expo bridge message exceeds 64 KiB.');
132
+ window.ReactNativeWebView.postMessage(source);
133
+ };
134
+ globalThis.__absoluteExpoReceive = source => {
135
+ const message = JSON.parse(source);
136
+ const operation = pending.get(message.id);
137
+ if (!operation) return;
138
+ pending.delete(message.id);
139
+ clearTimeout(operation.timer);
140
+ message.error ? operation.reject(new Error(message.error.message)) : operation.resolve(message.result);
141
+ };
142
+ globalThis.__absoluteExpoBridge = {
143
+ request(method, params) {
144
+ const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
145
+ send({ format: 1, id, kind: 'request', method, params, path: currentPath });
146
+ return new Promise((resolve, reject) => {
147
+ const timer = setTimeout(() => {
148
+ pending.delete(id);
149
+ reject(new Error('Expo bridge request timed out.'));
150
+ }, 10000);
151
+ pending.set(id, { reject, resolve, timer });
152
+ });
153
+ },
154
+ setPath(path) {
155
+ currentPath = path;
156
+ send({ format: 1, kind: 'event', event: 'navigation', path });
157
+ }
158
+ };
159
+ if (\${DEV_ORIGIN ? 'true' : 'false'}) {
160
+ const publishPath = () => {
161
+ const path = location.pathname + location.search + location.hash;
162
+ if (path === currentPath) return;
163
+ currentPath = path;
164
+ send({ format: 1, kind: 'event', event: 'navigation', path });
165
+ };
166
+ for (const method of ['pushState', 'replaceState']) {
167
+ const original = history[method];
168
+ history[method] = function(...args) {
169
+ const result = original.apply(this, args);
170
+ publishPath();
171
+ return result;
172
+ };
173
+ }
174
+ addEventListener('popstate', publishPath);
175
+ addEventListener('hashchange', publishPath);
176
+ }
177
+ document.addEventListener('click', event => {
178
+ const anchor = event.target instanceof Element ? event.target.closest('a[href]') : null;
179
+ if (!anchor) return;
180
+ const url = new URL(anchor.href, location.href);
181
+ if (!${JSON.stringify(r)}.includes(url.pathname)) return;
182
+ event.preventDefault();
183
+ send({ format: 1, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
184
+ }, true);
185
+ send({ format: 1, kind: 'event', event: 'ready', path: currentPath });
186
+ })(); true;\`;
187
+ };
188
+
189
+ const impact = async (params: Record<string, unknown>) => {
190
+ const style = params.style;
191
+ if (style === 'selection') return Haptics.selectionAsync();
192
+ if (style === 'success' || style === 'warning' || style === 'error') {
193
+ const value = style === 'success' ? Haptics.NotificationFeedbackType.Success : style === 'warning' ? Haptics.NotificationFeedbackType.Warning : Haptics.NotificationFeedbackType.Error;
194
+ return Haptics.notificationAsync(value);
195
+ }
196
+ const value = style === 'light' ? Haptics.ImpactFeedbackStyle.Light : style === 'heavy' ? Haptics.ImpactFeedbackStyle.Heavy : Haptics.ImpactFeedbackStyle.Medium;
197
+ return Haptics.impactAsync(value);
198
+ };
199
+
200
+ const bridgeFetch = async (params: Record<string, unknown>) => {
201
+ if (params.method !== 'GET' || typeof params.url !== 'string' || typeof params.headers !== 'object' || params.headers === null || Array.isArray(params.headers)) throw new Error('Expo bridge HTTP request is invalid.');
202
+ const url = new URL(params.url);
203
+ if (url.origin !== PRODUCTION_ORIGIN || url.username || url.password) throw new Error('Expo bridge HTTP request left productionOrigin.');
204
+ const headers = new Headers();
205
+ for (const [name, value] of Object.entries(params.headers as Record<string, unknown>)) {
206
+ const normalized = name.toLowerCase();
207
+ if (typeof value !== 'string' || (normalized !== 'accept' && !normalized.startsWith('x-absolute-mobile-'))) throw new Error('Expo bridge HTTP header is not allowed.');
208
+ headers.set(normalized, value);
209
+ }
210
+ const response = await fetch(url, { headers, method: 'GET', redirect: 'manual' });
211
+ if (new URL(response.url || url.href).origin !== PRODUCTION_ORIGIN || response.status >= 300 && response.status < 400) throw new Error('Expo bridge HTTP redirects are not allowed.');
212
+ const body = await response.text();
213
+ if (new TextEncoder().encode(body).byteLength > MAX_HTTP_BODY_BYTES) throw new Error('Expo bridge HTTP response exceeds 48 KiB.');
214
+ const responseHeaders: Record<string, string> = {};
215
+ for (const name of ['cache-control', 'content-type']) {
216
+ const value = response.headers.get(name);
217
+ if (value) responseHeaders[name] = value;
218
+ }
219
+ return { body, headers: responseHeaders, status: response.status };
220
+ };
221
+
222
+ export function AbsoluteWebHost() {
223
+ const pathname = usePathname() || '/';
224
+ const webView = useRef<WebView>(null);
225
+ const [indexUri, setIndexUri] = useState<string>();
226
+ const [canGoBack, setCanGoBack] = useState(false);
227
+ const activeWebPath = useRef(pathname);
228
+
229
+ useEffect(() => {
230
+ if (DEV_ORIGIN) {
231
+ const target = new URL(pathname, DEV_ORIGIN);
232
+ target.searchParams.set('__absolute_target', HMR_TARGET);
233
+ setIndexUri(target.href);
234
+ return;
235
+ }
236
+ void materializeAbsoluteWebBundle().then(uri => setIndexUri(uri + '?absolutePath=' + encodeURIComponent(pathname)));
237
+ }, [pathname]);
238
+ useEffect(() => {
239
+ const subscription = BackHandler.addEventListener('hardwareBackPress', () => {
240
+ if (!canGoBack) return false;
241
+ webView.current?.goBack();
242
+ return true;
243
+ });
244
+ return () => subscription.remove();
245
+ }, [canGoBack]);
246
+
247
+ const respond = (message: Record<string, unknown>) => {
248
+ const source = JSON.stringify(message).replaceAll('\\u2028', '\\\\u2028').replaceAll('\\u2029', '\\\\u2029');
249
+ if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) throw new Error('Expo bridge response exceeds 64 KiB.');
250
+ webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
251
+ };
252
+ const hasOrigin = (source: string, origin: string) => {
253
+ try { return new URL(source).origin === origin; } catch { return false; }
254
+ };
255
+ const onMessage = async (event: WebViewMessageEvent) => {
256
+ const source = event.nativeEvent.data;
257
+ if (new TextEncoder().encode(source).byteLength > MAX_MESSAGE_BYTES) return;
258
+ let message: Record<string, unknown>;
259
+ try { message = JSON.parse(source); } catch { return; }
260
+ if (message.format !== BRIDGE_FORMAT || typeof message.path !== 'string' || !message.path.startsWith('/') || message.path.startsWith('//')) return;
261
+ if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'ready')) {
262
+ const target = new URL(message.path, PRODUCTION_ORIGIN);
263
+ if (target.origin !== PRODUCTION_ORIGIN) return;
264
+ if (NATIVE_ROUTES.has(target.pathname)) router.push(message.path as never);
265
+ else activeWebPath.current = message.path;
266
+ return;
267
+ }
268
+ if (message.kind !== 'request' || typeof message.id !== 'string' || message.path !== activeWebPath.current) return;
269
+ try {
270
+ if (typeof message.params !== 'object' || message.params === null || Array.isArray(message.params)) throw new Error('Expo bridge method params are invalid.');
271
+ if (message.method === 'devices.haptics.impact') {
272
+ const style = (message.params as Record<string, unknown>).style;
273
+ if (typeof style !== 'string' || !['error', 'heavy', 'light', 'medium', 'selection', 'success', 'vibrate', 'warning'].includes(style)) throw new Error('Expo bridge haptics style is invalid.');
274
+ await impact(message.params as Record<string, unknown>);
275
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });
276
+ } else if (message.method === 'http.fetch') {
277
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await bridgeFetch(message.params as Record<string, unknown>) });
278
+ } else {
279
+ throw new Error('Expo bridge method is not allowed.');
280
+ }
281
+ } catch (error) {
282
+ respond({ error: { code: 'failed', message: error instanceof Error ? error.message : 'Native operation failed.' }, format: BRIDGE_FORMAT, id: message.id, kind: 'response' });
283
+ }
284
+ };
285
+
286
+ if (!indexUri) return <View style={styles.loading}><ActivityIndicator /></View>;
287
+ return <WebView
288
+ allowFileAccess
289
+ allowFileAccessFromFileURLs
290
+ allowUniversalAccessFromFileURLs={false}
291
+ allowingReadAccessToURL={indexUri.slice(0, indexUri.lastIndexOf('/') + 1)}
292
+ injectedJavaScriptBeforeContentLoaded={bridgeBootstrap(pathname)}
293
+ onMessage={onMessage}
294
+ onNavigationStateChange={state => setCanGoBack(state.canGoBack)}
295
+ onShouldStartLoadWithRequest={request => {
296
+ if (request.url.startsWith('file:') || hasOrigin(request.url, PRODUCTION_ORIGIN) || DEV_ORIGIN && hasOrigin(request.url, DEV_ORIGIN)) return true;
297
+ void Linking.openURL(request.url);
298
+ return false;
299
+ }}
300
+ ref={webView}
301
+ source={{ uri: indexUri }}
302
+ style={styles.web}
303
+ />;
304
+ }
305
+
306
+ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
307
+ `},Aa=`${I}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
308
+
309
+ export default AbsoluteWebHost;
310
+ `,ya=`${I}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
311
+
312
+ export default AbsoluteWebHost;
313
+ `,xa=(e,r)=>`${I}export { default } from ${JSON.stringify(Pe(Ke(e),r).replace(/\.(?:[cm]?[jt]sx?)$/u,""))};
314
+ `,Sa=(e,r)=>({compilerOptions:{paths:{"*":["./node_modules/*",`${Pe(r,e)}/node_modules/*`],react:["./node_modules/@types/react/index.d.ts"],"react/*":["./node_modules/@types/react/*"]},strict:!0},extends:"expo/tsconfig.base"}),ga=async(e,r,a)=>{if(await Fe(Ke(e),{recursive:!0}),await Z(e)){let c=await or(e,"utf8");if(c===r)return!1;if(!a&&!c.startsWith(I))throw TypeError(`Expo project file ${e} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`)}let s=`${e}.${crypto.randomUUID()}.tmp`;return await Xe(s,r,{flag:"wx"}),await pr(s,e),!0},he=(e)=>`${JSON.stringify(e,null,"\t")}
315
+ `,ha=`${I}export const materializeAbsoluteWebBundle = async () => {
316
+ throw new Error('The embedded AbsoluteJS bundle is unavailable. Run absolute prepare before a production Expo build.');
317
+ };
318
+ `,Ye=async(e,r)=>{if(e.engine!=="expo")throw TypeError("Expo project generation requires mobile.engine: expo.");let a=ra(r.projectRoot),s=e.nativeProjectDirectory,c=Object.entries(e.expoNativeRoutes),t=(await Promise.all(c.map(async([f,O])=>({exists:await Z(O),module:O,route:f})))).find((f)=>!f.exists);if(t)throw TypeError(`Expo native route ${t.route} references missing module ${t.module}.`);let u=_(s,aa);if(await Z(s)&&!await Z(u)){if((await jr(s)).length>0&&!r.force)throw TypeError(`Expo project directory ${s} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`)}await Fe(s,{recursive:!0}),await Xe(u,`format=1
319
+ `);let w=new Map([[_(s,".gitignore"),`.expo/
320
+ android/
321
+ ios/
322
+ node_modules/
323
+ `],[_(s,"app.json"),he(ta(e))],[_(s,"app.config.js"),wa],[_(s,"package.json"),he(la())],[_(s,"metro.config.js"),ua(a)],[_(s,"plugins","withAbsoluteDevelopmentCa.js"),ba],[_(s,"tsconfig.json"),he(Sa(a,s))],[_(s,"app","_layout.tsx"),da],[_(s,"app","__absolute","native","index.tsx"),na],[_(s,"src","generated","AbsoluteWebHost.tsx"),fa(e)]]),b=_(s,"src","generated","webAssets.ts");if(!await Z(b))w.set(b,ha);if(!e.expoNativeRoutes["/"])w.set(_(s,"app","index.tsx"),Aa);w.set(_(s,"app","[...absolute].tsx"),ya);for(let[f,O]of c){let n=f==="/"?_(s,"app","index.tsx"):ca(s,f);w.set(n,xa(n,O))}return{changed:(await Promise.all([...w].map(([f,O])=>ga(f,O,!0)))).filter(Boolean).length,path:s,written:[...w.keys()]}};import{createHash as dr,randomUUID as Fa}from"crypto";import{access as Xa,copyFile as ar,mkdir as P,readFile as te,rename as Ka,rm as _e,writeFile as G}from"fs/promises";import{isIP as Pa}from"net";import{dirname as nr,isAbsolute as Ya,join as T,relative as qa,resolve as we,sep as Za}from"path";import{access as Ea}from"fs/promises";import{homedir as Qe}from"os";import{join as i}from"path";import{existsSync as nc,readFileSync as Oa}from"fs";var Q=1000;var qe=60000;var Oe=2;var z=(e)=>{let r;if(e<Q)r=`${e.toFixed(Oe)}ms`;else if(e<qe)r=`${(e/Q).toFixed(Oe)}s`;else{let a=Math.round(e/Q),s=Math.floor(a/60),c=a%60;r=c===0?`${s}m`:`${s}m ${c}s`}return r};var Ze=()=>{try{let e=Oa("/proc/version","utf-8");return/microsoft|wsl/i.test(e)}catch{return!1}};var ze="AbsoluteJS_API_36",$a=(e)=>{try{let r=Bun.spawnSync(e,{stderr:"ignore",stdout:"pipe"});return{exitCode:r.exitCode,stdout:r.stdout.toString()}}catch{return{exitCode:1,stdout:""}}},_a=(e)=>{try{let r=JSON.parse(e);if(typeof r!=="object"||r===null)return!1;let a=Reflect.get(r,"runtimes");if(!Array.isArray(a))return!1;return a.some((s)=>typeof s==="object"&&s!==null&&Reflect.get(s,"isAvailable")===!0&&typeof Reflect.get(s,"identifier")==="string"&&String(Reflect.get(s,"identifier")).includes("iOS"))}catch{return!1}},Ta=(e)=>{let r=/^([a-z]):[\\/](.*)$/i.exec(e.trim());if(!r)return e.trim().replaceAll("\\","/");return`/mnt/${r[1]?.toLowerCase()}/${r[2]?.replaceAll("\\","/")}`},ma=()=>{try{let e=Bun.spawnSync(["cmd.exe","/d","/c","echo","%LOCALAPPDATA%"],{stderr:"ignore",stdout:"pipe"});if(e.exitCode!==0)return;let r=e.stdout.toString().trim();if(!r||r==="%LOCALAPPDATA%")return;return Ta(r)}catch{return}},Da=(e,r=process.env)=>{if(e==="windows")return i(r.LOCALAPPDATA??i(Qe(),"AppData","Local"),"AbsoluteJS","Android","Sdk");if(e==="wsl"){let a=ma();if(a)return i(a,"AbsoluteJS","Android","Sdk")}return i(Qe(),".absolutejs","android-sdk")},Na=async(e)=>{try{return await Ea(e),!0}catch{return!1}},ce=(e=process.platform,r=Ze())=>{if(e==="darwin")return"macos";if(e==="win32")return"windows";if(e==="linux"&&r)return"wsl";return"linux"},Ia=(e,r)=>{if(e==="wsl")return[`${r}.exe`,`${r}.bat`,r];if(e==="windows")return[r,`${r}.exe`,`${r}.bat`];return[r]},L=async(e,r,a,s)=>{let l=(await Promise.all(r.map(async(t)=>await a.exists(t)?t:void 0))).find((t)=>t!==void 0);if(l)return l;for(let t of Ia(s,e)){let u=a.which(t);if(u)return u}return},V=(e,r,a,s,c)=>s?{id:e,label:r,path:s,platform:a,status:"pass"}:{id:e,label:r,platform:a,remediation:c,status:"fail"},ie=async(e={})=>{let r=e.env??process.env,a=e.host??ce(),s=e.exists??Na,c=e.which??((h)=>Bun.which(h)),l=e.capture??$a,t=e.androidRoot===null?void 0:e.androidRoot??r.ANDROID_HOME??r.ANDROID_SDK_ROOT??Da(a,r),u=a==="windows"||a==="wsl",w=(h)=>t?i(t,...h):void 0,b=(h)=>h.filter((g)=>Boolean(g)),x=await L("adb",b([w(["platform-tools",u?"adb.exe":"adb"])]),{exists:s,which:c},a),A=await L("emulator",b([w(["emulator",u?"emulator.exe":"emulator"])]),{exists:s,which:c},a),f=await L("sdkmanager",b([w(["cmdline-tools","latest","bin",u?"sdkmanager.bat":"sdkmanager"])]),{exists:s,which:c},a),O=await L("avdmanager",b([w(["cmdline-tools","latest","bin",u?"avdmanager.bat":"avdmanager"])]),{exists:s,which:c},a),n=await L("java",[],{exists:s,which:c},a),y=[{id:"host",label:`Development host: ${a}`,platform:"host",status:"pass"},V("android.adb","Android Debug Bridge","android",x,"Install Android SDK Platform Tools or expose adb on PATH."),V("android.emulator","Android Emulator","android",A,"Install the Android Emulator from Android Studio SDK Manager."),V("android.sdkmanager","Android SDK Manager","android",f,"Install Android SDK Command-line Tools (latest)."),V("android.avdmanager","Android Virtual Device Manager","android",O,"Install Android SDK Command-line Tools (latest)."),V("android.java","Java runtime","android",n,"Install the JDK required by the configured Android Gradle plugin.")];if(A){let h=l([A,"-list-avds"]),g=h.exitCode===0&&h.stdout.split(/\r?\n/).includes(ze);y.push({id:"android.avd",label:`AbsoluteJS Android emulator (${ze})`,platform:"android",remediation:g?void 0:"Run absolute mobile doctor android --fix to provision the managed emulator.",status:g?"pass":"fail"})}if(a==="wsl")y.push({id:"android.virtualization",label:x?.endsWith(".exe")?"Windows-host Android bridge available to WSL":"WSL requires a Windows-host emulator bridge or Linux KVM",platform:"android",remediation:x?.endsWith(".exe")?void 0:"Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",status:x?.endsWith(".exe")?"pass":"warn"});else if(a==="linux"){let h=await s("/dev/kvm");y.push({id:"android.virtualization",label:"Linux KVM acceleration",platform:"android",remediation:h?void 0:"Enable KVM and grant the current user access to /dev/kvm.",status:h?"pass":"warn"})}if(a!=="macos")return y.push({id:"ios.simulator",label:"iOS Simulator requires macOS and Xcode",platform:"ios",status:"skip"}),y;let S=await L("xcrun",[],{exists:s,which:c},a),D=await L("xcodebuild",[],{exists:s,which:c},a);if(y.push(V("ios.xcrun","Xcode command runner","ios",S,"Install Xcode and select it with xcode-select."),V("ios.xcodebuild","Xcode build system","ios",D,"Install Xcode and select it with xcode-select.")),S){let h=l([S,"simctl","list","runtimes","--json"]),g=h.exitCode===0&&_a(h.stdout);y.push({id:"ios.runtime",label:"iOS Simulator runtime",platform:"ios",remediation:g?void 0:"Run absolute mobile doctor ios --fix to download an iOS Simulator runtime.",status:g?"pass":"fail"})}return y};import{access as Ma,readFile as ka,rename as Ra,writeFile as Ca}from"fs/promises";import{relative as Wa,resolve as ve}from"path";var je="capacitor.config.ts",Ee=(e,r)=>Wa(e,r).replaceAll("\\","/"),Ua=(e,r)=>`import type { CapacitorConfig } from '@capacitor/cli';
3
324
 
4
325
  const config: CapacitorConfig = {
5
- appId: ${JSON.stringify(b.appId)},
6
- appName: ${JSON.stringify(b.appName)},
7
- webDir: ${JSON.stringify(p(w,b.bundleDirectory))},
326
+ appId: ${JSON.stringify(e.appId)},
327
+ appName: ${JSON.stringify(e.appName)},
328
+ webDir: ${JSON.stringify(Ee(r,e.bundleDirectory))},
8
329
  android: {
9
- path: ${JSON.stringify(p(w,`${b.nativeProjectDirectory}/android`))}
330
+ path: ${JSON.stringify(Ee(r,`${e.nativeProjectDirectory}/android`))}
10
331
  },
11
332
  ios: {
12
- path: ${JSON.stringify(p(w,`${b.nativeProjectDirectory}/ios`))}
333
+ path: ${JSON.stringify(Ee(r,`${e.nativeProjectDirectory}/ios`))}
13
334
  }
14
335
  };
15
336
 
16
337
  export default config;
17
- `,Ew=async(b)=>{try{return await Iw(b),!0}catch{return!1}},Ib=async(b,w)=>{let $=Fb(w.projectRoot),A=Fb($,Gb),S=Zw(b,$);if(await Ew(A)){if(await Hw(A,"utf8")===S)return{changed:!1,path:A};if(!w.force)throw TypeError(`${Gb} already exists and differs; rerun with --force only after reviewing it.`)}let M=`${A}.${crypto.randomUUID()}.tmp`;return await Yw(M,S,{flag:"wx"}),await Vw(M,A),{changed:!0,path:A}};import{createHash as Lw}from"crypto";import{access as JA,copyFile as NA,mkdir as WA,mkdtemp as UA,readdir as kw,readFile as qw,rename as KA,rm as TA,stat as XA,writeFile as _A}from"fs/promises";import{dirname as FA,isAbsolute as GA,join as zw,relative as Hb,resolve as IA,sep as HA}from"path";var yw=new Set(["Pods","DerivedData","build","xcuserdata"]),Vb=async(b,w=b,$={})=>{let A=await kw(w,{withFileTypes:!0});return(await Promise.all(A.sort((M,O)=>M.name.localeCompare(O.name)).map(async(M)=>{let O=zw(w,M.name),D=Hb(b,O).replaceAll("\\","/");if(M.isDirectory()&&(yw.has(M.name)||D==="App/App/public"&&$.includePublicBundle!==!0))return[];if(M.isDirectory())return Vb(b,O,$);return M.isFile()?[O]:[]}))).flat()},Yb=async(b,w={})=>{let $=Lw("sha256"),A=await Vb(b,b,w),S=await Promise.all(A.map((M)=>qw(M)));return A.forEach((M,O)=>{$.update(Hb(b,M).replaceAll("\\","/")),$.update("\x00"),$.update(S[O]??new Uint8Array),$.update("\x00")}),$.digest("hex")};import{randomUUID as Rw,X509Certificate as Pw}from"crypto";import{createServer as fw}from"http";import{connect as lw,createServer as Qb,isIP as mw}from"net";import{readFile as hw}from"fs/promises";var t=(b)=>new Promise((w,$)=>{b.close((A)=>{if(A)$(A);else w()})}),Zb=(b,w)=>new Promise(($,A)=>{b.once("error",A),b.listen(w,"0.0.0.0",()=>{b.off("error",A);let S=b.address();if(!S||typeof S==="string"){A(Error("Could not determine the iOS device helper port."));return}$(S.port)})}),gw=async()=>{let b=Qb(),w=await new Promise(($,A)=>{b.once("error",A),b.listen(0,"127.0.0.1",()=>{let S=b.address();if(!S||typeof S==="string"){A(Error("Could not allocate the iOS CA enrollment port."));return}$(S.port)})});return await t(b),w},e=(b)=>{let w=b.trim();if(!w||w.length>253||/[\0\s/?#]/u.test(w))throw TypeError("Physical iOS development requires a valid LAN host.");return w},Eb=(b)=>{let w=b.trim();if(!w||w.length>256||/[\0\r\n]/u.test(w))throw TypeError("--ios-device requires a valid Xcode device identifier or name.");return w},dw=(b,w,$)=>{let A=new URL(`${b}://localhost:${$}`),S=e(w);return A.hostname=mw(S)===6?`[${S}]`:S,A},Lb=async(b)=>{let $=new Pw(await hw(b.certificateAuthorityPath)).raw,S=`/${Rw().replaceAll("-","")}/absolutejs-development-ca.cer`,M=fw((C,J)=>{if(C.method!=="GET"||C.url!==S){J.writeHead(404,{"Cache-Control":"no-store","Content-Type":"text/plain; charset=utf-8"}),J.end("Not found.");return}J.writeHead(200,{"Cache-Control":"no-store","Content-Disposition":'attachment; filename="absolutejs-development-ca.cer"',"Content-Length":String($.byteLength),"Content-Type":"application/x-x509-ca-cert","X-Content-Type-Options":"nosniff"}),J.end($)}),O=await gw();await Zb(M,O);let D=dw("http",b.displayHost,O);return D.pathname=S,{url:D.href,close:()=>t(M)}},kb=async(b)=>{let w=Qb(($)=>{let A=lw({host:"127.0.0.1",port:b.targetPort});$.pipe(A),A.pipe($);let S=()=>{$.destroy(),A.destroy()};$.once("error",S),A.once("error",S)});return await Zb(w,b.listenPort),{close:()=>t(w)}};var o="AbsoluteJS iPhone",zb=180000,nw=1000,wb=1,$b=1,I=(b)=>typeof b==="object"&&b!==null&&!Array.isArray(b),Y=async(b)=>{try{return await uw(b),!0}catch{return!1}},q=(b)=>b?.throwIfAborted(),iw=(b,w={})=>{try{let $=Bun.spawnSync(b,{cwd:w.cwd,env:w.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:$.exitCode,stderr:$.stderr.toString(),stdout:$.stdout.toString()}}catch($){return{exitCode:1,stderr:$ instanceof Error?$.message:String($),stdout:""}}},db=async(b,w={})=>{return Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"inherit",stdin:"inherit",stdout:"inherit"}).exited},pw=(b,w={})=>{Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})},yb=async(b,w)=>{let $=b.getReader(),A=new TextDecoder,S="",M=async()=>{let{done:O,value:D}=await $.read();if(O)return;S+=A.decode(D,{stream:!0});let C=S.split(/\r?\n/u);S=C.pop()??"",C.forEach(w),await M()};try{if(await M(),S+=A.decode(),S)w(S)}finally{$.releaseLock()}},tw=(b,w,$)=>{let A=Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return yb(A.stdout,$),yb(A.stderr,$),{close:async()=>{try{A.kill()}catch{}await A.exited.catch(()=>{return})}}},G=async(b,w,$,A)=>{let S=await $(b,A);if(S!==0)throw Error(`${w} failed with status ${S}.`)},ew=async(b,w,$,A)=>{if(!b.https)return;if(!b.certificateAuthorityPath)throw Error("iOS Simulator HTTPS requires the AbsoluteJS development CA certificate.");await G([b.project.xcrun,"simctl","keychain",w,"add-root-cert",b.certificateAuthorityPath],"iOS Simulator development CA trust",$,{signal:b.signal}),A("Installed the AbsoluteJS development CA into this iOS Simulator trust store.")},Rb=(b,w,$)=>$?[b.xcrun,"devicectl","device","process","launch","--terminate-existing","--device",w,b.config.appId]:[b.xcrun,"simctl","launch","--terminate-running-process",w,b.config.appId],g=(b,w)=>{if(b.exitCode!==0)throw Error(`${w} failed: ${b.stderr.trim()||b.stdout.trim()||`status ${b.exitCode}`}`);return b.stdout.trim()},Ab=(b,w)=>{try{let $=JSON.parse(b);if(I($))return $}catch{}throw Error(`Invalid ${w} JSON from simctl.`)},ow=(b)=>{let $=Ab(b,"device type").devicetypes;if(!Array.isArray($))return[];return $.flatMap((A)=>{if(!I(A))return[];let{identifier:S}=A,{name:M}=A;return typeof S==="string"&&typeof M==="string"?[{identifier:S,name:M}]:[]})},b$=(b)=>{let w=Ab(b,"runtime"),{runtimes:$}=w;if(!Array.isArray($))return[];return $.flatMap((A)=>{if(!I(A))return[];let{identifier:S}=A,{name:M}=A,{version:O}=A;if(typeof S!=="string"||typeof M!=="string"||typeof O!=="string")return[];return[{identifier:S,isAvailable:A.isAvailable!==!1,name:M,version:O}]})},w$=(b)=>{let w=Ab(b,"device"),{devices:$}=w;if(!I($))return[];return Object.entries($).flatMap(([A,S])=>{if(!Array.isArray(S))return[];return S.flatMap((M)=>{if(!I(M))return[];let{name:O}=M,{state:D}=M,{udid:C}=M;if(typeof O!=="string"||typeof D!=="string"||typeof C!=="string")return[];return[{isAvailable:M.isAvailable!==!1,name:O,runtime:A,state:D,udid:C}]})})},Pb=(b)=>b.split(".").map((w)=>Number(w)),$$=(b,w)=>{let $=Pb(b),A=Pb(w),S=Math.max($.length,A.length);for(let M=0;M<S;M++){let O=($[M]??0)-(A[M]??0);if(O!==0)return O}return 0},A$=(b)=>b.filter((w)=>w.isAvailable&&w.identifier.includes("SimRuntime.iOS-")).sort((w,$)=>$$($.version,w.version))[0],fb=(b)=>Number(/iPhone\s+(\d+)/u.exec(b)?.[1]??0),S$=(b)=>b.filter((w)=>w.name.startsWith("iPhone")).sort((w,$)=>{let A=fb($.name)-fb(w.name);if(A!==0)return A;let S=$.name.includes("Pro")?1:0,M=w.name.includes("Pro")?1:0;return S-M})[0],jb=(b)=>{let w=X(b,".absolutejs","mobile","ios-dev-session");return{configBackup:X(w,"capacitor-config.backup"),infoBackup:X(w,"Info.plist.backup"),journal:X(w,"journal.json"),root:w}},ub=(b)=>X(b,".absolutejs","mobile","ios-native-cache.json"),h=(b,w)=>{let $=rw(s(b),s(w));return $===""||!$.startsWith(`..${sw}`)&&$!==".."&&!aw($)},M$=(b)=>{if(!I(b)||b.format!==wb)return null;let{configBackupPath:w}=b,{infoBackupPath:$}=b,{infoPath:A}=b,{nativeConfigPath:S}=b;if(typeof w!=="string"||typeof $!=="string"||typeof A!=="string"||typeof S!=="string")return null;return{configBackupPath:w,format:wb,infoBackupPath:$,infoPath:A,nativeConfigPath:S}},a=async(b)=>{let w=jb(b);if(!await Y(w.journal))return await bb(w.root,{force:!0,recursive:!0}),!1;let $=await r(w.journal,"utf8").then((A)=>M$(JSON.parse(A))).catch(()=>null);if(!$||!h(b,$.nativeConfigPath)||!h(b,$.infoPath)||!h(w.root,$.configBackupPath)||!h(w.root,$.infoBackupPath))throw Error(`Refusing unsafe or invalid iOS dev journal at ${w.journal}.`);if(await Y($.configBackupPath))await qb($.configBackupPath,$.nativeConfigPath);if(await Y($.infoBackupPath))await qb($.infoBackupPath,$.infoPath);return await bb(w.root,{force:!0,recursive:!0}),!0},O$=(b,w)=>{if(!w)return b;let $=/(<key>NSAllowsArbitraryLoads<\/key>\s*)<false\s*\/>/u;if($.test(b))return b.replace($,"$1<true/>");if(/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(b))return b;let A=/(<key>NSAppTransportSecurity<\/key>\s*<dict>)/u;if(A.test(b))return b.replace(A,`$1
338
+ `,Ba=async(e)=>{try{return await Ma(e),!0}catch{return!1}},oe=async(e,r)=>{let a=ve(r.projectRoot),s=ve(a,je),c=Ua(e,a);if(await Ba(s)){if(await ka(s,"utf8")===c)return{changed:!1,path:s};if(!r.force)throw TypeError(`${je} already exists and differs; rerun with --force only after reviewing it.`)}let l=`${s}.${crypto.randomUUID()}.tmp`;return await Ca(l,c,{flag:"wx"}),await Ra(l,s),{changed:!0,path:s}};import{createHash as Ja}from"crypto";import{access as Dc,copyFile as Nc,mkdir as Ic,mkdtemp as Mc,readdir as Ha,readFile as La,rename as kc,rm as Rc,stat as Cc,writeFile as Wc}from"fs/promises";import{dirname as Bc,isAbsolute as Jc,join as Va,relative as pe,resolve as Hc,sep as Lc}from"path";var Ga=new Set(["Pods","DerivedData","build","xcuserdata"]),er=async(e,r=e,a={})=>{let s=await Ha(r,{withFileTypes:!0});return(await Promise.all(s.sort((l,t)=>l.name.localeCompare(t.name)).map(async(l)=>{let t=Va(r,l.name),u=pe(e,t).replaceAll("\\","/");if(l.isDirectory()&&(Ga.has(l.name)||u==="App/App/public"&&a.includePublicBundle!==!0))return[];if(l.isDirectory())return er(e,t,a);return l.isFile()?[t]:[]}))).flat()},rr=async(e,r={})=>{let a=Ja("sha256"),s=await er(e,e,r),c=await Promise.all(s.map((l)=>La(l)));return s.forEach((l,t)=>{a.update(pe(e,l).replaceAll("\\","/")),a.update("\x00"),a.update(c[t]??new Uint8Array),a.update("\x00")}),a.digest("hex")};var $e="AbsoluteJS iPhone",sr=180000,Qa=1000,Te=1,me=1,R=(e)=>typeof e==="object"&&e!==null&&!Array.isArray(e),J=async(e)=>{try{return await Xa(e),!0}catch{return!1}},K=(e)=>e?.throwIfAborted(),za=(e,r={})=>{try{let a=Bun.spawnSync(e,{cwd:r.cwd,env:r.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:a.exitCode,stderr:a.stderr.toString(),stdout:a.stdout.toString()}}catch(a){return{exitCode:1,stderr:a instanceof Error?a.message:String(a),stdout:""}}},fr=async(e,r={})=>{return Bun.spawn(e,{cwd:r.cwd,env:r.env,signal:r.signal,stderr:"inherit",stdin:"inherit",stdout:"inherit"}).exited},ia=(e,r={})=>{Bun.spawn(e,{cwd:r.cwd,env:r.env,signal:r.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})},cr=async(e,r)=>{let a=e.getReader(),s=new TextDecoder,c="",l=async()=>{let{done:t,value:u}=await a.read();if(t)return;c+=s.decode(u,{stream:!0});let w=c.split(/\r?\n/u);c=w.pop()??"",w.forEach(r),await l()};try{if(await l(),c+=s.decode(),c)r(c)}finally{a.releaseLock()}},va=(e,r,a)=>{let s=Bun.spawn(e,{cwd:r.cwd,env:r.env,signal:r.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return cr(s.stdout,a),cr(s.stderr,a),{close:async()=>{try{s.kill()}catch{}await s.exited.catch(()=>{return})}}},k=async(e,r,a,s)=>{let c=await a(e,s);if(c!==0)throw Error(`${r} failed with status ${c}.`)},ja=async(e,r,a,s)=>{if(!e.https)return;if(!e.certificateAuthorityPath)throw Error("iOS Simulator HTTPS requires the AbsoluteJS development CA certificate.");await k([e.project.xcrun,"simctl","keychain",r,"add-root-cert",e.certificateAuthorityPath],"iOS Simulator development CA trust",a,{signal:e.signal}),s("Installed the AbsoluteJS development CA into this iOS Simulator trust store.")},lr=(e,r,a)=>a?[e.xcrun,"devicectl","device","process","launch","--terminate-existing","--device",r,e.config.appId]:[e.xcrun,"simctl","launch","--terminate-running-process",r,e.config.appId],j=(e,r)=>{if(e.exitCode!==0)throw Error(`${r} failed: ${e.stderr.trim()||e.stdout.trim()||`status ${e.exitCode}`}`);return e.stdout.trim()},De=(e,r)=>{try{let a=JSON.parse(e);if(R(a))return a}catch{}throw Error(`Invalid ${r} JSON from simctl.`)},oa=(e)=>{let a=De(e,"device type").devicetypes;if(!Array.isArray(a))return[];return a.flatMap((s)=>{if(!R(s))return[];let{identifier:c}=s,{name:l}=s;return typeof c==="string"&&typeof l==="string"?[{identifier:c,name:l}]:[]})},pa=(e)=>{let r=De(e,"runtime"),{runtimes:a}=r;if(!Array.isArray(a))return[];return a.flatMap((s)=>{if(!R(s))return[];let{identifier:c}=s,{name:l}=s,{version:t}=s;if(typeof c!=="string"||typeof l!=="string"||typeof t!=="string")return[];return[{identifier:c,isAvailable:s.isAvailable!==!1,name:l,version:t}]})},es=(e)=>{let r=De(e,"device"),{devices:a}=r;if(!R(a))return[];return Object.entries(a).flatMap(([s,c])=>{if(!Array.isArray(c))return[];return c.flatMap((l)=>{if(!R(l))return[];let{name:t}=l,{state:u}=l,{udid:w}=l;if(typeof t!=="string"||typeof u!=="string"||typeof w!=="string")return[];return[{isAvailable:l.isAvailable!==!1,name:t,runtime:s,state:u,udid:w}]})})},tr=(e)=>e.split(".").map((r)=>Number(r)),rs=(e,r)=>{let a=tr(e),s=tr(r),c=Math.max(a.length,s.length);for(let l=0;l<c;l++){let t=(a[l]??0)-(s[l]??0);if(t!==0)return t}return 0},as=(e)=>e.filter((r)=>r.isAvailable&&r.identifier.includes("SimRuntime.iOS-")).sort((r,a)=>rs(a.version,r.version))[0],wr=(e)=>Number(/iPhone\s+(\d+)/u.exec(e)?.[1]??0),ss=(e)=>e.filter((r)=>r.name.startsWith("iPhone")).sort((r,a)=>{let s=wr(a.name)-wr(r.name);if(s!==0)return s;let c=a.name.includes("Pro")?1:0,l=r.name.includes("Pro")?1:0;return c-l})[0],Ar=(e)=>{let r=T(e,".absolutejs","mobile","ios-dev-session");return{configBackup:T(r,"capacitor-config.backup"),infoBackup:T(r,"Info.plist.backup"),journal:T(r,"journal.json"),root:r}},yr=(e)=>T(e,".absolutejs","mobile","ios-native-cache.json"),v=(e,r)=>{let a=qa(we(e),we(r));return a===""||!a.startsWith(`..${Za}`)&&a!==".."&&!Ya(a)},cs=(e)=>{if(!R(e)||e.format!==Te)return null;let{configBackupPath:r}=e,{infoBackupPath:a}=e,{infoPath:s}=e,{nativeConfigPath:c}=e;if(typeof r!=="string"||typeof a!=="string"||typeof s!=="string"||typeof c!=="string")return null;return{configBackupPath:r,format:Te,infoBackupPath:a,infoPath:s,nativeConfigPath:c}},le=async(e)=>{let r=Ar(e);if(!await J(r.journal))return await _e(r.root,{force:!0,recursive:!0}),!1;let a=await te(r.journal,"utf8").then((s)=>cs(JSON.parse(s))).catch(()=>null);if(!a||!v(e,a.nativeConfigPath)||!v(e,a.infoPath)||!v(r.root,a.configBackupPath)||!v(r.root,a.infoBackupPath))throw Error(`Refusing unsafe or invalid iOS dev journal at ${r.journal}.`);if(await J(a.configBackupPath))await ar(a.configBackupPath,a.nativeConfigPath);if(await J(a.infoBackupPath))await ar(a.infoBackupPath,a.infoPath);return await _e(r.root,{force:!0,recursive:!0}),!0},ls=(e,r)=>{if(!r)return e;let a=/(<key>NSAllowsArbitraryLoads<\/key>\s*)<false\s*\/>/u;if(a.test(e))return e.replace(a,"$1<true/>");if(/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(e))return e;let s=/(<key>NSAppTransportSecurity<\/key>\s*<dict>)/u;if(s.test(e))return e.replace(s,`$1
18
339
  <key>NSAllowsArbitraryLoads</key>
19
- <true/>`);return b.replace(/<dict>/u,`<dict>
340
+ <true/>`);return e.replace(/<dict>/u,`<dict>
20
341
  <key>NSAppTransportSecurity</key>
21
342
  <dict>
22
343
  <key>NSAllowsArbitraryLoads</key>
23
344
  <true/>
24
- </dict>`)},C$=async(b,w,$,A="localhost")=>{let S=jb(b.projectRoot);await a(b.projectRoot);let M=X(b.nativeDirectory,"App","App","capacitor.config.json"),O=X(b.nativeDirectory,"App","App","Info.plist"),[D,C]=await Promise.all([r(M,"utf8"),r(O,"utf8")]),J=JSON.parse(D);if(!I(J))throw Error(`Invalid Capacitor native config at ${M}.`);await z(S.root,{recursive:!0}),await Promise.all([L(S.configBackup,D,{flag:"wx"}),L(S.infoBackup,C,{flag:"wx"})]);let _={configBackupPath:S.configBackup,format:wb,infoBackupPath:S.infoBackup,infoPath:O,nativeConfigPath:M};await L(S.journal,`${JSON.stringify(_,null,"\t")}
25
- `,{flag:"wx"});let W=new URL(`${$?"https":"http"}://localhost:${w}${b.config.entry}`);W.hostname=cw(A)===6?`[${A}]`:A,W.searchParams.set("__absolute_target","capacitor-ios");let U=J.server;J.server={...I(U)?U:{},cleartext:!$,url:W.href},await Promise.all([L(M,`${JSON.stringify(J,null,"\t")}
26
- `),L(O,O$(C,!$))])},D$=(b)=>{if(!I(b))return null;let{appId:w,fingerprint:$,format:A,installations:S}=b;if(A!==$b||typeof w!=="string"||typeof $!=="string"||!I(S)||!Object.values(S).every((M)=>typeof M==="string"))return null;return{appId:w,fingerprint:$,format:A,installations:Object.fromEntries(Object.entries(S).map(([M,O])=>[M,String(O)]))}},x$=(b)=>r(ub(b),"utf8").then((w)=>D$(JSON.parse(w))).catch(()=>null),vb=async(b,w)=>{let $=ub(b),A=`${$}.${process.pid}.${jw()}.tmp`;await z(gb($),{recursive:!0});try{await L(A,`${JSON.stringify(w,null,"\t")}
27
- `,{flag:"wx"}),await vw(A,$)}finally{await bb(A,{force:!0}).catch(()=>{return})}},J$=async(b,w={})=>Yb(b.nativeDirectory,w),cb=(b,w)=>{let $=w([b,"simctl","list","devices","available","-j"]);return w$(g($,"iOS simulator discovery"))},N$=async(b,w)=>{let $=b$(g(w([b.xcrun,"simctl","list","runtimes","-j"]),"iOS runtime discovery")),A=A$($);if(!A)throw Error("No available iOS Simulator runtime. Run absolute mobile doctor ios --fix.");let[S]=cb(b.xcrun,w).filter((C)=>C.isAvailable&&C.name===o&&C.runtime===A.identifier).sort((C,J)=>Number(J.state==="Booted")-Number(C.state==="Booted"));if(S)return{created:!1,device:S};let M=ow(g(w([b.xcrun,"simctl","list","devicetypes","-j"]),"iOS device-type discovery")),O=S$(M);if(!O)throw Error("Xcode did not report an iPhone simulator type.");let[D]=g(w([b.xcrun,"simctl","create",o,O.identifier,A.identifier]),"iOS simulator creation").split(/\s/u);if(!D)throw Error("simctl did not return the created simulator UDID.");return{created:!0,device:{isAvailable:!0,name:o,runtime:A.identifier,state:"Shutdown",udid:D}}},W$=async(b,w,$,A,S)=>{let M=Date.now()+zb,O=async()=>{if(q(S),cb(b.xcrun,$).find((C)=>C.udid===w)?.state==="Booted")return;if(Date.now()>M)throw Error(`iOS simulator ${w} did not finish booting within ${zb/1000}s.`);await A(nw),await O()};return O()},U$=(b,w,$)=>{if(w.state==="Booted")return;g($([b.xcrun,"simctl","boot",w.udid]),"iOS simulator boot")},lb=(b,w,$)=>{let A=$([b.xcrun,"simctl","get_app_container",w,b.config.appId,"app"]);return A.exitCode===0&&A.stdout.trim()?A.stdout.trim():void 0},K$=(b,w,$)=>{let A=$([b.xcrun,"devicectl","device","info","details","--device",w]);if(A.exitCode!==0)throw Error(`Physical iOS device ${JSON.stringify(w)} is unavailable: ${A.stderr.trim()||A.stdout.trim()||"pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode."}`)},T$=(b,w,$)=>{let A=$([b.xcrun,"devicectl","device","info","apps","--device",w]);return A.exitCode===0&&A.stdout.includes(b.config.appId)},X$=async(b,w,$,A,S)=>{let M=X(b.projectRoot,".absolutejs","mobile","ios-derived-data",hb("sha256").update(b.config.appId).digest("hex").slice(0,16));await z(M,{recursive:!0}),await G([b.xcodebuild,"-workspace",X(b.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS Simulator,id=${w}`,"-derivedDataPath",M,"build"],"iOS simulator build",A,{cwd:b.nativeDirectory,signal:S});let O=X(M,"Build","Products","Debug-iphonesimulator","App.app");if(!await Y(O))throw Error(`Xcode did not produce the simulator app at ${O}.`);return O},_$=async(b,w,$,A)=>{let S=X(b.projectRoot,".absolutejs","mobile","ios-derived-data",hb("sha256").update(b.config.appId).digest("hex").slice(0,16));await z(S,{recursive:!0}),await G([b.xcodebuild,"-workspace",X(b.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS,id=${w}`,"-derivedDataPath",S,"-allowProvisioningUpdates","build"],"iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)",$,{cwd:b.nativeDirectory,signal:A});let M=X(S,"Build","Products","Debug-iphoneos","App.app");if(!await Y(M))throw Error(`Xcode did not produce the physical-device app at ${M}.`);return M},B$=async(b)=>{if(b.cache?.appId===b.project.config.appId&&b.cache.fingerprint===b.fingerprint&&b.cache.installations[b.identifier]===b.fingerprint&&T$(b.project,b.identifier,b.capture))return b.log("iOS native app is unchanged on the selected physical device; skipped Xcode build and install."),!0;b.log("iOS native inputs changed or the physical-device install is stale; rebuilding."),b.transition("building");let $=await _$(b.project,b.identifier,b.run,b.signal);return q(b.signal),b.transition("installing"),await G([b.project.xcrun,"devicectl","device","install","app","--device",b.identifier,$],"iOS physical-device app installation",b.run,{signal:b.signal}),await vb(b.project.projectRoot,{appId:b.project.config.appId,fingerprint:b.fingerprint,format:$b,installations:{...b.cache?.appId===b.project.config.appId?b.cache.installations:{},[b.identifier]:b.fingerprint}}).catch((A)=>b.log(`iOS native cache could not be saved: ${A instanceof Error?A.message:String(A)}`)),!1},F$=async(b)=>{let w=lb(b.project,b.udid,b.capture);if(b.cache?.appId===b.project.config.appId&&b.cache.fingerprint===b.fingerprint&&w!==void 0&&b.cache.installations[b.udid]===w)return b.log(`iOS native app is unchanged on ${b.udid}; skipped Xcode build and install.`),!0;b.log("iOS native inputs changed or the installed app is stale; rebuilding."),b.transition("building");let A=await X$(b.project,b.udid,b.fingerprint,b.run,b.signal);q(b.signal),b.transition("installing"),await G([b.project.xcrun,"simctl","install",b.udid,A],"iOS simulator app installation",b.run,{signal:b.signal});let S=lb(b.project,b.udid,b.capture);if(S)await vb(b.project.projectRoot,{appId:b.project.config.appId,fingerprint:b.fingerprint,format:$b,installations:{[b.udid]:S}}).catch((M)=>b.log(`iOS native cache could not be saved: ${M instanceof Error?M.message:String(M)}`));return!1},G$=/((?:authorization|cookie|password|secret|token|oauth[_-]?code)\s*[:=]\s*)([^\s,;]+)/giu,I$=new RegExp(String.raw`\bBearer\s+[A-Za-z0-9._~+/-]+=*`,"giu"),H$=/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu,V$=new RegExp(String.raw`\s(Debug|Info|Notice|Error|Fault)\s+.*?\[[^\]]+\]\s+\[([^\]]+)\]\s*(.*)$`,"iu"),Y$=(b)=>{let w=Q$(b).trim();if(!w)return null;let $=V$.exec(w),A=$?.[1]?.toLowerCase();return{level:A==="debug"||A==="error"||A==="fault"||A==="notice"?A:"info",message:$?.[3]?.trim()||w,tag:$?.[2]?.trim()||"App"}},Q$=(b)=>b.replaceAll(I$,"Bearer [REDACTED]").replaceAll(H$,"[REDACTED_JWT]").replaceAll(G$,"$1[REDACTED]").replaceAll(/\p{C}/gu,""),mb=(b,w,$)=>{if(!$.nativeLog)return null;let A=$.startNativeLogs??tw,S=$.deviceIdentifier?[b.xcrun,"devicectl","device","process","launch","--console","--terminate-existing","--device",w,b.config.appId]:[b.xcrun,"simctl","spawn",w,"log","stream","--style","compact","--level","debug","--predicate",'process == "App"'];return A(S,{signal:$.signal},(M)=>{let O=Y$(M);if(O)$.nativeLog?.(O)})},Z$=[["syncing","Capacitor sync"],["configuring","dev config"],["fingerprinting","fingerprint"],["booting","simulator"],["connecting","device ready"],["enrolling-trust","HTTPS trust"],["checking-native","app check"],["building","Xcode"],["installing","install"],["launching","launch"],["streaming-logs","logs"]],E$=(b)=>Z$.map(([w,$])=>{let A=b[w];return A===void 0?null:`${$} ${l(A)}`}).filter((w)=>w!==null).join(", "),ab=async(b,w)=>{if(c()!=="macos")throw Error("iOS development requires macOS and Xcode.");let $=w.target??"simulator",A=s(w.projectRoot),S=await Bb({host:"macos"}),M=S.filter((W)=>W.platform==="ios"&&!($==="device"&&W.id==="ios.runtime")&&(W.status==="fail"||W.status==="warn"));if(M.length>0)throw Error(`iOS ${$} development is not ready: ${M.map(({label:W})=>W).join(", ")}.`);let O=S.find((W)=>W.id==="ios.xcrun")?.path,D=S.find((W)=>W.id==="ios.xcodebuild")?.path;if(!O||!D)throw Error("Xcode tools disappeared after readiness checks.");let C=X(A,"node_modules",".bin","cap");if(!await Y(C))throw Error("Capacitor CLI is not installed. Run absolute mobile init first.");await Ib(b,{projectRoot:A}),await z(b.bundleDirectory,{recursive:!0});let J=X(b.bundleDirectory,"index.html");if(!await Y(J))await L(J,`<!doctype html><title>AbsoluteJS mobile development</title>
28
- `);let _=X(b.nativeProjectDirectory,"ios");if(!await Y(_)){if(!w.createNativeProject)throw Error("iOS native project has not been created.");if(await(w.run??db)([C,"add","ios"],{cwd:A})!==0)throw Error("Capacitor iOS project creation failed.")}return{cap:C,config:b,nativeDirectory:_,projectRoot:A,xcodebuild:D,xcrun:O}},L$=async(b)=>{if(b.transition("connecting"),K$(b.project,b.deviceIdentifier,b.capture),!b.startOptions.https)return{caEnrollmentServer:null,startedSimulator:!1,udid:b.deviceIdentifier};if(!b.startOptions.certificateAuthorityPath)throw Error("Physical iOS HTTPS development requires the AbsoluteJS development CA certificate.");b.transition("enrolling-trust");let $=await(b.startOptions.startCaEnrollmentServer??Lb)({certificateAuthorityPath:b.startOptions.certificateAuthorityPath,displayHost:b.serverHost});return b.log(`On the iOS device, open ${$.url}, install the AbsoluteJS development CA profile, then enable it under Settings > General > About > Certificate Trust Settings. This public CA endpoint exists only for this dev session.`),{caEnrollmentServer:$,startedSimulator:!1,udid:b.deviceIdentifier}},k$=async(b)=>{b.transition("booting");let w=await N$(b.project,b.capture),{device:$}=w,A=w.created||$.state!=="Booted";return U$(b.project,$,b.capture),b.spawn(["open","-a","Simulator","--args","-CurrentDeviceUDID",$.udid]),b.transition("connecting"),await W$(b.project,$.udid,b.capture,b.sleep,b.startOptions.signal),await G([b.project.xcrun,"simctl","bootstatus",$.udid,"-b"],"iOS simulator boot readiness",b.run,{signal:b.startOptions.signal}),await ew(b.startOptions,$.udid,b.run,b.log),{caEnrollmentServer:null,startedSimulator:A,udid:$.udid}},Sb=async(b)=>{let{project:w}=b,$=b.deviceIdentifier?Eb(b.deviceIdentifier):void 0,A=$?"device":"simulator",S=$?e(b.serverHost??""):"localhost",M=b.capture??iw,O=b.run??db,D=b.sleep??Bun.sleep,C=b.spawn??pw,J=b.log??console.log,_=performance.now(),W=performance.now(),U={},F="syncing",x=(K)=>{if(K===F){b.onStateChange?.(K);return}let R=performance.now(),d=R-W;U[F]=(U[F]??0)+d,b.onPhaseTiming?.({durationMs:d,phase:F,totalMs:R-_}),F=K,W=R,b.onStateChange?.(K)},N=null,B=null,Q=async()=>{let K=N;N=null,await K?.close().catch(()=>{return})},T=async(K)=>{if($&&b.nativeLog){await Q(),N=mb(w,K,b);return}await G(Rb(w,K,$!==void 0),"iOS app relaunch",O,{signal:b.signal})};try{if(await a(w.projectRoot),q(b.signal),x("syncing"),await G([w.cap,"sync","ios"],"Capacitor iOS synchronization",O,{cwd:w.projectRoot,signal:b.signal}),x("configuring"),b.embeddedBundle!==!0)await C$(w,b.port,b.https===!0,S);q(b.signal);let K=performance.now(),R=J$(w,{includePublicBundle:b.embeddedBundle===!0}).then((P)=>{return U.fingerprinting=performance.now()-K,P}),d=$?await L$({capture:M,deviceIdentifier:$,log:J,project:w,serverHost:S,startOptions:b,transition:x}):await k$({capture:M,log:J,project:w,run:O,sleep:D,spawn:C,startOptions:b,transition:x}),{caEnrollmentServer:eb,startedSimulator:ob,udid:k}=d;B=eb;let Db=await R;x("checking-native");let xb=await x$(w.projectRoot),n=$?await B$({cache:xb,capture:M,fingerprint:Db,identifier:$,log:J,project:w,run:O,signal:b.signal,transition:x}):await F$({cache:xb,capture:M,fingerprint:Db,log:J,project:w,run:O,signal:b.signal,transition:x,udid:k});if(q(b.signal),b.nativeLog)x("streaming-logs");if(N=mb(w,k,b),x("launching"),!$||!N)await G(Rb(w,k,$!==void 0),"iOS app launch",O,{signal:b.signal});x("ready"),U.total=performance.now()-_,J(b.embeddedBundle===!0?`iOS ${A} connected with the embedded bundle and backend on port ${b.port} in ${l(U.total)} (${n?"native cache hit":"native build installed"}).`:`iOS ${A} connected with HMR on port ${b.port} in ${l(U.total)} (${n?"native cache hit":"native build installed"}).`),J(`iOS startup: ${E$(U)}.`);let j=!1,Jb=async()=>{if(j)return;j=!0,x("closing"),await Q(),await B?.close().catch(()=>{return}),B=null,await a(w.projectRoot),x("closed")};return{close:Jb,nativeCacheHit:n,startedSimulator:ob,targetKind:A,timings:{...U},udid:k,rebuild:async()=>{if(j)throw Error("iOS development session is closed.");return J("iOS native inputs changed; rebuilding without restarting the dev server."),await Jb(),Sb(b)},relaunch:async()=>{if(j)throw Error("iOS development session is closed.");x("launching");try{await T(k),x("ready"),J(`iOS app relaunched on the selected ${A}.`)}catch(P){throw x("failed"),P}},screenshot:async(P)=>{if($)throw Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");let u=s(w.projectRoot,P);if(!h(w.projectRoot,u))throw Error("iOS screenshot destination must remain inside the project.");return await z(gb(u),{recursive:!0}),await G([w.xcrun,"simctl","io",k,"screenshot",u],"iOS simulator screenshot",O,{signal:b.signal}),u},get state(){return F}}}catch(K){throw x("failed"),await Q(),await B?.close().catch(()=>{return}),await a(w.projectRoot),K}};var rb="ABSOLUTE_REMOTE_MAC\t",Mb=1;var H=(b)=>process.stdout.write(`${rb}${JSON.stringify({...b,v:Mb})}
29
- `),Cb=(b)=>b instanceof Error?b.message:String(b),y=(b,w)=>{let $=b.indexOf(w);return $<0?void 0:b[$+1]},P$=(b)=>{let w=Number(y(b,"--port"));if(!Number.isInteger(w)||w<1||w>65535)throw TypeError("Remote iOS agent requires a valid --port.");return w},f$=(b,w)=>{let $=y(b,w);if($===void 0)return;let A=Number($);if(!Number.isInteger(A)||A<1||A>65535)throw TypeError(`Remote iOS agent requires a valid ${w}.`);return A},l$=(b)=>{let w=y(b,"--mobile-config");if(!w)throw TypeError("Remote iOS agent requires --mobile-config.");let $=JSON.parse(Buffer.from(w,"base64url").toString("utf8"));if(typeof $!=="object"||$===null)throw TypeError("Remote iOS agent received an invalid mobile config.");return $},nb=async(b,w)=>{let $=b.getReader(),A=new TextDecoder,S="";try{while(!0){let{done:M,value:O}=await $.read();if(M)break;S+=A.decode(O,{stream:!0});let D=S.split(/\r?\n/u);S=D.pop()??"",D.forEach(w)}}finally{$.releaseLock()}},ib=async(b,w={})=>{let $=Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return nb($.stdout,(A)=>H({message:A,type:"log"})),nb($.stderr,(A)=>H({message:A,type:"log"})),$.exited},m$=(b,w={})=>{try{let $=Bun.spawnSync(b,{cwd:w.cwd,env:w.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:$.exitCode,stderr:$.stderr.toString(),stdout:$.stdout.toString()}}catch($){return{exitCode:1,stderr:Cb($),stdout:""}}},pb=(b)=>({nativeCacheHit:b.nativeCacheHit,startedSimulator:b.startedSimulator,targetKind:b.targetKind,timings:b.timings,type:"ready",udid:b.udid}),h$=async(b)=>{if(process.platform!=="darwin")throw Error("The AbsoluteJS remote iOS agent can run only on macOS.");let w=process.cwd(),$=Ub(l$(b),w),A=P$(b),S=y(b,"--ios-device"),M=y(b,"--server-host"),O=f$(b,"--relay-port");if(S&&(!M||O===void 0))throw TypeError("Remote physical iOS development requires --server-host and --relay-port.");let D=y(b,"--certificate-authority"),C=D?Ob(w,".absolutejs","mobile",`remote-dev-ca-${process.pid}.pem`):void 0;if(C&&D)await q$(Ob(w,".absolutejs","mobile"),{recursive:!0}),await y$(C,Buffer.from(D,"base64url"));let J=await ab($,{createNativeProject:!1,projectRoot:w,run:ib,target:S?"device":"simulator"}),_=S?await kb({listenPort:A,targetPort:O??0}):void 0,W={capture:m$,certificateAuthorityPath:C,deviceIdentifier:S,https:b.includes("--https"),port:A,project:J,run:ib,serverHost:M,log:(x)=>H({message:x,type:"log"}),nativeLog:(x)=>H({entry:x,type:"native-log"}),onPhaseTiming:(x)=>H({...x,type:"timing"}),onStateChange:(x)=>H({state:x,type:"state"}),spawn:(x,N={})=>{Bun.spawn(x,{cwd:N.cwd,env:N.env,signal:N.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})}},U;try{U=await Sb(W)}catch(x){if(await _?.close().catch(()=>{return}),C)await sb(C,{force:!0});throw x}H(pb(U));let F=R$({input:process.stdin,terminal:!1});try{for await(let x of F){let N;try{if(N=JSON.parse(x),N.v!==Mb||typeof N.id!=="string")throw Error("Invalid remote Mac request.");let B;if(N.command==="close")await U.close();else if(N.command==="relaunch")await U.relaunch();else if(N.command==="rebuild")U=await U.rebuild(),B=pb(U);else if(N.command==="screenshot"){let Q=Ob(".absolutejs","mobile","remote-screenshot.png"),T=await U.screenshot(Q);B={data:(await z$(T)).toString("base64")}}else throw Error("Unknown remote Mac request.");if(H({id:N.id,ok:!0,result:B,type:"response"}),N.command==="close")return}catch(B){H({error:Cb(B),id:N?.id??"",ok:!1,type:"response"})}}}finally{if(F.close(),await U.close().catch(()=>{return}),await _?.close().catch(()=>{return}),C)await sb(C,{force:!0})}},tb=async(b)=>{try{await h$(b)}catch(w){H({error:Cb(w),type:"fatal"}),process.exitCode=1}};await tb(process.argv.slice(2));
345
+ </dict>`)},ts=async(e,r,a,s="localhost")=>{let c=Ar(e.projectRoot);await le(e.projectRoot);let l=T(e.nativeDirectory,"App","App","capacitor.config.json"),t=T(e.nativeDirectory,"App","App","Info.plist"),[u,w]=await Promise.all([te(l,"utf8"),te(t,"utf8")]),b=JSON.parse(u);if(!R(b))throw Error(`Invalid Capacitor native config at ${l}.`);await P(c.root,{recursive:!0}),await Promise.all([G(c.configBackup,u,{flag:"wx"}),G(c.infoBackup,w,{flag:"wx"})]);let x={configBackupPath:c.configBackup,format:Te,infoBackupPath:c.infoBackup,infoPath:t,nativeConfigPath:l};await G(c.journal,`${JSON.stringify(x,null,"\t")}
346
+ `,{flag:"wx"});let A=new URL(`${a?"https":"http"}://localhost:${r}${e.config.entry}`);A.hostname=Pa(s)===6?`[${s}]`:s,A.searchParams.set("__absolute_target","capacitor-ios");let f=b.server;b.server={...R(f)?f:{},cleartext:!a,url:A.href},await Promise.all([G(l,`${JSON.stringify(b,null,"\t")}
347
+ `),G(t,ls(w,!a))])},ws=(e)=>{if(!R(e))return null;let{appId:r,fingerprint:a,format:s,installations:c}=e;if(s!==me||typeof r!=="string"||typeof a!=="string"||!R(c)||!Object.values(c).every((l)=>typeof l==="string"))return null;return{appId:r,fingerprint:a,format:s,installations:Object.fromEntries(Object.entries(c).map(([l,t])=>[l,String(t)]))}},bs=(e)=>te(yr(e),"utf8").then((r)=>ws(JSON.parse(r))).catch(()=>null),xr=async(e,r)=>{let a=yr(e),s=`${a}.${process.pid}.${Fa()}.tmp`;await P(nr(a),{recursive:!0});try{await G(s,`${JSON.stringify(r,null,"\t")}
348
+ `,{flag:"wx"}),await Ka(s,a)}finally{await _e(s,{force:!0}).catch(()=>{return})}},us=async(e,r={})=>rr(e.nativeDirectory,r),Sr=(e,r)=>{let a=r([e,"simctl","list","devices","available","-j"]);return es(j(a,"iOS simulator discovery"))},ds=async(e,r)=>{let a=pa(j(r([e.xcrun,"simctl","list","runtimes","-j"]),"iOS runtime discovery")),s=as(a);if(!s)throw Error("No available iOS Simulator runtime. Run absolute mobile doctor ios --fix.");let[c]=Sr(e.xcrun,r).filter((w)=>w.isAvailable&&w.name===$e&&w.runtime===s.identifier).sort((w,b)=>Number(b.state==="Booted")-Number(w.state==="Booted"));if(c)return{created:!1,device:c};let l=oa(j(r([e.xcrun,"simctl","list","devicetypes","-j"]),"iOS device-type discovery")),t=ss(l);if(!t)throw Error("Xcode did not report an iPhone simulator type.");let[u]=j(r([e.xcrun,"simctl","create",$e,t.identifier,s.identifier]),"iOS simulator creation").split(/\s/u);if(!u)throw Error("simctl did not return the created simulator UDID.");return{created:!0,device:{isAvailable:!0,name:$e,runtime:s.identifier,state:"Shutdown",udid:u}}},ns=async(e,r,a,s,c)=>{let l=Date.now()+sr,t=async()=>{if(K(c),Sr(e.xcrun,a).find((w)=>w.udid===r)?.state==="Booted")return;if(Date.now()>l)throw Error(`iOS simulator ${r} did not finish booting within ${sr/1000}s.`);await s(Qa),await t()};return t()},fs=(e,r,a)=>{if(r.state==="Booted")return;j(a([e.xcrun,"simctl","boot",r.udid]),"iOS simulator boot")},br=(e,r,a)=>{let s=a([e.xcrun,"simctl","get_app_container",r,e.config.appId,"app"]);return s.exitCode===0&&s.stdout.trim()?s.stdout.trim():void 0},As=(e,r,a)=>{let s=a([e.xcrun,"devicectl","device","info","details","--device",r]);if(s.exitCode!==0)throw Error(`Physical iOS device ${JSON.stringify(r)} is unavailable: ${s.stderr.trim()||s.stdout.trim()||"pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode."}`)},ys=(e,r,a)=>{let s=a([e.xcrun,"devicectl","device","info","apps","--device",r]);return s.exitCode===0&&s.stdout.includes(e.config.appId)},xs=async(e,r,a,s,c)=>{let l=T(e.projectRoot,".absolutejs","mobile","ios-derived-data",dr("sha256").update(e.config.appId).digest("hex").slice(0,16));await P(l,{recursive:!0}),await k([e.xcodebuild,"-workspace",T(e.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS Simulator,id=${r}`,"-derivedDataPath",l,"build"],"iOS simulator build",s,{cwd:e.nativeDirectory,signal:c});let t=T(l,"Build","Products","Debug-iphonesimulator","App.app");if(!await J(t))throw Error(`Xcode did not produce the simulator app at ${t}.`);return t},Ss=async(e,r,a,s)=>{let c=T(e.projectRoot,".absolutejs","mobile","ios-derived-data",dr("sha256").update(e.config.appId).digest("hex").slice(0,16));await P(c,{recursive:!0}),await k([e.xcodebuild,"-workspace",T(e.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS,id=${r}`,"-derivedDataPath",c,"-allowProvisioningUpdates","build"],"iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)",a,{cwd:e.nativeDirectory,signal:s});let l=T(c,"Build","Products","Debug-iphoneos","App.app");if(!await J(l))throw Error(`Xcode did not produce the physical-device app at ${l}.`);return l},gs=async(e)=>{if(e.cache?.appId===e.project.config.appId&&e.cache.fingerprint===e.fingerprint&&e.cache.installations[e.identifier]===e.fingerprint&&ys(e.project,e.identifier,e.capture))return e.log("iOS native app is unchanged on the selected physical device; skipped Xcode build and install."),!0;e.log("iOS native inputs changed or the physical-device install is stale; rebuilding."),e.transition("building");let a=await Ss(e.project,e.identifier,e.run,e.signal);return K(e.signal),e.transition("installing"),await k([e.project.xcrun,"devicectl","device","install","app","--device",e.identifier,a],"iOS physical-device app installation",e.run,{signal:e.signal}),await xr(e.project.projectRoot,{appId:e.project.config.appId,fingerprint:e.fingerprint,format:me,installations:{...e.cache?.appId===e.project.config.appId?e.cache.installations:{},[e.identifier]:e.fingerprint}}).catch((s)=>e.log(`iOS native cache could not be saved: ${s instanceof Error?s.message:String(s)}`)),!1},hs=async(e)=>{let r=br(e.project,e.udid,e.capture);if(e.cache?.appId===e.project.config.appId&&e.cache.fingerprint===e.fingerprint&&r!==void 0&&e.cache.installations[e.udid]===r)return e.log(`iOS native app is unchanged on ${e.udid}; skipped Xcode build and install.`),!0;e.log("iOS native inputs changed or the installed app is stale; rebuilding."),e.transition("building");let s=await xs(e.project,e.udid,e.fingerprint,e.run,e.signal);K(e.signal),e.transition("installing"),await k([e.project.xcrun,"simctl","install",e.udid,s],"iOS simulator app installation",e.run,{signal:e.signal});let c=br(e.project,e.udid,e.capture);if(c)await xr(e.project.projectRoot,{appId:e.project.config.appId,fingerprint:e.fingerprint,format:me,installations:{[e.udid]:c}}).catch((l)=>e.log(`iOS native cache could not be saved: ${l instanceof Error?l.message:String(l)}`));return!1},Os=/((?:authorization|cookie|password|secret|token|oauth[_-]?code)\s*[:=]\s*)([^\s,;]+)/giu,Es=new RegExp(String.raw`\bBearer\s+[A-Za-z0-9._~+/-]+=*`,"giu"),$s=/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu,_s=new RegExp(String.raw`\s(Debug|Info|Notice|Error|Fault)\s+.*?\[[^\]]+\]\s+\[([^\]]+)\]\s*(.*)$`,"iu"),Ts=(e)=>{let r=ms(e).trim();if(!r)return null;let a=_s.exec(r),s=a?.[1]?.toLowerCase();return{level:s==="debug"||s==="error"||s==="fault"||s==="notice"?s:"info",message:a?.[3]?.trim()||r,tag:a?.[2]?.trim()||"App"}},ms=(e)=>e.replaceAll(Es,"Bearer [REDACTED]").replaceAll($s,"[REDACTED_JWT]").replaceAll(Os,"$1[REDACTED]").replaceAll(/\p{C}/gu,""),ur=(e,r,a)=>{if(!a.nativeLog)return null;let s=a.startNativeLogs??va,c=a.deviceIdentifier?[e.xcrun,"devicectl","device","process","launch","--console","--terminate-existing","--device",r,e.config.appId]:[e.xcrun,"simctl","spawn",r,"log","stream","--style","compact","--level","debug","--predicate",'process == "App"'];return s(c,{signal:a.signal},(l)=>{let t=Ts(l);if(t)a.nativeLog?.(t)})},Ds=[["syncing","Capacitor sync"],["configuring","dev config"],["fingerprinting","fingerprint"],["booting","simulator"],["connecting","device ready"],["enrolling-trust","HTTPS trust"],["checking-native","app check"],["building","Xcode"],["installing","install"],["launching","launch"],["streaming-logs","logs"]],Ns=(e)=>Ds.map(([r,a])=>{let s=e[r];return s===void 0?null:`${a} ${z(s)}`}).filter((r)=>r!==null).join(", "),gr=async(e,r)=>{if(ce()!=="macos")throw Error("iOS development requires macOS and Xcode.");let a=r.target??"simulator",s=we(r.projectRoot),c=await ie({host:"macos"}),l=c.filter((A)=>A.platform==="ios"&&!(a==="device"&&A.id==="ios.runtime")&&(A.status==="fail"||A.status==="warn"));if(l.length>0)throw Error(`iOS ${a} development is not ready: ${l.map(({label:A})=>A).join(", ")}.`);let t=c.find((A)=>A.id==="ios.xcrun")?.path,u=c.find((A)=>A.id==="ios.xcodebuild")?.path;if(!t||!u)throw Error("Xcode tools disappeared after readiness checks.");let w=T(s,"node_modules",".bin","cap");if(!await J(w))throw Error("Capacitor CLI is not installed. Run absolute mobile init first.");await oe(e,{projectRoot:s}),await P(e.bundleDirectory,{recursive:!0});let b=T(e.bundleDirectory,"index.html");if(!await J(b))await G(b,`<!doctype html><title>AbsoluteJS mobile development</title>
349
+ `);let x=T(e.nativeProjectDirectory,"ios");if(!await J(x)){if(!r.createNativeProject)throw Error("iOS native project has not been created.");if(await(r.run??fr)([w,"add","ios"],{cwd:s})!==0)throw Error("Capacitor iOS project creation failed.")}return{cap:w,config:e,nativeDirectory:x,projectRoot:s,xcodebuild:u,xcrun:t}},Is=async(e)=>{if(e.transition("connecting"),As(e.project,e.deviceIdentifier,e.capture),!e.startOptions.https)return{caEnrollmentServer:null,startedSimulator:!1,udid:e.deviceIdentifier};if(!e.startOptions.certificateAuthorityPath)throw Error("Physical iOS HTTPS development requires the AbsoluteJS development CA certificate.");e.transition("enrolling-trust");let a=await(e.startOptions.startCaEnrollmentServer??re)({certificateAuthorityPath:e.startOptions.certificateAuthorityPath,displayHost:e.serverHost});return e.log(`On the iOS device, open ${a.url}, install the AbsoluteJS development CA profile, then enable it under Settings > General > About > Certificate Trust Settings. This public CA endpoint exists only for this dev session.`),{caEnrollmentServer:a,startedSimulator:!1,udid:e.deviceIdentifier}},Ms=async(e)=>{e.transition("booting");let r=await ds(e.project,e.capture),{device:a}=r,s=r.created||a.state!=="Booted";return fs(e.project,a,e.capture),e.spawn(["open","-a","Simulator","--args","-CurrentDeviceUDID",a.udid]),e.transition("connecting"),await ns(e.project,a.udid,e.capture,e.sleep,e.startOptions.signal),await k([e.project.xcrun,"simctl","bootstatus",a.udid,"-b"],"iOS simulator boot readiness",e.run,{signal:e.startOptions.signal}),await ja(e.startOptions,a.udid,e.run,e.log),{caEnrollmentServer:null,startedSimulator:s,udid:a.udid}},Ne=async(e)=>{let{project:r}=e,a=e.deviceIdentifier?Ve(e.deviceIdentifier):void 0,s=a?"device":"simulator",c=a?ye(e.serverHost??""):"localhost",l=e.capture??za,t=e.run??fr,u=e.sleep??Bun.sleep,w=e.spawn??ia,b=e.log??console.log,x=performance.now(),A=performance.now(),f={},O="syncing",n=(g)=>{if(g===O){e.onStateChange?.(g);return}let C=performance.now(),F=C-A;f[O]=(f[O]??0)+F,e.onPhaseTiming?.({durationMs:F,phase:O,totalMs:C-x}),O=g,A=C,e.onStateChange?.(g)},y=null,S=null,D=async()=>{let g=y;y=null,await g?.close().catch(()=>{return})},h=async(g)=>{if(a&&e.nativeLog){await D(),y=ur(r,g,e);return}await k(lr(r,g,a!==void 0),"iOS app relaunch",t,{signal:e.signal})};try{if(await le(r.projectRoot),K(e.signal),n("syncing"),await k([r.cap,"sync","ios"],"Capacitor iOS synchronization",t,{cwd:r.projectRoot,signal:e.signal}),n("configuring"),e.embeddedBundle!==!0)await ts(r,e.port,e.https===!0,c);K(e.signal);let g=performance.now(),C=us(r,{includePublicBundle:e.embeddedBundle===!0}).then((B)=>{return f.fingerprinting=performance.now()-g,B}),F=a?await Is({capture:l,deviceIdentifier:a,log:b,project:r,serverHost:c,startOptions:e,transition:n}):await Ms({capture:l,log:b,project:r,run:t,sleep:u,spawn:w,startOptions:e,transition:n}),{caEnrollmentServer:o,startedSimulator:ne,udid:d}=F;S=o;let E=await C;n("checking-native");let m=await bs(r.projectRoot),M=a?await gs({cache:m,capture:l,fingerprint:E,identifier:a,log:b,project:r,run:t,signal:e.signal,transition:n}):await hs({cache:m,capture:l,fingerprint:E,log:b,project:r,run:t,signal:e.signal,transition:n,udid:d});if(K(e.signal),e.nativeLog)n("streaming-logs");if(y=ur(r,d,e),n("launching"),!a||!y)await k(lr(r,d,a!==void 0),"iOS app launch",t,{signal:e.signal});n("ready"),f.total=performance.now()-x,b(e.embeddedBundle===!0?`iOS ${s} connected with the embedded bundle and backend on port ${e.port} in ${z(f.total)} (${M?"native cache hit":"native build installed"}).`:`iOS ${s} connected with HMR on port ${e.port} in ${z(f.total)} (${M?"native cache hit":"native build installed"}).`),b(`iOS startup: ${Ns(f)}.`);let N=!1,U=async()=>{if(N)return;N=!0,n("closing"),await D(),await S?.close().catch(()=>{return}),S=null,await le(r.projectRoot),n("closed")};return{close:U,nativeCacheHit:M,startedSimulator:ne,targetKind:s,timings:{...f},udid:d,rebuild:async()=>{if(N)throw Error("iOS development session is closed.");return b("iOS native inputs changed; rebuilding without restarting the dev server."),await U(),Ne(e)},relaunch:async()=>{if(N)throw Error("iOS development session is closed.");n("launching");try{await h(d),n("ready"),b(`iOS app relaunched on the selected ${s}.`)}catch(B){throw n("failed"),B}},screenshot:async(B)=>{if(a)throw Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");let H=we(r.projectRoot,B);if(!v(r.projectRoot,H))throw Error("iOS screenshot destination must remain inside the project.");return await P(nr(H),{recursive:!0}),await k([r.xcrun,"simctl","io",d,"screenshot",H],"iOS simulator screenshot",t,{signal:e.signal}),H},get state(){return O}}}catch(g){throw n("failed"),await D(),await S?.close().catch(()=>{return}),await le(r.projectRoot),g}};var hr="ABSOLUTE_REMOTE_MAC\t",be=2;var $=(e)=>process.stdout.write(`${hr}${JSON.stringify({...e,v:be})}
350
+ `),de=(e)=>e instanceof Error?e.message:String(e),Y=(e,r)=>{let a=e.indexOf(r);return a<0?void 0:e[a+1]},Ws=(e)=>{let r=Number(Y(e,"--port"));if(!Number.isInteger(r)||r<1||r>65535)throw TypeError("Remote iOS agent requires a valid --port.");return r},Me=(e,r)=>{let a=Y(e,r);if(a===void 0)return;let s=Number(a);if(!Number.isInteger(s)||s<1||s>65535)throw TypeError(`Remote iOS agent requires a valid ${r}.`);return s},Us=(e)=>{let r=Y(e,"--mobile-config");if(!r)throw TypeError("Remote iOS agent requires --mobile-config.");let a=JSON.parse(Buffer.from(r,"base64url").toString("utf8"));if(typeof a!=="object"||a===null)throw TypeError("Remote iOS agent received an invalid mobile config.");return a},Or=async(e,r)=>{let a=e.getReader(),s=new TextDecoder,c="";try{while(!0){let{done:l,value:t}=await a.read();if(l)break;c+=s.decode(t,{stream:!0});let u=c.split(/\r?\n/u);c=u.pop()??"",u.forEach(r)}}finally{a.releaseLock()}},ke=async(e,r={})=>{let a=Bun.spawn(e,{cwd:r.cwd,env:r.env,signal:r.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return Or(a.stdout,(s)=>$({message:s,type:"log"})),Or(a.stderr,(s)=>$({message:s,type:"log"})),a.exited},Bs=(e,r={})=>{try{let a=Bun.spawnSync(e,{cwd:r.cwd,env:r.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:a.exitCode,stderr:a.stderr.toString(),stdout:a.stdout.toString()}}catch(a){return{exitCode:1,stderr:de(a),stdout:""}}},Er=(e)=>({engine:"capacitor",nativeCacheHit:e.nativeCacheHit,startedSimulator:e.startedSimulator,targetKind:e.targetKind,timings:e.timings,type:"ready",udid:e.udid}),Js=async(e)=>{if(e.config.engine!=="expo")throw TypeError("The remote Expo executor requires Expo configuration.");let r=Me(e.args,"--metro-port");if(r===void 0)throw TypeError("Remote Expo execution requires --metro-port.");let a=Me(e.args,"--metro-relay-port");if(e.deviceIdentifier&&a===void 0)throw TypeError("Remote physical Expo execution requires --metro-relay-port.");let s=await Ye(e.config,{projectRoot:process.cwd()}),c=await Bun.file(ue(s.path,"node_modules","expo","package.json")).exists();if(!c){$({state:"preparing-native",type:"state"});let w=performance.now(),b=await ke([process.execPath,"install"],{cwd:s.path});if(b!==0)throw Error(`Remote Expo dependency installation exited with status ${b}.`);$({durationMs:performance.now()-w,phase:"preparing-native",type:"timing"})}let l,t,u;try{l=e.deviceIdentifier?await ae({listenPort:e.port,targetPort:e.relayPort??0}):void 0,t=e.deviceIdentifier?await ae({listenPort:r,targetPort:a??0}):void 0,u=await Ge({certificateAuthorityPath:e.certificateAuthorityPath,config:e.config,executable:await ge(s.path),iosDevice:e.deviceIdentifier,iosOrigin:`${e.args.includes("--https")?"https":"http"}://${e.serverHost??"localhost"}:${e.port}`,metro:"external",metroHost:e.serverHost??"localhost",metroPort:r,platforms:["ios"],log:(b)=>$({message:b,type:"log"}),onPhaseTiming:(b)=>$({...b,type:"timing"}),onStateChange:(b)=>$({state:b,type:"state"})}),$({engine:"expo",nativeCacheHit:c,startedSimulator:!1,targetKind:e.deviceIdentifier?"device":"simulator",timings:u.timings,type:"ready",udid:e.deviceIdentifier??"booted"});let w=$r({input:process.stdin,terminal:!1});try{for await(let b of w){let x;try{if(x=JSON.parse(b),x.v!==be||typeof x.id!=="string"||x.command!=="close")throw Error("Invalid remote Expo request.");await u.close(),$({id:x.id,ok:!0,type:"response"});return}catch(A){$({error:de(A),id:x?.id??"",ok:!1,type:"response"})}}}finally{w.close()}}finally{await u?.close().catch(()=>{return}),await Promise.all([l?.close().catch(()=>{return}),t?.close().catch(()=>{return})])}},Hs=async(e)=>{if(process.platform!=="darwin")throw Error("The AbsoluteJS remote iOS agent can run only on macOS.");let r=process.cwd(),a=Je(Us(e),r),s=Ws(e),c=Y(e,"--ios-device"),l=Y(e,"--server-host"),t=Me(e,"--relay-port");if(c&&(!l||t===void 0))throw TypeError("Remote physical iOS development requires --server-host and --relay-port.");let u=Y(e,"--certificate-authority"),w=u?ue(r,".absolutejs","mobile",`remote-dev-ca-${process.pid}.pem`):void 0;if(w&&u)await ks(ue(r,".absolutejs","mobile"),{recursive:!0}),await Cs(w,Buffer.from(u,"base64url"));if(a.engine==="expo"){try{await Js({args:e,certificateAuthorityPath:w,config:a,deviceIdentifier:c,port:s,relayPort:t,serverHost:l})}finally{if(w)await Ie(w,{force:!0})}return}let b=await gr(a,{createNativeProject:!1,projectRoot:r,run:ke,target:c?"device":"simulator"}),x=c?await ae({listenPort:s,targetPort:t??0}):void 0,A={capture:Bs,certificateAuthorityPath:w,deviceIdentifier:c,https:e.includes("--https"),port:s,project:b,run:ke,serverHost:l,log:(n)=>$({message:n,type:"log"}),nativeLog:(n)=>$({entry:n,type:"native-log"}),onPhaseTiming:(n)=>$({...n,type:"timing"}),onStateChange:(n)=>$({state:n,type:"state"}),spawn:(n,y={})=>{Bun.spawn(n,{cwd:y.cwd,env:y.env,signal:y.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})}},f;try{f=await Ne(A)}catch(n){if(await x?.close().catch(()=>{return}),w)await Ie(w,{force:!0});throw n}$(Er(f));let O=$r({input:process.stdin,terminal:!1});try{for await(let n of O){let y;try{if(y=JSON.parse(n),y.v!==be||typeof y.id!=="string")throw Error("Invalid remote Mac request.");let S;if(y.command==="close")await f.close();else if(y.command==="relaunch")await f.relaunch();else if(y.command==="rebuild")f=await f.rebuild(),S=Er(f);else if(y.command==="screenshot"){let D=ue(".absolutejs","mobile","remote-screenshot.png"),h=await f.screenshot(D);S={data:(await Rs(h)).toString("base64")}}else throw Error("Unknown remote Mac request.");if($({id:y.id,ok:!0,result:S,type:"response"}),y.command==="close")return}catch(S){$({error:de(S),id:y?.id??"",ok:!1,type:"response"})}}}finally{if(O.close(),await f.close().catch(()=>{return}),await x?.close().catch(()=>{return}),w)await Ie(w,{force:!0})}},_r=async(e)=>{try{await Hs(e)}catch(r){$({error:de(r),type:"fatal"}),process.exitCode=1}};await _r(process.argv.slice(2));