@absolutejs/absolute 0.20.0-beta.39 → 0.20.0-beta.40

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,5 +1,5 @@
1
1
  // @bun
2
- import{mkdir as k$,readFile as q$,rm as rb,writeFile as z$}from"fs/promises";import{join as Ob}from"path";import{createInterface as y$}from"readline";import{resolve as Nb}from"path";var ob=/^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/,bw=/^[a-z][a-z0-9+.-]*$/,ww=/^[A-Z0-9]{10}$/,$w=/^[0-9A-F]{64}$/,Aw=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/,n=(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 $},Sw=(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(!Aw.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(!ww.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(!$w.test(w))throw TypeError("mobile.deepLinks.android.sha256CertificateFingerprints entries must be SHA-256 certificate fingerprints.");return w.match(/.{2}/g)?.join(":")??w}))].sort(),Wb=(b,w)=>{let $=V(b.appId,"mobile.appId");if(!ob.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&&!bw.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:n(w,b.bundleDirectory??".absolutejs/mobile/web","mobile.bundleDirectory"),deepLinkHosts:Cw(b.deepLinks?.hosts,A),deepLinkScheme:S,engine:"capacitor",entry:Sw(b.entry),iosVersion:xw(b.ios?.version),nativeProjectDirectory:n(w,b.nativeProject?.directory??"mobile","mobile.nativeProject.directory"),platforms:Ow(b.platforms),productionOrigin:A,pushAndroidGoogleServicesFile:n(w,b.pushNotifications?.android?.googleServicesFile??"google-services.json","mobile.pushNotifications.android.googleServicesFile")}};import{createHash as mb,randomUUID as dw}from"crypto";import{access as jw,copyFile as kb,mkdir as z,readFile as a,rename as uw,rm as bb,writeFile as L}from"fs/promises";import{isIP as cw}from"net";import{dirname as hb,isAbsolute as vw,join as X,relative as aw,resolve as r,sep as rw}from"path";import{access as Ww}from"fs/promises";import{homedir as Tb}from"os";import{join as m}from"path";import{existsSync as i$,readFileSync as Nw}from"fs";var P=1000;var Ub=60000;var i=2;var l=(b)=>{let w;if(b<P)w=`${b.toFixed(i)}ms`;else if(b<Ub)w=`${(b/P).toFixed(i)}s`;else{let $=Math.round(b/P),A=Math.floor($/60),S=$%60;w=S===0?`${A}m`:`${A}m ${S}s`}return w};var Kb=()=>{try{let b=Nw("/proc/version","utf-8");return/microsoft|wsl/i.test(b)}catch{return!1}};var Xb="AbsoluteJS_API_36",Uw=(b)=>{try{let w=Bun.spawnSync(b,{stderr:"ignore",stdout:"pipe"});return{exitCode:w.exitCode,stdout:w.stdout.toString()}}catch{return{exitCode:1,stdout:""}}},Kw=(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}},Tw=(b)=>{let w=/^([a-z]):[\\/](.*)$/i.exec(b.trim());if(!w)return b.trim().replaceAll("\\","/");return`/mnt/${w[1]?.toLowerCase()}/${w[2]?.replaceAll("\\","/")}`},Xw=()=>{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 Tw(w)}catch{return}},_w=(b,w=process.env)=>{if(b==="windows")return m(w.LOCALAPPDATA??m(Tb(),"AppData","Local"),"AbsoluteJS","Android","Sdk");if(b==="wsl"){let $=Xw();if($)return m($,"AbsoluteJS","Android","Sdk")}return m(Tb(),".absolutejs","android-sdk")},Bw=async(b)=>{try{return await Ww(b),!0}catch{return!1}},c=(b=process.platform,w=Kb())=>{if(b==="darwin")return"macos";if(b==="win32")return"windows";if(b==="linux"&&w)return"wsl";return"linux"},Fw=(b,w)=>{if(b==="wsl")return[`${w}.exe`,`${w}.bat`,w];if(b==="windows")return[w,`${w}.exe`,`${w}.bat`];return[w]},Q=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 Fw(A,b)){let D=$.which(O);if(D)return D}return},Z=(b,w,$,A,S)=>A?{id:b,label:w,path:A,platform:$,status:"pass"}:{id:b,label:w,platform:$,remediation:S,status:"fail"},_b=async(b={})=>{let w=b.env??process.env,$=b.host??c(),A=b.exists??Bw,S=b.which??((T)=>Bun.which(T)),M=b.capture??Uw,O=b.androidRoot===null?void 0:b.androidRoot??w.ANDROID_HOME??w.ANDROID_SDK_ROOT??_w($,w),D=$==="windows"||$==="wsl",C=(T)=>O?m(O,...T):void 0,J=(T)=>T.filter((K)=>Boolean(K)),_=await Q("adb",J([C(["platform-tools",D?"adb.exe":"adb"])]),{exists:A,which:S},$),W=await Q("emulator",J([C(["emulator",D?"emulator.exe":"emulator"])]),{exists:A,which:S},$),U=await Q("sdkmanager",J([C(["cmdline-tools","latest","bin",D?"sdkmanager.bat":"sdkmanager"])]),{exists:A,which:S},$),F=await Q("avdmanager",J([C(["cmdline-tools","latest","bin",D?"avdmanager.bat":"avdmanager"])]),{exists:A,which:S},$),x=await Q("java",[],{exists:A,which:S},$),N=[{id:"host",label:`Development host: ${$}`,platform:"host",status:"pass"},Z("android.adb","Android Debug Bridge","android",_,"Install Android SDK Platform Tools or expose adb on PATH."),Z("android.emulator","Android Emulator","android",W,"Install the Android Emulator from Android Studio SDK Manager."),Z("android.sdkmanager","Android SDK Manager","android",U,"Install Android SDK Command-line Tools (latest)."),Z("android.avdmanager","Android Virtual Device Manager","android",F,"Install Android SDK Command-line Tools (latest)."),Z("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(Xb);N.push({id:"android.avd",label:`AbsoluteJS Android emulator (${Xb})`,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 Q("xcrun",[],{exists:A,which:S},$),E=await Q("xcodebuild",[],{exists:A,which:S},$);if(N.push(Z("ios.xcrun","Xcode command runner","ios",B,"Install Xcode and select it with xcode-select."),Z("ios.xcodebuild","Xcode build system","ios",E,"Install Xcode and select it with xcode-select.")),B){let T=M([B,"simctl","list","runtimes","--json"]),K=T.exitCode===0&&Kw(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 Gw,readFile as Iw,rename as Hw,writeFile as Vw}from"fs/promises";import{relative as Yw,resolve as Bb}from"path";var Fb="capacitor.config.ts",p=(b,w)=>Yw(b,w).replaceAll("\\","/"),Ew=(b,w)=>`import type { CapacitorConfig } from '@capacitor/cli';
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';
3
3
 
4
4
  const config: CapacitorConfig = {
5
5
  appId: ${JSON.stringify(b.appId)},
@@ -14,16 +14,16 @@ const config: CapacitorConfig = {
14
14
  };
15
15
 
16
16
  export default config;
17
- `,Qw=async(b)=>{try{return await Gw(b),!0}catch{return!1}},Gb=async(b,w)=>{let $=Bb(w.projectRoot),A=Bb($,Fb),S=Ew(b,$);if(await Qw(A)){if(await Iw(A,"utf8")===S)return{changed:!1,path:A};if(!w.force)throw TypeError(`${Fb} already exists and differs; rerun with --force only after reviewing it.`)}let M=`${A}.${crypto.randomUUID()}.tmp`;return await Vw(M,S,{flag:"wx"}),await Hw(M,A),{changed:!0,path:A}};import{createHash as Zw}from"crypto";import{access as xA,copyFile as JA,mkdir as NA,mkdtemp as WA,readdir as Lw,readFile as kw,rename as UA,rm as KA,stat as TA,writeFile as XA}from"fs/promises";import{dirname as BA,isAbsolute as FA,join as qw,relative as Ib,resolve as GA,sep as IA}from"path";var zw=new Set(["Pods","DerivedData","build","xcuserdata"]),Hb=async(b,w=b,$={})=>{let A=await Lw(w,{withFileTypes:!0});return(await Promise.all(A.sort((M,O)=>M.name.localeCompare(O.name)).map(async(M)=>{let O=qw(w,M.name),D=Ib(b,O).replaceAll("\\","/");if(M.isDirectory()&&(zw.has(M.name)||D==="App/App/public"&&$.includePublicBundle!==!0))return[];if(M.isDirectory())return Hb(b,O,$);return M.isFile()?[O]:[]}))).flat()},Vb=async(b,w={})=>{let $=Zw("sha256"),A=await Hb(b,b,w),S=await Promise.all(A.map((M)=>kw(M)));return A.forEach((M,O)=>{$.update(Ib(b,M).replaceAll("\\","/")),$.update("\x00"),$.update(S[O]??new Uint8Array),$.update("\x00")}),$.digest("hex")};import{randomUUID as yw,X509Certificate as Rw}from"crypto";import{createServer as fw}from"http";import{connect as Pw,createServer as Yb,isIP as lw}from"net";import{readFile as mw}from"fs/promises";var t=(b)=>new Promise((w,$)=>{b.close((A)=>{if(A)$(A);else w()})}),Eb=(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)})}),hw=async()=>{let b=Yb(),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},Qb=(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},gw=(b,w,$)=>{let A=new URL(`${b}://localhost:${$}`),S=e(w);return A.hostname=lw(S)===6?`[${S}]`:S,A},Zb=async(b)=>{let $=new Rw(await mw(b.certificateAuthorityPath)).raw,S=`/${yw().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 hw();await Eb(M,O);let D=gw("http",b.displayHost,O);return D.pathname=S,{url:D.href,close:()=>t(M)}},Lb=async(b)=>{let w=Yb(($)=>{let A=Pw({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 Eb(w,b.listenPort),{close:()=>t(w)}};var o="AbsoluteJS iPhone",qb=180000,sw=1000,wb=1,$b=1,I=(b)=>typeof b==="object"&&b!==null&&!Array.isArray(b),Y=async(b)=>{try{return await jw(b),!0}catch{return!1}},q=(b)=>b?.throwIfAborted(),nw=(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:""}}},gb=async(b,w={})=>{return Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"inherit",stdin:"inherit",stdout:"inherit"}).exited},iw=(b,w={})=>{Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})},zb=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()}},pw=(b,w,$)=>{let A=Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return zb(A.stdout,$),zb(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}.`)},tw=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.")},yb=(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.`)},ew=(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}]:[]})},ow=(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}]})},b$=(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}]})})},Rb=(b)=>b.split(".").map((w)=>Number(w)),w$=(b,w)=>{let $=Rb(b),A=Rb(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},$$=(b)=>b.filter((w)=>w.isAvailable&&w.identifier.includes("SimRuntime.iOS-")).sort((w,$)=>w$($.version,w.version))[0],fb=(b)=>Number(/iPhone\s+(\d+)/u.exec(b)?.[1]??0),A$=(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],db=(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}},jb=(b)=>X(b,".absolutejs","mobile","ios-native-cache.json"),h=(b,w)=>{let $=aw(r(b),r(w));return $===""||!$.startsWith(`..${rw}`)&&$!==".."&&!vw($)},S$=(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}},v=async(b)=>{let w=db(b);if(!await Y(w.journal))return await bb(w.root,{force:!0,recursive:!0}),!1;let $=await a(w.journal,"utf8").then((A)=>S$(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 kb($.configBackupPath,$.nativeConfigPath);if(await Y($.infoBackupPath))await kb($.infoBackupPath,$.infoPath);return await bb(w.root,{force:!0,recursive:!0}),!0},M$=(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
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
18
18
  <key>NSAllowsArbitraryLoads</key>
19
19
  <true/>`);return b.replace(/<dict>/u,`<dict>
20
20
  <key>NSAppTransportSecurity</key>
21
21
  <dict>
22
22
  <key>NSAllowsArbitraryLoads</key>
23
23
  <true/>
24
- </dict>`)},O$=async(b,w,$,A="localhost")=>{let S=db(b.projectRoot);await v(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([a(M,"utf8"),a(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")}
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
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,M$(C,!$))])},C$=(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)]))}},D$=(b)=>a(jb(b),"utf8").then((w)=>C$(JSON.parse(w))).catch(()=>null),ub=async(b,w)=>{let $=jb(b),A=`${$}.${process.pid}.${dw()}.tmp`;await z(hb($),{recursive:!0});try{await L(A,`${JSON.stringify(w,null,"\t")}
27
- `,{flag:"wx"}),await uw(A,$)}finally{await bb(A,{force:!0}).catch(()=>{return})}},x$=async(b,w={})=>Vb(b.nativeDirectory,w),cb=(b,w)=>{let $=w([b,"simctl","list","devices","available","-j"]);return b$(g($,"iOS simulator discovery"))},J$=async(b,w)=>{let $=ow(g(w([b.xcrun,"simctl","list","runtimes","-j"]),"iOS runtime discovery")),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=ew(g(w([b.xcrun,"simctl","list","devicetypes","-j"]),"iOS device-type discovery")),O=A$(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}}},N$=async(b,w,$,A,S)=>{let M=Date.now()+qb,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 ${qb/1000}s.`);await A(sw),await O()};return O()},W$=(b,w,$)=>{if(w.state==="Booted")return;g($([b.xcrun,"simctl","boot",w.udid]),"iOS simulator boot")},Pb=(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},U$=(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."}`)},K$=(b,w,$)=>{let A=$([b.xcrun,"devicectl","device","info","apps","--device",w]);return A.exitCode===0&&A.stdout.includes(b.config.appId)},T$=async(b,w,$,A,S)=>{let M=X(b.projectRoot,".absolutejs","mobile","ios-derived-data",mb("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},X$=async(b,w,$,A)=>{let S=X(b.projectRoot,".absolutejs","mobile","ios-derived-data",mb("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},_$=async(b)=>{if(b.cache?.appId===b.project.config.appId&&b.cache.fingerprint===b.fingerprint&&b.cache.installations[b.identifier]===b.fingerprint&&K$(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 X$(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 ub(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},B$=async(b)=>{let w=Pb(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 T$(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=Pb(b.project,b.udid,b.capture);if(S)await ub(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},F$=/((?:authorization|cookie|password|secret|token|oauth[_-]?code)\s*[:=]\s*)([^\s,;]+)/giu,G$=new RegExp(String.raw`\bBearer\s+[A-Za-z0-9._~+/-]+=*`,"giu"),I$=/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu,H$=new RegExp(String.raw`\s(Debug|Info|Notice|Error|Fault)\s+.*?\[[^\]]+\]\s+\[([^\]]+)\]\s*(.*)$`,"iu"),V$=(b)=>{let w=Y$(b).trim();if(!w)return null;let $=H$.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"}},Y$=(b)=>b.replaceAll(G$,"Bearer [REDACTED]").replaceAll(I$,"[REDACTED_JWT]").replaceAll(F$,"$1[REDACTED]").replaceAll(/\p{C}/gu,""),lb=(b,w,$)=>{if(!$.nativeLog)return null;let A=$.startNativeLogs??pw,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=V$(M);if(O)$.nativeLog?.(O)})},E$=[["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"]],Q$=(b)=>E$.map(([w,$])=>{let A=b[w];return A===void 0?null:`${$} ${l(A)}`}).filter((w)=>w!==null).join(", "),vb=async(b,w)=>{if(c()!=="macos")throw Error("iOS development requires macOS and Xcode.");let $=w.target??"simulator",A=r(w.projectRoot),S=await _b({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 Gb(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??gb)([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}},Z$=async(b)=>{if(b.transition("connecting"),U$(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??Zb)({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}},L$=async(b)=>{b.transition("booting");let w=await J$(b.project,b.capture),{device:$}=w,A=w.created||$.state!=="Booted";return W$(b.project,$,b.capture),b.spawn(["open","-a","Simulator","--args","-CurrentDeviceUDID",$.udid]),b.transition("connecting"),await N$(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 tw(b.startOptions,$.udid,b.run,b.log),{caEnrollmentServer:null,startedSimulator:A,udid:$.udid}},Sb=async(b)=>{let{project:w}=b,$=b.deviceIdentifier?Qb(b.deviceIdentifier):void 0,A=$?"device":"simulator",S=$?e(b.serverHost??""):"localhost",M=b.capture??nw,O=b.run??gb,D=b.sleep??Bun.sleep,C=b.spawn??iw,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,E=async()=>{let K=N;N=null,await K?.close().catch(()=>{return})},T=async(K)=>{if($&&b.nativeLog){await E(),N=lb(w,K,b);return}await G(yb(w,K,$!==void 0),"iOS app relaunch",O,{signal:b.signal})};try{if(await v(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 O$(w,b.port,b.https===!0,S);q(b.signal);let K=performance.now(),R=x$(w,{includePublicBundle:b.embeddedBundle===!0}).then((f)=>{return U.fingerprinting=performance.now()-K,f}),d=$?await Z$({capture:M,deviceIdentifier:$,log:J,project:w,serverHost:S,startOptions:b,transition:x}):await L$({capture:M,log:J,project:w,run:O,sleep:D,spawn:C,startOptions:b,transition:x}),{caEnrollmentServer:tb,startedSimulator:eb,udid:k}=d;B=tb;let Db=await R;x("checking-native");let xb=await D$(w.projectRoot),s=$?await _$({cache:xb,capture:M,fingerprint:Db,identifier:$,log:J,project:w,run:O,signal:b.signal,transition:x}):await B$({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=lb(w,k,b),x("launching"),!$||!N)await G(yb(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)} (${s?"native cache hit":"native build installed"}).`:`iOS ${A} connected with HMR on port ${b.port} in ${l(U.total)} (${s?"native cache hit":"native build installed"}).`),J(`iOS startup: ${Q$(U)}.`);let j=!1,Jb=async()=>{if(j)return;j=!0,x("closing"),await E(),await B?.close().catch(()=>{return}),B=null,await v(w.projectRoot),x("closed")};return{close:Jb,nativeCacheHit:s,startedSimulator:eb,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(f){throw x("failed"),f}},screenshot:async(f)=>{if($)throw Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");let u=r(w.projectRoot,f);if(!h(w.projectRoot,u))throw Error("iOS screenshot destination must remain inside the project.");return await z(hb(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 E(),await B?.close().catch(()=>{return}),await v(w.projectRoot),K}};var ab="ABSOLUTE_REMOTE_MAC\t",Mb=1;var H=(b)=>process.stdout.write(`${ab}${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]},R$=(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},P$=(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 $},sb=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()}},nb=async(b,w={})=>{let $=Bun.spawn(b,{cwd:w.cwd,env:w.env,signal:w.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return sb($.stdout,(A)=>H({message:A,type:"log"})),sb($.stderr,(A)=>H({message:A,type:"log"})),$.exited},l$=(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:""}}},ib=(b)=>({nativeCacheHit:b.nativeCacheHit,startedSimulator:b.startedSimulator,targetKind:b.targetKind,timings:b.timings,type:"ready",udid:b.udid}),m$=async(b)=>{if(process.platform!=="darwin")throw Error("The AbsoluteJS remote iOS agent can run only on macOS.");let w=process.cwd(),$=Wb(P$(b),w),A=R$(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 k$(Ob(w,".absolutejs","mobile"),{recursive:!0}),await z$(C,Buffer.from(D,"base64url"));let J=await vb($,{createNativeProject:!1,projectRoot:w,run:nb,target:S?"device":"simulator"}),_=S?await Lb({listenPort:A,targetPort:O??0}):void 0,W={capture:l$,certificateAuthorityPath:C,deviceIdentifier:S,https:b.includes("--https"),port:A,project:J,run:nb,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 rb(C,{force:!0});throw x}H(ib(U));let F=y$({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=ib(U);else if(N.command==="screenshot"){let E=Ob(".absolutejs","mobile","remote-screenshot.png"),T=await U.screenshot(E);B={data:(await q$(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 rb(C,{force:!0})}},pb=async(b)=>{try{await m$(b)}catch(w){H({error:Cb(w),type:"fatal"}),process.exitCode=1}};await pb(process.argv.slice(2));
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));
@@ -641,9 +641,37 @@ var installAbsoluteMobileShellHttp = (origin, fetch2 = globalThis.fetch) => inst
641
641
  var MANIFEST_PATH = "./absolute-mobile-manifest.json";
642
642
  var STATUS_ID = "absolute-mobile-status";
643
643
  var initialNavigationPath = (entry) => {
644
+ const expoPath = new URLSearchParams(location.search).get("absolutePath");
645
+ if (expoPath?.startsWith("/") && !expoPath.startsWith("//"))
646
+ return expoPath;
644
647
  const current = `${location.pathname}${location.search}${location.hash}`;
645
648
  return current === "/" || current === "/index.html" ? entry : current;
646
649
  };
650
+ var currentNavigationPath = () => {
651
+ const expoPath = new URLSearchParams(location.search).get("absolutePath");
652
+ return expoPath?.startsWith("/") && !expoPath.startsWith("//") ? expoPath : `${location.pathname}${location.search}${location.hash}`;
653
+ };
654
+ var pushNavigationHistory = (path) => {
655
+ if (!Reflect.get(globalThis, "__absoluteExpoBridge")) {
656
+ history.pushState({ absoluteMobile: true }, "", path);
657
+ return;
658
+ }
659
+ const url = new URL(location.href);
660
+ url.search = "";
661
+ url.hash = "";
662
+ url.searchParams.set("absolutePath", path);
663
+ history.pushState({ absoluteMobile: true }, "", url.href);
664
+ const bridge = Reflect.get(globalThis, "__absoluteExpoBridge");
665
+ if (typeof bridge === "object" && bridge !== null && typeof Reflect.get(bridge, "setPath") === "function") {
666
+ Reflect.get(bridge, "setPath").call(bridge, path);
667
+ }
668
+ };
669
+ var notifyExpoNavigationPath = (path) => {
670
+ const bridge = Reflect.get(globalThis, "__absoluteExpoBridge");
671
+ if (typeof bridge === "object" && bridge !== null && typeof Reflect.get(bridge, "setPath") === "function") {
672
+ Reflect.get(bridge, "setPath").call(bridge, path);
673
+ }
674
+ };
647
675
  var navigationGeneration = 0;
648
676
  var notifyCapacitorSystemBarsDomReady = () => {
649
677
  const provider = Reflect.get(globalThis, "CapacitorSystemBarsAndroidInterface");
@@ -721,7 +749,7 @@ var navigate = async (manifest, path, pushHistory, fetchImpl) => {
721
749
  return;
722
750
  }
723
751
  if (pushHistory)
724
- history.pushState({ absoluteMobile: true }, "", path);
752
+ pushNavigationHistory(path);
725
753
  };
726
754
  var installAnchorNavigation = (manifest, onNavigate) => {
727
755
  const handleClick = (event) => {
@@ -778,7 +806,8 @@ var startAbsoluteMobileShell = async (options = {}) => {
778
806
  const auth = manifest.auth && options.createAuth ? await options.createAuth(manifest.auth, {
779
807
  beforeSignOut: options.beforeSignOut
780
808
  }) : undefined;
781
- installAbsoluteMobileShellHttp(manifest.productionOrigin, auth?.fetch ?? globalThis.fetch);
809
+ const applicationFetch = auth?.fetch ?? options.createFetch?.(manifest) ?? globalThis.fetch;
810
+ installAbsoluteMobileShellHttp(manifest.productionOrigin, applicationFetch);
782
811
  if (auth)
783
812
  options.connectPush?.(auth);
784
813
  if (auth && manifest.sync?.socketTickets)
@@ -787,7 +816,9 @@ var startAbsoluteMobileShell = async (options = {}) => {
787
816
  return;
788
817
  };
789
818
  const handlePopState = () => {
790
- navigateWithFailureState(manifest, `${location.pathname}${location.search}${location.hash}`, false, reinstallBrowserNavigation, auth?.fetch);
819
+ const path = currentNavigationPath();
820
+ notifyExpoNavigationPath(path);
821
+ navigateWithFailureState(manifest, path, false, reinstallBrowserNavigation, applicationFetch);
791
822
  };
792
823
  const reinstallBrowserNavigation = () => {
793
824
  removeAnchorNavigation();
@@ -796,9 +827,9 @@ var startAbsoluteMobileShell = async (options = {}) => {
796
827
  addEventListener("popstate", handlePopState);
797
828
  };
798
829
  const onNavigate = (path) => {
799
- navigateWithFailureState(manifest, path, true, reinstallBrowserNavigation, auth?.fetch);
830
+ navigateWithFailureState(manifest, path, true, reinstallBrowserNavigation, applicationFetch);
800
831
  };
801
- await navigateWithFailureState(manifest, initialNavigationPath(manifest.entry), false, reinstallBrowserNavigation, auth?.fetch);
832
+ await navigateWithFailureState(manifest, initialNavigationPath(manifest.entry), false, reinstallBrowserNavigation, applicationFetch);
802
833
  await installDeepLinks(manifest, onNavigate, auth?.redirectUri);
803
834
  };
804
835
  export {
@@ -0,0 +1,99 @@
1
+ // src/mobile/shellExpoDevices.ts
2
+ import { createWebDeviceAdapter } from "@absolutejs/devices/web";
3
+ import { installDeviceAdapter } from "@absolutejs/devices/runtime";
4
+ var bridge = () => {
5
+ const value = Reflect.get(globalThis, "__absoluteExpoBridge");
6
+ if (typeof value !== "object" || value === null || typeof Reflect.get(value, "request") !== "function") {
7
+ return;
8
+ }
9
+ return {
10
+ request: (method, params) => Promise.resolve(Reflect.apply(Reflect.get(value, "request"), value, [
11
+ method,
12
+ params
13
+ ]))
14
+ };
15
+ };
16
+ var parseFetchResult = (value) => {
17
+ if (!value || typeof value !== "object")
18
+ throw new TypeError("The Expo HTTP bridge returned an invalid response.");
19
+ const body = Reflect.get(value, "body");
20
+ const headers = Reflect.get(value, "headers");
21
+ const status = Reflect.get(value, "status");
22
+ if (typeof body !== "string" || typeof status !== "number" || !Number.isInteger(status) || !headers || typeof headers !== "object") {
23
+ throw new TypeError("The Expo HTTP bridge returned an invalid response.");
24
+ }
25
+ const entries = Object.entries(headers);
26
+ if (!entries.every(([, header]) => typeof header === "string")) {
27
+ throw new TypeError("The Expo HTTP bridge returned invalid headers.");
28
+ }
29
+ return {
30
+ body,
31
+ headers: Object.fromEntries(entries.map(([name, header]) => [name, String(header)])),
32
+ status
33
+ };
34
+ };
35
+ var requireBridge = () => {
36
+ const provider = bridge();
37
+ if (!provider)
38
+ throw new TypeError("The Expo WebView bridge is unavailable.");
39
+ return provider;
40
+ };
41
+ var createAbsoluteExpoBridgeFetch = () => async (input, init) => {
42
+ const request = new Request(input, init);
43
+ if (request.method !== "GET") {
44
+ throw new TypeError("The experimental Expo envelope bridge currently supports GET only.");
45
+ }
46
+ const headers = Object.fromEntries(request.headers);
47
+ const result = parseFetchResult(await requireBridge().request("http.fetch", {
48
+ headers,
49
+ method: request.method,
50
+ url: request.url
51
+ }));
52
+ return new Response(result.body, {
53
+ headers: result.headers,
54
+ status: result.status
55
+ });
56
+ };
57
+ var installAbsoluteExpoWebDeviceAdapter = () => {
58
+ const web = createWebDeviceAdapter();
59
+ return installDeviceAdapter({
60
+ ...web,
61
+ haptics: {
62
+ capability: async () => bridge() ? {
63
+ available: true,
64
+ fidelity: "native",
65
+ native: true
66
+ } : {
67
+ available: false,
68
+ message: "The Expo WebView bridge is unavailable.",
69
+ reason: "unavailable"
70
+ },
71
+ impact: async (style) => {
72
+ await requireBridge().request("devices.haptics.impact", {
73
+ style
74
+ });
75
+ },
76
+ notification: async (style) => {
77
+ await requireBridge().request("devices.haptics.impact", {
78
+ style
79
+ });
80
+ },
81
+ selectionChanged: async () => {
82
+ await requireBridge().request("devices.haptics.impact", {
83
+ style: "selection"
84
+ });
85
+ },
86
+ vibrate: async (durationMs) => {
87
+ await requireBridge().request("devices.haptics.impact", {
88
+ durationMs,
89
+ style: "vibrate"
90
+ });
91
+ }
92
+ },
93
+ runtime: "expo"
94
+ });
95
+ };
96
+ export {
97
+ installAbsoluteExpoWebDeviceAdapter,
98
+ createAbsoluteExpoBridgeFetch
99
+ };
@@ -7,8 +7,10 @@ export type NormalizedAbsoluteMobileConfig = {
7
7
  bundleDirectory: string;
8
8
  deepLinkHosts: string[];
9
9
  deepLinkScheme?: string;
10
- engine: 'capacitor';
10
+ engine: 'capacitor' | 'expo';
11
11
  entry: string;
12
+ expoNativeRoutes: Record<string, string>;
13
+ expoSdkVersion?: 57;
12
14
  iosVersion?: string;
13
15
  nativeProjectDirectory: string;
14
16
  platforms: MobilePlatform[];
@@ -0,0 +1,91 @@
1
+ export declare const ABSOLUTE_EXPO_BRIDGE_FORMAT: 1;
2
+ export declare const ABSOLUTE_EXPO_BRIDGE_MAX_BYTES: number;
3
+ export declare const ABSOLUTE_EXPO_BRIDGE_METHODS: readonly ["devices.haptics.impact", "http.fetch"];
4
+ export type AbsoluteExpoBridgeMethod = (typeof ABSOLUTE_EXPO_BRIDGE_METHODS)[number];
5
+ export type AbsoluteExpoBridgeRequest = {
6
+ format: typeof ABSOLUTE_EXPO_BRIDGE_FORMAT;
7
+ id: string;
8
+ kind: 'request';
9
+ method: AbsoluteExpoBridgeMethod;
10
+ params: Record<string, unknown>;
11
+ path: string;
12
+ };
13
+ export type AbsoluteExpoBridgeResponse = {
14
+ format: typeof ABSOLUTE_EXPO_BRIDGE_FORMAT;
15
+ id: string;
16
+ kind: 'response';
17
+ result?: unknown;
18
+ error?: {
19
+ code: string;
20
+ message: string;
21
+ };
22
+ };
23
+ export type AbsoluteExpoBridgeEvent = {
24
+ format: typeof ABSOLUTE_EXPO_BRIDGE_FORMAT;
25
+ kind: 'event';
26
+ event: 'ready' | 'navigation';
27
+ path: string;
28
+ payload?: Record<string, unknown>;
29
+ };
30
+ export type AbsoluteExpoBridgeMessage = AbsoluteExpoBridgeEvent | AbsoluteExpoBridgeRequest | AbsoluteExpoBridgeResponse;
31
+ export declare const createAbsoluteExpoBridgeError: (id: string, code: string, message: string) => {
32
+ error: {
33
+ code: string;
34
+ message: string;
35
+ };
36
+ format: 1;
37
+ id: string;
38
+ kind: "response";
39
+ result?: undefined;
40
+ } | {
41
+ format: 1;
42
+ id: string;
43
+ kind: "response";
44
+ result: unknown;
45
+ error?: undefined;
46
+ };
47
+ export declare const createAbsoluteExpoBridgeResponse: (id: string, result: unknown) => {
48
+ error: {
49
+ code: string;
50
+ message: string;
51
+ };
52
+ format: 1;
53
+ id: string;
54
+ kind: "response";
55
+ result?: undefined;
56
+ } | {
57
+ format: 1;
58
+ id: string;
59
+ kind: "response";
60
+ result: unknown;
61
+ error?: undefined;
62
+ };
63
+ export declare const parseAbsoluteExpoBridgeMessage: (source: string) => {
64
+ format: 1;
65
+ id: string;
66
+ kind: "request";
67
+ method: "devices.haptics.impact" | "http.fetch";
68
+ params: Record<string, unknown>;
69
+ path: string;
70
+ } | {
71
+ error: {
72
+ code: string;
73
+ message: string;
74
+ };
75
+ format: 1;
76
+ id: string;
77
+ kind: "response";
78
+ result?: undefined;
79
+ } | {
80
+ format: 1;
81
+ id: string;
82
+ kind: "response";
83
+ result: unknown;
84
+ error?: undefined;
85
+ } | {
86
+ payload?: Record<string, unknown> | undefined;
87
+ event: string;
88
+ format: 1;
89
+ kind: "event";
90
+ path: string;
91
+ };
@@ -0,0 +1,16 @@
1
+ import type { NormalizedAbsoluteMobileConfig } from './config';
2
+ export type WriteAbsoluteExpoProjectOptions = {
3
+ force?: boolean;
4
+ projectRoot: string;
5
+ };
6
+ export declare const writeAbsoluteExpoProject: (config: NormalizedAbsoluteMobileConfig, options: WriteAbsoluteExpoProjectOptions) => Promise<{
7
+ changed: number;
8
+ path: string;
9
+ written: string[];
10
+ }>;
11
+ export declare const syncAbsoluteExpoWebAssets: (config: NormalizedAbsoluteMobileConfig) => Promise<{
12
+ appBuild: string;
13
+ assets: number;
14
+ bundleId: string;
15
+ path: string;
16
+ }>;
@@ -16,6 +16,8 @@ export * from './capacitorBundle';
16
16
  export * from './syncSchema';
17
17
  export * from './syncRemediation';
18
18
  export * from './deviceCapabilities';
19
+ export * from './expoBridge';
20
+ export * from './expoProject';
19
21
  export * from './capacitorProject';
20
22
  export * from './config';
21
23
  export * from './client';
@@ -21,7 +21,7 @@ export type AbsoluteMobileProjectInspection = {
21
21
  bundleDirectory: string;
22
22
  deepLinkHosts: string[];
23
23
  deepLinkScheme?: string;
24
- engine: 'capacitor';
24
+ engine: 'capacitor' | 'expo';
25
25
  entry: string;
26
26
  iosVersion?: string;
27
27
  nativeProjectDirectory: string;
@@ -103,7 +103,7 @@ export declare const inspectAbsoluteMobileProject: (config: NormalizedAbsoluteMo
103
103
  bundleDirectory: string;
104
104
  deepLinkHosts: string[];
105
105
  deepLinkScheme: string | undefined;
106
- engine: "capacitor";
106
+ engine: "capacitor" | "expo";
107
107
  entry: string;
108
108
  iosVersion: string | undefined;
109
109
  nativeProjectDirectory: string;
@@ -14,7 +14,7 @@ export declare const ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT: 1;
14
14
  export type AbsoluteMobileComplianceReport = {
15
15
  app: {
16
16
  appId: string;
17
- engine: 'capacitor';
17
+ engine: 'capacitor' | 'expo';
18
18
  platforms: string[];
19
19
  productionOrigin: string;
20
20
  };
@@ -12,6 +12,7 @@ export type AbsoluteMobileShellPrincipal = {
12
12
  namespace: string;
13
13
  };
14
14
  export type AbsoluteMobileShellOptions = {
15
+ createFetch?: (manifest: AbsoluteMobileClientManifest) => AbsoluteMobileFetch;
15
16
  createAuth?: (config: NonNullable<AbsoluteMobileClientManifest['auth']>, options?: {
16
17
  beforeSignOut?: () => Promise<void> | void;
17
18
  }) => Promise<AbsoluteMobileShellAuthRuntime>;
@@ -0,0 +1,3 @@
1
+ /** Installs only capabilities implemented by the versioned Expo WebView bridge. */
2
+ export declare const createAbsoluteExpoBridgeFetch: () => (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
3
+ export declare const installAbsoluteExpoWebDeviceAdapter: () => () => void;
@@ -42,9 +42,7 @@ export type PwaConfig = {
42
42
  route?: string;
43
43
  };
44
44
  };
45
- export type MobileConfig = {
46
- /** Capacitor is the universal v1 engine. Expo remains a future React-only engine. */
47
- engine?: 'capacitor';
45
+ type MobileSharedConfig = {
48
46
  /** Native application identifier, for example `com.example.app`. */
49
47
  appId: string;
50
48
  /** Human-facing native application name. */
@@ -91,6 +89,26 @@ export type MobileConfig = {
91
89
  };
92
90
  };
93
91
  };
92
+ export type CapacitorMobileConfig = MobileSharedConfig & {
93
+ /** Capacitor is the default, universal all-framework mobile engine. */
94
+ engine?: 'capacitor';
95
+ };
96
+ export type ExpoMobileConfig = MobileSharedConfig & {
97
+ /** Experimental hybrid Expo Router shell. Capacitor remains the default. */
98
+ engine: 'expo';
99
+ /** Explicit route ownership for React Native replacement screens. */
100
+ routes?: {
101
+ /** Unclaimed routes remain ordinary AbsoluteJS web routes. */
102
+ default?: 'web';
103
+ /** Absolute route path to a React Native module, relative to the app root. */
104
+ native?: Readonly<Record<string, string>>;
105
+ };
106
+ expo?: {
107
+ /** Expo SDK line used by the generated shell. Currently only 57 is supported. */
108
+ sdkVersion?: 57;
109
+ };
110
+ };
111
+ export type MobileConfig = CapacitorMobileConfig | ExpoMobileConfig;
94
112
  export type BuildPassError = {
95
113
  /** Internal pass id, e.g. `global-css`, `non-react-client`. */
96
114
  pass: string;
package/package.json CHANGED
@@ -506,7 +506,7 @@
506
506
  ]
507
507
  }
508
508
  },
509
- "version": "0.20.0-beta.39",
509
+ "version": "0.20.0-beta.40",
510
510
  "workspaces": [
511
511
  "tests/fixtures/*",
512
512
  "tests/fixtures/_packages/*"