@absolutejs/absolute 0.20.0-beta.44 → 0.20.0-beta.45

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,8 +1,8 @@
1
1
  // @bun
2
- import{mkdir as Jo,readFile as Vo,rm as Te,writeFile as zo}from"fs/promises";import{join as ue}from"path";import{createInterface as _t}from"readline";import{resolve as Me}from"path";var Tt=/^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/,Pt=/^[a-z][a-z0-9+.-]*$/,Dt=/^[A-Z0-9]{10}$/,Ct=/^[0-9A-F]{64}$/,Rt=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/,te=(e,t,r)=>{let o=Me(e),n=Me(o,t);if(n!==o&&!n.startsWith(`${o}/`))throw TypeError(`${r} must remain inside the project root.`);return n},R=(e,t)=>{let r=e.trim();if(!r)throw TypeError(`${t} must not be empty.`);return r},Le=(e)=>{let t=R(e??"/","mobile.entry");if(!t.startsWith("/")||t.startsWith("//"))throw TypeError("mobile.entry must be an absolute application path.");return t},Nt=(e)=>{let t=new URL(R(e,"mobile.server.productionOrigin")),r=t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]");if(t.protocol!=="https:"&&!r)throw TypeError("mobile.server.productionOrigin must use HTTPS, except for a loopback development origin.");if(t.username||t.password||t.pathname!=="/"||t.search||t.hash)throw TypeError("mobile.server.productionOrigin must be an origin without credentials, path, query, or hash.");return t.origin},Mt=(e)=>{let t=[...new Set(e??["ios","android"])];if(t.length===0)throw TypeError("mobile.platforms must contain at least one platform.");return t},Lt=(e,t)=>{let r=(s)=>{let i=R(s,"mobile.deepLinks.hosts").toLowerCase();if(!Rt.test(i))throw TypeError("mobile.deepLinks.hosts entries must be valid hostnames without ports, wildcards, or paths.");return i},o=new URL(t).hostname,n=new Set(o==="[::1]"?[]:[r(o)]);for(let s of e??[])n.add(r(s));return[...n].sort()},Ut=(e)=>{if(e===void 0)return;let t=R(e,"mobile.deepLinks.apple.appIdPrefix").toUpperCase();if(!Dt.test(t))throw TypeError("mobile.deepLinks.apple.appIdPrefix must contain ten letters or digits.");return t},$t=(e)=>{if(e===void 0)return;let t=R(e,"mobile.ios.version");if(!/^\d+(?:\.\d+){0,2}$/u.test(t))throw TypeError("mobile.ios.version must contain one to three dot-separated integer components, for example 1.4.0.");return t},kt=(e)=>[...new Set((e??[]).map((t)=>R(t,"mobile.deepLinks.android.sha256CertificateFingerprints").replaceAll(":","").toUpperCase()).map((t)=>{if(!Ct.test(t))throw TypeError("mobile.deepLinks.android.sha256CertificateFingerprints entries must be SHA-256 certificate fingerprints.");return t.match(/.{2}/g)?.join(":")??t}))].sort(),jt=(e,t)=>{if(e.engine!=="expo")return{};let r=e.routes?.native??{},o={};for(let[n,s]of Object.entries(r)){let i=Le(n);if(i.includes("?")||i.includes("#")||i!=="/"&&i.endsWith("/"))throw TypeError(`mobile.routes.native route ${i} must be a canonical path without a query, fragment, or trailing slash.`);if(i==="/__absolute/native")throw TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");if(i.includes("*")||i.includes(":"))throw TypeError(`mobile.routes.native route ${i} must be static during the Expo experiment; parameters and wildcards are not supported yet.`);o[i]=te(t,R(s,`mobile.routes.native[${i}]`),`mobile.routes.native[${i}]`)}return Object.fromEntries(Object.entries(o).sort(([n],[s])=>n.localeCompare(s)))},Ue=(e,t)=>{let r=R(e.appId,"mobile.appId");if(!Tt.test(r))throw TypeError("mobile.appId must use reverse-domain notation, for example com.example.app.");let o=Nt(e.server.productionOrigin),n=(e.deepLinks?.scheme??r).trim().toLowerCase();if(n&&!Pt.test(n))throw TypeError("mobile.deepLinks.scheme is not a valid URL scheme.");return{androidCertificateFingerprints:kt(e.deepLinks?.android?.sha256CertificateFingerprints),appId:r,appleAppIdPrefix:Ut(e.deepLinks?.apple?.appIdPrefix),appName:R(e.appName,"mobile.appName"),bundleDirectory:te(t,e.bundleDirectory??".absolutejs/mobile/web","mobile.bundleDirectory"),deepLinkHosts:Lt(e.deepLinks?.hosts,o),deepLinkScheme:n,engine:e.engine??"capacitor",entry:Le(e.entry),expoNativeRoutes:jt(e,t),...e.engine==="expo"?{expoSdkVersion:e.expo?.sdkVersion??57}:{},iosVersion:$t(e.ios?.version),nativeProjectDirectory:te(t,e.nativeProject?.directory??(e.engine==="expo"?".absolutejs/mobile/expo":"mobile"),"mobile.nativeProject.directory"),platforms:Mt(e.platforms),productionOrigin:o,pushAndroidGoogleServicesFile:te(t,e.pushNotifications?.android?.googleServicesFile??"google-services.json","mobile.pushNotifications.android.googleServicesFile")}};import{spawn as Xt}from"child_process";import{access as qt}from"fs/promises";import{join as Kt}from"path";import{randomUUID as Bt,X509Certificate as Ht}from"crypto";import{createServer as Ft}from"http";import{connect as Wt,createServer as $e,isIP as Gt}from"net";import{readFile as Jt}from"fs/promises";var ge=(e)=>new Promise((t,r)=>{e.close((o)=>{if(o)r(o);else t()})}),ke=(e,t)=>new Promise((r,o)=>{e.once("error",o),e.listen(t,"0.0.0.0",()=>{e.off("error",o);let n=e.address();if(!n||typeof n==="string"){o(Error("Could not determine the iOS device helper port."));return}r(n.port)})}),Vt=async()=>{let e=$e(),t=await new Promise((r,o)=>{e.once("error",o),e.listen(0,"127.0.0.1",()=>{let n=e.address();if(!n||typeof n==="string"){o(Error("Could not allocate the iOS CA enrollment port."));return}r(n.port)})});return await ge(e),t},fe=(e)=>{let t=e.trim();if(!t||t.length>253||/[\0\s/?#]/u.test(t))throw TypeError("Physical iOS development requires a valid LAN host.");return t},je=(e)=>{let t=e.trim();if(!t||t.length>256||/[\0\r\n]/u.test(t))throw TypeError("--ios-device requires a valid Xcode device identifier or name.");return t},zt=(e,t,r)=>{let o=new URL(`${e}://localhost:${r}`),n=fe(t);return o.hostname=Gt(n)===6?`[${n}]`:n,o},re=async(e)=>{let r=new Ht(await Jt(e.certificateAuthorityPath)).raw,n=`/${Bt().replaceAll("-","")}/absolutejs-development-ca.cer`,s=Ft((a,c)=>{if(a.method!=="GET"||a.url!==n){c.writeHead(404,{"Cache-Control":"no-store","Content-Type":"text/plain; charset=utf-8"}),c.end("Not found.");return}c.writeHead(200,{"Cache-Control":"no-store","Content-Disposition":'attachment; filename="absolutejs-development-ca.cer"',"Content-Length":String(r.byteLength),"Content-Type":"application/x-x509-ca-cert","X-Content-Type-Options":"nosniff"}),c.end(r)}),i=await Vt();await ke(s,i);let l=zt("http",e.displayHost,i);return l.pathname=n,{url:l.href,close:()=>ge(s)}},oe=async(e)=>{let t=$e((r)=>{let o=Wt({host:"127.0.0.1",port:e.targetPort});r.pipe(o),o.pipe(r);let n=()=>{r.destroy(),o.destroy()};r.once("error",n),o.once("error",n)});return await ke(t,e.listenPort),{close:()=>ge(t)}};var Yt=60000,Zt=2000,Qt=(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}:{}}),Ae=async(e)=>{let t=Kt(e,"node_modules",".bin","expo");try{return await qt(t),t}catch{throw TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.")}},er=(e,t)=>{if(e.engine!=="expo")throw TypeError("The Expo development controller requires Expo.");if(t.platforms.length===0&&t.metro==="external")throw TypeError("External Expo execution requires a target platform.");if([t.androidOrigin,t.iosOrigin].some((l)=>l&&new URL(l).protocol==="https:")&&!t.certificateAuthorityPath)throw TypeError("Expo HTTPS development requires the AbsoluteJS development CA certificate.");let o=Qt(t),n={args:["start","--dev-client","--host","localhost","--port",String(t.metroPort)],env:o,role:"metro"},s=t.platforms.length===0?void 0:{args:["prebuild","--clean","--no-install","--platform",t.platforms.length===2?"all":t.platforms[0]??"all"],env:o,role:"native-prepare"},i=t.platforms.map((l)=>{let a=l==="android"?t.androidDevice:t.iosDevice;return{args:[`run:${l}`,"--no-bundler","--port",String(t.metroPort),...a?["--device",a]:[]],env:o,platform:l,role:"native-build"}});return{commands:[...s?[s]:[],...t.metro==="external"?[]:[n],...i],metroPort:t.metroPort,project:e.nativeProjectDirectory}},V=()=>new DOMException("Expo development aborted.","AbortError"),ne=(e,t)=>{let r=(o)=>{if(!o)return;let n="";o.on("data",(s)=>{n+=s.toString("utf8");let i=n.indexOf(`
3
- `);while(i>=0)t(n.slice(0,i).replace(/\r$/u,"")),n=n.slice(i+1),i=n.indexOf(`
4
- `)}),o.on("end",()=>{if(n)t(n)})};r(e.stdout),r(e.stderr)},F=async(e)=>{if(e.exitCode!==null||e.killed)return;if(e.kill("SIGTERM"),await Promise.race([new Promise((t)=>e.once("exit",()=>t())),new Promise((t)=>setTimeout(t,Zt))]),e.exitCode===null)e.kill("SIGKILL")},he=(e)=>new Promise((t)=>{if(e.exitCode!==null){t(e.exitCode);return}e.once("exit",(r)=>t(r??1))}),be=async(e,t,r,o)=>{let n=e(t,r,{cwd:o.cwd,env:process.env,stdio:["ignore","pipe","pipe"]});ne(n,o.log);let s=()=>void F(n);o.signal?.addEventListener("abort",s,{once:!0});let i=await he(n);if(o.signal?.removeEventListener("abort",s),o.signal?.aborted)throw V();return i},Be=async(e)=>{let t=er(e.config,e),r=e.executable??await Ae(t.project),o=e.spawnProcess??Xt,n=e.log??(()=>{return}),s={},i=null,l=async()=>{let d=i;i=null,await d?.close()},a=(d,w)=>{s[d]=(s[d]??0)+w,e.onPhaseTiming?.({durationMs:w,phase:d})},c=(d)=>{e.onStateChange?.(d)};if(e.signal?.aborted)throw V();let g=t.commands.find((d)=>d.role==="native-prepare"),m=t.commands.find((d)=>d.role==="metro"),b=t.commands.filter((d)=>d.role==="native-build"),x=async(d)=>{c("preparing-native");let w=performance.now(),y=o(r,d.args,{cwd:t.project,env:{...process.env,...d.env},stdio:["ignore","pipe","pipe"]});ne(y,(N)=>{if(N)n(`[prebuild] ${N}`)});let T=()=>void F(y);e.signal?.addEventListener("abort",T,{once:!0});let O=await he(y);if(e.signal?.removeEventListener("abort",T),e.signal?.aborted)throw V();if(O!==0)throw c("failed"),Error(`Expo native preparation exited with status ${O}.`);a("preparing-native",performance.now()-w)};if(g)await x(g);let u=m!==void 0;if(u)c("starting-metro");let p=performance.now(),f=m?o(r,m.args,{cwd:t.project,env:{...process.env,...m.env},stdio:["ignore","pipe","pipe"]}):void 0,_=!1,A,h=new Promise((d,w)=>{if(!f){d();return}let y=setTimeout(()=>{w(Error("Expo Metro did not become ready within 60 seconds."))},Yt);A=()=>{clearTimeout(y),d()},f.once("exit",(T)=>{if(!_)clearTimeout(y),w(Error(`Expo Metro exited with status ${T??1}.`))})});if(f)ne(f,(d)=>{if(d)n(`[metro] ${d}`);if(!_&&/(?:Waiting on|Metro waiting on|Dev server ready)/iu.test(d))_=!0,A?.()});let C=()=>{if(f)F(f)};e.signal?.addEventListener("abort",C,{once:!0});let H=async(d)=>{if(e.signal?.aborted)throw V();let{platform:w}=d;if(!w)throw TypeError("Expo native build command is missing a platform.");let y=w==="android"?"building-android":"building-ios";c(y);let T=performance.now(),O=o(r,d.args,{cwd:t.project,env:{...process.env,...d.env},stdio:["ignore","pipe","pipe"]});ne(O,(ee)=>{if(ee)n(`[${w}] ${ee}`)});let N=()=>void F(O);e.signal?.addEventListener("abort",N,{once:!0});let M=await he(O);if(e.signal?.removeEventListener("abort",N),e.signal?.aborted)throw V();if(M!==0)throw Error(`Expo ${w} development build exited with status ${M}.`);if(w==="ios"&&e.certificateAuthorityPath&&e.iosOrigin&&new URL(e.iosOrigin).protocol==="https:"&&!e.iosDevice){c("enrolling-trust");let ee=performance.now(),me={cwd:t.project,signal:e.signal,log:(Ne)=>Ne&&n(`[ios-trust] ${Ne}`)},Ce=await be(o,"xcrun",["simctl","keychain","booted","add-root-cert",e.certificateAuthorityPath],me);if(Ce!==0)throw Error(`Expo iOS Simulator development CA trust exited with status ${Ce}.`);await be(o,"xcrun",["simctl","terminate","booted",e.config.appId],me);let Re=await be(o,"xcrun",["simctl","launch","booted",e.config.appId],me);if(Re!==0)throw Error(`Expo iOS Simulator relaunch exited with status ${Re}.`);n("Installed the AbsoluteJS development CA into the Expo iOS Simulator and relaunched the app."),a("enrolling-trust",performance.now()-ee)}let U=performance.now()-T;s[y]=U,e.onPhaseTiming?.({durationMs:U,phase:y})},Q=async(d)=>{let[w,...y]=d;if(!w)return;await H(w),await Q(y)},pe=async()=>{if(!e.iosDevice||!e.certificateAuthorityPath||!e.iosOrigin||new URL(e.iosOrigin).protocol!=="https:")return;c("enrolling-trust");let d=performance.now();i=await(e.startCaEnrollmentServer??re)({certificateAuthorityPath:e.certificateAuthorityPath,displayHost:new URL(e.iosOrigin).hostname}),n(`On the iOS device, open ${i.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.`),a("enrolling-trust",performance.now()-d)};try{if(await pe(),await h,u)a("starting-metro",performance.now()-p);return await Q(b),c("ready"),{metroPort:t.metroPort,platforms:e.platforms,timings:s,close:async()=>{if(e.signal?.removeEventListener("abort",C),f)await F(f);await l(),c("closed")}}}catch(d){if(e.signal?.removeEventListener("abort",C),f)await F(f);throw await l(),c("failed"),d}};import{access as lr,cp as bn,mkdir as Je,mkdtemp as hn,readdir as ur,readFile as dr,rename as pr,rm as An,writeFile as Ve}from"fs/promises";import{createHash as mr}from"crypto";import{basename as vn,dirname as ze,join as v,relative as gr,resolve as fr}from"path";import{readFileSync as tr}from"fs";import{join as rr}from"path";var or="@absolutejs/auth",He="0.75.6",Fe="@absolutejs/auth-expo",We="0.0.2";var nr=["openid","profile"];var sr=(e)=>{try{return JSON.parse(tr(rr(e,"package.json"),"utf8"))}catch{return}},ir=(e,t)=>{if(typeof e!=="object"||e===null)return!1;return[Reflect.get(e,"dependencies"),Reflect.get(e,"devDependencies"),Reflect.get(e,"optionalDependencies"),Reflect.get(e,"peerDependencies")].some((r)=>typeof r==="object"&&r!==null&&Object.hasOwn(r,t))},ar=(e)=>{let t=e.deepLinkScheme??e.appId.toLowerCase();return{clientId:`absolutejs-native:${e.appId}`,issuer:e.productionOrigin,redirectUri:`${t}://auth/callback`,scopes:[...nr]}};var cr=(e)=>ir(sr(e),or);var Ge=(e,t)=>cr(e)?ar(t):void 0;var I=`// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
5
- `;var br=".absolutejs-expo-project",z=async(e)=>{try{return await lr(e),!0}catch{return!1}},Xe=(e,t)=>{let r=gr(e,t).replaceAll("\\","/");return r.startsWith(".")?r:`./${r}`},hr=(e)=>e.split("/").filter(Boolean).map((t)=>{if(t.startsWith(":"))return`[${t.slice(1)}]`;if(t==="."||t===".."||!/^[A-Za-z0-9._~-]+$/u.test(t))throw TypeError(`Expo native route ${e} contains an unsupported segment ${t}.`);return t}),Ar=(e,t)=>v(e,"app",...hr(t),"index.tsx"),wr=(e)=>({dependencies:{...e?{"@absolutejs/auth":He,[Fe]:We}:{},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",...e?{"expo-secure-store":"~57.0.2","expo-web-browser":"~57.0.2"}:{},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"}),Er=(e,t)=>({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"}],...t?["expo-secure-store"]:[]],runtimeVersion:{policy:"appVersion"},scheme:e.deepLinkScheme,slug:e.appId.toLowerCase().replaceAll(".","-"),version:e.iosVersion??"0.1.0"}}),vr=`${I}const config = require('./app.json');
2
+ import{mkdir as Co,readFile as Do,rm as Ue,writeFile as Ro}from"fs/promises";import{join as ve}from"path";import{createInterface as en}from"readline";import{resolve as We}from"path";var nn=/^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/,rn=/^[a-z][a-z0-9+.-]*$/,on=/^[A-Z0-9]{10}$/,sn=/^[0-9A-F]{64}$/,an=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/,de=(e,t,n)=>{let r=We(e),o=We(r,t);if(o!==r&&!o.startsWith(`${r}/`))throw TypeError(`${n} must remain inside the project root.`);return o},U=(e,t)=>{let n=e.trim();if(!n)throw TypeError(`${t} must not be empty.`);return n},qe=(e)=>{let t=U(e??"/","mobile.entry");if(!t.startsWith("/")||t.startsWith("//"))throw TypeError("mobile.entry must be an absolute application path.");return t},cn=(e)=>{let t=new URL(U(e,"mobile.server.productionOrigin")),n=t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]");if(t.protocol!=="https:"&&!n)throw TypeError("mobile.server.productionOrigin must use HTTPS, except for a loopback development origin.");if(t.username||t.password||t.pathname!=="/"||t.search||t.hash)throw TypeError("mobile.server.productionOrigin must be an origin without credentials, path, query, or hash.");return t.origin},ln=(e)=>{let t=[...new Set(e??["ios","android"])];if(t.length===0)throw TypeError("mobile.platforms must contain at least one platform.");return t},dn=(e,t)=>{let n=(s)=>{let i=U(s,"mobile.deepLinks.hosts").toLowerCase();if(!an.test(i))throw TypeError("mobile.deepLinks.hosts entries must be valid hostnames without ports, wildcards, or paths.");return i},r=new URL(t).hostname,o=new Set(r==="[::1]"?[]:[n(r)]);for(let s of e??[])o.add(n(s));return[...o].sort()},un=(e)=>{if(e===void 0)return;let t=U(e,"mobile.deepLinks.apple.appIdPrefix").toUpperCase();if(!on.test(t))throw TypeError("mobile.deepLinks.apple.appIdPrefix must contain ten letters or digits.");return t},pn=(e)=>{if(e===void 0)return;let t=U(e,"mobile.ios.version");if(!/^\d+(?:\.\d+){0,2}$/u.test(t))throw TypeError("mobile.ios.version must contain one to three dot-separated integer components, for example 1.4.0.");return t},mn=(e)=>[...new Set((e??[]).map((t)=>U(t,"mobile.deepLinks.android.sha256CertificateFingerprints").replaceAll(":","").toUpperCase()).map((t)=>{if(!sn.test(t))throw TypeError("mobile.deepLinks.android.sha256CertificateFingerprints entries must be SHA-256 certificate fingerprints.");return t.match(/.{2}/g)?.join(":")??t}))].sort(),fn=(e,t)=>{if(e.engine!=="expo")return{};let n=e.routes?.native??{},r={};for(let[o,s]of Object.entries(n)){let i=qe(o);if(i.includes("?")||i.includes("#")||i!=="/"&&i.endsWith("/"))throw TypeError(`mobile.routes.native route ${i} must be a canonical path without a query, fragment, or trailing slash.`);if(i==="/__absolute/native")throw TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");if(i.includes("*")||i.includes(":"))throw TypeError(`mobile.routes.native route ${i} must be static during the Expo experiment; parameters and wildcards are not supported yet.`);r[i]=de(t,U(s,`mobile.routes.native[${i}]`),`mobile.routes.native[${i}]`)}return Object.fromEntries(Object.entries(r).sort(([o],[s])=>o.localeCompare(s)))},Ge=(e,t)=>{let n=U(e.appId,"mobile.appId");if(!nn.test(n))throw TypeError("mobile.appId must use reverse-domain notation, for example com.example.app.");let r=cn(e.server.productionOrigin),o=(e.deepLinks?.scheme??n).trim().toLowerCase();if(o&&!rn.test(o))throw TypeError("mobile.deepLinks.scheme is not a valid URL scheme.");return{androidCertificateFingerprints:mn(e.deepLinks?.android?.sha256CertificateFingerprints),appId:n,appleAppIdPrefix:un(e.deepLinks?.apple?.appIdPrefix),appName:U(e.appName,"mobile.appName"),bundleDirectory:de(t,e.bundleDirectory??".absolutejs/mobile/web","mobile.bundleDirectory"),deepLinkHosts:dn(e.deepLinks?.hosts,r),deepLinkScheme:o,engine:e.engine??"capacitor",entry:qe(e.entry),expoNativeRoutes:fn(e,t),...e.engine==="expo"?{expoSdkVersion:e.expo?.sdkVersion??57}:{},iosVersion:pn(e.ios?.version),nativeProjectDirectory:de(t,e.nativeProject?.directory??(e.engine==="expo"?".absolutejs/mobile/expo":"mobile"),"mobile.nativeProject.directory"),platforms:ln(e.platforms),productionOrigin:r,pushAndroidGoogleServicesFile:de(t,e.pushNotifications?.android?.googleServicesFile??"google-services.json","mobile.pushNotifications.android.googleServicesFile")}};import{spawn as En}from"child_process";import{access as xn}from"fs/promises";import{join as In}from"path";import{randomUUID as gn,X509Certificate as hn}from"crypto";import{createServer as yn}from"http";import{connect as bn,createServer as ze,isIP as wn}from"net";import{readFile as vn}from"fs/promises";var Ee=(e)=>new Promise((t,n)=>{e.close((r)=>{if(r)n(r);else t()})}),Ke=(e,t)=>new Promise((n,r)=>{e.once("error",r),e.listen(t,"0.0.0.0",()=>{e.off("error",r);let o=e.address();if(!o||typeof o==="string"){r(Error("Could not determine the iOS device helper port."));return}n(o.port)})}),An=async()=>{let e=ze(),t=await new Promise((n,r)=>{e.once("error",r),e.listen(0,"127.0.0.1",()=>{let o=e.address();if(!o||typeof o==="string"){r(Error("Could not allocate the iOS CA enrollment port."));return}n(o.port)})});return await Ee(e),t},xe=(e)=>{let t=e.trim();if(!t||t.length>253||/[\0\s/?#]/u.test(t))throw TypeError("Physical iOS development requires a valid LAN host.");return t},Xe=(e)=>{let t=e.trim();if(!t||t.length>256||/[\0\r\n]/u.test(t))throw TypeError("--ios-device requires a valid Xcode device identifier or name.");return t},Sn=(e,t,n)=>{let r=new URL(`${e}://localhost:${n}`),o=xe(t);return r.hostname=wn(o)===6?`[${o}]`:o,r},ue=async(e)=>{let n=new hn(await vn(e.certificateAuthorityPath)).raw,o=`/${gn().replaceAll("-","")}/absolutejs-development-ca.cer`,s=yn((a,c)=>{if(a.method!=="GET"||a.url!==o){c.writeHead(404,{"Cache-Control":"no-store","Content-Type":"text/plain; charset=utf-8"}),c.end("Not found.");return}c.writeHead(200,{"Cache-Control":"no-store","Content-Disposition":'attachment; filename="absolutejs-development-ca.cer"',"Content-Length":String(n.byteLength),"Content-Type":"application/x-x509-ca-cert","X-Content-Type-Options":"nosniff"}),c.end(n)}),i=await An();await Ke(s,i);let l=Sn("http",e.displayHost,i);return l.pathname=o,{url:l.href,close:()=>Ee(s)}},pe=async(e)=>{let t=ze((n)=>{let r=bn({host:"127.0.0.1",port:e.targetPort});n.pipe(r),r.pipe(n);let o=()=>{n.destroy(),r.destroy()};n.once("error",o),r.once("error",o)});return await Ke(t,e.listenPort),{close:()=>Ee(t)}};var On=60000,_n=2000,Tn=(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}:{}}),_e=async(e)=>{let t=In(e,"node_modules",".bin","expo");try{return await xn(t),t}catch{throw TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.")}},Pn=(e,t)=>{if(e.engine!=="expo")throw TypeError("The Expo development controller requires Expo.");if(t.platforms.length===0&&t.metro==="external")throw TypeError("External Expo execution requires a target platform.");if([t.androidOrigin,t.iosOrigin].some((l)=>l&&new URL(l).protocol==="https:")&&!t.certificateAuthorityPath)throw TypeError("Expo HTTPS development requires the AbsoluteJS development CA certificate.");let r=Tn(t),o={args:["start","--dev-client","--host","localhost","--port",String(t.metroPort)],env:r,role:"metro"},s=t.platforms.length===0?void 0:{args:["prebuild","--clean","--no-install","--platform",t.platforms.length===2?"all":t.platforms[0]??"all"],env:r,role:"native-prepare"},i=t.platforms.map((l)=>{let a=l==="android"?t.androidDevice:t.iosDevice;return{args:[`run:${l}`,"--no-bundler","--port",String(t.metroPort),...a?["--device",a]:[]],env:r,platform:l,role:"native-build"}});return{commands:[...s?[s]:[],...t.metro==="external"?[]:[o],...i],metroPort:t.metroPort,project:e.nativeProjectDirectory}},ne=()=>new DOMException("Expo development aborted.","AbortError"),me=(e,t)=>{let n=(r)=>{if(!r)return;let o="";r.on("data",(s)=>{o+=s.toString("utf8");let i=o.indexOf(`
3
+ `);while(i>=0)t(o.slice(0,i).replace(/\r$/u,"")),o=o.slice(i+1),i=o.indexOf(`
4
+ `)}),r.on("end",()=>{if(o)t(o)})};n(e.stdout),n(e.stderr)},K=async(e)=>{if(e.exitCode!==null||e.killed)return;if(e.kill("SIGTERM"),await Promise.race([new Promise((t)=>e.once("exit",()=>t())),new Promise((t)=>setTimeout(t,_n))]),e.exitCode===null)e.kill("SIGKILL")},Oe=(e)=>new Promise((t)=>{if(e.exitCode!==null){t(e.exitCode);return}e.once("exit",(n)=>t(n??1))}),Ie=async(e,t,n,r)=>{let o=e(t,n,{cwd:r.cwd,env:process.env,stdio:["ignore","pipe","pipe"]});me(o,r.log);let s=()=>void K(o);r.signal?.addEventListener("abort",s,{once:!0});let i=await Oe(o);if(r.signal?.removeEventListener("abort",s),r.signal?.aborted)throw ne();return i},Ye=async(e)=>{let t=Pn(e.config,e),n=e.executable??await _e(t.project),r=e.spawnProcess??En,o=e.log??(()=>{return}),s={},i=null,l=async()=>{let m=i;i=null,await m?.close()},a=(m,A)=>{s[m]=(s[m]??0)+A,e.onPhaseTiming?.({durationMs:A,phase:m})},c=(m)=>{e.onStateChange?.(m)};if(e.signal?.aborted)throw ne();let h=t.commands.find((m)=>m.role==="native-prepare"),d=t.commands.find((m)=>m.role==="metro"),u=t.commands.filter((m)=>m.role==="native-build"),S=async(m)=>{c("preparing-native");let A=performance.now(),T=r(n,m.args,{cwd:t.project,env:{...process.env,...m.env},stdio:["ignore","pipe","pipe"]});me(T,(H)=>{if(H)o(`[prebuild] ${H}`)});let N=()=>void K(T);e.signal?.addEventListener("abort",N,{once:!0});let D=await Oe(T);if(e.signal?.removeEventListener("abort",N),e.signal?.aborted)throw ne();if(D!==0)throw c("failed"),Error(`Expo native preparation exited with status ${D}.`);a("preparing-native",performance.now()-A)};if(h)await S(h);let f=d!==void 0;if(f)c("starting-metro");let g=performance.now(),p=d?r(n,d.args,{cwd:t.project,env:{...process.env,...d.env},stdio:["ignore","pipe","pipe"]}):void 0,w=!1,y,b=new Promise((m,A)=>{if(!p){m();return}let T=setTimeout(()=>{A(Error("Expo Metro did not become ready within 60 seconds."))},On);y=()=>{clearTimeout(T),m()},p.once("exit",(N)=>{if(!w)clearTimeout(T),A(Error(`Expo Metro exited with status ${N??1}.`))})});if(p)me(p,(m)=>{if(m)o(`[metro] ${m}`);if(!w&&/(?:Waiting on|Metro waiting on|Dev server ready)/iu.test(m))w=!0,y?.()});let E=()=>{if(p)K(p)};e.signal?.addEventListener("abort",E,{once:!0});let _=async(m)=>{if(e.signal?.aborted)throw ne();let{platform:A}=m;if(!A)throw TypeError("Expo native build command is missing a platform.");let T=A==="android"?"building-android":"building-ios";c(T);let N=performance.now(),D=r(n,m.args,{cwd:t.project,env:{...process.env,...m.env},stdio:["ignore","pipe","pipe"]});me(D,(le)=>{if(le)o(`[${A}] ${le}`)});let H=()=>void K(D);e.signal?.addEventListener("abort",H,{once:!0});let V=await Oe(D);if(e.signal?.removeEventListener("abort",H),e.signal?.aborted)throw ne();if(V!==0)throw Error(`Expo ${A} development build exited with status ${V}.`);if(A==="ios"&&e.certificateAuthorityPath&&e.iosOrigin&&new URL(e.iosOrigin).protocol==="https:"&&!e.iosDevice){c("enrolling-trust");let le=performance.now(),Se={cwd:t.project,signal:e.signal,log:(Je)=>Je&&o(`[ios-trust] ${Je}`)},Ve=await Ie(r,"xcrun",["simctl","keychain","booted","add-root-cert",e.certificateAuthorityPath],Se);if(Ve!==0)throw Error(`Expo iOS Simulator development CA trust exited with status ${Ve}.`);await Ie(r,"xcrun",["simctl","terminate","booted",e.config.appId],Se);let Fe=await Ie(r,"xcrun",["simctl","launch","booted",e.config.appId],Se);if(Fe!==0)throw Error(`Expo iOS Simulator relaunch exited with status ${Fe}.`);o("Installed the AbsoluteJS development CA into the Expo iOS Simulator and relaunched the app."),a("enrolling-trust",performance.now()-le)}let J=performance.now()-N;s[T]=J,e.onPhaseTiming?.({durationMs:J,phase:T})},L=async(m)=>{let[A,...T]=m;if(!A)return;await _(A),await L(T)},j=async()=>{if(!e.iosDevice||!e.certificateAuthorityPath||!e.iosOrigin||new URL(e.iosOrigin).protocol!=="https:")return;c("enrolling-trust");let m=performance.now();i=await(e.startCaEnrollmentServer??ue)({certificateAuthorityPath:e.certificateAuthorityPath,displayHost:new URL(e.iosOrigin).hostname}),o(`On the iOS device, open ${i.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.`),a("enrolling-trust",performance.now()-m)};try{if(await j(),await b,f)a("starting-metro",performance.now()-g);return await L(u),c("ready"),{metroPort:t.metroPort,platforms:e.platforms,timings:s,close:async()=>{if(e.signal?.removeEventListener("abort",E),p)await K(p);await l(),c("closed")}}}catch(m){if(e.signal?.removeEventListener("abort",E),p)await K(p);throw await l(),c("failed"),m}};import{access as zn,cp as is,mkdir as bt,mkdtemp as as,readdir as Kn,readFile as Xn,rename as Yn,rm as cs,writeFile as wt}from"fs/promises";import{createHash as vt}from"crypto";import{basename as us,dirname as At,join as x,relative as Zn,resolve as Qn}from"path";import{readFileSync as Cn}from"fs";import{join as Dn}from"path";var Rn="@absolutejs/auth",Ze="0.75.6",Qe="@absolutejs/auth-expo",et="0.0.2",tt="2.31.0",nt="@absolutejs/sync-expo",rt="0.0.2";var Nn=["openid","profile"],Mn="@absolutejs/sync",ot=(e)=>{try{return JSON.parse(Cn(Dn(e,"package.json"),"utf8"))}catch{return}},st=(e,t)=>{if(typeof e!=="object"||e===null)return!1;return[Reflect.get(e,"dependencies"),Reflect.get(e,"devDependencies"),Reflect.get(e,"optionalDependencies"),Reflect.get(e,"peerDependencies")].some((n)=>typeof n==="object"&&n!==null&&Object.hasOwn(n,t))},kn=(e)=>{let t=e.deepLinkScheme??e.appId.toLowerCase();return{clientId:`absolutejs-native:${e.appId}`,issuer:e.productionOrigin,redirectUri:`${t}://auth/callback`,scopes:[...Nn]}};var Ln=(e)=>st(ot(e),Rn),it=(e)=>st(ot(e),Mn),at=(e,t)=>Ln(e)?kn(t):void 0;import{readFileSync as Hn}from"fs";import{dirname as Vn,join as gt,resolve as ht}from"path";var ct=Symbol.for("@absolutejs/sync/client-runtime-transport"),lt=globalThis,$n=(e)=>typeof e==="object"&&e!==null&&Array.isArray(Reflect.get(e,"installations"))&&Array.isArray(Reflect.get(e,"clients")),Qo=(()=>{let e=lt[ct];if($n(e))return e;if(typeof e==="object"&&e!==null&&Array.isArray(Reflect.get(e,"installations")))return Reflect.set(e,"clients",[]),e;let t={clients:[],installations:[]};return Object.defineProperty(lt,ct,{configurable:!1,enumerable:!1,value:t,writable:!1}),t})();class R extends Error{code;constructor(e,t){super(t);this.name="SyncLocalDataPolicyError",this.code=e}}class B extends Error{code;storedVersion;targetVersion;constructor(e,t,n={}){super(t);this.name="SyncLocalStoreSchemaError",this.code=e,this.storedVersion=n.storedVersion,this.targetVersion=n.targetVersion}}var fe=(e,t)=>{if(!Number.isSafeInteger(e)||e<1)throw new B("INVALID_PLAN",`${t} must be a positive safe integer`);return e},jn=(e)=>("components"in e),dt=(e,t)=>{if(e.length===0||e.trim()!==e||/^\*+$/.test(e)||e.includes("**"))throw new R("INVALID_POLICY",`${t}.match must be an exact name or a non-empty glob without adjacent wildcards.`)},Un=(e,t="localData")=>{if(e.maxBytesPerNamespace!==void 0&&(!Number.isSafeInteger(e.maxBytesPerNamespace)||e.maxBytesPerNamespace<1))throw new R("INVALID_POLICY",`${t}.maxBytesPerNamespace must be a positive safe integer.`);for(let[n,r]of(e.collections??[]).entries()){if(dt(r.match,`${t}.collections[${n}]`),r.maxAgeMs!==void 0&&(!Number.isSafeInteger(r.maxAgeMs)||r.maxAgeMs<1))throw new R("INVALID_POLICY",`${t}.collections[${n}].maxAgeMs must be a positive safe integer.`);if(r.persistence==="memory-only"&&r.protection==="required")throw new R("INVALID_POLICY",`${t}.collections[${n}] cannot require at-rest protection when it is memory-only.`);if(r.sensitivity!==void 0&&r.sensitivity!=="public"&&r.protection!=="required"&&r.persistence!=="memory-only")throw new R("INVALID_POLICY",`${t}.collections[${n}] declares ${r.sensitivity} data without required protection or memory-only persistence.`)}for(let[n,r]of(e.mutations??[]).entries()){if(dt(r.match,`${t}.mutations[${n}]`),r.conflict!==void 0&&r.conflict.strategy!=="client-wins"&&r.conflict.strategy!=="manual"&&r.conflict.strategy!=="server-wins")throw new R("INVALID_POLICY",`${t}.mutations[${n}].conflict.strategy is invalid.`);if(r.conflict?.maxAttempts!==void 0&&(!Number.isSafeInteger(r.conflict.maxAttempts)||r.conflict.maxAttempts<1))throw new R("INVALID_POLICY",`${t}.mutations[${n}].conflict.maxAttempts must be a positive safe integer.`);if(r.conflict?.maxAttempts!==void 0&&r.conflict.strategy!=="client-wins")throw new R("INVALID_POLICY",`${t}.mutations[${n}].conflict.maxAttempts is only valid for client-wins.`);if(r.persistence==="memory-only"&&r.protection==="required")throw new R("INVALID_POLICY",`${t}.mutations[${n}] cannot require at-rest protection when it is memory-only.`);if(r.sensitivity!==void 0&&r.sensitivity!=="public"&&r.protection!=="required"&&r.persistence!=="memory-only")throw new R("INVALID_POLICY",`${t}.mutations[${n}] declares ${r.sensitivity} arguments without required protection.`)}return e};var Bn=(e={version:1})=>{let t=jn(e)?[...e.components]:[{...e,id:"@absolutejs/app"}],n=new Set;for(let r of t){if(typeof r.id!=="string"||r.id.trim()!==r.id||r.id.length===0)throw new B("INVALID_PLAN","Sync schema component id must be non-empty and trimmed");if(n.has(r.id))throw new B("INVALID_PLAN",`Sync schema component "${r.id}" is declared more than once`);if(n.add(r.id),r.localData)Un(r.localData,`${r.id}.localData`)}return t.sort((r,o)=>r.id.localeCompare(o.id))};var pt=(e,t={version:1})=>{let n=Bn(t).map((s)=>{let i=ut(s.version,s);return{id:s.id,...ut(e[s.id]??i.minimumCompatibleVersion,s)}}),r=new Set(n.map((s)=>s.id)),o=Object.keys(e).filter((s)=>!r.has(s)).sort();return{components:n,orphanedComponents:o}};var ut=(e,t={version:1})=>{fe(e,"Stored Sync schema version");let n=fe(t.version,"Target Sync schema version"),r=[...t.migrations??[]].sort((a,c)=>a.toVersion-c.toVersion),o=new Set;for(let a of r){if(fe(a.toVersion,"Sync migration toVersion"),o.has(a.toVersion))throw new B("INVALID_PLAN",`Sync migration ${a.toVersion} is declared more than once`);o.add(a.toVersion)}let s=r[0]?r[0].toVersion-1:n,i=fe(t.minimumCompatibleVersion??s,"Minimum compatible Sync schema version");if(i>n)throw new B("INVALID_PLAN","Minimum compatible Sync schema version cannot exceed its target");if(e>n)throw new B("SCHEMA_TOO_NEW",`Stored Sync schema ${e} is newer than this runtime's schema ${n}`,{storedVersion:e,targetVersion:n});if(e<i)throw new B("SCHEMA_TOO_OLD",`Stored Sync schema ${e} is older than the minimum compatible schema ${i}`,{storedVersion:e,targetVersion:n});let l=[];for(let a=e+1;a<=n;a++){let c=r.find((h)=>h.toVersion===a);if(c===void 0)throw new B("MIGRATION_MISSING",`Sync migration ${a-1} -> ${a} is missing`,{storedVersion:e,targetVersion:n});l.push(c)}return{minimumCompatibleVersion:i,steps:l,targetVersion:n}};var Z=(e)=>typeof e==="object"&&e!==null&&!Array.isArray(e),Te=(e)=>{try{let t=JSON.parse(Hn(e,"utf8"));return Z(t)?t:void 0}catch{return}},mt=(e)=>{let t=Reflect.get(e,"absolutejs");if(!Z(t))return;let n=Reflect.get(t,"sync");if(!Z(n))return;return Reflect.get(n,"localSchema")},Fn=(e,t)=>{let n=ht(e);while(!0){let r=gt(n,"node_modules",t,"package.json"),o=Te(r);if(o&&Reflect.get(o,"name")===t)return r;let s=Vn(n);if(s===n)return;n=s}},v=(e,t)=>TypeError(`Invalid AbsoluteJS Sync schema metadata for ${e}: ${t}`),Y=(e,t,n)=>{if(typeof e!=="number"||!Number.isSafeInteger(e)||e<1)throw v(t,`${n} must be a positive safe integer.`);return e},X=(e,t,n)=>{if(typeof e!=="string"||e.trim()!==e||e.length===0)throw v(t,`${n} must be a non-empty trimmed string.`);return e},W=(e,t,n)=>{if(!Z(e))throw v(t,n);return e},P=(e,t)=>e[t],Pe=(e,t,n)=>{if(e===null||typeof e==="string"||typeof e==="boolean")return e;if(typeof e==="number"&&Number.isFinite(e))return e;if(Array.isArray(e))return e.map((r)=>Pe(r,t,n));if(Z(e))return Object.fromEntries(Object.entries(e).map(([r,o])=>[r,Pe(o,t,n)]));throw v(t,`${n} must be JSON-safe.`)},Jn=(e,t,n)=>{let r=W(e,t,`migration operation ${n} must be an object.`),o=Reflect.get(r,"type"),s=X(Reflect.get(r,"collection"),t,`operation ${n}.collection`);if(o==="delete-collection")return{collection:s,type:o};if(o==="rename-field")return{collection:s,from:X(Reflect.get(r,"from"),t,`operation ${n}.from`),to:X(Reflect.get(r,"to"),t,`operation ${n}.to`),type:o};let i=X(Reflect.get(r,"field"),t,`operation ${n}.field`);if(o==="remove-field")return{collection:s,field:i,type:o};if(o==="set-default")return{collection:s,field:i,type:o,value:Pe(Reflect.get(r,"value"),t,`operation ${n}.value`)};throw v(t,`operation ${n}.type is not supported.`)},Wn=(e,t,n)=>{let r=W(e,t,`migration ${n} must be an object.`),o=new Set(["operations","toVersion"]),s=Object.keys(r).find((a)=>!o.has(a));if(s)throw v(t,`migration ${n}.${s} is not declarative metadata.`);let i=Reflect.get(r,"operations");if(i!==void 0&&!Array.isArray(i))throw v(t,`migration ${n}.operations must be an array.`);return{operations:(Array.isArray(i)?i:[]).map((a,c)=>Jn(a,t,c)),toVersion:Y(Reflect.get(r,"toVersion"),t,`migration ${n}.toVersion`)}},qn=(e,t)=>{let n=W(e,t,"localData must be an object."),r=new Set(["collections","maxBytesPerNamespace","mutations"]),o=Object.keys(n).find((h)=>!r.has(h));if(o)throw v(t,`localData.${o} is not supported.`);let s=Reflect.get(n,"collections"),i=Reflect.get(n,"mutations");if(s!==void 0&&!Array.isArray(s))throw v(t,"localData.collections must be an array.");if(i!==void 0&&!Array.isArray(i))throw v(t,"localData.mutations must be an array.");let l=Array.isArray(s)?s.map((h,d)=>{let u=W(h,t,`localData.collections[${d}] must be an object.`),S=new Set(["evictionPriority","match","maxAgeMs","onProtectionUnavailable","persistence","protection","sensitivity"]),f=Object.keys(u).find((L)=>!S.has(L));if(f)throw v(t,`localData.collections[${d}].${f} is not supported.`);let g=X(Reflect.get(u,"match"),t,`localData.collections[${d}].match`),p=P(u,"persistence"),w=P(u,"sensitivity"),y=P(u,"protection"),b=P(u,"onProtectionUnavailable"),E=P(u,"evictionPriority"),_=P(u,"maxAgeMs");if(p!==void 0&&p!=="durable"&&p!=="memory-only")throw v(t,`localData.collections[${d}].persistence is invalid.`);if(w!==void 0&&w!=="public"&&w!=="private"&&w!=="secret")throw v(t,`localData.collections[${d}].sensitivity is invalid.`);if(y!==void 0&&y!=="none"&&y!=="required")throw v(t,`localData.collections[${d}].protection is invalid.`);if(b!==void 0&&b!=="error"&&b!=="memory-only")throw v(t,`localData.collections[${d}].onProtectionUnavailable is invalid.`);if(E!==void 0&&E!=="critical"&&E!=="normal"&&E!=="disposable")throw v(t,`localData.collections[${d}].evictionPriority is invalid.`);return{match:g,...w?{sensitivity:w}:{},...p?{persistence:p}:{},...y?{protection:y}:{},...b?{onProtectionUnavailable:b}:{},...E?{evictionPriority:E}:{},..._===void 0?{}:{maxAgeMs:Y(_,t,`localData.collections[${d}].maxAgeMs`)}}}):void 0,a=Array.isArray(i)?i.map((h,d)=>{let u=W(h,t,`localData.mutations[${d}] must be an object.`),S=new Set(["conflict","match","onProtectionUnavailable","persistence","protection","sensitivity"]),f=Object.keys(u).find((_)=>!S.has(_));if(f)throw v(t,`localData.mutations[${d}].${f} is not supported.`);let g=P(u,"protection"),p=P(u,"sensitivity"),w=P(u,"persistence"),y=P(u,"onProtectionUnavailable"),b=P(u,"conflict"),E;if(b!==void 0){let _=W(b,t,`localData.mutations[${d}].conflict must be an object.`),L=Object.keys(_).find((A)=>A!=="maxAttempts"&&A!=="strategy");if(L)throw v(t,`localData.mutations[${d}].conflict.${L} is not supported.`);let j=P(_,"strategy");if(j!=="client-wins"&&j!=="manual"&&j!=="server-wins")throw v(t,`localData.mutations[${d}].conflict.strategy is invalid.`);let m=P(_,"maxAttempts");if(m!==void 0&&j!=="client-wins")throw v(t,`localData.mutations[${d}].conflict.maxAttempts requires client-wins.`);E={strategy:j,...m===void 0?{}:{maxAttempts:Y(m,t,`localData.mutations[${d}].conflict.maxAttempts`)}}}if(g!==void 0&&g!=="none"&&g!=="required")throw v(t,`localData.mutations[${d}].protection is invalid.`);if(p!==void 0&&p!=="public"&&p!=="private"&&p!=="secret")throw v(t,`localData.mutations[${d}].sensitivity is invalid.`);if(y!==void 0&&y!=="error"&&y!=="memory-only")throw v(t,`localData.mutations[${d}].onProtectionUnavailable is invalid.`);if(w!==void 0&&w!=="durable"&&w!=="memory-only")throw v(t,`localData.mutations[${d}].persistence is invalid.`);return{match:X(Reflect.get(u,"match"),t,`localData.mutations[${d}].match`),...E?{conflict:E}:{},...p?{sensitivity:p}:{},...y?{onProtectionUnavailable:y}:{},...w?{persistence:w}:{},...g?{protection:g}:{}}}):void 0,c=Reflect.get(n,"maxBytesPerNamespace");return{...l?{collections:l}:{},...a?{mutations:a}:{},...c===void 0?{}:{maxBytesPerNamespace:Y(c,t,"localData.maxBytesPerNamespace")}}},ft=(e,t)=>{let n=W(t,e,"localSchema must be an object."),r=new Set(["localData","migrations","minimumCompatibleVersion","version"]),o=Object.keys(n).find((d)=>!r.has(d));if(o)throw v(e,`${o} is not supported.`);let s=Y(Reflect.get(n,"version"),e,"version"),i=Reflect.get(n,"minimumCompatibleVersion"),l=i===void 0?Math.max(1,s-2):Y(i,e,"minimumCompatibleVersion"),a=Reflect.get(n,"migrations"),c=Reflect.get(n,"localData");if(a!==void 0&&!Array.isArray(a))throw v(e,"migrations must be an array.");let h=Array.isArray(a)?a:void 0;return{id:e,...c===void 0?{}:{localData:qn(c,e)},minimumCompatibleVersion:l,...Array.isArray(h)?{migrations:h.map((d,u)=>Wn(d,e,u))}:{},version:s}},Gn=(e)=>[Reflect.get(e,"dependencies"),Reflect.get(e,"optionalDependencies"),Reflect.get(e,"devDependencies"),Reflect.get(e,"peerDependencies")].flatMap((t)=>Z(t)?Object.keys(t):[]).filter((t,n,r)=>r.indexOf(t)===n).sort(),yt=(e)=>{let t=gt(ht(e),"package.json"),n=Te(t);if(!n)return{components:[{id:"@absolutejs/app",minimumCompatibleVersion:1,version:1}],sources:[]};let r=mt(n),o=[r===void 0?{id:"@absolutejs/app",minimumCompatibleVersion:1,version:1}:ft("@absolutejs/app",r)],s=[{id:"@absolutejs/app",manifestPath:t}];for(let i of Gn(n)){let l=Fn(e,i);if(!l)continue;let a=Te(l);if(!a)continue;let c=mt(a);if(c===void 0)continue;o.push(ft(i,c)),s.push({id:i,manifestPath:l})}return o.sort((i,l)=>i.id.localeCompare(l.id)),s.sort((i,l)=>i.id.localeCompare(l.id)),pt({},{components:o}),{components:o,sources:s}};var C=`// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
5
+ `;var er=".absolutejs-expo-project",re=async(e)=>{try{return await zn(e),!0}catch{return!1}},St=(e,t)=>{let n=Zn(e,t).replaceAll("\\","/");return n.startsWith(".")?n:`./${n}`},tr=(e)=>e.split("/").filter(Boolean).map((t)=>{if(t.startsWith(":"))return`[${t.slice(1)}]`;if(t==="."||t===".."||!/^[A-Za-z0-9._~-]+$/u.test(t))throw TypeError(`Expo native route ${e} contains an unsupported segment ${t}.`);return t}),nr=(e,t)=>x(e,"app",...tr(t),"index.tsx"),rr=(e,t)=>({dependencies:{...e?{"@absolutejs/auth":Ze,[Qe]:et}:{},...t?{"@absolutejs/sync":tt,[nt]:rt}:{},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",...t?{"expo-background-task":"~57.0.14","expo-network":"~57.0.1","expo-sqlite":"~57.0.2","expo-task-manager":"~57.0.14","expo-updates":"~57.0.19"}:{},"expo-router":"~57.0.17",...e?{"expo-secure-store":"~57.0.2","expo-web-browser":"~57.0.2"}:{},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"}),or=(e,t,n)=>({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"}],...t?["expo-secure-store"]:[],...n?["expo-sqlite","expo-background-task","expo-task-manager"]:[]],runtimeVersion:{policy:"appVersion"},scheme:e.deepLinkScheme,slug:e.appId.toLowerCase().replaceAll(".","-"),version:e.iosVersion??"0.1.0"}}),sr=`${C}const config = require('./app.json');
6
6
 
7
7
  if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
8
8
  config.expo.plugins = [
@@ -12,7 +12,7 @@ if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_D
12
12
  }
13
13
 
14
14
  module.exports = config;
15
- `,Sr=`${I}const { AndroidConfig, withAndroidManifest, withDangerousMod } = require('expo/config-plugins');
15
+ `,ir=`${C}const { AndroidConfig, withAndroidManifest, withDangerousMod } = require('expo/config-plugins');
16
16
  const { copyFile, mkdir } = require('node:fs/promises');
17
17
  const path = require('node:path');
18
18
 
@@ -51,7 +51,7 @@ const withAbsoluteDevelopmentCa = config => {
51
51
  };
52
52
 
53
53
  module.exports = withAbsoluteDevelopmentCa;
54
- `,yr=(e)=>`${I}const { getDefaultConfig } = require('expo/metro-config');
54
+ `,ar=(e)=>`${C}const { getDefaultConfig } = require('expo/metro-config');
55
55
  const path = require('node:path');
56
56
 
57
57
  const projectRoot = __dirname;
@@ -65,17 +65,22 @@ config.resolver.nodeModulesPaths = [
65
65
  config.watchFolders = [appRoot];
66
66
 
67
67
  module.exports = config;
68
- `,xr=(e)=>`${I}import { Stack } from 'expo-router';
69
- ${e?`import { useEffect } from 'react';
68
+ `,cr=(e,t)=>`${C}import { Stack } from 'expo-router';
69
+ ${e?`import { useEffect, useState } from 'react';
70
70
  import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';`:""}
71
+ ${t?"import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';":""}
71
72
 
72
73
  export default function AbsoluteLayout() {
73
- ${e?`useEffect(() => {
74
- void startAbsoluteExpoAuth();
75
- }, []);`:""}
74
+ ${e?`const [ready, setReady] = useState(false);
75
+ useEffect(() => {
76
+ let active = true;
77
+ void ${t?"startAbsoluteExpoSync":"startAbsoluteExpoAuth"}().then(() => { if (active) setReady(true); });
78
+ return () => { active = false; };
79
+ }, []);
80
+ if (!ready) return null;`:""}
76
81
  return <Stack screenOptions={{ headerShown: false }} />;
77
82
  }
78
- `,Ir=`${I}import * as Haptics from 'expo-haptics';
83
+ `,lr=`${C}import * as Haptics from 'expo-haptics';
79
84
  import { Link } from 'expo-router';
80
85
  import { Pressable, SafeAreaView, StyleSheet, Text, View } from 'react-native';
81
86
 
@@ -105,7 +110,7 @@ const styles = StyleSheet.create({
105
110
  page: { alignItems: 'center', backgroundColor: '#020617', flex: 1, justifyContent: 'center', padding: 20 },
106
111
  title: { color: '#f8fafc', fontSize: 32, fontWeight: '800' }
107
112
  });
108
- `,_r=(e,t)=>{let r=mr("sha256").update(t).digest("hex").slice(0,24);return`${I}import { createAbsoluteExpoAuthClient } from '@absolutejs/auth-expo';
113
+ `,dr=(e,t)=>{let n=vt("sha256").update(t).digest("hex").slice(0,24);return`${C}import { createAbsoluteExpoAuthClient } from '@absolutejs/auth-expo';
109
114
  import { createMobileAuthTransport, installAuthClientRuntimeTransport } from '@absolutejs/auth/client/mobile';
110
115
 
111
116
  export const absoluteExpoAuth = createAbsoluteExpoAuthClient({
@@ -115,7 +120,7 @@ export const absoluteExpoAuth = createAbsoluteExpoAuthClient({
115
120
  redirectUri: ${JSON.stringify(e.redirectUri)},
116
121
  resource: ${JSON.stringify(e.issuer)},
117
122
  scopes: ${JSON.stringify(e.scopes)},
118
- storagePrefix: ${JSON.stringify(`absolutejs.auth.${r}`)}
123
+ storagePrefix: ${JSON.stringify(`absolutejs.auth.${n}`)}
119
124
  });
120
125
  installAuthClientRuntimeTransport(createMobileAuthTransport(absoluteExpoAuth, { baseUrl: ${JSON.stringify(e.issuer)} }));
121
126
 
@@ -128,12 +133,104 @@ export const getAbsoluteExpoAuthPrincipal = () => currentPrincipal;
128
133
  let startPromise: Promise<void> | undefined;
129
134
  export const startAbsoluteExpoAuth = () => {
130
135
  startPromise ??= absoluteExpoAuth.start().then(async () => {
131
- await absoluteExpoAuth.principal();
136
+ currentPrincipal = await absoluteExpoAuth.principal();
132
137
  });
133
138
 
134
139
  return startPromise;
135
140
  };
136
- `},Or=(e,t)=>{let r=["/__absolute/native",...Object.keys(e.expoNativeRoutes)];return`${I}import * as Haptics from 'expo-haptics';
141
+ `},ur=(e,t)=>{let n=vt("sha256").update(e.appId).digest("hex").slice(0,24),r=new URL("/__absolute/sync/background",e.productionOrigin).href,o=`${e.appId}.absolutejs.sync`;return`${C}import { runHeadlessSync } from '@absolutejs/sync/client/headless';
142
+ import type { SyncLocalStoreSchemaBundle } from '@absolutejs/sync/client';
143
+ import { installSyncClientRuntimeTransport } from '@absolutejs/sync/client/runtime';
144
+ import {
145
+ createExpoSyncBridgeHost,
146
+ createExpoSyncLocalStore,
147
+ createExpoSyncProtection,
148
+ createExpoSyncSocketBridgeHost,
149
+ defineExpoSyncBackgroundTask,
150
+ installExpoSyncLifecycle,
151
+ registerExpoSyncBackgroundTask
152
+ } from '@absolutejs/sync-expo';
153
+ import * as Updates from 'expo-updates';
154
+ import { absoluteExpoAuth, startAbsoluteExpoAuth } from './AbsoluteAuth';
155
+
156
+ const BACKGROUND_TASK = ${JSON.stringify(o)};
157
+ const BACKGROUND_ENDPOINT = ${JSON.stringify(r)};
158
+ const PRODUCTION_ORIGIN = ${JSON.stringify(e.productionOrigin)};
159
+ const STORAGE_SCHEMA: SyncLocalStoreSchemaBundle = ${JSON.stringify(t)};
160
+ const store = createExpoSyncLocalStore({
161
+ databaseName: ${JSON.stringify(`absolutejs-sync-${n}.db`)},
162
+ protection: createExpoSyncProtection({ storagePrefix: ${JSON.stringify(`absolutejs.sync.${n}`)} }),
163
+ storageSchema: STORAGE_SCHEMA
164
+ });
165
+
166
+ const runBackgroundSync = async () => {
167
+ await startAbsoluteExpoAuth();
168
+ const principal = await absoluteExpoAuth.principal();
169
+ if (!principal) return;
170
+ await runHeadlessSync({
171
+ endpoint: BACKGROUND_ENDPOINT,
172
+ fetch: (url, init) => absoluteExpoAuth.fetch(url, init),
173
+ namespace: principal.namespace,
174
+ store
175
+ });
176
+ };
177
+ defineExpoSyncBackgroundTask(BACKGROUND_TASK, runBackgroundSync);
178
+
179
+ let activeNamespace: string | undefined;
180
+ let started = false;
181
+ let startPromise: Promise<void> | undefined;
182
+ export const startAbsoluteExpoSync = () => {
183
+ startPromise ??= (async () => {
184
+ await startAbsoluteExpoAuth();
185
+ const principal = await absoluteExpoAuth.principal();
186
+ activeNamespace = principal?.namespace;
187
+ installSyncClientRuntimeTransport({
188
+ ...(principal ? { durable: { namespace: principal.namespace, store }, socketTicket: () => absoluteExpoAuth.socketTicket() } : {}),
189
+ registerClient: client => installExpoSyncLifecycle({ client })
190
+ });
191
+ await registerExpoSyncBackgroundTask(BACKGROUND_TASK, { minimumInterval: 15 });
192
+ started = true;
193
+ })();
194
+
195
+ return startPromise;
196
+ };
197
+
198
+ absoluteExpoAuth.onPrincipalChange(principal => {
199
+ if (!started || principal?.namespace === activeNamespace) return;
200
+ void Updates.reloadAsync();
201
+ });
202
+
203
+ export const createAbsoluteExpoSyncBridge = async (
204
+ emit: (event: 'sync.socket' | 'sync.wake', payload: Record<string, unknown>) => void
205
+ ) => {
206
+ await startAbsoluteExpoSync();
207
+ const principal = await absoluteExpoAuth.principal();
208
+ if (!principal) return {
209
+ close: () => undefined,
210
+ request: async () => { throw new Error('Expo Sync requires an authenticated principal.'); }
211
+ };
212
+ const transactions = createExpoSyncBridgeHost({ namespace: principal.namespace, store });
213
+ const sockets = createExpoSyncSocketBridgeHost({
214
+ allowedOrigin: PRODUCTION_ORIGIN,
215
+ emit: payload => emit('sync.socket', payload),
216
+ socketTicket: audience => absoluteExpoAuth.socketTicket(audience)
217
+ });
218
+ const removeLifecycle = installExpoSyncLifecycle({
219
+ client: { reconnect: () => emit('sync.wake', {}) }
220
+ });
221
+
222
+ return {
223
+ close: async () => {
224
+ removeLifecycle();
225
+ await Promise.all([transactions.close(), sockets.close()]);
226
+ },
227
+ request: (method: string, params: Record<string, unknown>) =>
228
+ method.startsWith('sync.socket.')
229
+ ? sockets.request(method, params)
230
+ : transactions.request(method, params)
231
+ };
232
+ };
233
+ `},pr=(e,t,n)=>{let r=["/__absolute/native",...Object.keys(e.expoNativeRoutes)];return`${C}import * as Haptics from 'expo-haptics';
137
234
  import * as Linking from 'expo-linking';
138
235
  import { router, usePathname } from 'expo-router';
139
236
  import { useEffect, useRef, useState } from 'react';
@@ -141,8 +238,9 @@ import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'reac
141
238
  import { WebView, type WebViewMessageEvent } from 'react-native-webview';
142
239
  import { materializeAbsoluteWebBundle } from './webAssets';
143
240
  ${t?"import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';":""}
241
+ ${n?"import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from './AbsoluteSync';":""}
144
242
 
145
- const BRIDGE_FORMAT = 2;
243
+ const BRIDGE_FORMAT = 3;
146
244
  const MAX_MESSAGE_BYTES = 64 * 1024;
147
245
  const MAX_HTTP_BODY_BYTES = 48 * 1024;
148
246
  const NATIVE_ROUTES = new Set(${JSON.stringify(r)});
@@ -152,6 +250,7 @@ const DEV_ORIGIN = Platform.OS === 'android'
152
250
  : process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
153
251
  const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
154
252
  const AUTH_ENABLED = ${t?"true":"false"};
253
+ const SYNC_ENABLED = ${n?"true":"false"};
155
254
 
156
255
  const bridgeBootstrap = (path: string) => {
157
256
  const initialPath = DEV_ORIGIN
@@ -191,7 +290,7 @@ const bridgeBootstrap = (path: string) => {
191
290
  },
192
291
  request(method, params) {
193
292
  const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
194
- send({ format: 2, id, kind: 'request', method, params, path: currentPath });
293
+ send({ format: 3, id, kind: 'request', method, params, path: currentPath });
195
294
  return new Promise((resolve, reject) => {
196
295
  const timer = setTimeout(() => {
197
296
  pending.delete(id);
@@ -202,7 +301,7 @@ const bridgeBootstrap = (path: string) => {
202
301
  },
203
302
  setPath(path) {
204
303
  currentPath = path;
205
- send({ format: 2, kind: 'event', event: 'navigation', path });
304
+ send({ format: 3, kind: 'event', event: 'navigation', path });
206
305
  }
207
306
  };
208
307
  if (\${DEV_ORIGIN ? 'true' : 'false'}) {
@@ -210,7 +309,7 @@ const bridgeBootstrap = (path: string) => {
210
309
  const path = location.pathname + location.search + location.hash;
211
310
  if (path === currentPath) return;
212
311
  currentPath = path;
213
- send({ format: 2, kind: 'event', event: 'navigation', path });
312
+ send({ format: 3, kind: 'event', event: 'navigation', path });
214
313
  };
215
314
  for (const method of ['pushState', 'replaceState']) {
216
315
  const original = history[method];
@@ -229,9 +328,9 @@ const bridgeBootstrap = (path: string) => {
229
328
  const url = new URL(anchor.href, location.href);
230
329
  if (!${JSON.stringify(r)}.includes(url.pathname)) return;
231
330
  event.preventDefault();
232
- send({ format: 2, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
331
+ send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
233
332
  }, true);
234
- send({ format: 2, kind: 'event', event: 'ready', path: currentPath });
333
+ send({ format: 3, kind: 'event', event: 'ready', path: currentPath });
235
334
  })(); true;\`;
236
335
  };
237
336
 
@@ -277,21 +376,31 @@ const authStatus = async () => {
277
376
  export function AbsoluteWebHost() {
278
377
  const pathname = usePathname() || '/';
279
378
  const webView = useRef<WebView>(null);
379
+ const syncBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
280
380
  const [indexUri, setIndexUri] = useState<string>();
281
381
  const [canGoBack, setCanGoBack] = useState(false);
282
- const [authReady, setAuthReady] = useState(!AUTH_ENABLED);
382
+ const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
283
383
  const activeWebPath = useRef(pathname);
284
384
 
285
385
  useEffect(() => {
286
- if (!AUTH_ENABLED) return;
386
+ if (!AUTH_ENABLED && !SYNC_ENABLED) return;
287
387
  let active = true;
288
388
  ${t?`const stop = absoluteExpoAuth.onPrincipalChange(principal => {
289
389
  if (!active) return;
290
390
  const source = JSON.stringify({ event: 'auth.principal', format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload: { principal: principal ? { namespace: principal.namespace } : null } });
291
391
  webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
292
392
  });
293
- void startAbsoluteExpoAuth().then(() => { if (active) setAuthReady(true); });
294
- return () => { active = false; stop(); };`:""}
393
+ void ${n?"startAbsoluteExpoSync":"startAbsoluteExpoAuth"}().then(async () => {
394
+ ${n?"syncBridge.current = await createAbsoluteExpoSyncBridge((event, payload) => {\n\t\t\t\tconst source = JSON.stringify({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });\n\t\t\t\twebView.current?.injectJavaScript(`globalThis.__absoluteExpoReceive(${JSON.stringify(source)}); true;`);\n\t\t\t});":""}
395
+ if (active) setRuntimeReady(true);
396
+ });
397
+ return () => {
398
+ active = false;
399
+ stop();
400
+ const bridge = syncBridge.current;
401
+ syncBridge.current = undefined;
402
+ void bridge?.close();
403
+ };`:""}
295
404
  }, []);
296
405
 
297
406
  useEffect(() => {
@@ -353,6 +462,9 @@ export function AbsoluteWebHost() {
353
462
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });`:"throw new Error('Expo Auth is not configured.');"}
354
463
  } else if (message.method === 'auth.status') {
355
464
  respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });
465
+ } else if (typeof message.method === 'string' && message.method.startsWith('sync.')) {
466
+ if (!syncBridge.current) throw new Error('Expo Sync bridge is unavailable.');
467
+ respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await syncBridge.current.request(message.method, message.params as Record<string, unknown>) });
356
468
  } else {
357
469
  throw new Error('Expo bridge method is not allowed.');
358
470
  }
@@ -361,7 +473,7 @@ export function AbsoluteWebHost() {
361
473
  }
362
474
  };
363
475
 
364
- if (!indexUri || !authReady) return <View style={styles.loading}><ActivityIndicator /></View>;
476
+ if (!indexUri || !runtimeReady) return <View style={styles.loading}><ActivityIndicator /></View>;
365
477
  return <WebView
366
478
  allowFileAccess
367
479
  allowFileAccessFromFileURLs
@@ -382,47 +494,47 @@ export function AbsoluteWebHost() {
382
494
  }
383
495
 
384
496
  const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
385
- `},Tr=`${I}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
497
+ `},mr=`${C}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
386
498
 
387
499
  export default AbsoluteWebHost;
388
- `,Pr=`${I}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
500
+ `,fr=`${C}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
389
501
 
390
502
  export default AbsoluteWebHost;
391
- `,Dr=(e,t)=>`${I}export { default } from ${JSON.stringify(Xe(ze(e),t).replace(/\.(?:[cm]?[jt]sx?)$/u,""))};
392
- `,Cr=(e,t,r)=>({compilerOptions:{paths:{...r?{"@absolutejs/auth":["./node_modules/@absolutejs/auth/dist/index.d.ts"],"@absolutejs/auth/*":["./node_modules/@absolutejs/auth/dist/*"]}:{},"*":["./node_modules/*",`${Xe(t,e)}/node_modules/*`],react:["./node_modules/@types/react/index.d.ts"],"react/*":["./node_modules/@types/react/*"]},strict:!0},extends:"expo/tsconfig.base"}),Rr=async(e,t,r)=>{if(await Je(ze(e),{recursive:!0}),await z(e)){let n=await dr(e,"utf8");if(n===t)return!1;if(!r&&!n.startsWith(I))throw TypeError(`Expo project file ${e} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`)}let o=`${e}.${crypto.randomUUID()}.tmp`;return await Ve(o,t,{flag:"wx"}),await pr(o,e),!0},we=(e)=>`${JSON.stringify(e,null,"\t")}
393
- `,Nr=`${I}export const materializeAbsoluteWebBundle = async () => {
503
+ `,gr=(e,t)=>`${C}export { default } from ${JSON.stringify(St(At(e),t).replace(/\.(?:[cm]?[jt]sx?)$/u,""))};
504
+ `,hr=(e,t,n,r)=>({compilerOptions:{paths:{...n?{"@absolutejs/auth":["./node_modules/@absolutejs/auth/dist/index.d.ts"],"@absolutejs/auth/*":["./node_modules/@absolutejs/auth/dist/*"]}:{},...r?{"@absolutejs/sync":["./node_modules/@absolutejs/sync/dist/index.d.ts"],"@absolutejs/sync-expo":["./node_modules/@absolutejs/sync-expo/dist/index.d.ts"],"@absolutejs/sync-expo/*":["./node_modules/@absolutejs/sync-expo/dist/*"],"@absolutejs/sync/*":["./node_modules/@absolutejs/sync/dist/*"]}:{},"*":["./node_modules/*",`${St(t,e)}/node_modules/*`],react:["./node_modules/@types/react/index.d.ts"],"react/*":["./node_modules/@types/react/*"]},strict:!0},extends:"expo/tsconfig.base"}),yr=async(e,t,n)=>{if(await bt(At(e),{recursive:!0}),await re(e)){let o=await Xn(e,"utf8");if(o===t)return!1;if(!n&&!o.startsWith(C))throw TypeError(`Expo project file ${e} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`)}let r=`${e}.${crypto.randomUUID()}.tmp`;return await wt(r,t,{flag:"wx"}),await Yn(r,e),!0},Ce=(e)=>`${JSON.stringify(e,null,"\t")}
505
+ `,br=`${C}export const materializeAbsoluteWebBundle = async () => {
394
506
  throw new Error('The embedded AbsoluteJS bundle is unavailable. Run absolute prepare before a production Expo build.');
395
507
  };
396
- `,qe=async(e,t)=>{if(e.engine!=="expo")throw TypeError("Expo project generation requires mobile.engine: expo.");let r=fr(t.projectRoot),o=e.nativeProjectDirectory,n=Ge(r,e),s=Object.entries(e.expoNativeRoutes),l=(await Promise.all(s.map(async([u,p])=>({exists:await z(p),module:p,route:u})))).find((u)=>!u.exists);if(l)throw TypeError(`Expo native route ${l.route} references missing module ${l.module}.`);let a=v(o,br);if(await z(o)&&!await z(a)){if((await ur(o)).length>0&&!t.force)throw TypeError(`Expo project directory ${o} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`)}await Je(o,{recursive:!0}),await Ve(a,`format=1
397
- `);let c=Boolean(n),g=new Map([[v(o,".gitignore"),`.expo/
508
+ `,Et=async(e,t)=>{if(e.engine!=="expo")throw TypeError("Expo project generation requires mobile.engine: expo.");let n=Qn(t.projectRoot),r=e.nativeProjectDirectory,o=at(n,e),s=Boolean(o&&it(n)),i=s?{components:yt(n).components}:void 0,l=Object.entries(e.expoNativeRoutes),c=(await Promise.all(l.map(async([p,w])=>({exists:await re(w),module:w,route:p})))).find((p)=>!p.exists);if(c)throw TypeError(`Expo native route ${c.route} references missing module ${c.module}.`);let h=x(r,er);if(await re(r)&&!await re(h)){if((await Kn(r)).length>0&&!t.force)throw TypeError(`Expo project directory ${r} is not AbsoluteJS-managed; rerun with --force only after reviewing it.`)}await bt(r,{recursive:!0}),await wt(h,`format=1
509
+ `);let d=Boolean(o),u=new Map([[x(r,".gitignore"),`.expo/
398
510
  android/
399
511
  ios/
400
512
  node_modules/
401
- `],[v(o,"app.json"),we(Er(e,c))],[v(o,"app.config.js"),vr],[v(o,"package.json"),we(wr(c))],[v(o,"metro.config.js"),yr(r)],[v(o,"plugins","withAbsoluteDevelopmentCa.js"),Sr],[v(o,"tsconfig.json"),we(Cr(r,o,c))],[v(o,"app","_layout.tsx"),xr(c)],[v(o,"app","__absolute","native","index.tsx"),Ir],[v(o,"src","generated","AbsoluteWebHost.tsx"),Or(e,n)]]);if(n)g.set(v(o,"src","generated","AbsoluteAuth.ts"),_r(n,e.appId));let m=v(o,"src","generated","webAssets.ts");if(!await z(m))g.set(m,Nr);if(!e.expoNativeRoutes["/"])g.set(v(o,"app","index.tsx"),Tr);g.set(v(o,"app","[...absolute].tsx"),Pr);for(let[u,p]of s){let f=u==="/"?v(o,"app","index.tsx"):Ar(o,u);g.set(f,Dr(f,p))}return{changed:(await Promise.all([...g].map(([u,p])=>Rr(u,p,!0)))).filter(Boolean).length,path:o,written:[...g.keys()]}};import{createHash as ft,randomUUID as to}from"crypto";import{access as ro,copyFile as at,mkdir as G,readFile as ae,rename as oo,rm as ye,writeFile as B}from"fs/promises";import{isIP as no}from"net";import{dirname as bt,isAbsolute as so,join as S,relative as io,resolve as ce,sep as ao}from"path";import{access as Lr}from"fs/promises";import{homedir as Ze}from"os";import{join as K}from"path";import{existsSync as Nn,readFileSync as Mr}from"fs";var X=1000;var Ke=60000;var Ee=2;var q=(e)=>{let t;if(e<X)t=`${e.toFixed(Ee)}ms`;else if(e<Ke)t=`${(e/X).toFixed(Ee)}s`;else{let r=Math.round(e/X),o=Math.floor(r/60),n=r%60;t=n===0?`${o}m`:`${o}m ${n}s`}return t};var Ye=()=>{try{let e=Mr("/proc/version","utf-8");return/microsoft|wsl/i.test(e)}catch{return!1}};var Qe="AbsoluteJS_API_36",Ur=(e)=>{try{let t=Bun.spawnSync(e,{stderr:"ignore",stdout:"pipe"});return{exitCode:t.exitCode,stdout:t.stdout.toString()}}catch{return{exitCode:1,stdout:""}}},$r=(e)=>{try{let t=JSON.parse(e);if(typeof t!=="object"||t===null)return!1;let r=Reflect.get(t,"runtimes");if(!Array.isArray(r))return!1;return r.some((o)=>typeof o==="object"&&o!==null&&Reflect.get(o,"isAvailable")===!0&&typeof Reflect.get(o,"identifier")==="string"&&String(Reflect.get(o,"identifier")).includes("iOS"))}catch{return!1}},kr=(e)=>{let t=/^([a-z]):[\\/](.*)$/i.exec(e.trim());if(!t)return e.trim().replaceAll("\\","/");return`/mnt/${t[1]?.toLowerCase()}/${t[2]?.replaceAll("\\","/")}`},jr=()=>{try{let e=Bun.spawnSync(["cmd.exe","/d","/c","echo","%LOCALAPPDATA%"],{stderr:"ignore",stdout:"pipe"});if(e.exitCode!==0)return;let t=e.stdout.toString().trim();if(!t||t==="%LOCALAPPDATA%")return;return kr(t)}catch{return}},Br=(e,t=process.env)=>{if(e==="windows")return K(t.LOCALAPPDATA??K(Ze(),"AppData","Local"),"AbsoluteJS","Android","Sdk");if(e==="wsl"){let r=jr();if(r)return K(r,"AbsoluteJS","Android","Sdk")}return K(Ze(),".absolutejs","android-sdk")},Hr=async(e)=>{try{return await Lr(e),!0}catch{return!1}},se=(e=process.platform,t=Ye())=>{if(e==="darwin")return"macos";if(e==="win32")return"windows";if(e==="linux"&&t)return"wsl";return"linux"},Fr=(e,t)=>{if(e==="wsl")return[`${t}.exe`,`${t}.bat`,t];if(e==="windows")return[t,`${t}.exe`,`${t}.bat`];return[t]},k=async(e,t,r,o)=>{let s=(await Promise.all(t.map(async(i)=>await r.exists(i)?i:void 0))).find((i)=>i!==void 0);if(s)return s;for(let i of Fr(o,e)){let l=r.which(i);if(l)return l}return},j=(e,t,r,o,n)=>o?{id:e,label:t,path:o,platform:r,status:"pass"}:{id:e,label:t,platform:r,remediation:n,status:"fail"},et=async(e={})=>{let t=e.env??process.env,r=e.host??se(),o=e.exists??Hr,n=e.which??((A)=>Bun.which(A)),s=e.capture??Ur,i=e.androidRoot===null?void 0:e.androidRoot??t.ANDROID_HOME??t.ANDROID_SDK_ROOT??Br(r,t),l=r==="windows"||r==="wsl",a=(A)=>i?K(i,...A):void 0,c=(A)=>A.filter((h)=>Boolean(h)),g=await k("adb",c([a(["platform-tools",l?"adb.exe":"adb"])]),{exists:o,which:n},r),m=await k("emulator",c([a(["emulator",l?"emulator.exe":"emulator"])]),{exists:o,which:n},r),b=await k("sdkmanager",c([a(["cmdline-tools","latest","bin",l?"sdkmanager.bat":"sdkmanager"])]),{exists:o,which:n},r),x=await k("avdmanager",c([a(["cmdline-tools","latest","bin",l?"avdmanager.bat":"avdmanager"])]),{exists:o,which:n},r),u=await k("java",[],{exists:o,which:n},r),p=[{id:"host",label:`Development host: ${r}`,platform:"host",status:"pass"},j("android.adb","Android Debug Bridge","android",g,"Install Android SDK Platform Tools or expose adb on PATH."),j("android.emulator","Android Emulator","android",m,"Install the Android Emulator from Android Studio SDK Manager."),j("android.sdkmanager","Android SDK Manager","android",b,"Install Android SDK Command-line Tools (latest)."),j("android.avdmanager","Android Virtual Device Manager","android",x,"Install Android SDK Command-line Tools (latest)."),j("android.java","Java runtime","android",u,"Install the JDK required by the configured Android Gradle plugin.")];if(m){let A=s([m,"-list-avds"]),h=A.exitCode===0&&A.stdout.split(/\r?\n/).includes(Qe);p.push({id:"android.avd",label:`AbsoluteJS Android emulator (${Qe})`,platform:"android",remediation:h?void 0:"Run absolute mobile doctor android --fix to provision the managed emulator.",status:h?"pass":"fail"})}if(r==="wsl")p.push({id:"android.virtualization",label:g?.endsWith(".exe")?"Windows-host Android bridge available to WSL":"WSL requires a Windows-host emulator bridge or Linux KVM",platform:"android",remediation:g?.endsWith(".exe")?void 0:"Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",status:g?.endsWith(".exe")?"pass":"warn"});else if(r==="linux"){let A=await o("/dev/kvm");p.push({id:"android.virtualization",label:"Linux KVM acceleration",platform:"android",remediation:A?void 0:"Enable KVM and grant the current user access to /dev/kvm.",status:A?"pass":"warn"})}if(r!=="macos")return p.push({id:"ios.simulator",label:"iOS Simulator requires macOS and Xcode",platform:"ios",status:"skip"}),p;let f=await k("xcrun",[],{exists:o,which:n},r),_=await k("xcodebuild",[],{exists:o,which:n},r);if(p.push(j("ios.xcrun","Xcode command runner","ios",f,"Install Xcode and select it with xcode-select."),j("ios.xcodebuild","Xcode build system","ios",_,"Install Xcode and select it with xcode-select.")),f){let A=s([f,"simctl","list","runtimes","--json"]),h=A.exitCode===0&&$r(A.stdout);p.push({id:"ios.runtime",label:"iOS Simulator runtime",platform:"ios",remediation:h?void 0:"Run absolute mobile doctor ios --fix to download an iOS Simulator runtime.",status:h?"pass":"fail"})}return p};import{access as Wr,readFile as Gr,rename as Jr,writeFile as Vr}from"fs/promises";import{relative as zr,resolve as tt}from"path";var rt="capacitor.config.ts",ve=(e,t)=>zr(e,t).replaceAll("\\","/"),Xr=(e,t)=>`import type { CapacitorConfig } from '@capacitor/cli';
513
+ `],[x(r,"app.json"),Ce(or(e,d,s))],[x(r,"app.config.js"),sr],[x(r,"package.json"),Ce(rr(d,s))],[x(r,"metro.config.js"),ar(n)],[x(r,"plugins","withAbsoluteDevelopmentCa.js"),ir],[x(r,"tsconfig.json"),Ce(hr(n,r,d,s))],[x(r,"app","_layout.tsx"),cr(d,s)],[x(r,"app","__absolute","native","index.tsx"),lr],[x(r,"src","generated","AbsoluteWebHost.tsx"),pr(e,o,s)]]);if(o)u.set(x(r,"src","generated","AbsoluteAuth.ts"),dr(o,e.appId));if(i)u.set(x(r,"src","generated","AbsoluteSync.ts"),ur(e,i));let S=x(r,"src","generated","webAssets.ts");if(!await re(S))u.set(S,br);if(!e.expoNativeRoutes["/"])u.set(x(r,"app","index.tsx"),mr);u.set(x(r,"app","[...absolute].tsx"),fr);for(let[p,w]of l){let y=p==="/"?x(r,"app","index.tsx"):nr(r,p);u.set(y,gr(y,w))}return{changed:(await Promise.all([...u].map(([p,w])=>yr(p,w,!0)))).filter(Boolean).length,path:r,written:[...u.keys()]}};import{createHash as Ft,randomUUID as Br}from"crypto";import{access as Hr,copyFile as kt,mkdir as ee,readFile as ye,rename as Vr,rm as Me,writeFile as z}from"fs/promises";import{isIP as Fr}from"net";import{dirname as Jt,isAbsolute as Jr,join as O,relative as Wr,resolve as be,sep as qr}from"path";import{access as vr}from"fs/promises";import{homedir as Ot}from"os";import{join as ie}from"path";import{existsSync as xs,readFileSync as wr}from"fs";var oe=1000;var xt=60000;var De=2;var se=(e)=>{let t;if(e<oe)t=`${e.toFixed(De)}ms`;else if(e<xt)t=`${(e/oe).toFixed(De)}s`;else{let n=Math.round(e/oe),r=Math.floor(n/60),o=n%60;t=o===0?`${r}m`:`${r}m ${o}s`}return t};var It=()=>{try{let e=wr("/proc/version","utf-8");return/microsoft|wsl/i.test(e)}catch{return!1}};var _t="AbsoluteJS_API_36",Ar=(e)=>{try{let t=Bun.spawnSync(e,{stderr:"ignore",stdout:"pipe"});return{exitCode:t.exitCode,stdout:t.stdout.toString()}}catch{return{exitCode:1,stdout:""}}},Sr=(e)=>{try{let t=JSON.parse(e);if(typeof t!=="object"||t===null)return!1;let n=Reflect.get(t,"runtimes");if(!Array.isArray(n))return!1;return n.some((r)=>typeof r==="object"&&r!==null&&Reflect.get(r,"isAvailable")===!0&&typeof Reflect.get(r,"identifier")==="string"&&String(Reflect.get(r,"identifier")).includes("iOS"))}catch{return!1}},Er=(e)=>{let t=/^([a-z]):[\\/](.*)$/i.exec(e.trim());if(!t)return e.trim().replaceAll("\\","/");return`/mnt/${t[1]?.toLowerCase()}/${t[2]?.replaceAll("\\","/")}`},xr=()=>{try{let e=Bun.spawnSync(["cmd.exe","/d","/c","echo","%LOCALAPPDATA%"],{stderr:"ignore",stdout:"pipe"});if(e.exitCode!==0)return;let t=e.stdout.toString().trim();if(!t||t==="%LOCALAPPDATA%")return;return Er(t)}catch{return}},Ir=(e,t=process.env)=>{if(e==="windows")return ie(t.LOCALAPPDATA??ie(Ot(),"AppData","Local"),"AbsoluteJS","Android","Sdk");if(e==="wsl"){let n=xr();if(n)return ie(n,"AbsoluteJS","Android","Sdk")}return ie(Ot(),".absolutejs","android-sdk")},Or=async(e)=>{try{return await vr(e),!0}catch{return!1}},ge=(e=process.platform,t=It())=>{if(e==="darwin")return"macos";if(e==="win32")return"windows";if(e==="linux"&&t)return"wsl";return"linux"},_r=(e,t)=>{if(e==="wsl")return[`${t}.exe`,`${t}.bat`,t];if(e==="windows")return[t,`${t}.exe`,`${t}.bat`];return[t]},q=async(e,t,n,r)=>{let s=(await Promise.all(t.map(async(i)=>await n.exists(i)?i:void 0))).find((i)=>i!==void 0);if(s)return s;for(let i of _r(r,e)){let l=n.which(i);if(l)return l}return},G=(e,t,n,r,o)=>r?{id:e,label:t,path:r,platform:n,status:"pass"}:{id:e,label:t,platform:n,remediation:o,status:"fail"},Tt=async(e={})=>{let t=e.env??process.env,n=e.host??ge(),r=e.exists??Or,o=e.which??((y)=>Bun.which(y)),s=e.capture??Ar,i=e.androidRoot===null?void 0:e.androidRoot??t.ANDROID_HOME??t.ANDROID_SDK_ROOT??Ir(n,t),l=n==="windows"||n==="wsl",a=(y)=>i?ie(i,...y):void 0,c=(y)=>y.filter((b)=>Boolean(b)),h=await q("adb",c([a(["platform-tools",l?"adb.exe":"adb"])]),{exists:r,which:o},n),d=await q("emulator",c([a(["emulator",l?"emulator.exe":"emulator"])]),{exists:r,which:o},n),u=await q("sdkmanager",c([a(["cmdline-tools","latest","bin",l?"sdkmanager.bat":"sdkmanager"])]),{exists:r,which:o},n),S=await q("avdmanager",c([a(["cmdline-tools","latest","bin",l?"avdmanager.bat":"avdmanager"])]),{exists:r,which:o},n),f=await q("java",[],{exists:r,which:o},n),g=[{id:"host",label:`Development host: ${n}`,platform:"host",status:"pass"},G("android.adb","Android Debug Bridge","android",h,"Install Android SDK Platform Tools or expose adb on PATH."),G("android.emulator","Android Emulator","android",d,"Install the Android Emulator from Android Studio SDK Manager."),G("android.sdkmanager","Android SDK Manager","android",u,"Install Android SDK Command-line Tools (latest)."),G("android.avdmanager","Android Virtual Device Manager","android",S,"Install Android SDK Command-line Tools (latest)."),G("android.java","Java runtime","android",f,"Install the JDK required by the configured Android Gradle plugin.")];if(d){let y=s([d,"-list-avds"]),b=y.exitCode===0&&y.stdout.split(/\r?\n/).includes(_t);g.push({id:"android.avd",label:`AbsoluteJS Android emulator (${_t})`,platform:"android",remediation:b?void 0:"Run absolute mobile doctor android --fix to provision the managed emulator.",status:b?"pass":"fail"})}if(n==="wsl")g.push({id:"android.virtualization",label:h?.endsWith(".exe")?"Windows-host Android bridge available to WSL":"WSL requires a Windows-host emulator bridge or Linux KVM",platform:"android",remediation:h?.endsWith(".exe")?void 0:"Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",status:h?.endsWith(".exe")?"pass":"warn"});else if(n==="linux"){let y=await r("/dev/kvm");g.push({id:"android.virtualization",label:"Linux KVM acceleration",platform:"android",remediation:y?void 0:"Enable KVM and grant the current user access to /dev/kvm.",status:y?"pass":"warn"})}if(n!=="macos")return g.push({id:"ios.simulator",label:"iOS Simulator requires macOS and Xcode",platform:"ios",status:"skip"}),g;let p=await q("xcrun",[],{exists:r,which:o},n),w=await q("xcodebuild",[],{exists:r,which:o},n);if(g.push(G("ios.xcrun","Xcode command runner","ios",p,"Install Xcode and select it with xcode-select."),G("ios.xcodebuild","Xcode build system","ios",w,"Install Xcode and select it with xcode-select.")),p){let y=s([p,"simctl","list","runtimes","--json"]),b=y.exitCode===0&&Sr(y.stdout);g.push({id:"ios.runtime",label:"iOS Simulator runtime",platform:"ios",remediation:b?void 0:"Run absolute mobile doctor ios --fix to download an iOS Simulator runtime.",status:b?"pass":"fail"})}return g};import{access as Tr,readFile as Pr,rename as Cr,writeFile as Dr}from"fs/promises";import{relative as Rr,resolve as Pt}from"path";var Ct="capacitor.config.ts",Re=(e,t)=>Rr(e,t).replaceAll("\\","/"),Nr=(e,t)=>`import type { CapacitorConfig } from '@capacitor/cli';
402
514
 
403
515
  const config: CapacitorConfig = {
404
516
  appId: ${JSON.stringify(e.appId)},
405
517
  appName: ${JSON.stringify(e.appName)},
406
- webDir: ${JSON.stringify(ve(t,e.bundleDirectory))},
518
+ webDir: ${JSON.stringify(Re(t,e.bundleDirectory))},
407
519
  android: {
408
- path: ${JSON.stringify(ve(t,`${e.nativeProjectDirectory}/android`))}
520
+ path: ${JSON.stringify(Re(t,`${e.nativeProjectDirectory}/android`))}
409
521
  },
410
522
  ios: {
411
- path: ${JSON.stringify(ve(t,`${e.nativeProjectDirectory}/ios`))}
523
+ path: ${JSON.stringify(Re(t,`${e.nativeProjectDirectory}/ios`))}
412
524
  }
413
525
  };
414
526
 
415
527
  export default config;
416
- `,qr=async(e)=>{try{return await Wr(e),!0}catch{return!1}},ot=async(e,t)=>{let r=tt(t.projectRoot),o=tt(r,rt),n=Xr(e,r);if(await qr(o)){if(await Gr(o,"utf8")===n)return{changed:!1,path:o};if(!t.force)throw TypeError(`${rt} already exists and differs; rerun with --force only after reviewing it.`)}let s=`${o}.${crypto.randomUUID()}.tmp`;return await Vr(s,n,{flag:"wx"}),await Jr(s,o),{changed:!0,path:o}};import{createHash as Kr}from"crypto";import{access as zn,copyFile as Xn,mkdir as qn,mkdtemp as Kn,readdir as Yr,readFile as Zr,rename as Yn,rm as Zn,stat as Qn,writeFile as es}from"fs/promises";import{dirname as rs,isAbsolute as os,join as Qr,relative as nt,resolve as ns,sep as ss}from"path";var eo=new Set(["Pods","DerivedData","build","xcuserdata"]),st=async(e,t=e,r={})=>{let o=await Yr(t,{withFileTypes:!0});return(await Promise.all(o.sort((s,i)=>s.name.localeCompare(i.name)).map(async(s)=>{let i=Qr(t,s.name),l=nt(e,i).replaceAll("\\","/");if(s.isDirectory()&&(eo.has(s.name)||l==="App/App/public"&&r.includePublicBundle!==!0))return[];if(s.isDirectory())return st(e,i,r);return s.isFile()?[i]:[]}))).flat()},it=async(e,t={})=>{let r=Kr("sha256"),o=await st(e,e,t),n=await Promise.all(o.map((s)=>Zr(s)));return o.forEach((s,i)=>{r.update(nt(e,s).replaceAll("\\","/")),r.update("\x00"),r.update(n[i]??new Uint8Array),r.update("\x00")}),r.digest("hex")};var Se="AbsoluteJS iPhone",ct=180000,co=1000,xe=1,Ie=1,D=(e)=>typeof e==="object"&&e!==null&&!Array.isArray(e),L=async(e)=>{try{return await ro(e),!0}catch{return!1}},W=(e)=>e?.throwIfAborted(),lo=(e,t={})=>{try{let r=Bun.spawnSync(e,{cwd:t.cwd,env:t.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:r.exitCode,stderr:r.stderr.toString(),stdout:r.stdout.toString()}}catch(r){return{exitCode:1,stderr:r instanceof Error?r.message:String(r),stdout:""}}},ht=async(e,t={})=>Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"inherit",stdin:"inherit",stdout:"inherit"}).exited,uo=(e,t={})=>{Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})},lt=async(e,t)=>{let r=e.getReader(),o=new TextDecoder,n="",s=async()=>{let{done:i,value:l}=await r.read();if(i)return;n+=o.decode(l,{stream:!0});let a=n.split(/\r?\n/u);n=a.pop()??"",a.forEach(t),await s()};try{if(await s(),n+=o.decode(),n)t(n)}finally{r.releaseLock()}},po=(e,t,r)=>{let o=Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return lt(o.stdout,r),lt(o.stderr,r),{close:async()=>{try{o.kill()}catch{}await o.exited.catch(()=>{return})}}},P=async(e,t,r,o)=>{let n=await r(e,o);if(n!==0)throw Error(`${t} failed with status ${n}.`)},mo=async(e,t,r,o)=>{if(!e.https)return;if(!e.certificateAuthorityPath)throw Error("iOS Simulator HTTPS requires the AbsoluteJS development CA certificate.");await P([e.project.xcrun,"simctl","keychain",t,"add-root-cert",e.certificateAuthorityPath],"iOS Simulator development CA trust",r,{signal:e.signal}),o("Installed the AbsoluteJS development CA into this iOS Simulator trust store.")},ut=(e,t,r)=>r?[e.xcrun,"devicectl","device","process","launch","--terminate-existing","--device",t,e.config.appId]:[e.xcrun,"simctl","launch","--terminate-running-process",t,e.config.appId],Z=(e,t)=>{if(e.exitCode!==0)throw Error(`${t} failed: ${e.stderr.trim()||e.stdout.trim()||`status ${e.exitCode}`}`);return e.stdout.trim()},_e=(e,t)=>{try{let r=JSON.parse(e);if(D(r))return r}catch{}throw Error(`Invalid ${t} JSON from simctl.`)},go=(e)=>{let r=_e(e,"device type").devicetypes;if(!Array.isArray(r))return[];return r.flatMap((o)=>{if(!D(o))return[];let{identifier:n}=o,{name:s}=o;return typeof n==="string"&&typeof s==="string"?[{identifier:n,name:s}]:[]})},fo=(e)=>{let t=_e(e,"runtime"),{runtimes:r}=t;if(!Array.isArray(r))return[];return r.flatMap((o)=>{if(!D(o))return[];let{identifier:n}=o,{name:s}=o,{version:i}=o;if(typeof n!=="string"||typeof s!=="string"||typeof i!=="string")return[];return[{identifier:n,isAvailable:o.isAvailable!==!1,name:s,version:i}]})},bo=(e)=>{let t=_e(e,"device"),{devices:r}=t;if(!D(r))return[];return Object.entries(r).flatMap(([o,n])=>{if(!Array.isArray(n))return[];return n.flatMap((s)=>{if(!D(s))return[];let{name:i}=s,{state:l}=s,{udid:a}=s;if(typeof i!=="string"||typeof l!=="string"||typeof a!=="string")return[];return[{isAvailable:s.isAvailable!==!1,name:i,runtime:o,state:l,udid:a}]})})},dt=(e)=>e.split(".").map((t)=>Number(t)),ho=(e,t)=>{let r=dt(e),o=dt(t),n=Math.max(r.length,o.length);for(let s=0;s<n;s++){let i=(r[s]??0)-(o[s]??0);if(i!==0)return i}return 0},Ao=(e)=>e.filter((t)=>t.isAvailable&&t.identifier.includes("SimRuntime.iOS-")).sort((t,r)=>ho(r.version,t.version))[0],pt=(e)=>Number(/iPhone\s+(\d+)/u.exec(e)?.[1]??0),wo=(e)=>e.filter((t)=>t.name.startsWith("iPhone")).sort((t,r)=>{let o=pt(r.name)-pt(t.name);if(o!==0)return o;let n=r.name.includes("Pro")?1:0,s=t.name.includes("Pro")?1:0;return n-s})[0],At=(e)=>{let t=S(e,".absolutejs","mobile","ios-dev-session");return{configBackup:S(t,"capacitor-config.backup"),infoBackup:S(t,"Info.plist.backup"),journal:S(t,"journal.json"),root:t}},wt=(e)=>S(e,".absolutejs","mobile","ios-native-cache.json"),Y=(e,t)=>{let r=io(ce(e),ce(t));return r===""||!r.startsWith(`..${ao}`)&&r!==".."&&!so(r)},Eo=(e)=>{if(!D(e)||e.format!==xe)return null;let{configBackupPath:t}=e,{infoBackupPath:r}=e,{infoPath:o}=e,{nativeConfigPath:n}=e;if(typeof t!=="string"||typeof r!=="string"||typeof o!=="string"||typeof n!=="string")return null;return{configBackupPath:t,format:xe,infoBackupPath:r,infoPath:o,nativeConfigPath:n}},ie=async(e)=>{let t=At(e);if(!await L(t.journal))return await ye(t.root,{force:!0,recursive:!0}),!1;let r=await ae(t.journal,"utf8").then((o)=>Eo(JSON.parse(o))).catch(()=>null);if(!r||!Y(e,r.nativeConfigPath)||!Y(e,r.infoPath)||!Y(t.root,r.configBackupPath)||!Y(t.root,r.infoBackupPath))throw Error(`Refusing unsafe or invalid iOS dev journal at ${t.journal}.`);if(await L(r.configBackupPath))await at(r.configBackupPath,r.nativeConfigPath);if(await L(r.infoBackupPath))await at(r.infoBackupPath,r.infoPath);return await ye(t.root,{force:!0,recursive:!0}),!0},vo=(e,t)=>{if(!t)return e;let r=/(<key>NSAllowsArbitraryLoads<\/key>\s*)<false\s*\/>/u;if(r.test(e))return e.replace(r,"$1<true/>");if(/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(e))return e;let o=/(<key>NSAppTransportSecurity<\/key>\s*<dict>)/u;if(o.test(e))return e.replace(o,`$1
528
+ `,Mr=async(e)=>{try{return await Tr(e),!0}catch{return!1}},Dt=async(e,t)=>{let n=Pt(t.projectRoot),r=Pt(n,Ct),o=Nr(e,n);if(await Mr(r)){if(await Pr(r,"utf8")===o)return{changed:!1,path:r};if(!t.force)throw TypeError(`${Ct} already exists and differs; rerun with --force only after reviewing it.`)}let s=`${r}.${crypto.randomUUID()}.tmp`;return await Dr(s,o,{flag:"wx"}),await Cr(s,r),{changed:!0,path:r}};import{createHash as kr}from"crypto";import{access as js,copyFile as Us,mkdir as Bs,mkdtemp as Hs,readdir as Lr,readFile as $r,rename as Vs,rm as Fs,stat as Js,writeFile as Ws}from"fs/promises";import{dirname as Gs,isAbsolute as zs,join as jr,relative as Rt,resolve as Ks,sep as Xs}from"path";var Ur=new Set(["Pods","DerivedData","build","xcuserdata"]),Nt=async(e,t=e,n={})=>{let r=await Lr(t,{withFileTypes:!0});return(await Promise.all(r.sort((s,i)=>s.name.localeCompare(i.name)).map(async(s)=>{let i=jr(t,s.name),l=Rt(e,i).replaceAll("\\","/");if(s.isDirectory()&&(Ur.has(s.name)||l==="App/App/public"&&n.includePublicBundle!==!0))return[];if(s.isDirectory())return Nt(e,i,n);return s.isFile()?[i]:[]}))).flat()},Mt=async(e,t={})=>{let n=kr("sha256"),r=await Nt(e,e,t),o=await Promise.all(r.map((s)=>$r(s)));return r.forEach((s,i)=>{n.update(Rt(e,s).replaceAll("\\","/")),n.update("\x00"),n.update(o[i]??new Uint8Array),n.update("\x00")}),n.digest("hex")};var Ne="AbsoluteJS iPhone",Lt=180000,Gr=1000,ke=1,Le=1,k=(e)=>typeof e==="object"&&e!==null&&!Array.isArray(e),F=async(e)=>{try{return await Hr(e),!0}catch{return!1}},Q=(e)=>e?.throwIfAborted(),zr=(e,t={})=>{try{let n=Bun.spawnSync(e,{cwd:t.cwd,env:t.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:n.exitCode,stderr:n.stderr.toString(),stdout:n.stdout.toString()}}catch(n){return{exitCode:1,stderr:n instanceof Error?n.message:String(n),stdout:""}}},Wt=async(e,t={})=>Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"inherit",stdin:"inherit",stdout:"inherit"}).exited,Kr=(e,t={})=>{Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})},$t=async(e,t)=>{let n=e.getReader(),r=new TextDecoder,o="",s=async()=>{let{done:i,value:l}=await n.read();if(i)return;o+=r.decode(l,{stream:!0});let a=o.split(/\r?\n/u);o=a.pop()??"",a.forEach(t),await s()};try{if(await s(),o+=r.decode(),o)t(o)}finally{n.releaseLock()}},Xr=(e,t,n)=>{let r=Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return $t(r.stdout,n),$t(r.stderr,n),{close:async()=>{try{r.kill()}catch{}await r.exited.catch(()=>{return})}}},M=async(e,t,n,r)=>{let o=await n(e,r);if(o!==0)throw Error(`${t} failed with status ${o}.`)},Yr=async(e,t,n,r)=>{if(!e.https)return;if(!e.certificateAuthorityPath)throw Error("iOS Simulator HTTPS requires the AbsoluteJS development CA certificate.");await M([e.project.xcrun,"simctl","keychain",t,"add-root-cert",e.certificateAuthorityPath],"iOS Simulator development CA trust",n,{signal:e.signal}),r("Installed the AbsoluteJS development CA into this iOS Simulator trust store.")},jt=(e,t,n)=>n?[e.xcrun,"devicectl","device","process","launch","--terminate-existing","--device",t,e.config.appId]:[e.xcrun,"simctl","launch","--terminate-running-process",t,e.config.appId],ce=(e,t)=>{if(e.exitCode!==0)throw Error(`${t} failed: ${e.stderr.trim()||e.stdout.trim()||`status ${e.exitCode}`}`);return e.stdout.trim()},$e=(e,t)=>{try{let n=JSON.parse(e);if(k(n))return n}catch{}throw Error(`Invalid ${t} JSON from simctl.`)},Zr=(e)=>{let n=$e(e,"device type").devicetypes;if(!Array.isArray(n))return[];return n.flatMap((r)=>{if(!k(r))return[];let{identifier:o}=r,{name:s}=r;return typeof o==="string"&&typeof s==="string"?[{identifier:o,name:s}]:[]})},Qr=(e)=>{let t=$e(e,"runtime"),{runtimes:n}=t;if(!Array.isArray(n))return[];return n.flatMap((r)=>{if(!k(r))return[];let{identifier:o}=r,{name:s}=r,{version:i}=r;if(typeof o!=="string"||typeof s!=="string"||typeof i!=="string")return[];return[{identifier:o,isAvailable:r.isAvailable!==!1,name:s,version:i}]})},eo=(e)=>{let t=$e(e,"device"),{devices:n}=t;if(!k(n))return[];return Object.entries(n).flatMap(([r,o])=>{if(!Array.isArray(o))return[];return o.flatMap((s)=>{if(!k(s))return[];let{name:i}=s,{state:l}=s,{udid:a}=s;if(typeof i!=="string"||typeof l!=="string"||typeof a!=="string")return[];return[{isAvailable:s.isAvailable!==!1,name:i,runtime:r,state:l,udid:a}]})})},Ut=(e)=>e.split(".").map((t)=>Number(t)),to=(e,t)=>{let n=Ut(e),r=Ut(t),o=Math.max(n.length,r.length);for(let s=0;s<o;s++){let i=(n[s]??0)-(r[s]??0);if(i!==0)return i}return 0},no=(e)=>e.filter((t)=>t.isAvailable&&t.identifier.includes("SimRuntime.iOS-")).sort((t,n)=>to(n.version,t.version))[0],Bt=(e)=>Number(/iPhone\s+(\d+)/u.exec(e)?.[1]??0),ro=(e)=>e.filter((t)=>t.name.startsWith("iPhone")).sort((t,n)=>{let r=Bt(n.name)-Bt(t.name);if(r!==0)return r;let o=n.name.includes("Pro")?1:0,s=t.name.includes("Pro")?1:0;return o-s})[0],qt=(e)=>{let t=O(e,".absolutejs","mobile","ios-dev-session");return{configBackup:O(t,"capacitor-config.backup"),infoBackup:O(t,"Info.plist.backup"),journal:O(t,"journal.json"),root:t}},Gt=(e)=>O(e,".absolutejs","mobile","ios-native-cache.json"),ae=(e,t)=>{let n=Wr(be(e),be(t));return n===""||!n.startsWith(`..${qr}`)&&n!==".."&&!Jr(n)},oo=(e)=>{if(!k(e)||e.format!==ke)return null;let{configBackupPath:t}=e,{infoBackupPath:n}=e,{infoPath:r}=e,{nativeConfigPath:o}=e;if(typeof t!=="string"||typeof n!=="string"||typeof r!=="string"||typeof o!=="string")return null;return{configBackupPath:t,format:ke,infoBackupPath:n,infoPath:r,nativeConfigPath:o}},he=async(e)=>{let t=qt(e);if(!await F(t.journal))return await Me(t.root,{force:!0,recursive:!0}),!1;let n=await ye(t.journal,"utf8").then((r)=>oo(JSON.parse(r))).catch(()=>null);if(!n||!ae(e,n.nativeConfigPath)||!ae(e,n.infoPath)||!ae(t.root,n.configBackupPath)||!ae(t.root,n.infoBackupPath))throw Error(`Refusing unsafe or invalid iOS dev journal at ${t.journal}.`);if(await F(n.configBackupPath))await kt(n.configBackupPath,n.nativeConfigPath);if(await F(n.infoBackupPath))await kt(n.infoBackupPath,n.infoPath);return await Me(t.root,{force:!0,recursive:!0}),!0},so=(e,t)=>{if(!t)return e;let n=/(<key>NSAllowsArbitraryLoads<\/key>\s*)<false\s*\/>/u;if(n.test(e))return e.replace(n,"$1<true/>");if(/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(e))return e;let r=/(<key>NSAppTransportSecurity<\/key>\s*<dict>)/u;if(r.test(e))return e.replace(r,`$1
417
529
  <key>NSAllowsArbitraryLoads</key>
418
530
  <true/>`);return e.replace(/<dict>/u,`<dict>
419
531
  <key>NSAppTransportSecurity</key>
420
532
  <dict>
421
533
  <key>NSAllowsArbitraryLoads</key>
422
534
  <true/>
423
- </dict>`)},So=async(e,t,r,o="localhost")=>{let n=At(e.projectRoot);await ie(e.projectRoot);let s=S(e.nativeDirectory,"App","App","capacitor.config.json"),i=S(e.nativeDirectory,"App","App","Info.plist"),[l,a]=await Promise.all([ae(s,"utf8"),ae(i,"utf8")]),c=JSON.parse(l);if(!D(c))throw Error(`Invalid Capacitor native config at ${s}.`);await G(n.root,{recursive:!0}),await Promise.all([B(n.configBackup,l,{flag:"wx"}),B(n.infoBackup,a,{flag:"wx"})]);let g={configBackupPath:n.configBackup,format:xe,infoBackupPath:n.infoBackup,infoPath:i,nativeConfigPath:s};await B(n.journal,`${JSON.stringify(g,null,"\t")}
424
- `,{flag:"wx"});let m=new URL(`${r?"https":"http"}://localhost:${t}${e.config.entry}`);m.hostname=no(o)===6?`[${o}]`:o,m.searchParams.set("__absolute_target","capacitor-ios");let b=c.server;c.server={...D(b)?b:{},cleartext:!r,url:m.href},await Promise.all([B(s,`${JSON.stringify(c,null,"\t")}
425
- `),B(i,vo(a,!r))])},yo=(e)=>{if(!D(e))return null;let{appId:t,fingerprint:r,format:o,installations:n}=e;if(o!==Ie||typeof t!=="string"||typeof r!=="string"||!D(n)||!Object.values(n).every((s)=>typeof s==="string"))return null;return{appId:t,fingerprint:r,format:o,installations:Object.fromEntries(Object.entries(n).map(([s,i])=>[s,String(i)]))}},xo=(e)=>ae(wt(e),"utf8").then((t)=>yo(JSON.parse(t))).catch(()=>null),Et=async(e,t)=>{let r=wt(e),o=`${r}.${process.pid}.${to()}.tmp`;await G(bt(r),{recursive:!0});try{await B(o,`${JSON.stringify(t,null,"\t")}
426
- `,{flag:"wx"}),await oo(o,r)}finally{await ye(o,{force:!0}).catch(()=>{return})}},Io=async(e,t={})=>it(e.nativeDirectory,t),vt=(e,t)=>{let r=t([e,"simctl","list","devices","available","-j"]);return bo(Z(r,"iOS simulator discovery"))},_o=async(e,t)=>{let r=fo(Z(t([e.xcrun,"simctl","list","runtimes","-j"]),"iOS runtime discovery")),o=Ao(r);if(!o)throw Error("No available iOS Simulator runtime. Run absolute mobile doctor ios --fix.");let[n]=vt(e.xcrun,t).filter((a)=>a.isAvailable&&a.name===Se&&a.runtime===o.identifier).sort((a,c)=>Number(c.state==="Booted")-Number(a.state==="Booted"));if(n)return{created:!1,device:n};let s=go(Z(t([e.xcrun,"simctl","list","devicetypes","-j"]),"iOS device-type discovery")),i=wo(s);if(!i)throw Error("Xcode did not report an iPhone simulator type.");let[l]=Z(t([e.xcrun,"simctl","create",Se,i.identifier,o.identifier]),"iOS simulator creation").split(/\s/u);if(!l)throw Error("simctl did not return the created simulator UDID.");return{created:!0,device:{isAvailable:!0,name:Se,runtime:o.identifier,state:"Shutdown",udid:l}}},Oo=async(e,t,r,o,n)=>{let s=Date.now()+ct,i=async()=>{if(W(n),vt(e.xcrun,r).find((a)=>a.udid===t)?.state==="Booted")return;if(Date.now()>s)throw Error(`iOS simulator ${t} did not finish booting within ${ct/1000}s.`);await o(co),await i()};return i()},To=(e,t,r)=>{if(t.state==="Booted")return;Z(r([e.xcrun,"simctl","boot",t.udid]),"iOS simulator boot")},mt=(e,t,r)=>{let o=r([e.xcrun,"simctl","get_app_container",t,e.config.appId,"app"]);return o.exitCode===0&&o.stdout.trim()?o.stdout.trim():void 0},Po=(e,t,r)=>{let o=r([e.xcrun,"devicectl","device","info","details","--device",t]);if(o.exitCode!==0)throw Error(`Physical iOS device ${JSON.stringify(t)} is unavailable: ${o.stderr.trim()||o.stdout.trim()||"pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode."}`)},Do=(e,t,r)=>{let o=r([e.xcrun,"devicectl","device","info","apps","--device",t]);return o.exitCode===0&&o.stdout.includes(e.config.appId)},Co=async(e,t,r,o,n)=>{let s=S(e.projectRoot,".absolutejs","mobile","ios-derived-data",ft("sha256").update(e.config.appId).digest("hex").slice(0,16));await G(s,{recursive:!0}),await P([e.xcodebuild,"-workspace",S(e.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS Simulator,id=${t}`,"-derivedDataPath",s,"build"],"iOS simulator build",o,{cwd:e.nativeDirectory,signal:n});let i=S(s,"Build","Products","Debug-iphonesimulator","App.app");if(!await L(i))throw Error(`Xcode did not produce the simulator app at ${i}.`);return i},Ro=async(e,t,r,o)=>{let n=S(e.projectRoot,".absolutejs","mobile","ios-derived-data",ft("sha256").update(e.config.appId).digest("hex").slice(0,16));await G(n,{recursive:!0}),await P([e.xcodebuild,"-workspace",S(e.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS,id=${t}`,"-derivedDataPath",n,"-allowProvisioningUpdates","build"],"iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)",r,{cwd:e.nativeDirectory,signal:o});let s=S(n,"Build","Products","Debug-iphoneos","App.app");if(!await L(s))throw Error(`Xcode did not produce the physical-device app at ${s}.`);return s},No=async(e)=>{if(e.cache?.appId===e.project.config.appId&&e.cache.fingerprint===e.fingerprint&&e.cache.installations[e.identifier]===e.fingerprint&&Do(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 r=await Ro(e.project,e.identifier,e.run,e.signal);return W(e.signal),e.transition("installing"),await P([e.project.xcrun,"devicectl","device","install","app","--device",e.identifier,r],"iOS physical-device app installation",e.run,{signal:e.signal}),await Et(e.project.projectRoot,{appId:e.project.config.appId,fingerprint:e.fingerprint,format:Ie,installations:{...e.cache?.appId===e.project.config.appId?e.cache.installations:{},[e.identifier]:e.fingerprint}}).catch((o)=>e.log(`iOS native cache could not be saved: ${o instanceof Error?o.message:String(o)}`)),!1},Mo=async(e)=>{let t=mt(e.project,e.udid,e.capture);if(e.cache?.appId===e.project.config.appId&&e.cache.fingerprint===e.fingerprint&&t!==void 0&&e.cache.installations[e.udid]===t)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 o=await Co(e.project,e.udid,e.fingerprint,e.run,e.signal);W(e.signal),e.transition("installing"),await P([e.project.xcrun,"simctl","install",e.udid,o],"iOS simulator app installation",e.run,{signal:e.signal});let n=mt(e.project,e.udid,e.capture);if(n)await Et(e.project.projectRoot,{appId:e.project.config.appId,fingerprint:e.fingerprint,format:Ie,installations:{[e.udid]:n}}).catch((s)=>e.log(`iOS native cache could not be saved: ${s instanceof Error?s.message:String(s)}`));return!1},Lo=/((?:authorization|cookie|password|secret|token|oauth[_-]?code)\s*[:=]\s*)([^\s,;]+)/giu,Uo=new RegExp(String.raw`\bBearer\s+[A-Za-z0-9._~+/-]+=*`,"giu"),$o=/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu,ko=new RegExp(String.raw`\s(Debug|Info|Notice|Error|Fault)\s+.*?\[[^\]]+\]\s+\[([^\]]+)\]\s*(.*)$`,"iu"),jo=(e)=>{let t=Bo(e).trim();if(!t)return null;let r=ko.exec(t),o=r?.[1]?.toLowerCase();return{level:o==="debug"||o==="error"||o==="fault"||o==="notice"?o:"info",message:r?.[3]?.trim()||t,tag:r?.[2]?.trim()||"App"}},Bo=(e)=>e.replaceAll(Uo,"Bearer [REDACTED]").replaceAll($o,"[REDACTED_JWT]").replaceAll(Lo,"$1[REDACTED]").replaceAll(/\p{C}/gu,""),gt=(e,t,r)=>{if(!r.nativeLog)return null;let o=r.startNativeLogs??po,n=r.deviceIdentifier?[e.xcrun,"devicectl","device","process","launch","--console","--terminate-existing","--device",t,e.config.appId]:[e.xcrun,"simctl","spawn",t,"log","stream","--style","compact","--level","debug","--predicate",'process == "App"'];return o(n,{signal:r.signal},(s)=>{let i=jo(s);if(i)r.nativeLog?.(i)})},Ho=[["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"]],Fo=(e)=>Ho.map(([t,r])=>{let o=e[t];return o===void 0?null:`${r} ${q(o)}`}).filter((t)=>t!==null).join(", "),St=async(e,t)=>{if(se()!=="macos")throw Error("iOS development requires macOS and Xcode.");let r=t.target??"simulator",o=ce(t.projectRoot),n=await et({host:"macos"}),s=n.filter((m)=>m.platform==="ios"&&!(r==="device"&&m.id==="ios.runtime")&&(m.status==="fail"||m.status==="warn"));if(s.length>0)throw Error(`iOS ${r} development is not ready: ${s.map(({label:m})=>m).join(", ")}.`);let i=n.find((m)=>m.id==="ios.xcrun")?.path,l=n.find((m)=>m.id==="ios.xcodebuild")?.path;if(!i||!l)throw Error("Xcode tools disappeared after readiness checks.");let a=S(o,"node_modules",".bin","cap");if(!await L(a))throw Error("Capacitor CLI is not installed. Run absolute mobile init first.");await ot(e,{projectRoot:o}),await G(e.bundleDirectory,{recursive:!0});let c=S(e.bundleDirectory,"index.html");if(!await L(c))await B(c,`<!doctype html><title>AbsoluteJS mobile development</title>
427
- `);let g=S(e.nativeProjectDirectory,"ios");if(!await L(g)){if(!t.createNativeProject)throw Error("iOS native project has not been created.");if(await(t.run??ht)([a,"add","ios"],{cwd:o})!==0)throw Error("Capacitor iOS project creation failed.")}return{cap:a,config:e,nativeDirectory:g,projectRoot:o,xcodebuild:l,xcrun:i}},Wo=async(e)=>{if(e.transition("connecting"),Po(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 r=await(e.startOptions.startCaEnrollmentServer??re)({certificateAuthorityPath:e.startOptions.certificateAuthorityPath,displayHost:e.serverHost});return e.log(`On the iOS device, open ${r.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:r,startedSimulator:!1,udid:e.deviceIdentifier}},Go=async(e)=>{e.transition("booting");let t=await _o(e.project,e.capture),{device:r}=t,o=t.created||r.state!=="Booted";return To(e.project,r,e.capture),e.spawn(["open","-a","Simulator","--args","-CurrentDeviceUDID",r.udid]),e.transition("connecting"),await Oo(e.project,r.udid,e.capture,e.sleep,e.startOptions.signal),await P([e.project.xcrun,"simctl","bootstatus",r.udid,"-b"],"iOS simulator boot readiness",e.run,{signal:e.startOptions.signal}),await mo(e.startOptions,r.udid,e.run,e.log),{caEnrollmentServer:null,startedSimulator:o,udid:r.udid}},Oe=async(e)=>{let{project:t}=e,r=e.deviceIdentifier?je(e.deviceIdentifier):void 0,o=r?"device":"simulator",n=r?fe(e.serverHost??""):"localhost",s=e.capture??lo,i=e.run??ht,l=e.sleep??Bun.sleep,a=e.spawn??uo,c=e.log??console.log,g=performance.now(),m=performance.now(),b={},x="syncing",u=(h)=>{if(h===x){e.onStateChange?.(h);return}let C=performance.now(),H=C-m;b[x]=(b[x]??0)+H,e.onPhaseTiming?.({durationMs:H,phase:x,totalMs:C-g}),x=h,m=C,e.onStateChange?.(h)},p=null,f=null,_=async()=>{let h=p;p=null,await h?.close().catch(()=>{return})},A=async(h)=>{if(r&&e.nativeLog){await _(),p=gt(t,h,e);return}await P(ut(t,h,r!==void 0),"iOS app relaunch",i,{signal:e.signal})};try{if(await ie(t.projectRoot),W(e.signal),u("syncing"),await P([t.cap,"sync","ios"],"Capacitor iOS synchronization",i,{cwd:t.projectRoot,signal:e.signal}),u("configuring"),e.embeddedBundle!==!0)await So(t,e.port,e.https===!0,n);W(e.signal);let h=performance.now(),C=Io(t,{includePublicBundle:e.embeddedBundle===!0}).then((M)=>(b.fingerprinting=performance.now()-h,M)),H=r?await Wo({capture:s,deviceIdentifier:r,log:c,project:t,serverHost:n,startOptions:e,transition:u}):await Go({capture:s,log:c,project:t,run:i,sleep:l,spawn:a,startOptions:e,transition:u}),{caEnrollmentServer:Q,startedSimulator:pe,udid:d}=H;f=Q;let w=await C;u("checking-native");let y=await xo(t.projectRoot),T=r?await No({cache:y,capture:s,fingerprint:w,identifier:r,log:c,project:t,run:i,signal:e.signal,transition:u}):await Mo({cache:y,capture:s,fingerprint:w,log:c,project:t,run:i,signal:e.signal,transition:u,udid:d});if(W(e.signal),e.nativeLog)u("streaming-logs");if(p=gt(t,d,e),u("launching"),!r||!p)await P(ut(t,d,r!==void 0),"iOS app launch",i,{signal:e.signal});u("ready"),b.total=performance.now()-g,c(e.embeddedBundle===!0?`iOS ${o} connected with the embedded bundle and backend on port ${e.port} in ${q(b.total)} (${T?"native cache hit":"native build installed"}).`:`iOS ${o} connected with HMR on port ${e.port} in ${q(b.total)} (${T?"native cache hit":"native build installed"}).`),c(`iOS startup: ${Fo(b)}.`);let O=!1,N=async()=>{if(O)return;O=!0,u("closing"),await _(),await f?.close().catch(()=>{return}),f=null,await ie(t.projectRoot),u("closed")};return{close:N,nativeCacheHit:T,startedSimulator:pe,targetKind:o,timings:{...b},udid:d,rebuild:async()=>{if(O)throw Error("iOS development session is closed.");return c("iOS native inputs changed; rebuilding without restarting the dev server."),await N(),Oe(e)},relaunch:async()=>{if(O)throw Error("iOS development session is closed.");u("launching");try{await A(d),u("ready"),c(`iOS app relaunched on the selected ${o}.`)}catch(M){throw u("failed"),M}},screenshot:async(M)=>{if(r)throw Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");let U=ce(t.projectRoot,M);if(!Y(t.projectRoot,U))throw Error("iOS screenshot destination must remain inside the project.");return await G(bt(U),{recursive:!0}),await P([t.xcrun,"simctl","io",d,"screenshot",U],"iOS simulator screenshot",i,{signal:e.signal}),U},get state(){return x}}}catch(h){throw u("failed"),await _(),await f?.close().catch(()=>{return}),await ie(t.projectRoot),h}};var yt="ABSOLUTE_REMOTE_MAC\t",le=2;var E=(e)=>process.stdout.write(`${yt}${JSON.stringify({...e,v:le})}
428
- `),de=(e)=>e instanceof Error?e.message:String(e),J=(e,t)=>{let r=e.indexOf(t);return r<0?void 0:e[r+1]},Xo=(e)=>{let t=Number(J(e,"--port"));if(!Number.isInteger(t)||t<1||t>65535)throw TypeError("Remote iOS agent requires a valid --port.");return t},Pe=(e,t)=>{let r=J(e,t);if(r===void 0)return;let o=Number(r);if(!Number.isInteger(o)||o<1||o>65535)throw TypeError(`Remote iOS agent requires a valid ${t}.`);return o},qo=(e)=>{let t=J(e,"--mobile-config");if(!t)throw TypeError("Remote iOS agent requires --mobile-config.");let r=JSON.parse(Buffer.from(t,"base64url").toString("utf8"));if(typeof r!=="object"||r===null)throw TypeError("Remote iOS agent received an invalid mobile config.");return r},xt=async(e,t)=>{let r=e.getReader(),o=new TextDecoder,n="";try{while(!0){let{done:s,value:i}=await r.read();if(s)break;n+=o.decode(i,{stream:!0});let l=n.split(/\r?\n/u);n=l.pop()??"",l.forEach(t)}}finally{r.releaseLock()}},De=async(e,t={})=>{let r=Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return xt(r.stdout,(o)=>E({message:o,type:"log"})),xt(r.stderr,(o)=>E({message:o,type:"log"})),r.exited},Ko=(e,t={})=>{try{let r=Bun.spawnSync(e,{cwd:t.cwd,env:t.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:r.exitCode,stderr:r.stderr.toString(),stdout:r.stdout.toString()}}catch(r){return{exitCode:1,stderr:de(r),stdout:""}}},It=(e)=>({engine:"capacitor",nativeCacheHit:e.nativeCacheHit,startedSimulator:e.startedSimulator,targetKind:e.targetKind,timings:e.timings,type:"ready",udid:e.udid}),Yo=async(e)=>{if(e.config.engine!=="expo")throw TypeError("The remote Expo executor requires Expo configuration.");let t=Pe(e.args,"--metro-port");if(t===void 0)throw TypeError("Remote Expo execution requires --metro-port.");let r=Pe(e.args,"--metro-relay-port");if(e.deviceIdentifier&&r===void 0)throw TypeError("Remote physical Expo execution requires --metro-relay-port.");let o=await qe(e.config,{projectRoot:process.cwd()}),n=await Bun.file(ue(o.path,"node_modules","expo","package.json")).exists();if(!n){E({state:"preparing-native",type:"state"});let a=performance.now(),c=await De([process.execPath,"install"],{cwd:o.path});if(c!==0)throw Error(`Remote Expo dependency installation exited with status ${c}.`);E({durationMs:performance.now()-a,phase:"preparing-native",type:"timing"})}let s,i,l;try{s=e.deviceIdentifier?await oe({listenPort:e.port,targetPort:e.relayPort??0}):void 0,i=e.deviceIdentifier?await oe({listenPort:t,targetPort:r??0}):void 0,l=await Be({certificateAuthorityPath:e.certificateAuthorityPath,config:e.config,executable:await Ae(o.path),iosDevice:e.deviceIdentifier,iosOrigin:`${e.args.includes("--https")?"https":"http"}://${e.serverHost??"localhost"}:${e.port}`,metro:"external",metroHost:e.serverHost??"localhost",metroPort:t,platforms:["ios"],log:(c)=>E({message:c,type:"log"}),onPhaseTiming:(c)=>E({...c,type:"timing"}),onStateChange:(c)=>E({state:c,type:"state"})}),E({engine:"expo",nativeCacheHit:n,startedSimulator:!1,targetKind:e.deviceIdentifier?"device":"simulator",timings:l.timings,type:"ready",udid:e.deviceIdentifier??"booted"});let a=_t({input:process.stdin,terminal:!1});try{for await(let c of a){let g;try{if(g=JSON.parse(c),g.v!==le||typeof g.id!=="string"||g.command!=="close")throw Error("Invalid remote Expo request.");await l.close(),E({id:g.id,ok:!0,type:"response"});return}catch(m){E({error:de(m),id:g?.id??"",ok:!1,type:"response"})}}}finally{a.close()}}finally{await l?.close().catch(()=>{return}),await Promise.all([s?.close().catch(()=>{return}),i?.close().catch(()=>{return})])}},Zo=async(e)=>{if(process.platform!=="darwin")throw Error("The AbsoluteJS remote iOS agent can run only on macOS.");let t=process.cwd(),r=Ue(qo(e),t),o=Xo(e),n=J(e,"--ios-device"),s=J(e,"--server-host"),i=Pe(e,"--relay-port");if(n&&(!s||i===void 0))throw TypeError("Remote physical iOS development requires --server-host and --relay-port.");let l=J(e,"--certificate-authority"),a=l?ue(t,".absolutejs","mobile",`remote-dev-ca-${process.pid}.pem`):void 0;if(a&&l)await Jo(ue(t,".absolutejs","mobile"),{recursive:!0}),await zo(a,Buffer.from(l,"base64url"));if(r.engine==="expo"){try{await Yo({args:e,certificateAuthorityPath:a,config:r,deviceIdentifier:n,port:o,relayPort:i,serverHost:s})}finally{if(a)await Te(a,{force:!0})}return}let c=await St(r,{createNativeProject:!1,projectRoot:t,run:De,target:n?"device":"simulator"}),g=n?await oe({listenPort:o,targetPort:i??0}):void 0,m={capture:Ko,certificateAuthorityPath:a,deviceIdentifier:n,https:e.includes("--https"),port:o,project:c,run:De,serverHost:s,log:(u)=>E({message:u,type:"log"}),nativeLog:(u)=>E({entry:u,type:"native-log"}),onPhaseTiming:(u)=>E({...u,type:"timing"}),onStateChange:(u)=>E({state:u,type:"state"}),spawn:(u,p={})=>{Bun.spawn(u,{cwd:p.cwd,env:p.env,signal:p.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})}},b;try{b=await Oe(m)}catch(u){if(await g?.close().catch(()=>{return}),a)await Te(a,{force:!0});throw u}E(It(b));let x=_t({input:process.stdin,terminal:!1});try{for await(let u of x){let p;try{if(p=JSON.parse(u),p.v!==le||typeof p.id!=="string")throw Error("Invalid remote Mac request.");let f;if(p.command==="close")await b.close();else if(p.command==="relaunch")await b.relaunch();else if(p.command==="rebuild")b=await b.rebuild(),f=It(b);else if(p.command==="screenshot"){let _=ue(".absolutejs","mobile","remote-screenshot.png"),A=await b.screenshot(_);f={data:(await Vo(A)).toString("base64")}}else throw Error("Unknown remote Mac request.");if(E({id:p.id,ok:!0,result:f,type:"response"}),p.command==="close")return}catch(f){E({error:de(f),id:p?.id??"",ok:!1,type:"response"})}}}finally{if(x.close(),await b.close().catch(()=>{return}),await g?.close().catch(()=>{return}),a)await Te(a,{force:!0})}},Ot=async(e)=>{try{await Zo(e)}catch(t){E({error:de(t),type:"fatal"}),process.exitCode=1}};await Ot(process.argv.slice(2));
535
+ </dict>`)},io=async(e,t,n,r="localhost")=>{let o=qt(e.projectRoot);await he(e.projectRoot);let s=O(e.nativeDirectory,"App","App","capacitor.config.json"),i=O(e.nativeDirectory,"App","App","Info.plist"),[l,a]=await Promise.all([ye(s,"utf8"),ye(i,"utf8")]),c=JSON.parse(l);if(!k(c))throw Error(`Invalid Capacitor native config at ${s}.`);await ee(o.root,{recursive:!0}),await Promise.all([z(o.configBackup,l,{flag:"wx"}),z(o.infoBackup,a,{flag:"wx"})]);let h={configBackupPath:o.configBackup,format:ke,infoBackupPath:o.infoBackup,infoPath:i,nativeConfigPath:s};await z(o.journal,`${JSON.stringify(h,null,"\t")}
536
+ `,{flag:"wx"});let d=new URL(`${n?"https":"http"}://localhost:${t}${e.config.entry}`);d.hostname=Fr(r)===6?`[${r}]`:r,d.searchParams.set("__absolute_target","capacitor-ios");let u=c.server;c.server={...k(u)?u:{},cleartext:!n,url:d.href},await Promise.all([z(s,`${JSON.stringify(c,null,"\t")}
537
+ `),z(i,so(a,!n))])},ao=(e)=>{if(!k(e))return null;let{appId:t,fingerprint:n,format:r,installations:o}=e;if(r!==Le||typeof t!=="string"||typeof n!=="string"||!k(o)||!Object.values(o).every((s)=>typeof s==="string"))return null;return{appId:t,fingerprint:n,format:r,installations:Object.fromEntries(Object.entries(o).map(([s,i])=>[s,String(i)]))}},co=(e)=>ye(Gt(e),"utf8").then((t)=>ao(JSON.parse(t))).catch(()=>null),zt=async(e,t)=>{let n=Gt(e),r=`${n}.${process.pid}.${Br()}.tmp`;await ee(Jt(n),{recursive:!0});try{await z(r,`${JSON.stringify(t,null,"\t")}
538
+ `,{flag:"wx"}),await Vr(r,n)}finally{await Me(r,{force:!0}).catch(()=>{return})}},lo=async(e,t={})=>Mt(e.nativeDirectory,t),Kt=(e,t)=>{let n=t([e,"simctl","list","devices","available","-j"]);return eo(ce(n,"iOS simulator discovery"))},uo=async(e,t)=>{let n=Qr(ce(t([e.xcrun,"simctl","list","runtimes","-j"]),"iOS runtime discovery")),r=no(n);if(!r)throw Error("No available iOS Simulator runtime. Run absolute mobile doctor ios --fix.");let[o]=Kt(e.xcrun,t).filter((a)=>a.isAvailable&&a.name===Ne&&a.runtime===r.identifier).sort((a,c)=>Number(c.state==="Booted")-Number(a.state==="Booted"));if(o)return{created:!1,device:o};let s=Zr(ce(t([e.xcrun,"simctl","list","devicetypes","-j"]),"iOS device-type discovery")),i=ro(s);if(!i)throw Error("Xcode did not report an iPhone simulator type.");let[l]=ce(t([e.xcrun,"simctl","create",Ne,i.identifier,r.identifier]),"iOS simulator creation").split(/\s/u);if(!l)throw Error("simctl did not return the created simulator UDID.");return{created:!0,device:{isAvailable:!0,name:Ne,runtime:r.identifier,state:"Shutdown",udid:l}}},po=async(e,t,n,r,o)=>{let s=Date.now()+Lt,i=async()=>{if(Q(o),Kt(e.xcrun,n).find((a)=>a.udid===t)?.state==="Booted")return;if(Date.now()>s)throw Error(`iOS simulator ${t} did not finish booting within ${Lt/1000}s.`);await r(Gr),await i()};return i()},mo=(e,t,n)=>{if(t.state==="Booted")return;ce(n([e.xcrun,"simctl","boot",t.udid]),"iOS simulator boot")},Ht=(e,t,n)=>{let r=n([e.xcrun,"simctl","get_app_container",t,e.config.appId,"app"]);return r.exitCode===0&&r.stdout.trim()?r.stdout.trim():void 0},fo=(e,t,n)=>{let r=n([e.xcrun,"devicectl","device","info","details","--device",t]);if(r.exitCode!==0)throw Error(`Physical iOS device ${JSON.stringify(t)} is unavailable: ${r.stderr.trim()||r.stdout.trim()||"pair it in Xcode Device Hub, trust this Mac, unlock it, and enable Developer Mode."}`)},go=(e,t,n)=>{let r=n([e.xcrun,"devicectl","device","info","apps","--device",t]);return r.exitCode===0&&r.stdout.includes(e.config.appId)},ho=async(e,t,n,r,o)=>{let s=O(e.projectRoot,".absolutejs","mobile","ios-derived-data",Ft("sha256").update(e.config.appId).digest("hex").slice(0,16));await ee(s,{recursive:!0}),await M([e.xcodebuild,"-workspace",O(e.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS Simulator,id=${t}`,"-derivedDataPath",s,"build"],"iOS simulator build",r,{cwd:e.nativeDirectory,signal:o});let i=O(s,"Build","Products","Debug-iphonesimulator","App.app");if(!await F(i))throw Error(`Xcode did not produce the simulator app at ${i}.`);return i},yo=async(e,t,n,r)=>{let o=O(e.projectRoot,".absolutejs","mobile","ios-derived-data",Ft("sha256").update(e.config.appId).digest("hex").slice(0,16));await ee(o,{recursive:!0}),await M([e.xcodebuild,"-workspace",O(e.nativeDirectory,"App","App.xcworkspace"),"-scheme","App","-configuration","Debug","-destination",`platform=iOS,id=${t}`,"-derivedDataPath",o,"-allowProvisioningUpdates","build"],"iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)",n,{cwd:e.nativeDirectory,signal:r});let s=O(o,"Build","Products","Debug-iphoneos","App.app");if(!await F(s))throw Error(`Xcode did not produce the physical-device app at ${s}.`);return s},bo=async(e)=>{if(e.cache?.appId===e.project.config.appId&&e.cache.fingerprint===e.fingerprint&&e.cache.installations[e.identifier]===e.fingerprint&&go(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 n=await yo(e.project,e.identifier,e.run,e.signal);return Q(e.signal),e.transition("installing"),await M([e.project.xcrun,"devicectl","device","install","app","--device",e.identifier,n],"iOS physical-device app installation",e.run,{signal:e.signal}),await zt(e.project.projectRoot,{appId:e.project.config.appId,fingerprint:e.fingerprint,format:Le,installations:{...e.cache?.appId===e.project.config.appId?e.cache.installations:{},[e.identifier]:e.fingerprint}}).catch((r)=>e.log(`iOS native cache could not be saved: ${r instanceof Error?r.message:String(r)}`)),!1},wo=async(e)=>{let t=Ht(e.project,e.udid,e.capture);if(e.cache?.appId===e.project.config.appId&&e.cache.fingerprint===e.fingerprint&&t!==void 0&&e.cache.installations[e.udid]===t)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 r=await ho(e.project,e.udid,e.fingerprint,e.run,e.signal);Q(e.signal),e.transition("installing"),await M([e.project.xcrun,"simctl","install",e.udid,r],"iOS simulator app installation",e.run,{signal:e.signal});let o=Ht(e.project,e.udid,e.capture);if(o)await zt(e.project.projectRoot,{appId:e.project.config.appId,fingerprint:e.fingerprint,format:Le,installations:{[e.udid]:o}}).catch((s)=>e.log(`iOS native cache could not be saved: ${s instanceof Error?s.message:String(s)}`));return!1},vo=/((?:authorization|cookie|password|secret|token|oauth[_-]?code)\s*[:=]\s*)([^\s,;]+)/giu,Ao=new RegExp(String.raw`\bBearer\s+[A-Za-z0-9._~+/-]+=*`,"giu"),So=/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu,Eo=new RegExp(String.raw`\s(Debug|Info|Notice|Error|Fault)\s+.*?\[[^\]]+\]\s+\[([^\]]+)\]\s*(.*)$`,"iu"),xo=(e)=>{let t=Io(e).trim();if(!t)return null;let n=Eo.exec(t),r=n?.[1]?.toLowerCase();return{level:r==="debug"||r==="error"||r==="fault"||r==="notice"?r:"info",message:n?.[3]?.trim()||t,tag:n?.[2]?.trim()||"App"}},Io=(e)=>e.replaceAll(Ao,"Bearer [REDACTED]").replaceAll(So,"[REDACTED_JWT]").replaceAll(vo,"$1[REDACTED]").replaceAll(/\p{C}/gu,""),Vt=(e,t,n)=>{if(!n.nativeLog)return null;let r=n.startNativeLogs??Xr,o=n.deviceIdentifier?[e.xcrun,"devicectl","device","process","launch","--console","--terminate-existing","--device",t,e.config.appId]:[e.xcrun,"simctl","spawn",t,"log","stream","--style","compact","--level","debug","--predicate",'process == "App"'];return r(o,{signal:n.signal},(s)=>{let i=xo(s);if(i)n.nativeLog?.(i)})},Oo=[["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"]],_o=(e)=>Oo.map(([t,n])=>{let r=e[t];return r===void 0?null:`${n} ${se(r)}`}).filter((t)=>t!==null).join(", "),Xt=async(e,t)=>{if(ge()!=="macos")throw Error("iOS development requires macOS and Xcode.");let n=t.target??"simulator",r=be(t.projectRoot),o=await Tt({host:"macos"}),s=o.filter((d)=>d.platform==="ios"&&!(n==="device"&&d.id==="ios.runtime")&&(d.status==="fail"||d.status==="warn"));if(s.length>0)throw Error(`iOS ${n} development is not ready: ${s.map(({label:d})=>d).join(", ")}.`);let i=o.find((d)=>d.id==="ios.xcrun")?.path,l=o.find((d)=>d.id==="ios.xcodebuild")?.path;if(!i||!l)throw Error("Xcode tools disappeared after readiness checks.");let a=O(r,"node_modules",".bin","cap");if(!await F(a))throw Error("Capacitor CLI is not installed. Run absolute mobile init first.");await Dt(e,{projectRoot:r}),await ee(e.bundleDirectory,{recursive:!0});let c=O(e.bundleDirectory,"index.html");if(!await F(c))await z(c,`<!doctype html><title>AbsoluteJS mobile development</title>
539
+ `);let h=O(e.nativeProjectDirectory,"ios");if(!await F(h)){if(!t.createNativeProject)throw Error("iOS native project has not been created.");if(await(t.run??Wt)([a,"add","ios"],{cwd:r})!==0)throw Error("Capacitor iOS project creation failed.")}return{cap:a,config:e,nativeDirectory:h,projectRoot:r,xcodebuild:l,xcrun:i}},To=async(e)=>{if(e.transition("connecting"),fo(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 n=await(e.startOptions.startCaEnrollmentServer??ue)({certificateAuthorityPath:e.startOptions.certificateAuthorityPath,displayHost:e.serverHost});return e.log(`On the iOS device, open ${n.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:n,startedSimulator:!1,udid:e.deviceIdentifier}},Po=async(e)=>{e.transition("booting");let t=await uo(e.project,e.capture),{device:n}=t,r=t.created||n.state!=="Booted";return mo(e.project,n,e.capture),e.spawn(["open","-a","Simulator","--args","-CurrentDeviceUDID",n.udid]),e.transition("connecting"),await po(e.project,n.udid,e.capture,e.sleep,e.startOptions.signal),await M([e.project.xcrun,"simctl","bootstatus",n.udid,"-b"],"iOS simulator boot readiness",e.run,{signal:e.startOptions.signal}),await Yr(e.startOptions,n.udid,e.run,e.log),{caEnrollmentServer:null,startedSimulator:r,udid:n.udid}},je=async(e)=>{let{project:t}=e,n=e.deviceIdentifier?Xe(e.deviceIdentifier):void 0,r=n?"device":"simulator",o=n?xe(e.serverHost??""):"localhost",s=e.capture??zr,i=e.run??Wt,l=e.sleep??Bun.sleep,a=e.spawn??Kr,c=e.log??console.log,h=performance.now(),d=performance.now(),u={},S="syncing",f=(b)=>{if(b===S){e.onStateChange?.(b);return}let E=performance.now(),_=E-d;u[S]=(u[S]??0)+_,e.onPhaseTiming?.({durationMs:_,phase:S,totalMs:E-h}),S=b,d=E,e.onStateChange?.(b)},g=null,p=null,w=async()=>{let b=g;g=null,await b?.close().catch(()=>{return})},y=async(b)=>{if(n&&e.nativeLog){await w(),g=Vt(t,b,e);return}await M(jt(t,b,n!==void 0),"iOS app relaunch",i,{signal:e.signal})};try{if(await he(t.projectRoot),Q(e.signal),f("syncing"),await M([t.cap,"sync","ios"],"Capacitor iOS synchronization",i,{cwd:t.projectRoot,signal:e.signal}),f("configuring"),e.embeddedBundle!==!0)await io(t,e.port,e.https===!0,o);Q(e.signal);let b=performance.now(),E=lo(t,{includePublicBundle:e.embeddedBundle===!0}).then((V)=>(u.fingerprinting=performance.now()-b,V)),_=n?await To({capture:s,deviceIdentifier:n,log:c,project:t,serverHost:o,startOptions:e,transition:f}):await Po({capture:s,log:c,project:t,run:i,sleep:l,spawn:a,startOptions:e,transition:f}),{caEnrollmentServer:L,startedSimulator:j,udid:m}=_;p=L;let A=await E;f("checking-native");let T=await co(t.projectRoot),N=n?await bo({cache:T,capture:s,fingerprint:A,identifier:n,log:c,project:t,run:i,signal:e.signal,transition:f}):await wo({cache:T,capture:s,fingerprint:A,log:c,project:t,run:i,signal:e.signal,transition:f,udid:m});if(Q(e.signal),e.nativeLog)f("streaming-logs");if(g=Vt(t,m,e),f("launching"),!n||!g)await M(jt(t,m,n!==void 0),"iOS app launch",i,{signal:e.signal});f("ready"),u.total=performance.now()-h,c(e.embeddedBundle===!0?`iOS ${r} connected with the embedded bundle and backend on port ${e.port} in ${se(u.total)} (${N?"native cache hit":"native build installed"}).`:`iOS ${r} connected with HMR on port ${e.port} in ${se(u.total)} (${N?"native cache hit":"native build installed"}).`),c(`iOS startup: ${_o(u)}.`);let D=!1,H=async()=>{if(D)return;D=!0,f("closing"),await w(),await p?.close().catch(()=>{return}),p=null,await he(t.projectRoot),f("closed")};return{close:H,nativeCacheHit:N,startedSimulator:j,targetKind:r,timings:{...u},udid:m,rebuild:async()=>{if(D)throw Error("iOS development session is closed.");return c("iOS native inputs changed; rebuilding without restarting the dev server."),await H(),je(e)},relaunch:async()=>{if(D)throw Error("iOS development session is closed.");f("launching");try{await y(m),f("ready"),c(`iOS app relaunched on the selected ${r}.`)}catch(V){throw f("failed"),V}},screenshot:async(V)=>{if(n)throw Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");let J=be(t.projectRoot,V);if(!ae(t.projectRoot,J))throw Error("iOS screenshot destination must remain inside the project.");return await ee(Jt(J),{recursive:!0}),await M([t.xcrun,"simctl","io",m,"screenshot",J],"iOS simulator screenshot",i,{signal:e.signal}),J},get state(){return S}}}catch(b){throw f("failed"),await w(),await p?.close().catch(()=>{return}),await he(t.projectRoot),b}};var Yt="ABSOLUTE_REMOTE_MAC\t",we=2;var I=(e)=>process.stdout.write(`${Yt}${JSON.stringify({...e,v:we})}
540
+ `),Ae=(e)=>e instanceof Error?e.message:String(e),te=(e,t)=>{let n=e.indexOf(t);return n<0?void 0:e[n+1]},No=(e)=>{let t=Number(te(e,"--port"));if(!Number.isInteger(t)||t<1||t>65535)throw TypeError("Remote iOS agent requires a valid --port.");return t},Be=(e,t)=>{let n=te(e,t);if(n===void 0)return;let r=Number(n);if(!Number.isInteger(r)||r<1||r>65535)throw TypeError(`Remote iOS agent requires a valid ${t}.`);return r},Mo=(e)=>{let t=te(e,"--mobile-config");if(!t)throw TypeError("Remote iOS agent requires --mobile-config.");let n=JSON.parse(Buffer.from(t,"base64url").toString("utf8"));if(typeof n!=="object"||n===null)throw TypeError("Remote iOS agent received an invalid mobile config.");return n},Zt=async(e,t)=>{let n=e.getReader(),r=new TextDecoder,o="";try{while(!0){let{done:s,value:i}=await n.read();if(s)break;o+=r.decode(i,{stream:!0});let l=o.split(/\r?\n/u);o=l.pop()??"",l.forEach(t)}}finally{n.releaseLock()}},He=async(e,t={})=>{let n=Bun.spawn(e,{cwd:t.cwd,env:t.env,signal:t.signal,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return Zt(n.stdout,(r)=>I({message:r,type:"log"})),Zt(n.stderr,(r)=>I({message:r,type:"log"})),n.exited},ko=(e,t={})=>{try{let n=Bun.spawnSync(e,{cwd:t.cwd,env:t.env,stderr:"pipe",stdin:"ignore",stdout:"pipe"});return{exitCode:n.exitCode,stderr:n.stderr.toString(),stdout:n.stdout.toString()}}catch(n){return{exitCode:1,stderr:Ae(n),stdout:""}}},Qt=(e)=>({engine:"capacitor",nativeCacheHit:e.nativeCacheHit,startedSimulator:e.startedSimulator,targetKind:e.targetKind,timings:e.timings,type:"ready",udid:e.udid}),Lo=async(e)=>{if(e.config.engine!=="expo")throw TypeError("The remote Expo executor requires Expo configuration.");let t=Be(e.args,"--metro-port");if(t===void 0)throw TypeError("Remote Expo execution requires --metro-port.");let n=Be(e.args,"--metro-relay-port");if(e.deviceIdentifier&&n===void 0)throw TypeError("Remote physical Expo execution requires --metro-relay-port.");let r=await Et(e.config,{projectRoot:process.cwd()}),o=await Bun.file(ve(r.path,"node_modules","expo","package.json")).exists();if(!o){I({state:"preparing-native",type:"state"});let a=performance.now(),c=await He([process.execPath,"install"],{cwd:r.path});if(c!==0)throw Error(`Remote Expo dependency installation exited with status ${c}.`);I({durationMs:performance.now()-a,phase:"preparing-native",type:"timing"})}let s,i,l;try{s=e.deviceIdentifier?await pe({listenPort:e.port,targetPort:e.relayPort??0}):void 0,i=e.deviceIdentifier?await pe({listenPort:t,targetPort:n??0}):void 0,l=await Ye({certificateAuthorityPath:e.certificateAuthorityPath,config:e.config,executable:await _e(r.path),iosDevice:e.deviceIdentifier,iosOrigin:`${e.args.includes("--https")?"https":"http"}://${e.serverHost??"localhost"}:${e.port}`,metro:"external",metroHost:e.serverHost??"localhost",metroPort:t,platforms:["ios"],log:(c)=>I({message:c,type:"log"}),onPhaseTiming:(c)=>I({...c,type:"timing"}),onStateChange:(c)=>I({state:c,type:"state"})}),I({engine:"expo",nativeCacheHit:o,startedSimulator:!1,targetKind:e.deviceIdentifier?"device":"simulator",timings:l.timings,type:"ready",udid:e.deviceIdentifier??"booted"});let a=en({input:process.stdin,terminal:!1});try{for await(let c of a){let h;try{if(h=JSON.parse(c),h.v!==we||typeof h.id!=="string"||h.command!=="close")throw Error("Invalid remote Expo request.");await l.close(),I({id:h.id,ok:!0,type:"response"});return}catch(d){I({error:Ae(d),id:h?.id??"",ok:!1,type:"response"})}}}finally{a.close()}}finally{await l?.close().catch(()=>{return}),await Promise.all([s?.close().catch(()=>{return}),i?.close().catch(()=>{return})])}},$o=async(e)=>{if(process.platform!=="darwin")throw Error("The AbsoluteJS remote iOS agent can run only on macOS.");let t=process.cwd(),n=Ge(Mo(e),t),r=No(e),o=te(e,"--ios-device"),s=te(e,"--server-host"),i=Be(e,"--relay-port");if(o&&(!s||i===void 0))throw TypeError("Remote physical iOS development requires --server-host and --relay-port.");let l=te(e,"--certificate-authority"),a=l?ve(t,".absolutejs","mobile",`remote-dev-ca-${process.pid}.pem`):void 0;if(a&&l)await Co(ve(t,".absolutejs","mobile"),{recursive:!0}),await Ro(a,Buffer.from(l,"base64url"));if(n.engine==="expo"){try{await Lo({args:e,certificateAuthorityPath:a,config:n,deviceIdentifier:o,port:r,relayPort:i,serverHost:s})}finally{if(a)await Ue(a,{force:!0})}return}let c=await Xt(n,{createNativeProject:!1,projectRoot:t,run:He,target:o?"device":"simulator"}),h=o?await pe({listenPort:r,targetPort:i??0}):void 0,d={capture:ko,certificateAuthorityPath:a,deviceIdentifier:o,https:e.includes("--https"),port:r,project:c,run:He,serverHost:s,log:(f)=>I({message:f,type:"log"}),nativeLog:(f)=>I({entry:f,type:"native-log"}),onPhaseTiming:(f)=>I({...f,type:"timing"}),onStateChange:(f)=>I({state:f,type:"state"}),spawn:(f,g={})=>{Bun.spawn(f,{cwd:g.cwd,env:g.env,signal:g.signal,stderr:"ignore",stdin:"ignore",stdout:"ignore"})}},u;try{u=await je(d)}catch(f){if(await h?.close().catch(()=>{return}),a)await Ue(a,{force:!0});throw f}I(Qt(u));let S=en({input:process.stdin,terminal:!1});try{for await(let f of S){let g;try{if(g=JSON.parse(f),g.v!==we||typeof g.id!=="string")throw Error("Invalid remote Mac request.");let p;if(g.command==="close")await u.close();else if(g.command==="relaunch")await u.relaunch();else if(g.command==="rebuild")u=await u.rebuild(),p=Qt(u);else if(g.command==="screenshot"){let w=ve(".absolutejs","mobile","remote-screenshot.png"),y=await u.screenshot(w);p={data:(await Do(y)).toString("base64")}}else throw Error("Unknown remote Mac request.");if(I({id:g.id,ok:!0,result:p,type:"response"}),g.command==="close")return}catch(p){I({error:Ae(p),id:g?.id??"",ok:!1,type:"response"})}}}finally{if(S.close(),await u.close().catch(()=>{return}),await h?.close().catch(()=>{return}),a)await Ue(a,{force:!0})}},tn=async(e)=>{try{await $o(e)}catch(t){I({error:Ae(t),type:"fatal"}),process.exitCode=1}};await tn(process.argv.slice(2));