@radhya/mach 2.1.8 → 2.1.9

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.
@@ -5,10 +5,10 @@ ${o.stderr||""}`);if(d.length>0)return Wt(t,d,"Select the App Store Connect prov
5
5
  1. Open: ${ne.cyan(f)}
6
6
  `+(n==="ios"?`2. Generate an "App Store Connect API Key" with ${ne.bold("Admin")} role.
7
7
  3. Download the ${ne.bold(".p8")} file.`:`2. Create a "Service Account", generate a ${ne.bold("JSON")} key.
8
- 3. Download the ${ne.bold(".json")} file.`),"Guided Setup"),t.start("Scanning for downloaded keys...");let I=lr(n);if(t.stop(I.length>0?`Detected ${I.length} potential key(s)`:"No keys detected automatically"),I.length>0){let g=await Qe({message:"Found these potential keys. Use one of them?",options:[...I.map(h=>({value:h.path,label:`${ge.basename(h.path)} (${h.location})`})),{value:"manual",label:"Enter path manually..."}]});if(le(g)){Ee("Operation cancelled");return}g!=="manual"&&(a=g)}if(!a){let g=await xe({message:`Paste the path to your ${n==="ios"?".p8":".json"} file:`,validate:h=>se.existsSync(h)?void 0:"File not found"});if(le(g)){Ee("Operation cancelled");return}a=g}}let l=e.issuerId,p=e.keyId;if(n==="ios"){if(!p&&a){let f=ge.basename(a).match(/AuthKey_(.*)\.p8/);f&&(p=f[1],ee.info(`Auto-detected Key ID from filename: ${ne.green(p)}`))}if(!l){let f=await xe({message:"Enter App Store Connect Issuer ID (Found on the Keys page):",validate:I=>I.length>0?void 0:"Issuer ID is required"});if(le(f)){Ee("Operation cancelled");return}l=f}if(!p){let f=await xe({message:"Enter App Store Connect Key ID:",validate:I=>I.length>0?void 0:"Key ID is required"});if(le(f)){Ee("Operation cancelled");return}p=f}}if(n==="android"&&(!c||c==="*")){let f=await Pn();if(f===null)return;c=f}let d=n==="ios"?ze(r,s):{};await Zt(o,a,n,l,p,c,{...d})};async function rr(e,t,n){let i=await or(e),r=sr(t,n);if(r&&!i.includes(r)&&i.unshift(r),i.length>0){let o=await Qe({message:"Select Android package for this Google Play service key:",options:[...i.map(s=>({value:s,label:s,hint:s===r?"from config":void 0})),{value:"manual",label:"Enter another package name..."}]});if(le(o))return Ee("Operation cancelled"),null;if(o==="manual")return Pn();if(o!=="manual")return o}if(r){let o=await Cn({message:`Use Android package from local config (${r})?`,initialValue:!0});if(le(o))return Ee("Operation cancelled"),null;if(o)return r}}async function Pn(){let e=await xe({message:"Android package name for this Google Play service key:",placeholder:"com.example.app",validate:t=>t.includes(".")?void 0:"Enter a valid package name"});return le(e)?(Ee("Operation cancelled"),null):e}async function or(e){try{let n=(await Z.get(`/credentials/${e}`)).data.credentials||[],i=new Set;for(let r of n)(r.platform==="android"||r.type==="android_keystore"||r.type==="google_service_account")&&r.bundleId&&r.bundleId!=="*"&&i.add(r.bundleId);return Array.from(i).sort()}catch(t){return ee.warn(ne.yellow(`Could not fetch saved Android package identifiers: ${t.message}`)),[]}}function sr(e,t){let n=Je(e,t);if(n)return n;let i=ge.join(process.cwd(),"app.json");if(se.existsSync(i))try{return JSON.parse(se.readFileSync(i,"utf-8")).expo?.android?.package}catch{}let r=ge.join(process.cwd(),"app.config.json");if(se.existsSync(r))try{let o=JSON.parse(se.readFileSync(r,"utf-8"));return o.expo?.android?.package||o.android?.package}catch{}}async function ar(e,t){let n=lt(),i=t.submit?.production?.ios?.appleId,r=ze(t).teamId,o=Sn(t);if(!i){let c=await xe({message:"Apple ID:",placeholder:"your-email@example.com"});if(le(c))return;i=c}if(!r){let c=await at({appleId:i,config:t,profile:"production",initialTeam:ze(t),promptToPersistConfig:!0});if(!c?.teamId)return;r=c.teamId}let s=await xe({message:"Enter a name for the new API Key:",initialValue:`[${A.name}] Project ${e}`});if(le(s))return;let a=Dt();if(!se.existsSync(a)){ee.error(`Magic Error: Helper script not found at ${a}`);return}try{let c=await ir(a,t,i,r);if(c===null)return;let l;if(c)l=c,o=c.id;else if(!o)return;n.start("Creating App Store Connect API Key...");let p=x=>ct("ruby",[a,"create",s],{env:wn(i,r,x),stdio:["inherit","pipe","pipe"],encoding:"utf-8"}),d=p(o),f=d.stdout||"",I=d.stderr||"";if(d.status!==0){let x=Gt(`${f}
9
- ${I}`);if(x.length>0){n.stop("Select App Store Connect team"),bt(`Apple Developer Team IDs look like ${ne.bold(r)}.
10
- App Store Connect API keys use a numeric provider/team ID instead.`,"Team ID mismatch");let F=await Wt(t,x,"Select the App Store Connect provider for this API key:");if(!F)return;l=F,o=F.id,n.start("Creating API Key with selected App Store Connect team..."),d=p(o),f=d.stdout||"",I=d.stderr||""}}if(I&&(I.includes("DEBUG:")||I.includes("ERROR:"))&&I.split(`
11
- `).forEach(x=>{x.trim()&&ee.info(ne.dim(`[Ruby] ${x.trim()}`))}),d.status!==0){n.stop("Failed"),ee.error(`Magic creation failed: ${I}`);return}let g=f.match(new RegExp(`${A.jsonStartMarker}(.*)${A.jsonEndMarker}`));if(!g){n.stop("Parse Error"),ee.error("Could not parse response from Apple Portal.");return}let h=JSON.parse(g[1]),{id:w,issuerId:_,keyContent:C}=h,v=ze(t,"production",{teamId:r,teamName:l?.developerTeamName,developerTeamId:r,appStoreConnectTeamId:o,providerId:o,providerName:l?.name});if(n.stop("Key Created Successfully"),ee.success(`\u2713 Created Key ID: ${ne.green(w)}`),!_){bt(`Your Issuer ID is shown at the top of:
8
+ 3. Download the ${ne.bold(".json")} file.`),"Guided Setup"),t.start("Scanning for downloaded keys...");let y=lr(n);if(t.stop(y.length>0?`Detected ${y.length} potential key(s)`:"No keys detected automatically"),y.length>0){let g=await Qe({message:"Found these potential keys. Use one of them?",options:[...y.map(h=>({value:h.path,label:`${ge.basename(h.path)} (${h.location})`})),{value:"manual",label:"Enter path manually..."}]});if(le(g)){Ee("Operation cancelled");return}g!=="manual"&&(a=g)}if(!a){let g=await xe({message:`Paste the path to your ${n==="ios"?".p8":".json"} file:`,validate:h=>se.existsSync(h)?void 0:"File not found"});if(le(g)){Ee("Operation cancelled");return}a=g}}let l=e.issuerId,p=e.keyId;if(n==="ios"){if(!p&&a){let f=ge.basename(a).match(/AuthKey_(.*)\.p8/);f&&(p=f[1],ee.info(`Auto-detected Key ID from filename: ${ne.green(p)}`))}if(!l){let f=await xe({message:"Enter App Store Connect Issuer ID (Found on the Keys page):",validate:y=>y.length>0?void 0:"Issuer ID is required"});if(le(f)){Ee("Operation cancelled");return}l=f}if(!p){let f=await xe({message:"Enter App Store Connect Key ID:",validate:y=>y.length>0?void 0:"Key ID is required"});if(le(f)){Ee("Operation cancelled");return}p=f}}if(n==="android"&&(!c||c==="*")){let f=await Pn();if(f===null)return;c=f}let d=n==="ios"?ze(r,s):{};await Zt(o,a,n,l,p,c,{...d})};async function rr(e,t,n){let i=await or(e),r=sr(t,n);if(r&&!i.includes(r)&&i.unshift(r),i.length>0){let o=await Qe({message:"Select Android package for this Google Play service key:",options:[...i.map(s=>({value:s,label:s,hint:s===r?"from config":void 0})),{value:"manual",label:"Enter another package name..."}]});if(le(o))return Ee("Operation cancelled"),null;if(o==="manual")return Pn();if(o!=="manual")return o}if(r){let o=await Cn({message:`Use Android package from local config (${r})?`,initialValue:!0});if(le(o))return Ee("Operation cancelled"),null;if(o)return r}}async function Pn(){let e=await xe({message:"Android package name for this Google Play service key:",placeholder:"com.example.app",validate:t=>t.includes(".")?void 0:"Enter a valid package name"});return le(e)?(Ee("Operation cancelled"),null):e}async function or(e){try{let n=(await Z.get(`/credentials/${e}`)).data.credentials||[],i=new Set;for(let r of n)(r.platform==="android"||r.type==="android_keystore"||r.type==="google_service_account")&&r.bundleId&&r.bundleId!=="*"&&i.add(r.bundleId);return Array.from(i).sort()}catch(t){return ee.warn(ne.yellow(`Could not fetch saved Android package identifiers: ${t.message}`)),[]}}function sr(e,t){let n=Je(e,t);if(n)return n;let i=ge.join(process.cwd(),"app.json");if(se.existsSync(i))try{return JSON.parse(se.readFileSync(i,"utf-8")).expo?.android?.package}catch{}let r=ge.join(process.cwd(),"app.config.json");if(se.existsSync(r))try{let o=JSON.parse(se.readFileSync(r,"utf-8"));return o.expo?.android?.package||o.android?.package}catch{}}async function ar(e,t){let n=lt(),i=t.submit?.production?.ios?.appleId,r=ze(t).teamId,o=Sn(t);if(!i){let c=await xe({message:"Apple ID:",placeholder:"your-email@example.com"});if(le(c))return;i=c}if(!r){let c=await at({appleId:i,config:t,profile:"production",initialTeam:ze(t),promptToPersistConfig:!0});if(!c?.teamId)return;r=c.teamId}let s=await xe({message:"Enter a name for the new API Key:",initialValue:`[${A.name}] Project ${e}`});if(le(s))return;let a=Dt();if(!se.existsSync(a)){ee.error(`Magic Error: Helper script not found at ${a}`);return}try{let c=await ir(a,t,i,r);if(c===null)return;let l;if(c)l=c,o=c.id;else if(!o)return;n.start("Creating App Store Connect API Key...");let p=x=>ct("ruby",[a,"create",s],{env:wn(i,r,x),stdio:["inherit","pipe","pipe"],encoding:"utf-8"}),d=p(o),f=d.stdout||"",y=d.stderr||"";if(d.status!==0){let x=Gt(`${f}
9
+ ${y}`);if(x.length>0){n.stop("Select App Store Connect team"),bt(`Apple Developer Team IDs look like ${ne.bold(r)}.
10
+ App Store Connect API keys use a numeric provider/team ID instead.`,"Team ID mismatch");let F=await Wt(t,x,"Select the App Store Connect provider for this API key:");if(!F)return;l=F,o=F.id,n.start("Creating API Key with selected App Store Connect team..."),d=p(o),f=d.stdout||"",y=d.stderr||""}}if(y&&(y.includes("DEBUG:")||y.includes("ERROR:"))&&y.split(`
11
+ `).forEach(x=>{x.trim()&&ee.info(ne.dim(`[Ruby] ${x.trim()}`))}),d.status!==0){n.stop("Failed"),ee.error(`Magic creation failed: ${y}`);return}let g=f.match(new RegExp(`${A.jsonStartMarker}(.*)${A.jsonEndMarker}`));if(!g){n.stop("Parse Error"),ee.error("Could not parse response from Apple Portal.");return}let h=JSON.parse(g[1]),{id:w,issuerId:_,keyContent:C}=h,v=ze(t,"production",{teamId:r,teamName:l?.developerTeamName,developerTeamId:r,appStoreConnectTeamId:o,providerId:o,providerName:l?.name});if(n.stop("Key Created Successfully"),ee.success(`\u2713 Created Key ID: ${ne.green(w)}`),!_){bt(`Your Issuer ID is shown at the top of:
12
12
  ${ne.cyan("https://appstoreconnect.apple.com/access/integrations/api")}
13
13
 
14
14
  It looks like: ${ne.dim("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")}`,"One More Thing");let x=await xe({message:"Enter your App Store Connect Issuer ID:",validate:F=>F.trim().length>0?void 0:"Issuer ID is required"});if(le(x)){Ee("Operation cancelled.");return}_=x.trim()}if(C){let x=ge.join(Mt.tmpdir(),`AuthKey_${w}.p8`);se.writeFileSync(x,C),await Zt(e,x,"ios",_,w,t.ios?.bundleIdentifier||"*",{...v}),se.unlinkSync(x)}else{ee.warn(ne.yellow("\u26A0\uFE0F Apple did not return the private key in the response.")),bt(`Download the .p8 file manually:
@@ -17,7 +17,7 @@ It looks like: ${ne.dim("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")}`,"One More Thin
17
17
  2. Find Key ID: ${ne.green(w)}
18
18
  3. Click ${ne.bold("Download API Key")} (only available once)
19
19
  4. Drag & drop the downloaded .p8 file below`,"Manual Step Required");let x=await xe({message:"Path to the downloaded .p8 file (drag & drop here):",validate:F=>se.existsSync(F)?void 0:"File not found"});if(le(x)){Ee("Operation cancelled. Credential ID was registered but key content is missing.");return}await Zt(e,x,"ios",_,w,t.ios?.bundleIdentifier||"*",{...v})}}catch(c){n.stop("Error"),ee.error(`Error: ${c.message}`)}}async function cr(e,t){let n=lt(),i=t.submit?.production?.ios?.appleId,r=ze(t).teamId,o=Sn(t);if(!i){let a=await xe({message:"Apple ID:"});if(le(a))return;i=a}if(!r){let a=await at({appleId:i,config:t,profile:"production",initialTeam:ze(t),promptToPersistConfig:!0});if(!a?.teamId)return;r=a.teamId}n.start("Fetching existing API Keys...");let s=Dt();if(!se.existsSync(s)){ee.error(`Magic Error: Helper script not found at ${s}`);return}try{let a=g=>ct("ruby",[s,"list"],{env:{...Vt(),FASTLANE_USER:i,FASTLANE_TEAM_ID:r,...g?{FASTLANE_ITC_TEAM_ID:g,FASTLANE_ASC_TEAM_ID:g}:{}},stdio:["inherit","pipe","pipe"],encoding:"utf-8"}),c=a(o);if(c.status!==0){let g=Gt(`${c.stdout||""}
20
- ${c.stderr||""}`);if(g.length>0){n.stop("Select App Store Connect team");let h=await Qe({message:"Select the App Store Connect team to list API keys:",options:g.map(w=>({value:w.id,label:w.name,hint:w.id}))});if(le(h)){Ee("Operation cancelled");return}o=h,n.start("Fetching existing API Keys..."),c=a(o)}}if(c.status!==0){n.stop("Failed"),ee.error(`Listing failed: ${c.stderr}`);return}let l=c.stdout.match(new RegExp(`${A.jsonStartMarker}(.*)${A.jsonEndMarker}`));if(!l){n.stop("Parse Error");return}let p=JSON.parse(l[1]);if(n.stop(`Found ${p.length} keys`),p.length===0){ee.info("No API Keys found on this team.");return}let d=await Qe({message:"Select a key to delete from Apple Developer Portal:",options:[...p.map(g=>({value:g.id,label:`ID: ${g.id} - ${g.name} (${g.role})`})),{value:"cancel",label:"Cancel"}]});if(le(d)||d==="cancel")return;let f=await Cn({message:`Are you sure you want to delete Key ${d}? This cannot be undone.`});if(!f||le(f))return;n.start(`Deleting Key ${d}...`);let I=ct("ruby",[Dt(),"delete",d],{env:{...Vt(),FASTLANE_USER:i,FASTLANE_TEAM_ID:r,...o?{FASTLANE_ITC_TEAM_ID:o,FASTLANE_ASC_TEAM_ID:o}:{}},stdio:"pipe",encoding:"utf-8"});I.status===0?(n.stop("Deleted"),ee.success(`\u2713 Key ${d} has been removed from Apple Portal.`)):(n.stop("Deletion Failed"),ee.error(`Error: ${I.stderr}`))}catch(a){n.stop("Error"),ee.error(`Error: ${a.message}`)}}async function Zt(e,t,n,i,r,o="*",s={}){let a=lt();a.start(`Uploading Service Credentials for ${n}...`);try{let c=n==="ios"?"asc_api_key":"google_service_account",l=new URL(import.meta.url),p=ge.dirname(l.pathname),d=[ge.join(p,"isolated-upload.js"),ge.join(p,"commands","isolated-upload.js"),ge.resolve(p,"../commands/isolated-upload.js"),ge.resolve(process.cwd(),`node_modules/.bin/${A.nameLower}-upload`)],f="";for(let g of d)if(se.existsSync(g)){f=g;break}if(!f)throw new Error("Could not locate isolated-upload.js. Ensure the CLI is properly installed.");let I=ct("node",[f,e,t,c,o,"service","undefined","undefined",i||"undefined",r||"undefined","undefined","undefined","undefined",s.teamId||"undefined",s.teamName||"undefined",s.developerTeamId||"undefined",s.appStoreConnectTeamId||"undefined",s.providerId||"undefined",s.providerName||"undefined"],{stdio:"pipe",encoding:"utf-8",env:{...process.env,AT_CLI_ISOLATED:"1"}});if(I.status!==0){let g=I.stderr||I.stdout||"Unknown upload failure";a.stop("Upload Failed"),ee.error(ne.red(`Upload Failed: ${g}`));return}I.stdout.includes("SUCCESS")?(a.stop("Upload Success"),ee.success(ne.green(`\u2713 Service Credentials for ${n} uploaded successfully.`))):(a.stop("Upload Summary"),ee.warn(ne.yellow(`Upload finished but success not confirmed: ${I.stdout}`)))}catch(c){a.stop("Upload Error"),ee.error(ne.red(`Error: ${c.message}`))}}function lr(e){let t=e==="ios"?".p8":".json",n=[],i=[{path:"./",label:"Project Root"},{path:ge.join(Mt.homedir(),"Downloads"),label:"Downloads"}];for(let r of i)if(se.existsSync(r.path))try{let o=se.readdirSync(r.path);for(let s of o)if(s.endsWith(t)){if(e==="android"&&!se.readFileSync(ge.join(r.path,s),"utf8").includes("service_account")||e==="ios"&&!s.startsWith("AuthKey"))continue;n.push({path:ge.join(r.path,s),location:r.label})}}catch{}return n}import{spinner as vt}from"@clack/prompts";import Q from"chalk";import{spawnSync as Fo}from"child_process";import oe from"fs";import me from"path";import U from"fs";import z from"path";var dr={expo:["src/app/_layout.tsx","src/app/_layout.ts","src/app/_layout.jsx","src/app/_layout.js","app/_layout.tsx","app/_layout.ts","app/_layout.jsx","app/_layout.js","src/App.tsx","src/App.ts","src/App.jsx","src/App.js","App.tsx","App.ts","App.jsx","App.js"],"react-native":["index.ts","index.tsx","index.js","index.jsx","src/index.ts","src/index.tsx","src/index.js","src/index.jsx","App.tsx","App.ts","App.jsx","App.js","src/App.tsx","src/App.ts","src/App.jsx","src/App.js"]};function be(e,t){return z.relative(e,t).split(z.sep).join("/")}function pr(e,t){return t.find(n=>U.existsSync(z.join(e,n)))}function ur(e,t){return t.split(z.sep).join("/").startsWith("src/")?z.join(e,"src"):e}function mr(e){return e.endsWith(".ts")||e.endsWith(".tsx")}function fr(e,t){let n=t.replace(/\.(?:tsx?|jsx?)$/,""),i=z.relative(z.dirname(e),n).split(z.sep).join("/");return i.startsWith(".")||(i=`./${i}`),i}function gr(e,t){let n=U.readFileSync(e,"utf8");if(n.includes("MACH Push setup")||/(?:from\s+)?['"][^'"]*mach-push['"]/.test(n))return!1;let i=fr(e,t);return U.writeFileSync(e,`import '${i}'; // MACH Push setup
20
+ ${c.stderr||""}`);if(g.length>0){n.stop("Select App Store Connect team");let h=await Qe({message:"Select the App Store Connect team to list API keys:",options:g.map(w=>({value:w.id,label:w.name,hint:w.id}))});if(le(h)){Ee("Operation cancelled");return}o=h,n.start("Fetching existing API Keys..."),c=a(o)}}if(c.status!==0){n.stop("Failed"),ee.error(`Listing failed: ${c.stderr}`);return}let l=c.stdout.match(new RegExp(`${A.jsonStartMarker}(.*)${A.jsonEndMarker}`));if(!l){n.stop("Parse Error");return}let p=JSON.parse(l[1]);if(n.stop(`Found ${p.length} keys`),p.length===0){ee.info("No API Keys found on this team.");return}let d=await Qe({message:"Select a key to delete from Apple Developer Portal:",options:[...p.map(g=>({value:g.id,label:`ID: ${g.id} - ${g.name} (${g.role})`})),{value:"cancel",label:"Cancel"}]});if(le(d)||d==="cancel")return;let f=await Cn({message:`Are you sure you want to delete Key ${d}? This cannot be undone.`});if(!f||le(f))return;n.start(`Deleting Key ${d}...`);let y=ct("ruby",[Dt(),"delete",d],{env:{...Vt(),FASTLANE_USER:i,FASTLANE_TEAM_ID:r,...o?{FASTLANE_ITC_TEAM_ID:o,FASTLANE_ASC_TEAM_ID:o}:{}},stdio:"pipe",encoding:"utf-8"});y.status===0?(n.stop("Deleted"),ee.success(`\u2713 Key ${d} has been removed from Apple Portal.`)):(n.stop("Deletion Failed"),ee.error(`Error: ${y.stderr}`))}catch(a){n.stop("Error"),ee.error(`Error: ${a.message}`)}}async function Zt(e,t,n,i,r,o="*",s={}){let a=lt();a.start(`Uploading Service Credentials for ${n}...`);try{let c=n==="ios"?"asc_api_key":"google_service_account",l=new URL(import.meta.url),p=ge.dirname(l.pathname),d=[ge.join(p,"isolated-upload.js"),ge.join(p,"commands","isolated-upload.js"),ge.resolve(p,"../commands/isolated-upload.js"),ge.resolve(process.cwd(),`node_modules/.bin/${A.nameLower}-upload`)],f="";for(let g of d)if(se.existsSync(g)){f=g;break}if(!f)throw new Error("Could not locate isolated-upload.js. Ensure the CLI is properly installed.");let y=ct("node",[f,e,t,c,o,"service","undefined","undefined",i||"undefined",r||"undefined","undefined","undefined","undefined",s.teamId||"undefined",s.teamName||"undefined",s.developerTeamId||"undefined",s.appStoreConnectTeamId||"undefined",s.providerId||"undefined",s.providerName||"undefined"],{stdio:"pipe",encoding:"utf-8",env:{...process.env,AT_CLI_ISOLATED:"1"}});if(y.status!==0){let g=y.stderr||y.stdout||"Unknown upload failure";a.stop("Upload Failed"),ee.error(ne.red(`Upload Failed: ${g}`));return}y.stdout.includes("SUCCESS")?(a.stop("Upload Success"),ee.success(ne.green(`\u2713 Service Credentials for ${n} uploaded successfully.`))):(a.stop("Upload Summary"),ee.warn(ne.yellow(`Upload finished but success not confirmed: ${y.stdout}`)))}catch(c){a.stop("Upload Error"),ee.error(ne.red(`Error: ${c.message}`))}}function lr(e){let t=e==="ios"?".p8":".json",n=[],i=[{path:"./",label:"Project Root"},{path:ge.join(Mt.homedir(),"Downloads"),label:"Downloads"}];for(let r of i)if(se.existsSync(r.path))try{let o=se.readdirSync(r.path);for(let s of o)if(s.endsWith(t)){if(e==="android"&&!se.readFileSync(ge.join(r.path,s),"utf8").includes("service_account")||e==="ios"&&!s.startsWith("AuthKey"))continue;n.push({path:ge.join(r.path,s),location:r.label})}}catch{}return n}import{spinner as vt}from"@clack/prompts";import Y from"chalk";import{spawnSync as Fo}from"child_process";import oe from"fs";import me from"path";import U from"fs";import Q from"path";var dr={expo:["src/app/_layout.tsx","src/app/_layout.ts","src/app/_layout.jsx","src/app/_layout.js","app/_layout.tsx","app/_layout.ts","app/_layout.jsx","app/_layout.js","src/App.tsx","src/App.ts","src/App.jsx","src/App.js","App.tsx","App.ts","App.jsx","App.js"],"react-native":["index.ts","index.tsx","index.js","index.jsx","src/index.ts","src/index.tsx","src/index.js","src/index.jsx","App.tsx","App.ts","App.jsx","App.js","src/App.tsx","src/App.ts","src/App.jsx","src/App.js"]};function be(e,t){return Q.relative(e,t).split(Q.sep).join("/")}function pr(e,t){return t.find(n=>U.existsSync(Q.join(e,n)))}function ur(e,t){return t.split(Q.sep).join("/").startsWith("src/")?Q.join(e,"src"):e}function mr(e){return e.endsWith(".ts")||e.endsWith(".tsx")}function fr(e,t){let n=t.replace(/\.(?:tsx?|jsx?)$/,""),i=Q.relative(Q.dirname(e),n).split(Q.sep).join("/");return i.startsWith(".")||(i=`./${i}`),i}function gr(e,t){let n=U.readFileSync(e,"utf8");if(n.includes("MACH Push setup")||/(?:from\s+)?['"][^'"]*mach-push['"]/.test(n))return!1;let i=fr(e,t);return U.writeFileSync(e,`import '${i}'; // MACH Push setup
21
21
  ${n}`),!0}function hr(e,t){let n={projectId:e.projectId};return e.appId&&e.publishableKey&&(n.appId=e.appId,n.publishableKey=e.publishableKey),e.apiUrl&&e.apiUrl!=="https://mach-api.securejs.in"&&(n.apiUrl=e.apiUrl),e.environment&&e.environment!=="production"&&(n.environment=e.environment),`// Generated by \`mach push setup\`. Re-run the command to refresh.
22
22
  // Public client configuration only. Provider credentials are never written here.
23
23
  ${t?`import type { MachPushConfig } from '@radhya/mach-push-react-native';
@@ -137,7 +137,7 @@ export function startMachPush() {
137
137
  // The basic experience works immediately. Remove this line if your product
138
138
  // asks for notification permission at a later, contextual moment.
139
139
  void startMachPush()?.catch(() => undefined);
140
- `}function Nn(e,t,n){let i=[],r=[],o=pr(e,dr[t]);if(!o)return{written:i,notes:["Could not locate the application entry point. Import the generated mach-push file once from your root App or layout."]};let s=z.join(e,o),a=ur(e,o),c=mr(o)?"ts":"js",l=c==="ts",p=z.join(a,`mach-push.generated.${c}`),d=z.join(a,`mach-push.${c}`);return U.mkdirSync(a,{recursive:!0}),U.writeFileSync(p,hr(n,l)),i.push(be(e,p)),U.existsSync(d)?r.push(`${be(e,d)} already exists; developer callbacks were preserved.`):(U.writeFileSync(d,yr("./mach-push.generated",l)),i.push(be(e,d))),gr(s,d)?i.push(be(e,s)):r.push(`${be(e,s)} already starts MACH Push.`),{written:i,notes:r,editableFile:be(e,d),generatedFile:be(e,p),entryFile:be(e,s)}}function kn(e,t){if(!U.existsSync(e))return[];let n=[];for(let i of U.readdirSync(e,{withFileTypes:!0})){if(i.name==="Pods"||i.name==="build")continue;let r=z.join(e,i.name);i.isDirectory()?n.push(...kn(r,t)):t(r)&&n.push(r)}return n}function Ir(e,t){if(U.mkdirSync(z.dirname(e),{recursive:!0}),!U.existsSync(e)){U.writeFileSync(e,`<?xml version="1.0" encoding="UTF-8"?>
140
+ `}function Nn(e,t,n){let i=[],r=[],o=pr(e,dr[t]);if(!o)return{written:i,notes:["Could not locate the application entry point. Import the generated mach-push file once from your root App or layout."]};let s=Q.join(e,o),a=ur(e,o),c=mr(o)?"ts":"js",l=c==="ts",p=Q.join(a,`mach-push.generated.${c}`),d=Q.join(a,`mach-push.${c}`);return U.mkdirSync(a,{recursive:!0}),U.writeFileSync(p,hr(n,l)),i.push(be(e,p)),U.existsSync(d)?r.push(`${be(e,d)} already exists; developer callbacks were preserved.`):(U.writeFileSync(d,yr("./mach-push.generated",l)),i.push(be(e,d))),gr(s,d)?i.push(be(e,s)):r.push(`${be(e,s)} already starts MACH Push.`),{written:i,notes:r,editableFile:be(e,d),generatedFile:be(e,p),entryFile:be(e,s)}}function kn(e,t){if(!U.existsSync(e))return[];let n=[];for(let i of U.readdirSync(e,{withFileTypes:!0})){if(i.name==="Pods"||i.name==="build")continue;let r=Q.join(e,i.name);i.isDirectory()?n.push(...kn(r,t)):t(r)&&n.push(r)}return n}function Ir(e,t){if(U.mkdirSync(Q.dirname(e),{recursive:!0}),!U.existsSync(e)){U.writeFileSync(e,`<?xml version="1.0" encoding="UTF-8"?>
141
141
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
142
142
  <plist version="1.0">
143
143
  <dict>
@@ -147,20 +147,20 @@ void startMachPush()?.catch(() => undefined);
147
147
  </plist>
148
148
  `);return}let n=U.readFileSync(e,"utf8"),i=/(<key>aps-environment<\/key>\s*<string>)([^<]*)(<\/string>)/;if(i.test(n)){U.writeFileSync(e,n.replace(i,`$1${t}$3`));return}n.includes("</dict>")&&U.writeFileSync(e,n.replace("</dict>",` <key>aps-environment</key>
149
149
  <string>${t}</string>
150
- </dict>`))}function Ar(e,t,n){let i=[],r=[],o=z.join(e,"ios");if(!U.existsSync(o))return r.push("iOS native project is not present; no APNs entitlement was changed."),{written:i,notes:r};let a=kn(o,p=>p.endsWith(".xcodeproj/project.pbxproj"))[0];if(!a)return r.push("Could not locate an iOS Xcode project for the APNs entitlement."),{written:i,notes:r};let c=U.readFileSync(a,"utf8"),l=Array.from(c.matchAll(/CODE_SIGN_ENTITLEMENTS\s*=\s*"?([^";$]+\.entitlements)"?;/g),p=>p[1].trim());if(l.length===0&&t){let p=z.basename(z.dirname(a),".xcodeproj"),f=[U.existsSync(z.join(o,p))?p:"",`${p}.entitlements`].filter(Boolean).join("/"),I=!1;c=c.replace(/buildSettings = \{([\s\S]*?)\n(\s*)\};/g,(g,h,w)=>!new RegExp(`PRODUCT_BUNDLE_IDENTIFIER\\s*=\\s*"?${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}"?;`).test(h)||h.includes("CODE_SIGN_ENTITLEMENTS")?g:(I=!0,g.replace(/(\n\s*PRODUCT_BUNDLE_IDENTIFIER\s*=)/,`
151
- ${w} CODE_SIGN_ENTITLEMENTS = ${f};$1`))),I&&(U.writeFileSync(a,c),i.push(be(e,a)),l.push(f))}if(l.length===0)return r.push("Could not safely identify the iOS app target. Enable the Push Notifications capability in Xcode."),{written:i,notes:r};for(let p of new Set(l)){let d=z.join(o,p);Ir(d,n),i.push(be(e,d))}return r.push(`iOS APNs entitlement is configured for ${n}.`),{written:[...new Set(i)],notes:r}}function br(e,t){let n=U.readFileSync(e,"utf8");if(n.includes("com.google.gms.google-services"))return!1;let i=/plugins\s*\{/.exec(n);if(i?.index!==void 0){let r=t?` id("com.google.gms.google-services")
150
+ </dict>`))}function Ar(e,t,n){let i=[],r=[],o=Q.join(e,"ios");if(!U.existsSync(o))return r.push("iOS native project is not present; no APNs entitlement was changed."),{written:i,notes:r};let a=kn(o,p=>p.endsWith(".xcodeproj/project.pbxproj"))[0];if(!a)return r.push("Could not locate an iOS Xcode project for the APNs entitlement."),{written:i,notes:r};let c=U.readFileSync(a,"utf8"),l=Array.from(c.matchAll(/CODE_SIGN_ENTITLEMENTS\s*=\s*"?([^";$]+\.entitlements)"?;/g),p=>p[1].trim());if(l.length===0&&t){let p=Q.basename(Q.dirname(a),".xcodeproj"),f=[U.existsSync(Q.join(o,p))?p:"",`${p}.entitlements`].filter(Boolean).join("/"),y=!1;c=c.replace(/buildSettings = \{([\s\S]*?)\n(\s*)\};/g,(g,h,w)=>!new RegExp(`PRODUCT_BUNDLE_IDENTIFIER\\s*=\\s*"?${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}"?;`).test(h)||h.includes("CODE_SIGN_ENTITLEMENTS")?g:(y=!0,g.replace(/(\n\s*PRODUCT_BUNDLE_IDENTIFIER\s*=)/,`
151
+ ${w} CODE_SIGN_ENTITLEMENTS = ${f};$1`))),y&&(U.writeFileSync(a,c),i.push(be(e,a)),l.push(f))}if(l.length===0)return r.push("Could not safely identify the iOS app target. Enable the Push Notifications capability in Xcode."),{written:i,notes:r};for(let p of new Set(l)){let d=Q.join(o,p);Ir(d,n),i.push(be(e,d))}return r.push(`iOS APNs entitlement is configured for ${n}.`),{written:[...new Set(i)],notes:r}}function br(e,t){let n=U.readFileSync(e,"utf8");if(n.includes("com.google.gms.google-services"))return!1;let i=/plugins\s*\{/.exec(n);if(i?.index!==void 0){let r=t?` id("com.google.gms.google-services")
152
152
  `:` id 'com.google.gms.google-services'
153
153
  `,o=i.index+i[0].length;U.writeFileSync(e,`${n.slice(0,o)}
154
154
  ${r}${n.slice(o)}`)}else{let r=t?`
155
155
  apply(plugin = "com.google.gms.google-services")
156
156
  `:`
157
157
  apply plugin: "com.google.gms.google-services"
158
- `;U.writeFileSync(e,`${n.trimEnd()}${r}`)}return!0}function Cr(e){let t=["settings.gradle.kts","settings.gradle"].map(a=>z.join(e,a)).find(a=>U.existsSync(a));if(t){let a=U.readFileSync(t,"utf8");if(a.includes("com.google.gms.google-services"))return;let c=/plugins\s*\{/.exec(a);if(c?.index!==void 0){let p=t.endsWith(".kts")?` id("com.google.gms.google-services") version "4.4.4" apply false
158
+ `;U.writeFileSync(e,`${n.trimEnd()}${r}`)}return!0}function Cr(e){let t=["settings.gradle.kts","settings.gradle"].map(a=>Q.join(e,a)).find(a=>U.existsSync(a));if(t){let a=U.readFileSync(t,"utf8");if(a.includes("com.google.gms.google-services"))return;let c=/plugins\s*\{/.exec(a);if(c?.index!==void 0){let p=t.endsWith(".kts")?` id("com.google.gms.google-services") version "4.4.4" apply false
159
159
  `:` id "com.google.gms.google-services" version "4.4.4" apply false
160
160
  `,d=c.index+c[0].length;return U.writeFileSync(t,`${a.slice(0,d)}
161
- ${p}${a.slice(d)}`),t}}let n=["build.gradle.kts","build.gradle"].map(a=>z.join(e,a)).find(a=>U.existsSync(a));if(!n)return;let i=U.readFileSync(n,"utf8");if(i.includes("com.google.gms:google-services"))return;let r=/dependencies\s*\{/.exec(i);if(r?.index===void 0)return;let o=` classpath("com.google.gms:google-services:4.4.4")
161
+ ${p}${a.slice(d)}`),t}}let n=["build.gradle.kts","build.gradle"].map(a=>Q.join(e,a)).find(a=>U.existsSync(a));if(!n)return;let i=U.readFileSync(n,"utf8");if(i.includes("com.google.gms:google-services"))return;let r=/dependencies\s*\{/.exec(i);if(r?.index===void 0)return;let o=` classpath("com.google.gms:google-services:4.4.4")
162
162
  `,s=r.index+r[0].length;return U.writeFileSync(n,`${i.slice(0,s)}
163
- ${o}${i.slice(s)}`),n}function Sr(e,t){let n=[],i=[],r=z.join(e,"android");if(!U.existsSync(r))return i.push("Android native project is not present; no Firebase configuration was changed."),{written:n,notes:i};if(!t)return i.push("Android needs google-services.json. Add it at the project root and re-run mach push setup."),{written:n,notes:i};let o=z.resolve(e,t);if(!U.existsSync(o))return i.push(`Android Firebase file was not found at ${t}; re-run setup with --google-services-file.`),{written:n,notes:i};let s=z.join(r,"app/google-services.json");U.mkdirSync(z.dirname(s),{recursive:!0}),o!==s&&(U.copyFileSync(o,s),n.push(be(e,s)));let a=["build.gradle.kts","build.gradle"].map(l=>z.join(r,"app",l)).find(l=>U.existsSync(l));if(!a)return i.push("Could not locate android/app/build.gradle to enable Firebase."),{written:n,notes:i};br(a,a.endsWith(".kts"))&&n.push(be(e,a));let c=Cr(r);return c&&n.push(be(e,c)),i.push("Android Firebase configuration and notification permission are wired."),{written:[...new Set(n)],notes:i}}function Rn(e,t){let n=Ar(e,t.iosBundleId,t.iosEnvironment),i=Sr(e,t.googleServicesFile);return{written:[...new Set([...n.written,...i.written])],notes:[...n.notes,...i.notes]}}import{spinner as St,log as P,isCancel as wt,confirm as zr,select as Qt}from"@clack/prompts";import S from"chalk";import y from"fs";import b from"path";import{execFileSync as Te,execSync as L,spawn as Hn}from"child_process";import de from"os";import Qr from"crypto";import kr from"crypto";import{log as Ce}from"@clack/prompts";import Se from"chalk";import{execSync as wr}from"child_process";import we from"fs";import qe from"path";var xn={id:"expo",displayName:"Expo",applyLocalProcessEnv:e=>{e.developmentClient?(Ce.info(Se.blue("\u2139\uFE0F Configuring Expo build to INCLUDE expo-dev-client (Development Client mode)...")),delete process.env.EXPO_NO_DEV_CLIENT,delete process.env.EXPO_AUTOLINKING_EXCLUDE):(Ce.info(Se.blue("\u2139\uFE0F Configuring Expo build to EXCLUDE expo-dev-client (Production/Staging mode)...")),process.env.EXPO_NO_DEV_CLIENT="1",process.env.EXPO_AUTOLINKING_EXCLUDE="expo-dev-client")},localAndroidEnv:(e,t)=>({EXPO_NO_DOTENV:"1",MACH_FRAMEWORK:"expo",MACH_BUILD_PROFILE:t}),remoteEnvSetupScript:()=>`
163
+ ${o}${i.slice(s)}`),n}function Sr(e,t){let n=[],i=[],r=Q.join(e,"android");if(!U.existsSync(r))return i.push("Android native project is not present; no Firebase configuration was changed."),{written:n,notes:i};if(!t)return i.push("Android needs google-services.json. Add it at the project root and re-run mach push setup."),{written:n,notes:i};let o=Q.resolve(e,t);if(!U.existsSync(o))return i.push(`Android Firebase file was not found at ${t}; re-run setup with --google-services-file.`),{written:n,notes:i};let s=Q.join(r,"app/google-services.json");U.mkdirSync(Q.dirname(s),{recursive:!0}),o!==s&&(U.copyFileSync(o,s),n.push(be(e,s)));let a=["build.gradle.kts","build.gradle"].map(l=>Q.join(r,"app",l)).find(l=>U.existsSync(l));if(!a)return i.push("Could not locate android/app/build.gradle to enable Firebase."),{written:n,notes:i};br(a,a.endsWith(".kts"))&&n.push(be(e,a));let c=Cr(r);return c&&n.push(be(e,c)),i.push("Android Firebase configuration and notification permission are wired."),{written:[...new Set(n)],notes:i}}function Rn(e,t){let n=Ar(e,t.iosBundleId,t.iosEnvironment),i=Sr(e,t.googleServicesFile);return{written:[...new Set([...n.written,...i.written])],notes:[...n.notes,...i.notes]}}import{spinner as St,log as P,isCancel as wt,confirm as zr,select as Qt}from"@clack/prompts";import S from"chalk";import I from"fs";import b from"path";import{execFileSync as Te,execSync as L,spawn as Hn}from"child_process";import de from"os";import Qr from"crypto";import kr from"crypto";import{log as Ce}from"@clack/prompts";import Se from"chalk";import{execSync as wr}from"child_process";import we from"fs";import qe from"path";var xn={id:"expo",displayName:"Expo",applyLocalProcessEnv:e=>{e.developmentClient?(Ce.info(Se.blue("\u2139\uFE0F Configuring Expo build to INCLUDE expo-dev-client (Development Client mode)...")),delete process.env.EXPO_NO_DEV_CLIENT,delete process.env.EXPO_AUTOLINKING_EXCLUDE):(Ce.info(Se.blue("\u2139\uFE0F Configuring Expo build to EXCLUDE expo-dev-client (Production/Staging mode)...")),process.env.EXPO_NO_DEV_CLIENT="1",process.env.EXPO_AUTOLINKING_EXCLUDE="expo-dev-client")},localAndroidEnv:(e,t)=>({EXPO_NO_DOTENV:"1",MACH_FRAMEWORK:"expo",MACH_BUILD_PROFILE:t}),remoteEnvSetupScript:()=>`
164
164
  export MACH_FRAMEWORK="expo"
165
165
  echo "[ENV] MACH_FRAMEWORK=$MACH_FRAMEWORK"
166
166
  export EXPO_NO_DOTENV="\${EXPO_NO_DOTENV:-1}"
@@ -212,7 +212,7 @@ fi
212
212
  echo "expo.enableHermes=true" >> gradle.properties
213
213
  `,androidRemoteReleaseGradlePropertiesScript:()=>`
214
214
  echo "expo.enableProguardInReleaseBuilds=true" >> gradle.properties
215
- `,prepareLocalProject:async e=>{let{platform:t,options:n,cacheMeta:i,cacheMetaDir:r,currentBuildEnv:o,reportStep:s,loggedRun:a,configureXcodeNodeBinary:c,podsFingerprint:l,writeCacheMeta:p}=e,d=n.iosBundleIdentifier||"",f=n.name||"",I=qe.join(process.cwd(),"app.json"),g=null;Ce.info(Se.blue(`Running Expo prebuild for ${t}...`));try{if(we.existsSync(I)){g=we.readFileSync(I,"utf-8");let w=JSON.parse(g);w.expo=w.expo||{},f||(f=w.expo.name||""),t==="ios"&&!d&&(d=w.expo?.ios?.bundleIdentifier||""),n.name&&(w.expo.name=n.name),n.scheme&&(w.expo.scheme=n.scheme),t==="ios"&&n.iosBundleIdentifier?(w.expo.ios=w.expo.ios||{},w.expo.ios.bundleIdentifier=n.iosBundleIdentifier):t==="android"&&n.androidPackage&&(w.expo.android=w.expo.android||{},w.expo.android.package=n.androidPackage),we.writeFileSync(I,JSON.stringify(w,null,2))}let h=["exec","--","expo","prebuild","--platform",t,"--no-install"];if(await s("prebuild"),await a("npm",h,process.cwd(),o()),t!=="ios"||!we.existsSync("ios"))return{appName:f,bundleId:d};await s("pods"),Ce.info(Se.blue("Running pod install..."));try{let w=qe.resolve("ios"),_=qe.join(w,"Podfile");if(!we.existsSync(_))throw new Error("ios/Podfile not found. Skipping pod install.");let C=o();c(w,C);let v=we.readFileSync(_,"utf-8"),x=n.iosDeploymentTarget||"13.4";if(!n.developmentClient&&(Ce.info(Se.blue("\u2139\uFE0F Patching Podfile to EXCLUDE expo-dev-client...")),v.includes("use_expo_modules!")&&!v.includes("exclude:"))){let V=/use_expo_modules!(\s*)$/m;V.test(v)?v=v.replace(V,'use_expo_modules!(exclude: ["expo-dev-client"])$1'):v=v.replace("use_expo_modules!",'use_expo_modules!(exclude: ["expo-dev-client"])')}let F=`
215
+ `,prepareLocalProject:async e=>{let{platform:t,options:n,cacheMeta:i,cacheMetaDir:r,currentBuildEnv:o,reportStep:s,loggedRun:a,configureXcodeNodeBinary:c,podsFingerprint:l,writeCacheMeta:p}=e,d=n.iosBundleIdentifier||"",f=n.name||"",y=qe.join(process.cwd(),"app.json"),g=null;Ce.info(Se.blue(`Running Expo prebuild for ${t}...`));try{if(we.existsSync(y)){g=we.readFileSync(y,"utf-8");let w=JSON.parse(g);w.expo=w.expo||{},f||(f=w.expo.name||""),t==="ios"&&!d&&(d=w.expo?.ios?.bundleIdentifier||""),n.name&&(w.expo.name=n.name),n.scheme&&(w.expo.scheme=n.scheme),t==="ios"&&n.iosBundleIdentifier?(w.expo.ios=w.expo.ios||{},w.expo.ios.bundleIdentifier=n.iosBundleIdentifier):t==="android"&&n.androidPackage&&(w.expo.android=w.expo.android||{},w.expo.android.package=n.androidPackage),we.writeFileSync(y,JSON.stringify(w,null,2))}let h=["exec","--","expo","prebuild","--platform",t,"--no-install"];if(await s("prebuild"),await a("npm",h,process.cwd(),o()),t!=="ios"||!we.existsSync("ios"))return{appName:f,bundleId:d};await s("pods"),Ce.info(Se.blue("Running pod install..."));try{let w=qe.resolve("ios"),_=qe.join(w,"Podfile");if(!we.existsSync(_))throw new Error("ios/Podfile not found. Skipping pod install.");let C=o();c(w,C);let v=we.readFileSync(_,"utf-8"),x=n.iosDeploymentTarget||"13.4";if(!n.developmentClient&&(Ce.info(Se.blue("\u2139\uFE0F Patching Podfile to EXCLUDE expo-dev-client...")),v.includes("use_expo_modules!")&&!v.includes("exclude:"))){let V=/use_expo_modules!(\s*)$/m;V.test(v)?v=v.replace(V,'use_expo_modules!(exclude: ["expo-dev-client"])$1'):v=v.replace("use_expo_modules!",'use_expo_modules!(exclude: ["expo-dev-client"])')}let F=`
216
216
  installer.generated_projects.each do |project|
217
217
  project.targets.each do |target|
218
218
  target.build_configurations.each do |config|
@@ -231,7 +231,7 @@ post_install do |installer|
231
231
  ${F}
232
232
  end
233
233
  `;we.appendFileSync(_,V)}let j="/opt/homebrew/bin/pod",N=we.existsSync(j)?j:"pod",T=l(w);we.existsSync(qe.join(w,"Pods"))&&i.pods&&i.pods!==T&&(await e.reportLog(`[CACHE] Podfile/Podfile.lock changed \u2014 wiping ios/Pods
234
- `),Ce.info(Se.dim("Podfile fingerprint changed \u2014 clearing Pods for clean install...")),we.rmSync(qe.join(w,"Pods"),{recursive:!0,force:!0})),Ce.info(Se.dim(`Using pod command: ${N} in ${w}`)),await a(N,["install"],w,C),i.pods=T,p(r,i)}catch(w){let _=w.message||"Unknown error";Ce.warn(Se.yellow(`Native "pod" command failed: ${_}`)),Ce.info(Se.dim("Falling back to npm exec pod-install..."));let C=o();c(qe.resolve("ios"),C),Ce.info(Se.magenta(`${A.nameUpper}_DEBUG: Executing pod-install override via npx --yes pod-install@latest`)),await a("npx",["--yes","pod-install@latest","ios"],process.cwd(),C)}if(we.existsSync("ios/Pods")){Ce.info(Se.dim("Disabling signing for Pod targets to prevent conflicts..."));try{wr(`find ios/Pods -name "project.pbxproj" -exec sed -i '' 's/buildSettings = {/buildSettings = { CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; PROVISIONING_PROFILE_SPECIFIER = ""; EXPANDED_CODE_SIGN_IDENTITY = "";/g' {} +`,{stdio:"ignore"})}catch{}}return{appName:f,bundleId:d}}finally{g&&we.writeFileSync(I,g)}}};import{log as Me}from"@clack/prompts";import Ge from"chalk";import Fe from"fs";import dt from"path";import{spawnSync as vr}from"child_process";import $e from"fs";import Ze from"path";var $n=(e,t)=>Ze.join(e,"node_modules",".bin",process.platform==="win32"?`${t}.cmd`:t),Er=e=>{try{return JSON.parse($e.readFileSync(Ze.join(e,"package.json"),"utf-8"))}catch{return{}}};function _a(e,t){let n=Er(e);return!!(n.dependencies?.[t]||n.devDependencies?.[t])}function Ut(e,t,n,i={}){let r=`${t} ${n.join(" ")}`,o=vr(t,n,{cwd:e,stdio:"inherit",env:{...process.env,CI:process.env.CI||"1",EXPO_NO_TELEMETRY:"1",...i}});return o.error?{ok:!1,command:r,error:o.error.message}:o.status!==0?{ok:!1,command:r,error:`${t} exited with code ${o.status}`}:{ok:!0,command:r}}function Ta(e){return Ut(e,"npx",["--yes","install-expo-modules@latest"])}function Oa(e){let t=$n(e,"expo");return $e.existsSync(t)?Ut(e,t,["install","expo-updates"]):{ok:!1,command:"npx expo install expo-updates",error:"Expo Modules are not installed. Install Expo Modules first."}}function Ba(e){let t=[];return $e.existsSync(Ze.join(e,"ios"))&&t.push("ios"),$e.existsSync(Ze.join(e,"android"))&&t.push("android"),t}function Fn(e){let t=$n(e.cwd,"expo-updates");return $e.existsSync(t)?e.platforms.map(n=>Ut(e.cwd,t,["configuration:syncnative","--platform",n,"--workflow","generic"],{MACH_OTA_RUNTIME_VERSION:e.runtimeVersion,MACH_OTA_CHANNEL:e.channel,MACH_OTA_URL:e.url})):[{ok:!1,command:"expo-updates configuration:syncnative",error:"expo-updates is not installed in this project."}]}function Da(e){let t=Ze.join(e,"android","app","src","main","AndroidManifest.xml"),n=Ze.join(e,"android","app","src","main","res","values","strings.xml"),i,r=Ze.join(e,"ios");if($e.existsSync(r)){let o=[r];for(;o.length>0&&!i;){let s=o.shift();for(let a of $e.readdirSync(s,{withFileTypes:!0})){if(a.name==="Pods"||a.name==="build")continue;let c=Ze.join(s,a.name);if(a.isDirectory())o.push(c);else if(a.isFile()&&a.name==="Expo.plist"){i=c;break}}}}return{...$e.existsSync(t)?{androidManifest:t}:{},...$e.existsSync(n)?{androidStrings:n}:{},...i?{iosExpoPlist:i}:{}}}var Pr=(e,t)=>!Fe.existsSync(e)||!Fe.existsSync(t)?!1:Fe.readFileSync(e,"utf-8")!==Fe.readFileSync(t,"utf-8"),Xt={id:"react-native",displayName:"React Native",applyLocalProcessEnv:e=>{delete process.env.EXPO_NO_DEV_CLIENT,delete process.env.EXPO_AUTOLINKING_EXCLUDE,delete process.env.EXPO_NO_DOTENV},localAndroidEnv:(e,t)=>({MACH_FRAMEWORK:"react-native",MACH_BUILD_PROFILE:t}),remoteEnvSetupScript:()=>`
234
+ `),Ce.info(Se.dim("Podfile fingerprint changed \u2014 clearing Pods for clean install...")),we.rmSync(qe.join(w,"Pods"),{recursive:!0,force:!0})),Ce.info(Se.dim(`Using pod command: ${N} in ${w}`)),await a(N,["install"],w,C),i.pods=T,p(r,i)}catch(w){let _=w.message||"Unknown error";Ce.warn(Se.yellow(`Native "pod" command failed: ${_}`)),Ce.info(Se.dim("Falling back to npm exec pod-install..."));let C=o();c(qe.resolve("ios"),C),Ce.info(Se.magenta(`${A.nameUpper}_DEBUG: Executing pod-install override via npx --yes pod-install@latest`)),await a("npx",["--yes","pod-install@latest","ios"],process.cwd(),C)}if(we.existsSync("ios/Pods")){Ce.info(Se.dim("Disabling signing for Pod targets to prevent conflicts..."));try{wr(`find ios/Pods -name "project.pbxproj" -exec sed -i '' 's/buildSettings = {/buildSettings = { CODE_SIGNING_ALLOWED = NO; CODE_SIGNING_REQUIRED = NO; PROVISIONING_PROFILE_SPECIFIER = ""; EXPANDED_CODE_SIGN_IDENTITY = "";/g' {} +`,{stdio:"ignore"})}catch{}}return{appName:f,bundleId:d}}finally{g&&we.writeFileSync(y,g)}}};import{log as Me}from"@clack/prompts";import Ge from"chalk";import Fe from"fs";import dt from"path";import{spawnSync as vr}from"child_process";import $e from"fs";import Ze from"path";var $n=(e,t)=>Ze.join(e,"node_modules",".bin",process.platform==="win32"?`${t}.cmd`:t),Er=e=>{try{return JSON.parse($e.readFileSync(Ze.join(e,"package.json"),"utf-8"))}catch{return{}}};function _a(e,t){let n=Er(e);return!!(n.dependencies?.[t]||n.devDependencies?.[t])}function Ut(e,t,n,i={}){let r=`${t} ${n.join(" ")}`,o=vr(t,n,{cwd:e,stdio:"inherit",env:{...process.env,CI:process.env.CI||"1",EXPO_NO_TELEMETRY:"1",...i}});return o.error?{ok:!1,command:r,error:o.error.message}:o.status!==0?{ok:!1,command:r,error:`${t} exited with code ${o.status}`}:{ok:!0,command:r}}function Ta(e){return Ut(e,"npx",["--yes","install-expo-modules@latest"])}function Oa(e){let t=$n(e,"expo");return $e.existsSync(t)?Ut(e,t,["install","expo-updates"]):{ok:!1,command:"npx expo install expo-updates",error:"Expo Modules are not installed. Install Expo Modules first."}}function Ba(e){let t=[];return $e.existsSync(Ze.join(e,"ios"))&&t.push("ios"),$e.existsSync(Ze.join(e,"android"))&&t.push("android"),t}function Fn(e){let t=$n(e.cwd,"expo-updates");return $e.existsSync(t)?e.platforms.map(n=>Ut(e.cwd,t,["configuration:syncnative","--platform",n,"--workflow","generic"],{MACH_OTA_RUNTIME_VERSION:e.runtimeVersion,MACH_OTA_CHANNEL:e.channel,MACH_OTA_URL:e.url})):[{ok:!1,command:"expo-updates configuration:syncnative",error:"expo-updates is not installed in this project."}]}function Da(e){let t=Ze.join(e,"android","app","src","main","AndroidManifest.xml"),n=Ze.join(e,"android","app","src","main","res","values","strings.xml"),i,r=Ze.join(e,"ios");if($e.existsSync(r)){let o=[r];for(;o.length>0&&!i;){let s=o.shift();for(let a of $e.readdirSync(s,{withFileTypes:!0})){if(a.name==="Pods"||a.name==="build")continue;let c=Ze.join(s,a.name);if(a.isDirectory())o.push(c);else if(a.isFile()&&a.name==="Expo.plist"){i=c;break}}}}return{...$e.existsSync(t)?{androidManifest:t}:{},...$e.existsSync(n)?{androidStrings:n}:{},...i?{iosExpoPlist:i}:{}}}var Pr=(e,t)=>!Fe.existsSync(e)||!Fe.existsSync(t)?!1:Fe.readFileSync(e,"utf-8")!==Fe.readFileSync(t,"utf-8"),Xt={id:"react-native",displayName:"React Native",applyLocalProcessEnv:e=>{delete process.env.EXPO_NO_DEV_CLIENT,delete process.env.EXPO_AUTOLINKING_EXCLUDE,delete process.env.EXPO_NO_DOTENV},localAndroidEnv:(e,t)=>({MACH_FRAMEWORK:"react-native",MACH_BUILD_PROFILE:t}),remoteEnvSetupScript:()=>`
235
235
  export MACH_FRAMEWORK="react-native"
236
236
  echo "[ENV] MACH_FRAMEWORK=$MACH_FRAMEWORK"
237
237
  unset EXPO_NO_DOTENV
@@ -262,48 +262,48 @@ fi
262
262
  :
263
263
  `,androidRemoteReleaseGradlePropertiesScript:()=>`
264
264
  :
265
- `,prepareLocalProject:async e=>{let{platform:t,cacheMeta:n,cacheMetaDir:i,currentBuildEnv:r,reportStep:o,reportLog:s,loggedRun:a,configureXcodeNodeBinary:c,podsFingerprint:l,writeCacheMeta:p}=e,d=r(),f=d.MACH_OTA_RUNTIME_VERSION,I=d.MACH_OTA_CHANNEL,g=d.MACH_OTA_URL;if(f&&I&&g){let R=Fn({cwd:process.cwd(),platforms:[t],runtimeVersion:f,channel:I,url:g}).find(V=>!V.ok);if(R)throw new Error(`Could not synchronize ${t} Expo Updates configuration: ${R.error||R.command}. Run \`mach ota setup --platform ${t}\` and try again.`);Me.info(Ge.green(`\u2713 OTA runtime ${f} synchronized for ${t}`))}if(t!=="ios")return{};let h=dt.resolve("ios"),w=dt.join(h,"Podfile");if(!Fe.existsSync(w))throw new Error("React Native iOS build requires ios/Podfile. Commit the ios directory for vanilla React Native projects.");await o("pods"),Me.info(Ge.blue("Running React Native pod install..."));let _=r();c(h,_);let C=dt.join(h,"Pods"),v=dt.join(h,"Podfile.lock"),x=dt.join(C,"Manifest.lock"),F=Fe.existsSync(C),D=l(h);F&&n.reactNativePods&&n.reactNativePods!==D?(await s(`[CACHE] React Native Podfile/Podfile.lock changed - wiping ios/Pods
265
+ `,prepareLocalProject:async e=>{let{platform:t,cacheMeta:n,cacheMetaDir:i,currentBuildEnv:r,reportStep:o,reportLog:s,loggedRun:a,configureXcodeNodeBinary:c,podsFingerprint:l,writeCacheMeta:p}=e,d=r(),f=d.MACH_OTA_RUNTIME_VERSION,y=d.MACH_OTA_CHANNEL,g=d.MACH_OTA_URL;if(f&&y&&g){let R=Fn({cwd:process.cwd(),platforms:[t],runtimeVersion:f,channel:y,url:g}).find(V=>!V.ok);if(R)throw new Error(`Could not synchronize ${t} Expo Updates configuration: ${R.error||R.command}. Run \`mach ota setup --platform ${t}\` and try again.`);Me.info(Ge.green(`\u2713 OTA runtime ${f} synchronized for ${t}`))}if(t!=="ios")return{};let h=dt.resolve("ios"),w=dt.join(h,"Podfile");if(!Fe.existsSync(w))throw new Error("React Native iOS build requires ios/Podfile. Commit the ios directory for vanilla React Native projects.");await o("pods"),Me.info(Ge.blue("Running React Native pod install..."));let _=r();c(h,_);let C=dt.join(h,"Pods"),v=dt.join(h,"Podfile.lock"),x=dt.join(C,"Manifest.lock"),F=Fe.existsSync(C),D=l(h);F&&n.reactNativePods&&n.reactNativePods!==D?(await s(`[CACHE] React Native Podfile/Podfile.lock changed - wiping ios/Pods
266
266
  `),Me.info(Ge.dim("React Native Podfile fingerprint changed - clearing Pods for clean install...")),Fe.rmSync(C,{recursive:!0,force:!0})):F&&Pr(v,x)&&(await s(`[CACHE] React Native Pods Manifest.lock is out of sync - wiping ios/Pods
267
267
  `),Me.info(Ge.dim("React Native Pods manifest is out of sync - clearing Pods for clean install...")),Fe.rmSync(C,{recursive:!0,force:!0}));let j="/opt/homebrew/bin/pod",N=Fe.existsSync(j)?j:"pod";try{Me.info(Ge.dim(`Using pod command: ${N} in ${h}`)),await a(N,["install"],h,_)}catch(T){let R=T.message||"Unknown error";Me.warn(Ge.yellow(`Native "pod" command failed: ${R}`)),Me.info(Ge.dim("Falling back to npx pod-install..."));let V=r();c(h,V),Me.info(Ge.magenta(`${A.nameUpper}_DEBUG: Executing pod-install fallback via npx --yes pod-install@latest`)),await a("npx",["--yes","pod-install@latest","ios"],process.cwd(),V)}return n.reactNativePods=l(h),p(i,n),{}}};var Nr={expo:xn,"react-native":Xt};function pt(e){if(!e)return Xt;if(e!=="flutter")return Nr[e];throw new Error('Flutter builds are not implemented yet. Set framework to "expo" or "react-native" for this build.')}var Rr="mach-env-v2-js-bundle-cache",xr=new Set(["BUILD_ID","BUILD_NUMBER","ANDROID_VERSION_CODE","MACH_TOKEN","MACH_DEBUG","MACH_S3_DEBUG","MACH_ENV_FINGERPRINT","CODEARTIFACT_AUTH_TOKEN","EXPO_ZQRN_BB_REPO_TOKEN","SENTRY_AUTH_TOKEN","IOS_DIST_P12","IOS_PROVISIONING_PROFILE","IOS_P12_PASSWORD","MATCH_ENCRYPTION_PASSPHRASE","MATCH_PASSWORD","MATCH_KEYCHAIN_NAME","MATCH_KEYCHAIN_PASSWORD","APPLE_TEAM_ID","FASTLANE_TEAM_ID","ANDROID_KEYSTORE","ANDROID_KEYSTORE_BASE64","ANDROID_STORE_PASSWORD","ANDROID_KEY_PASSWORD","ANDROID_KEY_ALIAS","KEYSTORE_PASSWORD","KEYSTORE_ALIAS","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SESSION_TOKEN","AWS_SECURITY_TOKEN","GITHUB_TOKEN","NPM_TOKEN"]),$r=["PRESIGNED_","KEYSTORE_PASSWORD_"],Fr=e=>!e||xr.has(e)?!1:!$r.some(t=>e.startsWith(t)),jt=(e,t,n)=>{let i=pt(n.framework);return{...e,...i.localAndroidEnv(n,t),MACH_APP_NAME:n.appName||n.name||"App"}},_n=e=>{let t=Object.entries(e).filter(([n])=>Fr(n)).sort(([n],[i])=>n.localeCompare(i));return kr.createHash("sha256").update(JSON.stringify({version:Rr,entries:t})).digest("hex")};var _r=/^\d+(?:\.\d+){0,2}$/,Tr="auto";var Tn=e=>typeof e=="string"&&e.trim().toLowerCase()===Tr,Qa=(e,t,n,i=!0)=>e!=null&&String(e).trim()!==""?{kind:"persisted",value:e}:t!=null&&!Tn(t)?{kind:"explicit",value:t}:i&&(n||Tn(t))?{kind:"auto"}:{kind:"none"},ut=e=>{let t=String(e??"").trim();return!t||t==="undefined"||t==="null"?null:_r.test(t)?t:null},et=(e,t)=>{let n=ut(e);if(!n)throw new Error(`Invalid iOS buildNumber from ${t}: "${String(e??"")}". Use one to three period-separated integers, for example "68" or "1.2.3".`);return n},Or=e=>{if(typeof e=="string"&&!/^\d+$/.test(e.trim()))return null;let t=Number(e);return!Number.isSafeInteger(t)||t<1||t>21e8?null:String(t)},Re=(e,t)=>{let n=Or(e);if(!n)throw new Error(`Invalid Android versionCode from ${t}: "${String(e??"")}". Use an integer from 1 to 2100000000.`);return n},qa=(e,t,n,i)=>{let r=et(n,i);return e.resolvedBuildNumber=r,t.BUILD_NUMBER=r,t.CURRENT_PROJECT_VERSION=r,t.MACH_IOS_BUILD_NUMBER_LOCKED="1",r},ec=(e,t,n,i)=>{let r=Re(n,i);return e.resolvedVersionCode=r,t.ANDROID_VERSION_CODE=r,t.MACH_ANDROID_VERSION_CODE_LOCKED="1",r},tc=(e,t)=>{let n=t.buildNumber!==void 0&&t.buildNumber!==null&&String(t.buildNumber).trim()!=="",i=t.versionCode!==void 0&&t.versionCode!==null&&String(t.versionCode).trim()!=="";!e.resolvedBuildNumber&&n&&(e.resolvedBuildNumber=et(t.buildNumber,"saved MACH build record")),!e.resolvedVersionCode&&i&&(e.resolvedVersionCode=Re(t.versionCode,"saved MACH build record"))};import{execFileSync as Lt}from"child_process";import _e from"fs";import Le from"path";var Br=new Set(["Pods","build","DerivedData",".git"]),On=(e,t=[])=>{if(!_e.existsSync(e))return t;for(let n of _e.readdirSync(e,{withFileTypes:!0})){if(n.isSymbolicLink())continue;let i=Le.join(e,n.name);if(n.isDirectory()){if(Br.has(n.name)||n.name.endsWith(".xcworkspace")||n.name.endsWith(".xcarchive")||n.name.endsWith(".framework")||n.name.endsWith(".xcframework")||n.name.endsWith(".bundle")||n.name.endsWith(".app")||n.name.endsWith(".appex"))continue;On(i,t);continue}n.isFile()&&n.name==="Info.plist"&&t.push(i)}return t},Dr=(e,t,n)=>{let i=String(e||"").trim().replace(/^"|"$/g,"");if(!i||(i=i.replace(/\$\(([^)]+)\)|\$\{([^}]+)\}/g,(o,s,a)=>{let l=t[s||a];return l===void 0?"":String(l)}),!i||i.includes("$(")||i.includes("${")))return null;let r=String(t.SRCROOT||t.PROJECT_DIR||n);return Le.resolve(Le.isAbsolute(i)?i:Le.join(r,i))},Vr=e=>{let t=e.indexOf("["),n=e.lastIndexOf("]");if(t<0||n<t)return[];let i=JSON.parse(e.slice(t,n+1));return Array.isArray(i)?i:[]},Wr=(e,t)=>{let n=new Set,i=[];(t.workspace||t.project)&&i.push([...t.workspace?["-workspace",t.workspace]:["-project",t.project],"-scheme",t.scheme]),t.project&&i.push(["-project",t.project,"-alltargets"]);for(let r of i){let o="";try{o=Lt("xcodebuild",[...r,"-configuration",t.configuration,"-showBuildSettings","-json"],{cwd:e,encoding:"utf8",maxBuffer:16*1024*1024})}catch{continue}for(let s of Vr(o)){let a=s?.buildSettings;if(!a)continue;let c=String(a.WRAPPER_EXTENSION||"").toLowerCase();if(c!=="app"&&c!=="appex")continue;let l=Dr(String(a.INFOPLIST_FILE||""),a,e);if(!l||!_e.existsSync(l))continue;let p=Le.relative(e,l);p.startsWith("..")||Le.isAbsolute(p)||n.add(l)}}return[...n].sort()},Zr=(e,t)=>{let n=_e.readFileSync(e,"utf8");if(!/<plist(?:\s|>)/.test(n))return!1;let r=/<key>\s*CFBundleVersion\s*<\/key>/.exec(n),o;if(r){let s=r.index+r[0].length,a=n.slice(s),c=/^\s*<(string|integer)>[\s\S]*?<\/\1>/.exec(a);if(!c)throw new Error(`Could not update CFBundleVersion in ${e}: unsupported plist value type.`);o=n.slice(0,s)+`
268
268
  <string>${t}</string>`+a.slice(c[0].length)}else{let s=n.lastIndexOf("</dict>");if(s<0)throw new Error(`Could not update CFBundleVersion in ${e}: root dictionary not found.`);o=n.slice(0,s)+` <key>CFBundleVersion</key>
269
269
  <string>${t}</string>
270
- `+n.slice(s)}return _e.writeFileSync(e,o),!0},Mr=(e,t)=>{if(!Zr(e,t)){if(process.platform!=="darwin")throw new Error(`Could not update binary Info.plist outside macOS: ${e}`);try{Lt("/usr/bin/plutil",["-replace","CFBundleVersion","-string",t,e])}catch{Lt("/usr/bin/plutil",["-insert","CFBundleVersion","-string",t,e])}}},Bn=(e,t,n)=>{let i=et(t,"resolved MACH build"),r=Le.resolve(e),o=new Set;if(n)try{for(let l of Wr(r,n))o.add(l)}catch{}for(let l of On(r))o.add(l);let s=[...o].sort(),a=new Map,c=!1;try{for(let l of s)a.set(l,_e.readFileSync(l)),Mr(l,i)}catch(l){for(let[p,d]of a)_e.writeFileSync(p,d);throw l}return{buildNumber:i,plistPaths:s,restore:()=>{if(!c){c=!0;for(let[l,p]of a)_e.existsSync(l)&&_e.writeFileSync(l,p)}}}},Ht=(e,t,n)=>{let i=et(e,n),r=et(t,"resolved MACH build");if(i!==r)throw new Error(`iOS build number mismatch in ${n}: expected MACH buildNumber ${r}, but the artifact contains CFBundleVersion ${i}.`);return i};import{execFileSync as Dn}from"child_process";import mt from"fs";import ue from"path";import Gr from"adm-zip";var Kt=(e,t)=>{let n=0n,i=0n,r=t;for(;r<e.length&&i<=63n;){let o=e[r++];if(n|=BigInt(o&127)<<i,(o&128)===0)return{value:n,next:r};i+=7n}throw new Error("Malformed protobuf varint")},ft=e=>{let t=[],n=0;for(;n<e.length;){let i=Kt(e,n);n=i.next;let r=Number(i.value>>3n),o=Number(i.value&7n);if(r<1)throw new Error("Malformed protobuf field number");if(o===0){let s=Kt(e,n);n=s.next,t.push({number:r,wireType:o,varint:s.value});continue}if(o===1){if(n+8>e.length)throw new Error("Truncated protobuf fixed64");t.push({number:r,wireType:o,bytes:e.subarray(n,n+8)}),n+=8;continue}if(o===2){let s=Kt(e,n);n=s.next;let a=Number(s.value);if(!Number.isSafeInteger(a)||n+a>e.length)throw new Error("Truncated protobuf length-delimited field");t.push({number:r,wireType:o,bytes:e.subarray(n,n+a)}),n+=a;continue}if(o===5){if(n+4>e.length)throw new Error("Truncated protobuf fixed32");t.push({number:r,wireType:o,bytes:e.subarray(n,n+4)}),n+=4;continue}throw new Error(`Unsupported protobuf wire type ${o}`)}return t},Vn=(e,t)=>e.find(i=>i.number===t&&i.wireType===2)?.bytes?.toString("utf8"),Ur=e=>{let n=ft(e).find(o=>o.number===7&&o.wireType===2)?.bytes;if(!n)return null;let r=ft(n).find(o=>(o.number===6||o.number===7)&&o.wireType===0)?.varint;return r===void 0||r>BigInt(Number.MAX_SAFE_INTEGER)?null:r.toString()},Xr=e=>{let n=ft(e).find(l=>l.number===1&&l.wireType===2)?.bytes;if(!n)throw new Error("AAB base manifest has no root XML element");let o=ft(n).filter(l=>l.number===4&&l.wireType===2).map(l=>ft(l.bytes)).find(l=>Vn(l,2)==="versionCode");if(!o)throw new Error("AAB base manifest has no android:versionCode");let s=Vn(o,3)?.trim();if(s&&/^\d+$/.test(s))return Re(s,"packaged AAB manifest");let a=o.find(l=>l.number===6&&l.wireType===2)?.bytes,c=a?Ur(a):null;return Re(c,"packaged AAB manifest")},Wn=e=>{try{return mt.accessSync(e,mt.constants.X_OK),mt.statSync(e).isFile()}catch{return!1}},Jt=e=>String(process.env.PATH||"").split(ue.delimiter).filter(Boolean).map(t=>ue.join(t,e)),Zn=()=>Array.from(new Set([process.env.ANDROID_HOME,process.env.ANDROID_SDK_ROOT,process.platform==="darwin"?ue.join(process.env.HOME||"","Library/Android/sdk"):ue.join(process.env.HOME||"","Android/Sdk"),"/opt/android-sdk"].filter(e=>!!e))),Mn=e=>{try{return mt.readdirSync(e).map(t=>ue.join(e,t)).filter(t=>mt.statSync(t).isDirectory()).sort((t,n)=>n.localeCompare(t,void 0,{numeric:!0}))}catch{return[]}},jr=()=>{let e=Jt("apkanalyzer");for(let t of Zn()){let n=ue.join(t,"cmdline-tools");e.push(ue.join(n,"latest/bin/apkanalyzer"));for(let i of Mn(n))e.push(ue.join(i,"bin/apkanalyzer"))}return e},Lr=()=>{let e=[...Jt("aapt2"),...Jt("aapt")];for(let t of Zn())for(let n of Mn(ue.join(t,"build-tools")))e.push(ue.join(n,"aapt2"),ue.join(n,"aapt"));return e},Hr=e=>{let t=e.trim();return/^\d+$/.test(t)?t:null},Kr=e=>e.match(/^package:.*\bversionCode='(\d+)'/m)?.[1]||null,Jr=(e,t)=>{let n=t.apkanalyzer??jr();for(let r of n)if(Wn(r))try{let o=Dn(r,["manifest","version-code",e],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),s=Hr(o);if(s)return Re(s,"packaged APK manifest")}catch{}let i=t.aapt??Lr();for(let r of i)if(Wn(r))try{let o=Dn(r,["dump","badging",e],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),s=Kr(o);if(s)return Re(s,"packaged APK manifest")}catch{}throw new Error("Could not inspect the packaged APK versionCode. Install Android SDK command-line tools (apkanalyzer or aapt2) and rebuild; MACH will not publish an unverified artifact.")},Yr=(e,t={})=>{let n=ue.extname(e).toLowerCase();if(n===".apk")return Jr(e,t);if(n!==".aab")throw new Error(`Unsupported Android artifact for version validation: ${e}`);let i;try{i=new Gr(e)}catch(o){throw new Error(`Could not open AAB ${ue.basename(e)}: ${o.message}`)}let r=i.getEntry("base/manifest/AndroidManifest.xml")||i.getEntries().find(o=>o.entryName.replace(/\\/g,"/")==="base/manifest/AndroidManifest.xml");if(!r)throw new Error(`AAB ${ue.basename(e)} has no base module manifest`);try{return Xr(r.getData())}catch(o){throw new Error(`Could not read versionCode from ${ue.basename(e)}: ${o.message}`)}},Yt=(e,t,n={})=>{let i=Re(t,"resolved MACH build assignment"),r=Yr(e,n);if(r!==i)throw new Error(`Android versionCode mismatch in ${ue.basename(e)}: expected ${i}, packaged ${r}. MACH stopped the build before upload.`);return r};var Kn=(e,t)=>t.filter(n=>y.existsSync(b.join(e,n))).reduce((n,i)=>n.update(y.readFileSync(b.join(e,i))),Qr.createHash("sha256")).digest("hex").slice(0,16),qr=e=>Kn(e,["package.json","yarn.lock","package-lock.json","bun.lockb"]),eo=e=>Kn(e,["Podfile","Podfile.lock"]),to=e=>{let t=b.join(e,"fingerprint.json");try{return JSON.parse(y.readFileSync(t,"utf-8"))}catch{return{}}},Gn=(e,t)=>{y.mkdirSync(e,{recursive:!0}),y.writeFileSync(b.join(e,"fingerprint.json"),JSON.stringify(t,null,2))},no=7200*1e3,io=(e,t)=>{y.mkdirSync(e,{recursive:!0});let n=b.join(e,"build.lock");if(y.existsSync(n))try{let i=JSON.parse(y.readFileSync(n,"utf-8")),r=Date.now()-(i.timestamp||0);if(r<no)throw new Error(`Another build is already running for this project (build ${i.buildId}, started ${Math.round(r/6e4)}m ago). Cancel it from the dashboard first, or wait for it to complete.`)}catch(i){if(i.message.includes("Another build"))throw i}y.writeFileSync(n,JSON.stringify({buildId:t,pid:process.pid,timestamp:Date.now()}))},ro=(e,t)=>{let n=b.join(e,"build.lock");try{y.existsSync(n)&&JSON.parse(y.readFileSync(n,"utf-8")).buildId===t&&y.unlinkSync(n)}catch{}},Un=15e5,Xn=(e,t)=>{let n=e+t;return n.length>Un?n.slice(-Un):n},Jn=e=>e.replace(/\u001b\[[0-9;]*m/g,""),Yn=e=>/\berror:|fatal error:|xcodebuild: error|The following build commands failed|Command PhaseScriptExecution failed|PhaseScriptExecution|Command .* failed|CodeSign|Provisioning profile|No profiles|requires a provisioning profile|Undefined symbols|ld:|clang: error|SwiftCompile|CompileC|node: command not found|env: node|No such file or directory|Permission denied/i.test(e),oo=e=>{let t=new Set,n=[];e.forEach((r,o)=>{Yn(r)&&n.push(o)});for(let r of n){let o=/PhaseScriptExecution|Command PhaseScriptExecution failed|The following build commands failed/i.test(e[r])?18:8,s=/The following build commands failed/i.test(e[r])?18:10;for(let a=Math.max(0,r-o);a<=Math.min(e.length-1,r+s);a++)t.add(a)}if(t.size===0)return e.slice(-120);let i=Array.from(t).sort((r,o)=>r-o).map(r=>e[r]);return i.length>160?i.slice(-160):i},so=(e,t,n,i)=>{let r=Jn(i).replace(/\r/g,`
270
+ `+n.slice(s)}return _e.writeFileSync(e,o),!0},Mr=(e,t)=>{if(!Zr(e,t)){if(process.platform!=="darwin")throw new Error(`Could not update binary Info.plist outside macOS: ${e}`);try{Lt("/usr/bin/plutil",["-replace","CFBundleVersion","-string",t,e])}catch{Lt("/usr/bin/plutil",["-insert","CFBundleVersion","-string",t,e])}}},Bn=(e,t,n)=>{let i=et(t,"resolved MACH build"),r=Le.resolve(e),o=new Set;if(n)try{for(let l of Wr(r,n))o.add(l)}catch{}for(let l of On(r))o.add(l);let s=[...o].sort(),a=new Map,c=!1;try{for(let l of s)a.set(l,_e.readFileSync(l)),Mr(l,i)}catch(l){for(let[p,d]of a)_e.writeFileSync(p,d);throw l}return{buildNumber:i,plistPaths:s,restore:()=>{if(!c){c=!0;for(let[l,p]of a)_e.existsSync(l)&&_e.writeFileSync(l,p)}}}},Ht=(e,t,n)=>{let i=et(e,n),r=et(t,"resolved MACH build");if(i!==r)throw new Error(`iOS build number mismatch in ${n}: expected MACH buildNumber ${r}, but the artifact contains CFBundleVersion ${i}.`);return i};import{execFileSync as Dn}from"child_process";import mt from"fs";import ue from"path";import Gr from"adm-zip";var Kt=(e,t)=>{let n=0n,i=0n,r=t;for(;r<e.length&&i<=63n;){let o=e[r++];if(n|=BigInt(o&127)<<i,(o&128)===0)return{value:n,next:r};i+=7n}throw new Error("Malformed protobuf varint")},ft=e=>{let t=[],n=0;for(;n<e.length;){let i=Kt(e,n);n=i.next;let r=Number(i.value>>3n),o=Number(i.value&7n);if(r<1)throw new Error("Malformed protobuf field number");if(o===0){let s=Kt(e,n);n=s.next,t.push({number:r,wireType:o,varint:s.value});continue}if(o===1){if(n+8>e.length)throw new Error("Truncated protobuf fixed64");t.push({number:r,wireType:o,bytes:e.subarray(n,n+8)}),n+=8;continue}if(o===2){let s=Kt(e,n);n=s.next;let a=Number(s.value);if(!Number.isSafeInteger(a)||n+a>e.length)throw new Error("Truncated protobuf length-delimited field");t.push({number:r,wireType:o,bytes:e.subarray(n,n+a)}),n+=a;continue}if(o===5){if(n+4>e.length)throw new Error("Truncated protobuf fixed32");t.push({number:r,wireType:o,bytes:e.subarray(n,n+4)}),n+=4;continue}throw new Error(`Unsupported protobuf wire type ${o}`)}return t},Vn=(e,t)=>e.find(i=>i.number===t&&i.wireType===2)?.bytes?.toString("utf8"),Ur=e=>{let n=ft(e).find(o=>o.number===7&&o.wireType===2)?.bytes;if(!n)return null;let r=ft(n).find(o=>(o.number===6||o.number===7)&&o.wireType===0)?.varint;return r===void 0||r>BigInt(Number.MAX_SAFE_INTEGER)?null:r.toString()},Xr=e=>{let n=ft(e).find(l=>l.number===1&&l.wireType===2)?.bytes;if(!n)throw new Error("AAB base manifest has no root XML element");let o=ft(n).filter(l=>l.number===4&&l.wireType===2).map(l=>ft(l.bytes)).find(l=>Vn(l,2)==="versionCode");if(!o)throw new Error("AAB base manifest has no android:versionCode");let s=Vn(o,3)?.trim();if(s&&/^\d+$/.test(s))return Re(s,"packaged AAB manifest");let a=o.find(l=>l.number===6&&l.wireType===2)?.bytes,c=a?Ur(a):null;return Re(c,"packaged AAB manifest")},Wn=e=>{try{return mt.accessSync(e,mt.constants.X_OK),mt.statSync(e).isFile()}catch{return!1}},Jt=e=>String(process.env.PATH||"").split(ue.delimiter).filter(Boolean).map(t=>ue.join(t,e)),Zn=()=>Array.from(new Set([process.env.ANDROID_HOME,process.env.ANDROID_SDK_ROOT,process.platform==="darwin"?ue.join(process.env.HOME||"","Library/Android/sdk"):ue.join(process.env.HOME||"","Android/Sdk"),"/opt/android-sdk"].filter(e=>!!e))),Mn=e=>{try{return mt.readdirSync(e).map(t=>ue.join(e,t)).filter(t=>mt.statSync(t).isDirectory()).sort((t,n)=>n.localeCompare(t,void 0,{numeric:!0}))}catch{return[]}},jr=()=>{let e=Jt("apkanalyzer");for(let t of Zn()){let n=ue.join(t,"cmdline-tools");e.push(ue.join(n,"latest/bin/apkanalyzer"));for(let i of Mn(n))e.push(ue.join(i,"bin/apkanalyzer"))}return e},Lr=()=>{let e=[...Jt("aapt2"),...Jt("aapt")];for(let t of Zn())for(let n of Mn(ue.join(t,"build-tools")))e.push(ue.join(n,"aapt2"),ue.join(n,"aapt"));return e},Hr=e=>{let t=e.trim();return/^\d+$/.test(t)?t:null},Kr=e=>e.match(/^package:.*\bversionCode='(\d+)'/m)?.[1]||null,Jr=(e,t)=>{let n=t.apkanalyzer??jr();for(let r of n)if(Wn(r))try{let o=Dn(r,["manifest","version-code",e],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),s=Hr(o);if(s)return Re(s,"packaged APK manifest")}catch{}let i=t.aapt??Lr();for(let r of i)if(Wn(r))try{let o=Dn(r,["dump","badging",e],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),s=Kr(o);if(s)return Re(s,"packaged APK manifest")}catch{}throw new Error("Could not inspect the packaged APK versionCode. Install Android SDK command-line tools (apkanalyzer or aapt2) and rebuild; MACH will not publish an unverified artifact.")},Yr=(e,t={})=>{let n=ue.extname(e).toLowerCase();if(n===".apk")return Jr(e,t);if(n!==".aab")throw new Error(`Unsupported Android artifact for version validation: ${e}`);let i;try{i=new Gr(e)}catch(o){throw new Error(`Could not open AAB ${ue.basename(e)}: ${o.message}`)}let r=i.getEntry("base/manifest/AndroidManifest.xml")||i.getEntries().find(o=>o.entryName.replace(/\\/g,"/")==="base/manifest/AndroidManifest.xml");if(!r)throw new Error(`AAB ${ue.basename(e)} has no base module manifest`);try{return Xr(r.getData())}catch(o){throw new Error(`Could not read versionCode from ${ue.basename(e)}: ${o.message}`)}},Yt=(e,t,n={})=>{let i=Re(t,"resolved MACH build assignment"),r=Yr(e,n);if(r!==i)throw new Error(`Android versionCode mismatch in ${ue.basename(e)}: expected ${i}, packaged ${r}. MACH stopped the build before upload.`);return r};var Kn=(e,t)=>t.filter(n=>I.existsSync(b.join(e,n))).reduce((n,i)=>n.update(I.readFileSync(b.join(e,i))),Qr.createHash("sha256")).digest("hex").slice(0,16),qr=e=>Kn(e,["package.json","yarn.lock","package-lock.json","bun.lockb"]),eo=e=>Kn(e,["Podfile","Podfile.lock"]),to=e=>{let t=b.join(e,"fingerprint.json");try{return JSON.parse(I.readFileSync(t,"utf-8"))}catch{return{}}},Gn=(e,t)=>{I.mkdirSync(e,{recursive:!0}),I.writeFileSync(b.join(e,"fingerprint.json"),JSON.stringify(t,null,2))},no=7200*1e3,io=(e,t)=>{I.mkdirSync(e,{recursive:!0});let n=b.join(e,"build.lock");if(I.existsSync(n))try{let i=JSON.parse(I.readFileSync(n,"utf-8")),r=Date.now()-(i.timestamp||0);if(r<no)throw new Error(`Another build is already running for this project (build ${i.buildId}, started ${Math.round(r/6e4)}m ago). Cancel it from the dashboard first, or wait for it to complete.`)}catch(i){if(i.message.includes("Another build"))throw i}I.writeFileSync(n,JSON.stringify({buildId:t,pid:process.pid,timestamp:Date.now()}))},ro=(e,t)=>{let n=b.join(e,"build.lock");try{I.existsSync(n)&&JSON.parse(I.readFileSync(n,"utf-8")).buildId===t&&I.unlinkSync(n)}catch{}},Un=15e5,Xn=(e,t)=>{let n=e+t;return n.length>Un?n.slice(-Un):n},Jn=e=>e.replace(/\u001b\[[0-9;]*m/g,""),Yn=e=>/\berror:|fatal error:|xcodebuild: error|The following build commands failed|Command PhaseScriptExecution failed|PhaseScriptExecution|Command .* failed|CodeSign|Provisioning profile|No profiles|requires a provisioning profile|Undefined symbols|ld:|clang: error|SwiftCompile|CompileC|node: command not found|env: node|No such file or directory|Permission denied/i.test(e),oo=e=>{let t=new Set,n=[];e.forEach((r,o)=>{Yn(r)&&n.push(o)});for(let r of n){let o=/PhaseScriptExecution|Command PhaseScriptExecution failed|The following build commands failed/i.test(e[r])?18:8,s=/The following build commands failed/i.test(e[r])?18:10;for(let a=Math.max(0,r-o);a<=Math.min(e.length-1,r+s);a++)t.add(a)}if(t.size===0)return e.slice(-120);let i=Array.from(t).sort((r,o)=>r-o).map(r=>e[r]);return i.length>160?i.slice(-160):i},so=(e,t,n,i)=>{let r=Jn(i).replace(/\r/g,`
271
271
  `).split(`
272
272
  `).map(c=>c.trimEnd()).filter(Boolean),o=r.filter(Yn),s=o.length>0?oo(r):r.slice(-80),a=o.length>0?"Key failure output":"Last command output";return[`Command failed with code ${n}: ${e} ${t.join(" ")}`,s.length>0?`
273
273
  ${a}:
274
274
  ${s.join(`
275
- `)}`:""].join("")},ao=e=>e==="xcodebuild"&&process.env.MACH_XCODE_FULL_LOGS!=="1",co=e=>{let t=Jn(e).trim();return t?/\berror:|fatal error:|xcodebuild: error|The following build commands failed|Command PhaseScriptExecution failed|CodeSign|Provisioning profile|No profiles|requires a provisioning profile|Undefined symbols|ld:|clang: error|SwiftCompile|CompileC|CFBundleVersion|ARCHIVE SUCCEEDED|ARCHIVE FAILED|EXPORT SUCCEEDED|EXPORT FAILED|Exported .* to:|\[IPA VALID\]/i.test(t):!1},Pe=e=>{try{y.existsSync(e)&&y.rmSync(e,{recursive:!0,force:!0})}catch{}},lo=(e,t)=>{try{if(!y.existsSync(e))return;for(let n of y.readdirSync(e))t(n)&&Pe(b.join(e,n))}catch{}},zt=e=>{P.info(S.dim("Clearing Metro/Hermes JS transform caches..."));let t=de.tmpdir();lo(t,n=>n==="metro-cache"||n.startsWith("metro-")||n.startsWith("haste-map-")||n.startsWith("react-native-packager-cache-")),Pe(b.join(e,".expo")),Pe(b.join(e,"node_modules/.cache/metro")),Pe(b.join(de.homedir(),".cache/metro")),Pe(b.join(de.homedir(),".cache/react-native-packager")),Pe(b.join(de.homedir(),"Library/Caches/metro")),Pe(b.join(de.homedir(),"Library/Caches/react-native-packager"))},po=e=>/Internal inconsistency error|never received target ended message/i.test(String(e?.message||e)),uo=e=>{P.warn(S.yellow("Xcode build system hit an internal inconsistency. Clearing simulator build state and retrying once...")),Pe(b.join(e,"Build")),Pe(b.join(e,"Index.noindex")),Pe(b.join(e,"ModuleCache.noindex")),Pe(b.join(e,"SourcePackages"))},mo=e=>{let t=String(e?.message||e);return/Permission denied/i.test(t)&&/Pods\/.*\.sh/i.test(t)},zn=e=>{let t=b.join(e,"Pods"),i=[b.join(t,"Target Support Files"),t].filter(a=>y.existsSync(a)),r=new Set,o=0,s=a=>{let c=a;try{c=y.realpathSync(a)}catch{}if(r.has(c))return;r.add(c);let l;try{l=y.readdirSync(a,{withFileTypes:!0})}catch{return}for(let p of l){let d=b.join(a,p.name);if(p.isDirectory()){s(d);continue}if(!(!p.isFile()||!p.name.endsWith(".sh")))try{let f=y.statSync(d),I=f.mode|493;I!==f.mode&&(y.chmodSync(d,I),o+=1)}catch{}}};for(let a of i)s(a);return o>0&&P.info(S.dim(`Repaired executable permissions on ${o} CocoaPods script${o===1?"":"s"}.`)),o},fo=(e,t,n,i,r)=>{let o=c=>{let l=c.filter(d=>d?.id&&String(d?.platform||"").includes("iOS Simulator")&&!d?.error),p=l.find(d=>/iphone/i.test(d.name||""))||l[0];return p?.id?`id=${p.id}`:void 0},s=c=>{let l=[],p=!1;for(let d of c.split(`
276
- `)){if(/Ineligible destinations/i.test(d)&&(p=!0),p||!d.includes("platform:iOS Simulator")||d.includes("error:"))continue;let f=d.match(/\bid:([^,}]+)/)?.[1]?.trim(),I=d.match(/\bname:([^,}]+)/)?.[1]?.trim();f&&l.push({id:f,name:I,platform:"iOS Simulator"})}return o(l)},a=[t?"-workspace":"-project",t||n,"-scheme",i,"-configuration",r,"-sdk","iphonesimulator","-showdestinations"];try{let c=Te("xcodebuild",[...a,"-json"],{cwd:e,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}),l=JSON.parse(c),p=Array.isArray(l.destinations)?l.destinations:Array.isArray(l.availableDestinations)?l.availableDestinations:[],d=o(p);if(d)return d}catch{}try{let c=Te("xcodebuild",a,{cwd:e,encoding:"utf-8",stdio:["ignore","pipe","ignore"]});return s(c)}catch{}},Oe=(e,t,n=process.cwd(),i={},r,o)=>new Promise((s,a)=>{let c="",l=ao(e),p=Date.now(),d=["/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin","/usr/sbin","/sbin",b.join(de.homedir(),".npm-global/bin")],I=[...(process.env.PATH||"").split(":"),...d].filter((C,v,x)=>C&&x.indexOf(C)===v).join(":");process.env[`${A.envPrefix}DEBUG`]&&console.log(S.magenta(`[${A.nameUpper}_DEBUG] Execution PATH: ${I}`));let g={...process.env,...i,PATH:I,LANG:"en_US.UTF-8",LC_ALL:"en_US.UTF-8"};r&&process.env[`${A.envPrefix}DEBUG`]&&(r(S.magenta(`[ENVIRONMENT] node: ${process.execPath}
277
- `)),r(S.magenta(`[ENVIRONMENT] PATH: ${I}
275
+ `)}`:""].join("")},ao=e=>e==="xcodebuild"&&process.env.MACH_XCODE_FULL_LOGS!=="1",co=e=>{let t=Jn(e).trim();return t?/\berror:|fatal error:|xcodebuild: error|The following build commands failed|Command PhaseScriptExecution failed|CodeSign|Provisioning profile|No profiles|requires a provisioning profile|Undefined symbols|ld:|clang: error|SwiftCompile|CompileC|CFBundleVersion|ARCHIVE SUCCEEDED|ARCHIVE FAILED|EXPORT SUCCEEDED|EXPORT FAILED|Exported .* to:|\[IPA VALID\]/i.test(t):!1},Pe=e=>{try{I.existsSync(e)&&I.rmSync(e,{recursive:!0,force:!0})}catch{}},lo=(e,t)=>{try{if(!I.existsSync(e))return;for(let n of I.readdirSync(e))t(n)&&Pe(b.join(e,n))}catch{}},zt=e=>{P.info(S.dim("Clearing Metro/Hermes JS transform caches..."));let t=de.tmpdir();lo(t,n=>n==="metro-cache"||n.startsWith("metro-")||n.startsWith("haste-map-")||n.startsWith("react-native-packager-cache-")),Pe(b.join(e,".expo")),Pe(b.join(e,"node_modules/.cache/metro")),Pe(b.join(de.homedir(),".cache/metro")),Pe(b.join(de.homedir(),".cache/react-native-packager")),Pe(b.join(de.homedir(),"Library/Caches/metro")),Pe(b.join(de.homedir(),"Library/Caches/react-native-packager"))},po=e=>/Internal inconsistency error|never received target ended message/i.test(String(e?.message||e)),uo=e=>{P.warn(S.yellow("Xcode build system hit an internal inconsistency. Clearing simulator build state and retrying once...")),Pe(b.join(e,"Build")),Pe(b.join(e,"Index.noindex")),Pe(b.join(e,"ModuleCache.noindex")),Pe(b.join(e,"SourcePackages"))},mo=e=>{let t=String(e?.message||e);return/Permission denied/i.test(t)&&/Pods\/.*\.sh/i.test(t)},zn=e=>{let t=b.join(e,"Pods"),i=[b.join(t,"Target Support Files"),t].filter(a=>I.existsSync(a)),r=new Set,o=0,s=a=>{let c=a;try{c=I.realpathSync(a)}catch{}if(r.has(c))return;r.add(c);let l;try{l=I.readdirSync(a,{withFileTypes:!0})}catch{return}for(let p of l){let d=b.join(a,p.name);if(p.isDirectory()){s(d);continue}if(!(!p.isFile()||!p.name.endsWith(".sh")))try{let f=I.statSync(d),y=f.mode|493;y!==f.mode&&(I.chmodSync(d,y),o+=1)}catch{}}};for(let a of i)s(a);return o>0&&P.info(S.dim(`Repaired executable permissions on ${o} CocoaPods script${o===1?"":"s"}.`)),o},fo=(e,t,n,i,r)=>{let o=c=>{let l=c.filter(d=>d?.id&&String(d?.platform||"").includes("iOS Simulator")&&!d?.error),p=l.find(d=>/iphone/i.test(d.name||""))||l[0];return p?.id?`id=${p.id}`:void 0},s=c=>{let l=[],p=!1;for(let d of c.split(`
276
+ `)){if(/Ineligible destinations/i.test(d)&&(p=!0),p||!d.includes("platform:iOS Simulator")||d.includes("error:"))continue;let f=d.match(/\bid:([^,}]+)/)?.[1]?.trim(),y=d.match(/\bname:([^,}]+)/)?.[1]?.trim();f&&l.push({id:f,name:y,platform:"iOS Simulator"})}return o(l)},a=[t?"-workspace":"-project",t||n,"-scheme",i,"-configuration",r,"-sdk","iphonesimulator","-showdestinations"];try{let c=Te("xcodebuild",[...a,"-json"],{cwd:e,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}),l=JSON.parse(c),p=Array.isArray(l.destinations)?l.destinations:Array.isArray(l.availableDestinations)?l.availableDestinations:[],d=o(p);if(d)return d}catch{}try{let c=Te("xcodebuild",a,{cwd:e,encoding:"utf-8",stdio:["ignore","pipe","ignore"]});return s(c)}catch{}},Oe=(e,t,n=process.cwd(),i={},r,o)=>new Promise((s,a)=>{let c="",l=ao(e),p=Date.now(),d=["/opt/homebrew/bin","/usr/local/bin","/usr/bin","/bin","/usr/sbin","/sbin",b.join(de.homedir(),".npm-global/bin")],y=[...(process.env.PATH||"").split(":"),...d].filter((C,v,x)=>C&&x.indexOf(C)===v).join(":");process.env[`${A.envPrefix}DEBUG`]&&console.log(S.magenta(`[${A.nameUpper}_DEBUG] Execution PATH: ${y}`));let g={...process.env,...i,PATH:y,LANG:"en_US.UTF-8",LC_ALL:"en_US.UTF-8"};r&&process.env[`${A.envPrefix}DEBUG`]&&(r(S.magenta(`[ENVIRONMENT] node: ${process.execPath}
277
+ `)),r(S.magenta(`[ENVIRONMENT] PATH: ${y}
278
278
  `)),r(S.magenta(`[ENVIRONMENT] command: ${e} ${t.join(" ")}
279
- `)));let h=e;if(["node","npm","npx","pod"].includes(e)){let C=b.dirname(process.execPath),v=b.join(C,e);y.existsSync(v)&&(h=v,r&&r(S.dim(`[EXEC] Using absolute path: ${h}
279
+ `)));let h=e;if(["node","npm","npx","pod"].includes(e)){let C=b.dirname(process.execPath),v=b.join(C,e);I.existsSync(v)&&(h=v,r&&r(S.dim(`[EXEC] Using absolute path: ${h}
280
280
  `)))}let w=Hn(h,t,{stdio:"pipe",cwd:n,shell:!0,env:g,detached:process.platform!=="win32"});if(o){if(o.aborted){if(w.pid)try{process.kill(-w.pid,"SIGTERM")}catch{w.kill()}return a(new Error("Command aborted"))}o.addEventListener("abort",()=>{if(w.pid)try{process.kill(-w.pid,"SIGTERM")}catch{w.kill()}a(new Error("Command aborted"))})}let _=(C,v)=>{if(!l){v.write(C);return}let x=C.replace(/\r/g,`
281
281
  `).split(`
282
282
  `).filter(co);if(x.length>0){v.write(`${x.join(`
283
283
  `)}
284
284
  `),p=Date.now();return}let F=Date.now();F-p>3e4&&(v.write(`[xcodebuild] still running; detailed output is streamed to Mach logs.
285
- `),p=F)};w.stdout.on("data",C=>{let v=C.toString();c=Xn(c,v),_(v,process.stdout),r&&r(v)}),w.stderr.on("data",C=>{let v=C.toString();c=Xn(c,v),_(v,process.stderr),r&&r(v)}),w.on("close",C=>{C===0?s(C):a(new Error(so(e,t,C,c)))}),w.on("error",C=>a(C))}),Ct=async(e,t,n,i,r)=>{try{await Oe("xcodebuild",e,t,n,i,r)}catch(o){if(!mo(o))throw o;P.warn(S.yellow("CocoaPods script permission denied. Repairing Pods script permissions and retrying xcodebuild once...")),zn(t),await Oe("xcodebuild",e,t,n,i,r)}},go=e=>{let t=Math.floor(e/1e3%60),n=Math.floor(e/(1e3*60)%60),i=Math.floor(e/(1e3*60*60)%24),r=[];return i>0&&r.push(`${i}h`),n>0&&r.push(`${n}m`),(t>0||r.length===0)&&r.push(`${t}s`),r.join(" ")},He=(e,t)=>{let n=[];try{if(!y.existsSync(e))return n;let i=y.readdirSync(e);for(let r of i){let o=b.join(e,r);try{let s=y.statSync(o);if(t.some(c=>r.endsWith(c))){n.push(b.resolve(o));continue}s.isDirectory()&&(n=n.concat(He(o,t)))}catch{}}}catch{}return n},Qn=(e,t)=>{let n=ut(e);if(!n)throw new Error(`Invalid iOS CFBundleVersion from ${t}: "${e||""}". Apple requires one to three period-separated integers, for example "42" or "1.2.3". If you see "[Decryption Failed]", fix/remove the broken BUILD_NUMBER secret and rebuild.`);return n},qt=(e,t)=>Te("/usr/libexec/PlistBuddy",["-c",`Print :${t}`,e],{encoding:"utf-8"}).trim(),tt=(e,t)=>{try{return qt(e,t)}catch{return""}},jn=e=>String(e||"").replace(/\.app$/i,"").replace(/[^a-z0-9]/gi,"").toLowerCase(),ho=e=>{try{return y.statSync(e).isDirectory()}catch{return!1}},yo=(e,t,n)=>{if(!y.existsSync(e))throw new Error(`iOS simulator build output directory was not found: ${e}`);let i=y.readdirSync(e).filter(l=>l.endsWith(".app")).map(l=>b.join(e,l)).filter(ho);if(i.length===0){let p=He(e,[".app"]).map(d=>b.relative(e,d)).join(", ");throw new Error(`No top-level iOS simulator .app product was found in ${e}.`+(p?` Nested .app bundles found but ignored: ${p}`:""))}let r=new Set([t,n.iosScheme,n.scheme,n.appName].filter(Boolean).map(l=>jn(String(l))).filter(Boolean)),o=i.map(l=>{let p=b.join(l,"Info.plist"),d=y.existsSync(p)?tt(p,"CFBundleName"):"",f=y.existsSync(p)?tt(p,"CFBundleDisplayName"):"",I=y.existsSync(p)?tt(p,"CFBundleExecutable"):"",g=y.existsSync(p)?tt(p,"CFBundleIdentifier"):"",h=I?b.join(l,I):"";return{appPath:l,bundleIdentifier:g,executable:I,isValid:y.existsSync(p)&&!!I&&y.existsSync(h),names:[b.basename(l,".app"),d,f,I].map(jn).filter(Boolean)}}),s=o.filter(l=>l.isValid);if(s.length===0)throw new Error(`No valid iOS simulator .app product was found in ${e}. Candidates: `+o.map(l=>b.basename(l.appPath)).join(", "));let c=s.find(l=>l.names.some(p=>r.has(p)))||(s.length===1?s[0]:null);if(!c)throw new Error(`Multiple iOS simulator .app products were found in ${e}: `+s.map(l=>{let p=l.bundleIdentifier?` (${l.bundleIdentifier})`:"";return`${b.basename(l.appPath)}${p}`}).join(", ")+`. Set ios.scheme in ${A.configFileName} so ${A.name} can select the app target safely.`);return c.appPath},Io=(e,t)=>{let n=b.join(e,"Info.plist");if(!y.existsSync(n))throw new Error(`Could not validate iOS build number: ${n} not found.`);let i=Qn(qt(n,"CFBundleVersion"),n);return t?Ht(i,t,n):i},qn=(e,t=[])=>{if(!y.existsSync(e))return t;for(let n of y.readdirSync(e,{withFileTypes:!0})){if(!n.isDirectory()||n.isSymbolicLink())continue;let i=b.join(e,n.name);n.name!=="Frameworks"&&((n.name.endsWith(".app")||n.name.endsWith(".appex"))&&t.push(i),qn(i,t))}return t},Ln=(e,t)=>[e,...qn(e)].filter((i,r,o)=>o.indexOf(i)===r).map(i=>({bundlePath:i,buildNumber:Io(i,t)})),ei=e=>{let t=b.join(e,"Info.plist");if(!y.existsSync(t))throw new Error(`Could not validate iOS app executable: ${t} not found.`);let n=tt(t,"CFBundleExecutable");if(!n)throw new Error(`Could not validate iOS app executable: CFBundleExecutable missing in ${t}.`);let i=b.join(e,n);if(!y.existsSync(i))throw new Error(`Could not validate iOS app executable: ${i} not found.`);return i},Ao=()=>process.arch==="arm64"?"arm64":"x86_64",ti=e=>{let t=ei(e),n="";try{n=Te("lipo",["-info",t],{encoding:"utf-8"}).trim()}catch(r){throw new Error(`Could not inspect iOS simulator executable architecture for ${b.basename(e)}: ${r.message}`)}let i=Ao();if(!new RegExp(`\\b${i}\\b`).test(n))throw new Error(`iOS simulator app ${b.basename(e)} cannot be installed on this runner because its executable does not include the required ${i} simulator architecture. lipo output: ${n}. Check the React Native iOS project ARCHS/EXCLUDED_ARCHS settings for iphonesimulator builds.`);return n},bo=e=>{try{return Te("xcrun",["vtool","-show-build",e],{encoding:"utf-8"}).trim()}catch(t){throw new Error(`Could not inspect iOS executable build platform for ${b.basename(e)}: ${t.message}`)}},ni=e=>{let t=ei(e),n=bo(t);if(!/\bplatform\s+IOSSIMULATOR\b/i.test(n))throw new Error(`iOS simulator app ${b.basename(e)} was built for the wrong Apple platform. A simulator artifact must contain PLATFORM IOSSIMULATOR, not an iPhone device binary. vtool output: ${n}`);return n},ii=(e,t)=>{let i=Te("unzip",["-Z1",e],{encoding:"utf-8"}).split(`
286
- `).map(o=>o.trim()).filter(o=>/^Payload\/.+\.(?:app|appex)\/Info\.plist$/.test(o)&&!o.includes("/Frameworks/"));if(i.length===0)throw new Error(`Could not validate iOS build number: ${b.basename(e)} has no Payload/*.app/Info.plist.`);let r=y.mkdtempSync(b.join(de.tmpdir(),`${A.nameLower}-ipa-plist-`));try{let o="";for(let[s,a]of i.entries()){let c=b.join(r,`Info-${s}.plist`),l=Te("unzip",["-p",e,a]);y.writeFileSync(c,l);let p=`${b.basename(e)}:${a}`,d=Qn(qt(c,"CFBundleVersion"),p);t&&Ht(d,t,p),/^Payload\/[^/]+\.app\/Info\.plist$/.test(a)&&(o=d)}if(!o)throw new Error(`Could not validate iOS build number: ${b.basename(e)} has no main application Info.plist.`);return o}finally{y.rmSync(r,{recursive:!0,force:!0})}},Co=e=>`'${e.replace(/'/g,"'\\''")}'`,So=()=>process.execPath&&y.existsSync(process.execPath)?process.execPath:Te("which",["node"],{encoding:"utf-8"}).trim(),ri=(e,t,n)=>{if(!y.existsSync(e))return;let i=So();t.NODE_BINARY=i;let r=b.join(e,".xcode.env.local");y.writeFileSync(r,`export NODE_BINARY=${Co(i)}
285
+ `),p=F)};w.stdout.on("data",C=>{let v=C.toString();c=Xn(c,v),_(v,process.stdout),r&&r(v)}),w.stderr.on("data",C=>{let v=C.toString();c=Xn(c,v),_(v,process.stderr),r&&r(v)}),w.on("close",C=>{C===0?s(C):a(new Error(so(e,t,C,c)))}),w.on("error",C=>a(C))}),Ct=async(e,t,n,i,r)=>{try{await Oe("xcodebuild",e,t,n,i,r)}catch(o){if(!mo(o))throw o;P.warn(S.yellow("CocoaPods script permission denied. Repairing Pods script permissions and retrying xcodebuild once...")),zn(t),await Oe("xcodebuild",e,t,n,i,r)}},go=e=>{let t=Math.floor(e/1e3%60),n=Math.floor(e/(1e3*60)%60),i=Math.floor(e/(1e3*60*60)%24),r=[];return i>0&&r.push(`${i}h`),n>0&&r.push(`${n}m`),(t>0||r.length===0)&&r.push(`${t}s`),r.join(" ")},He=(e,t)=>{let n=[];try{if(!I.existsSync(e))return n;let i=I.readdirSync(e);for(let r of i){let o=b.join(e,r);try{let s=I.statSync(o);if(t.some(c=>r.endsWith(c))){n.push(b.resolve(o));continue}s.isDirectory()&&(n=n.concat(He(o,t)))}catch{}}}catch{}return n},Qn=(e,t)=>{let n=ut(e);if(!n)throw new Error(`Invalid iOS CFBundleVersion from ${t}: "${e||""}". Apple requires one to three period-separated integers, for example "42" or "1.2.3". If you see "[Decryption Failed]", fix/remove the broken BUILD_NUMBER secret and rebuild.`);return n},qt=(e,t)=>Te("/usr/libexec/PlistBuddy",["-c",`Print :${t}`,e],{encoding:"utf-8"}).trim(),tt=(e,t)=>{try{return qt(e,t)}catch{return""}},jn=e=>String(e||"").replace(/\.app$/i,"").replace(/[^a-z0-9]/gi,"").toLowerCase(),ho=e=>{try{return I.statSync(e).isDirectory()}catch{return!1}},yo=(e,t,n)=>{if(!I.existsSync(e))throw new Error(`iOS simulator build output directory was not found: ${e}`);let i=I.readdirSync(e).filter(l=>l.endsWith(".app")).map(l=>b.join(e,l)).filter(ho);if(i.length===0){let p=He(e,[".app"]).map(d=>b.relative(e,d)).join(", ");throw new Error(`No top-level iOS simulator .app product was found in ${e}.`+(p?` Nested .app bundles found but ignored: ${p}`:""))}let r=new Set([t,n.iosScheme,n.scheme,n.appName].filter(Boolean).map(l=>jn(String(l))).filter(Boolean)),o=i.map(l=>{let p=b.join(l,"Info.plist"),d=I.existsSync(p)?tt(p,"CFBundleName"):"",f=I.existsSync(p)?tt(p,"CFBundleDisplayName"):"",y=I.existsSync(p)?tt(p,"CFBundleExecutable"):"",g=I.existsSync(p)?tt(p,"CFBundleIdentifier"):"",h=y?b.join(l,y):"";return{appPath:l,bundleIdentifier:g,executable:y,isValid:I.existsSync(p)&&!!y&&I.existsSync(h),names:[b.basename(l,".app"),d,f,y].map(jn).filter(Boolean)}}),s=o.filter(l=>l.isValid);if(s.length===0)throw new Error(`No valid iOS simulator .app product was found in ${e}. Candidates: `+o.map(l=>b.basename(l.appPath)).join(", "));let c=s.find(l=>l.names.some(p=>r.has(p)))||(s.length===1?s[0]:null);if(!c)throw new Error(`Multiple iOS simulator .app products were found in ${e}: `+s.map(l=>{let p=l.bundleIdentifier?` (${l.bundleIdentifier})`:"";return`${b.basename(l.appPath)}${p}`}).join(", ")+`. Set ios.scheme in ${A.configFileName} so ${A.name} can select the app target safely.`);return c.appPath},Io=(e,t)=>{let n=b.join(e,"Info.plist");if(!I.existsSync(n))throw new Error(`Could not validate iOS build number: ${n} not found.`);let i=Qn(qt(n,"CFBundleVersion"),n);return t?Ht(i,t,n):i},qn=(e,t=[])=>{if(!I.existsSync(e))return t;for(let n of I.readdirSync(e,{withFileTypes:!0})){if(!n.isDirectory()||n.isSymbolicLink())continue;let i=b.join(e,n.name);n.name!=="Frameworks"&&((n.name.endsWith(".app")||n.name.endsWith(".appex"))&&t.push(i),qn(i,t))}return t},Ln=(e,t)=>[e,...qn(e)].filter((i,r,o)=>o.indexOf(i)===r).map(i=>({bundlePath:i,buildNumber:Io(i,t)})),ei=e=>{let t=b.join(e,"Info.plist");if(!I.existsSync(t))throw new Error(`Could not validate iOS app executable: ${t} not found.`);let n=tt(t,"CFBundleExecutable");if(!n)throw new Error(`Could not validate iOS app executable: CFBundleExecutable missing in ${t}.`);let i=b.join(e,n);if(!I.existsSync(i))throw new Error(`Could not validate iOS app executable: ${i} not found.`);return i},Ao=()=>process.arch==="arm64"?"arm64":"x86_64",ti=e=>{let t=ei(e),n="";try{n=Te("lipo",["-info",t],{encoding:"utf-8"}).trim()}catch(r){throw new Error(`Could not inspect iOS simulator executable architecture for ${b.basename(e)}: ${r.message}`)}let i=Ao();if(!new RegExp(`\\b${i}\\b`).test(n))throw new Error(`iOS simulator app ${b.basename(e)} cannot be installed on this runner because its executable does not include the required ${i} simulator architecture. lipo output: ${n}. Check the React Native iOS project ARCHS/EXCLUDED_ARCHS settings for iphonesimulator builds.`);return n},bo=e=>{try{return Te("xcrun",["vtool","-show-build",e],{encoding:"utf-8"}).trim()}catch(t){throw new Error(`Could not inspect iOS executable build platform for ${b.basename(e)}: ${t.message}`)}},ni=e=>{let t=ei(e),n=bo(t);if(!/\bplatform\s+IOSSIMULATOR\b/i.test(n))throw new Error(`iOS simulator app ${b.basename(e)} was built for the wrong Apple platform. A simulator artifact must contain PLATFORM IOSSIMULATOR, not an iPhone device binary. vtool output: ${n}`);return n},ii=(e,t)=>{let i=Te("unzip",["-Z1",e],{encoding:"utf-8"}).split(`
286
+ `).map(o=>o.trim()).filter(o=>/^Payload\/.+\.(?:app|appex)\/Info\.plist$/.test(o)&&!o.includes("/Frameworks/"));if(i.length===0)throw new Error(`Could not validate iOS build number: ${b.basename(e)} has no Payload/*.app/Info.plist.`);let r=I.mkdtempSync(b.join(de.tmpdir(),`${A.nameLower}-ipa-plist-`));try{let o="";for(let[s,a]of i.entries()){let c=b.join(r,`Info-${s}.plist`),l=Te("unzip",["-p",e,a]);I.writeFileSync(c,l);let p=`${b.basename(e)}:${a}`,d=Qn(qt(c,"CFBundleVersion"),p);t&&Ht(d,t,p),/^Payload\/[^/]+\.app\/Info\.plist$/.test(a)&&(o=d)}if(!o)throw new Error(`Could not validate iOS build number: ${b.basename(e)} has no main application Info.plist.`);return o}finally{I.rmSync(r,{recursive:!0,force:!0})}},Co=e=>`'${e.replace(/'/g,"'\\''")}'`,So=()=>process.execPath&&I.existsSync(process.execPath)?process.execPath:Te("which",["node"],{encoding:"utf-8"}).trim(),ri=(e,t,n)=>{if(!I.existsSync(e))return;let i=So();t.NODE_BINARY=i;let r=b.join(e,".xcode.env.local");I.writeFileSync(r,`export NODE_BINARY=${Co(i)}
287
287
  `);let o=`[NODE] Xcode NODE_BINARY: ${i}
288
- `;n&&n(S.dim(o)),P.info(S.dim(o.trim()))},Rc=async(e,t,n={},i,r={})=>{let o=St(),s=Date.now(),a=e.platform,c=e.buildProfile||"production",l=pt(e.framework),p=()=>jt(n,c,e),d=async(N,T={})=>{if(i)for(let R=1;R<=3;R++)try{await Z.patch(`/builds/${i}/${t}`,{status:N,...T});return}catch(V){let q=V?.response?.data?.message||V?.message||String(V);console.error(`[reportStatus] attempt ${R}/3 failed (status=${N}): ${q}`),R<3&&await new Promise(ye=>setTimeout(ye,2e3))}},f=new AbortController,{signal:I}=f,g=null;i&&(g=setInterval(async()=>{try{(await Z.get(`/builds/${i}/${t}`)).data.status==="cancelled"&&(P.warn(S.yellow(`
289
- \u{1F6D1} Build cancelled from dashboard. Terminating...`)),f.abort(),g&&clearInterval(g))}catch{}},5e3));let h=b.join(process.cwd(),".mach-cache"),w="setup",_="",C=null,v=async()=>{if(!_||!i)return;let N=_;_="";try{let T=N;Object.values(n).forEach(R=>{if(R&&R.length>5){let V=R.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");T=T.replace(new RegExp(V,"g"),"[SECRET]")}}),await Z.post(`/builds/${i}/${t}/logs`,{log:T,step:w})}catch{}},x=async()=>{C&&(clearTimeout(C),C=null),await v(),ro(h,t),g&&(clearInterval(g),g=null);try{let N=b.join(de.tmpdir(),`${A.buildPrefix}-${t}.keychain-db`);y.existsSync(N)&&(L(`security delete-keychain "${N}"`,{stdio:"ignore"}),P.info(S.dim("\u{1F511} Build keychain deleted.")))}catch{}try{let N=b.join(de.homedir(),"Library/MobileDevice/Provisioning Profiles");if(y.existsSync(N)){let T=y.readdirSync(N).filter(R=>R.includes(t)||R.startsWith(`${A.nameLower}-temp-${t}`));for(let R of T)y.unlinkSync(b.join(N,R))}}catch{}},F=async N=>{i&&(_+=N,_.length>=8192?(C&&(clearTimeout(C),C=null),await v()):C||(C=setTimeout(()=>{C=null,v()},2e3)))},D=async N=>{w=N,await F(`[STEP_START:${N}] ${Math.floor(Date.now()/1e3)}
290
- `)},j=async(N,T,R,V)=>await Oe(N,T,R,V,q=>{F(q)},I);P.info(S.blue(`\u{1F680} Starting local build for ${a} (${c})...`));try{io(h,t)}catch(N){throw await d("failed",{error:N.message,endTime:Date.now()}),N}await d("building"),await D("setup"),a==="ios"&&!e.simulator&&n.MACH_IOS_BUILD_NUMBER_LOCKED==="1"&&n.BUILD_NUMBER&&(P.info(S.dim(`Auto build number: ${n.BUILD_NUMBER}`)),await F(`[BUILD_NUMBER] ${n.BUILD_NUMBER}
291
- `)),await D("lock"),l.applyLocalProcessEnv(e);try{await D("clone"),P.info(S.dim("Preparing source...")),await D("read_config");let N=b.join(process.cwd(),A.configFileName);if(y.existsSync(N)){let E=JSON.parse(y.readFileSync(N,"utf-8"))?.build?.[c]||{};await F(`[CONFIG] Profile: ${c}, distribution: ${E.distribution||"not set"}, simulator: ${E.simulator||!1}
292
- `)}if(await D("read_package"),e.nodeVersion){let k=process.env.NVM_DIR||b.join(de.homedir(),".nvm"),E=b.join(k,"versions","node"),$;if(y.existsSync(E)){let B=y.readdirSync(E).sort().reverse(),Y=e.nodeVersion.startsWith("v")?e.nodeVersion:`v${e.nodeVersion}`,J=B.find(X=>X===Y||X.startsWith(Y+".")||X.startsWith(`v${e.nodeVersion}.`));J&&($=b.join(E,J,"bin"))}if($&&y.existsSync($)){let B=process.env.PATH||"";process.env.PATH=`${$}:${B}`,await F(`[NODE] Switched to Node ${e.nodeVersion} \u2014 using ${$}
288
+ `;n&&n(S.dim(o)),P.info(S.dim(o.trim()))},Rc=async(e,t,n={},i,r={})=>{let o=St(),s=Date.now(),a=e.platform,c=e.buildProfile||"production",l=pt(e.framework),p=()=>jt(n,c,e),d=async(N,T={})=>{if(i)for(let R=1;R<=3;R++)try{await Z.patch(`/builds/${i}/${t}`,{status:N,...T});return}catch(V){let q=V?.response?.data?.message||V?.message||String(V);console.error(`[reportStatus] attempt ${R}/3 failed (status=${N}): ${q}`),R<3&&await new Promise(ye=>setTimeout(ye,2e3))}},f=new AbortController,{signal:y}=f,g=null;i&&(g=setInterval(async()=>{try{(await Z.get(`/builds/${i}/${t}`)).data.status==="cancelled"&&(P.warn(S.yellow(`
289
+ \u{1F6D1} Build cancelled from dashboard. Terminating...`)),f.abort(),g&&clearInterval(g))}catch{}},5e3));let h=b.join(process.cwd(),".mach-cache"),w="setup",_="",C=null,v=async()=>{if(!_||!i)return;let N=_;_="";try{let T=N;Object.values(n).forEach(R=>{if(R&&R.length>5){let V=R.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");T=T.replace(new RegExp(V,"g"),"[SECRET]")}}),await Z.post(`/builds/${i}/${t}/logs`,{log:T,step:w})}catch{}},x=async()=>{C&&(clearTimeout(C),C=null),await v(),ro(h,t),g&&(clearInterval(g),g=null);try{let N=b.join(de.tmpdir(),`${A.buildPrefix}-${t}.keychain-db`);I.existsSync(N)&&(L(`security delete-keychain "${N}"`,{stdio:"ignore"}),P.info(S.dim("\u{1F511} Build keychain deleted.")))}catch{}try{let N=b.join(de.homedir(),"Library/MobileDevice/Provisioning Profiles");if(I.existsSync(N)){let T=I.readdirSync(N).filter(R=>R.includes(t)||R.startsWith(`${A.nameLower}-temp-${t}`));for(let R of T)I.unlinkSync(b.join(N,R))}}catch{}},F=async N=>{i&&(_+=N,_.length>=8192?(C&&(clearTimeout(C),C=null),await v()):C||(C=setTimeout(()=>{C=null,v()},2e3)))},D=async N=>{w=N,await F(`[STEP_START:${N}] ${Math.floor(Date.now()/1e3)}
290
+ `)},j=async(N,T,R,V)=>await Oe(N,T,R,V,q=>{F(q)},y);P.info(S.blue(`\u{1F680} Starting local build for ${a} (${c})...`));try{io(h,t)}catch(N){throw await d("failed",{error:N.message,endTime:Date.now()}),N}await d("building"),await D("setup"),a==="ios"&&!e.simulator&&n.MACH_IOS_BUILD_NUMBER_LOCKED==="1"&&n.BUILD_NUMBER&&(P.info(S.dim(`Auto build number: ${n.BUILD_NUMBER}`)),await F(`[BUILD_NUMBER] ${n.BUILD_NUMBER}
291
+ `)),await D("lock"),l.applyLocalProcessEnv(e);try{await D("clone"),P.info(S.dim("Preparing source...")),await D("read_config");let N=b.join(process.cwd(),A.configFileName);if(I.existsSync(N)){let E=JSON.parse(I.readFileSync(N,"utf-8"))?.build?.[c]||{};await F(`[CONFIG] Profile: ${c}, distribution: ${E.distribution||"not set"}, simulator: ${E.simulator||!1}
292
+ `)}if(await D("read_package"),e.nodeVersion){let k=process.env.NVM_DIR||b.join(de.homedir(),".nvm"),E=b.join(k,"versions","node"),$;if(I.existsSync(E)){let B=I.readdirSync(E).sort().reverse(),z=e.nodeVersion.startsWith("v")?e.nodeVersion:`v${e.nodeVersion}`,J=B.find(X=>X===z||X.startsWith(z+".")||X.startsWith(`v${e.nodeVersion}.`));J&&($=b.join(E,J,"bin"))}if($&&I.existsSync($)){let B=process.env.PATH||"";process.env.PATH=`${$}:${B}`,await F(`[NODE] Switched to Node ${e.nodeVersion} \u2014 using ${$}
293
293
  `),P.info(S.green(`\u2713 Node switched to ${e.nodeVersion} (${$})`))}else await F(`[NODE] Warning: Node ${e.nodeVersion} not found in nvm. Run: nvm install ${e.nodeVersion} on the build machine.
294
- `),P.warn(S.yellow(`Node ${e.nodeVersion} not found in nvm \u2014 using system default`))}await D("deps"),o.start("Checking dependencies...");let T=to(h),R=qr(process.cwd()),V=y.existsSync("node_modules"),q=y.existsSync("yarn.lock"),ye=y.existsSync("bun.lockb");V&&T.node&&T.node!==R&&(o.stop("Dependency fingerprint changed \u2014 clearing node_modules for clean install..."),await F(`[CACHE] package.json/lockfile changed \u2014 wiping node_modules
295
- `),y.rmSync(b.join(process.cwd(),"node_modules"),{recursive:!0,force:!0}),V=!1);let Ae="npm",re=["install","--prefer-offline"];q?(Ae="yarn",re=["install","--prefer-offline"]):ye&&(Ae="bun",re=["install"]),V?o.stop("Cached node_modules found. Syncing dependencies..."):o.stop("No cached dependencies. Running fresh install..."),e.preBuild&&(P.info(S.blue("Running pre-install hook...")),P.info(S.dim(`> ${e.preBuild}`)),await D("prebuild"),await j("bash",[e.preBuild],process.cwd(),p())),P.info(S.dim(`Running ${Ae} ${re.join(" ")}...`)),await j(Ae,re,process.cwd(),p()),T.node=R,Gn(h,T);let te=await l.prepareLocalProject({platform:a,options:e,cacheMeta:T,cacheMetaDir:h,currentBuildEnv:p,reportStep:D,reportLog:F,loggedRun:j,configureXcodeNodeBinary:ri,podsFingerprint:eo,writeCacheMeta:Gn}),ae=te.bundleId||e.iosBundleIdentifier||"",ie=te.appName||e.name||"",K=[];if(a==="android")await D("build"),K=await wo(e,c,n,k=>F(k),I);else if(a==="ios"){await D("signing"),P.info(S.dim("Preparing credentials..."));let k=r?.distributionType;K=await vo(e,t,c,n,i,E=>F(E),I,k,E=>D(E))}if(e.postBuild&&(P.info(S.blue("Running post-build hook...")),P.info(S.dim(`> ${e.postBuild}`)),await j(e.postBuild,[],process.cwd(),p())),a==="ios"){let k=ut(e.resolvedBuildNumber||n.BUILD_NUMBER);if(k)for(let E of K.filter($=>$.endsWith(".ipa"))){let $=ii(E,k);await F(`[IPA FINAL] CFBundleVersion ${$} matches MACH buildNumber ${k}
294
+ `),P.warn(S.yellow(`Node ${e.nodeVersion} not found in nvm \u2014 using system default`))}await D("deps"),o.start("Checking dependencies...");let T=to(h),R=qr(process.cwd()),V=I.existsSync("node_modules"),q=I.existsSync("yarn.lock"),ye=I.existsSync("bun.lockb");V&&T.node&&T.node!==R&&(o.stop("Dependency fingerprint changed \u2014 clearing node_modules for clean install..."),await F(`[CACHE] package.json/lockfile changed \u2014 wiping node_modules
295
+ `),I.rmSync(b.join(process.cwd(),"node_modules"),{recursive:!0,force:!0}),V=!1);let Ae="npm",re=["install","--prefer-offline"];q?(Ae="yarn",re=["install","--prefer-offline"]):ye&&(Ae="bun",re=["install"]),V?o.stop("Cached node_modules found. Syncing dependencies..."):o.stop("No cached dependencies. Running fresh install..."),e.preBuild&&(P.info(S.blue("Running pre-install hook...")),P.info(S.dim(`> ${e.preBuild}`)),await D("prebuild"),await j("bash",[e.preBuild],process.cwd(),p())),P.info(S.dim(`Running ${Ae} ${re.join(" ")}...`)),await j(Ae,re,process.cwd(),p()),T.node=R,Gn(h,T);let te=await l.prepareLocalProject({platform:a,options:e,cacheMeta:T,cacheMetaDir:h,currentBuildEnv:p,reportStep:D,reportLog:F,loggedRun:j,configureXcodeNodeBinary:ri,podsFingerprint:eo,writeCacheMeta:Gn}),ae=te.bundleId||e.iosBundleIdentifier||"",ie=te.appName||e.name||"",K=[];if(a==="android")await D("build"),K=await wo(e,c,n,k=>F(k),y);else if(a==="ios"){await D("signing"),P.info(S.dim("Preparing credentials..."));let k=r?.distributionType;K=await vo(e,t,c,n,i,E=>F(E),y,k,E=>D(E))}if(e.postBuild&&(P.info(S.blue("Running post-build hook...")),P.info(S.dim(`> ${e.postBuild}`)),await j(e.postBuild,[],process.cwd(),p())),a==="ios"){let k=ut(e.resolvedBuildNumber||n.BUILD_NUMBER);if(k)for(let E of K.filter($=>$.endsWith(".ipa"))){let $=ii(E,k);await F(`[IPA FINAL] CFBundleVersion ${$} matches MACH buildNumber ${k}
296
296
  `)}}if(a==="android"){let k=e.resolvedVersionCode||n.ANDROID_VERSION_CODE;if(k){let E=Re(k,"resolved MACH build assignment");if(K.length===0)throw new Error(`Android build produced no APK or AAB to verify against MACH versionCode ${E}.`);for(let $ of K){let B=Yt($,E);await F(`[ANDROID FINAL] ${b.basename($)} versionCode ${B} matches MACH assignment
297
297
  `)}}}let De=go(Date.now()-s);if(P.success(S.green(`
298
298
  \u2713 Local build completed successfully in ${De}`)),await d("building",{...ae&&{bundleId:ae},...ie&&{appName:ie}}),K.length>0&&(P.info(S.cyan(`
299
- \u{1F4E6} Generated Artifacts:`)),K.forEach(k=>{let E=b.resolve(k);P.info(S.dim(` - ${k}`)),P.info(S.gray(` Path: ${E}`))}),e.interactive)){let k=await zr({message:"Install on connected device?"});if(!wt(k)&&k){if(a==="android"){let E=K.find($=>$.endsWith(".apk"))||K[0];await Po(E,$=>F($))}else if(a==="ios"){let E=K.find(B=>B.endsWith(".ipa"))||K.find(B=>B.endsWith(".app"))||K[0],$=nt("ios");e.simulator?await No(E,$||"",B=>F(B)):await ko(E,$||"",B=>F(B))}}}await D("upload");let W=[];for(let k of K)try{let E=b.join(de.tmpdir(),`${t}-${b.basename(k)}`);y.copyFileSync(k,E),W.push(E),P.info(S.dim(` \u{1F4CB} Preserved artifact: ${b.basename(k)}`))}catch{P.warn(S.yellow(` Failed to preserve artifact: ${b.basename(k)}`))}K=W,P.info(S.dim("\u{1F9F9} Cleaning workspace (preserving dependency cache)..."));try{let k=process.cwd(),E=new Set(["node_modules"]),$=y.readdirSync(k),B=0;for(let Y of $)if(!E.has(Y)){if(Y==="ios"){let J=b.join(k,"ios"),X=y.readdirSync(J);for(let pe of X)if(pe!=="Pods")try{y.rmSync(b.join(J,pe),{recursive:!0,force:!0}),B++}catch{}continue}try{y.rmSync(b.join(k,Y),{recursive:!0,force:!0}),B++}catch{}}P.info(S.dim(` Cleaned ${B} items. Cached: node_modules${y.existsSync(b.join(k,"ios","Pods"))?", ios/Pods":""}`)),P.info(S.green("\u{1F512} Security: No source code retained on build server. Only public dependencies cached."))}catch{P.warn(S.yellow("Post-build cleanup encountered errors (non-fatal)."))}try{let E=b.join(de.homedir(),A.workspacesDir),$=L(`df -k "${E}" | tail -1 | awk '{print $4}'`,{encoding:"utf8"}).trim(),B=parseInt($,10)*1024;if(B<53687091200&&y.existsSync(E)){P.info(S.dim(` \u26A0\uFE0F Low disk space (${(B/1024/1024/1024).toFixed(0)} GB free). Running cache eviction...`));let Y=b.basename(process.cwd()),J=y.readdirSync(E).filter(X=>X!==Y).map(X=>{let pe=b.join(E,X);try{let Ve=y.statSync(pe);return Ve.isDirectory()?{name:X,dir:pe,mtime:Ve.mtimeMs}:null}catch{return null}}).filter(Boolean);J.sort((X,pe)=>X.mtime-pe.mtime);for(let X of J){if(B>=53687091200)break;try{y.rmSync(X.dir,{recursive:!0,force:!0}),P.info(S.dim(` \u{1F5D1}\uFE0F Evicted stale workspace: ${X.name}`));let pe=L(`df -k "${E}" | tail -1 | awk '{print $4}'`,{encoding:"utf8"}).trim();if(parseInt(pe,10)*1024>=53687091200)break}catch{}}}}catch{}return await x(),K}catch(N){throw await x(),N.message==="Command aborted"?(P.warn(S.yellow(`
299
+ \u{1F4E6} Generated Artifacts:`)),K.forEach(k=>{let E=b.resolve(k);P.info(S.dim(` - ${k}`)),P.info(S.gray(` Path: ${E}`))}),e.interactive)){let k=await zr({message:"Install on connected device?"});if(!wt(k)&&k){if(a==="android"){let E=K.find($=>$.endsWith(".apk"))||K[0];await Po(E,$=>F($))}else if(a==="ios"){let E=K.find(B=>B.endsWith(".ipa"))||K.find(B=>B.endsWith(".app"))||K[0],$=nt("ios");e.simulator?await No(E,$||"",B=>F(B)):await ko(E,$||"",B=>F(B))}}}await D("upload");let W=[];for(let k of K)try{let E=b.join(de.tmpdir(),`${t}-${b.basename(k)}`);I.copyFileSync(k,E),W.push(E),P.info(S.dim(` \u{1F4CB} Preserved artifact: ${b.basename(k)}`))}catch{P.warn(S.yellow(` Failed to preserve artifact: ${b.basename(k)}`))}K=W,P.info(S.dim("\u{1F9F9} Cleaning workspace (preserving dependency cache)..."));try{let k=process.cwd(),E=new Set(["node_modules"]),$=I.readdirSync(k),B=0;for(let z of $)if(!E.has(z)){if(z==="ios"){let J=b.join(k,"ios"),X=I.readdirSync(J);for(let pe of X)if(pe!=="Pods")try{I.rmSync(b.join(J,pe),{recursive:!0,force:!0}),B++}catch{}continue}try{I.rmSync(b.join(k,z),{recursive:!0,force:!0}),B++}catch{}}P.info(S.dim(` Cleaned ${B} items. Cached: node_modules${I.existsSync(b.join(k,"ios","Pods"))?", ios/Pods":""}`)),P.info(S.green("\u{1F512} Security: No source code retained on build server. Only public dependencies cached."))}catch{P.warn(S.yellow("Post-build cleanup encountered errors (non-fatal)."))}try{let E=b.join(de.homedir(),A.workspacesDir),$=L(`df -k "${E}" | tail -1 | awk '{print $4}'`,{encoding:"utf8"}).trim(),B=parseInt($,10)*1024;if(B<53687091200&&I.existsSync(E)){P.info(S.dim(` \u26A0\uFE0F Low disk space (${(B/1024/1024/1024).toFixed(0)} GB free). Running cache eviction...`));let z=b.basename(process.cwd()),J=I.readdirSync(E).filter(X=>X!==z).map(X=>{let pe=b.join(E,X);try{let Ve=I.statSync(pe);return Ve.isDirectory()?{name:X,dir:pe,mtime:Ve.mtimeMs}:null}catch{return null}}).filter(Boolean);J.sort((X,pe)=>X.mtime-pe.mtime);for(let X of J){if(B>=53687091200)break;try{I.rmSync(X.dir,{recursive:!0,force:!0}),P.info(S.dim(` \u{1F5D1}\uFE0F Evicted stale workspace: ${X.name}`));let pe=L(`df -k "${E}" | tail -1 | awk '{print $4}'`,{encoding:"utf8"}).trim();if(parseInt(pe,10)*1024>=53687091200)break}catch{}}}}catch{}return await x(),K}catch(N){throw await x(),N.message==="Command aborted"?(P.warn(S.yellow(`
300
300
  \u274C Build aborted.`)),await d("failed",{error:"Aborted by user",endTime:Date.now()}),N):(P.error(S.red(`
301
- \u2717 Local build failed: ${N.message}`)),await d("failed",{error:N.message,endTime:Date.now()}),N)}},wo=async(e,t,n={},i,r)=>{let o=y.existsSync("android/gradlew")?"android/gradlew":y.existsSync("gradlew")?"./gradlew":null;if(!o)throw new Error("Could not find gradlew. Is this an Android project?");let s=e.developmentClient?"assembleDebug":"assembleRelease";!e.developmentClient&&e.distribution==="store"?s="bundleRelease":!e.developmentClient&&e.distribution==="internal"&&(s="assembleRelease");let a=e.buildCommand||s;P.info(S.blue(`Running Android build: ${a}...`));let c=o.includes("android/")?"android":".",l=(o.includes("android/"),"./gradlew"),p=[a],d=pt(e.framework),f={...n,...d.localAndroidEnv(e,t),MACH_APP_NAME:e.appName||e.name||"App"},I=e.resolvedVersionCode||n.ANDROID_VERSION_CODE,g=I?Re(I,"resolved MACH build assignment"):null;g&&(p.push(`-Pandroid.injected.version.code=${g}`),f.ANDROID_VERSION_CODE=g,P.info(S.green(`\u2713 Applying Android versionCode ${g}`)));for(let _ of["app/build","build",".cxx"]){let C=b.join(c,_);y.existsSync(C)&&y.rmSync(C,{recursive:!0,force:!0})}zt(process.cwd()),await Oe(l,p,c,f,i,r);let h=b.join(c,"app/build/outputs"),w=He(h,[".apk",".aab"]);if(g&&w.length===0)throw new Error(`Android build produced no APK or AAB to verify against MACH versionCode ${g}.`);if(g)for(let _ of w){let C=Yt(_,g);P.info(S.dim(`Validated Android versionCode ${C} in ${b.basename(_)}`)),i?.(`[ANDROID VALID] ${b.basename(_)} versionCode ${C} matches MACH assignment
302
- `)}return w},vo=async(e,t,n,i={},r,o,s,a,c)=>{if(process.platform!=="darwin")throw new Error("iOS builds can only be run on macOS.");let l=b.resolve(process.cwd(),y.existsSync("ios")?"ios":".");zn(l);let p=y.readdirSync(l),d=p.find(F=>F.endsWith(".xcworkspace")),f=p.find(F=>F.endsWith(".xcodeproj")),I=jt(i,n,e);ri(l,I,o);let g=e.resolvedBuildNumber||I.BUILD_NUMBER||I.CURRENT_PROJECT_VERSION,h=ut(g);if(g&&!h)throw new Error(`Invalid iOS build number: "${g}". Apple requires one to three period-separated integers. Fix the Dashboard secret or remove it so Mach can use its auto build number.`);let w=h?[`BUILD_NUMBER=${h}`,`CURRENT_PROJECT_VERSION=${h}`,`INFOPLIST_KEY_CFBundleVersion=${h}`]:[];if(h&&(I.BUILD_NUMBER=h,I.CURRENT_PROJECT_VERSION=h,P.info(S.dim(`Using iOS build number: ${h}`))),!d&&!f)throw new Error("Could not find Xcode workspace or project in ios/ directory.");try{let F=L("xcode-select -p").toString().trim();P.info(S.dim(`Using Xcode at: ${F}`))}catch{P.warn(S.dim("Could not detect Xcode path."))}P.info(S.blue("Running iOS build via xcodebuild..."));let _=d?d.replace(".xcworkspace",""):f?.replace(".xcodeproj",""),C=e.iosScheme||_||e.scheme,v=e.developmentClient?"Debug":e.iosConfiguration||"Release",x;try{if(h){x=Bn(l,h,{workspace:d,project:f,scheme:C,configuration:v});let V=x.plistPaths.length>0?`${x.plistPaths.length} Xcode target Info.plist file(s)`:"generated Info.plist build settings";P.info(S.green(`\u2713 Applied iOS buildNumber ${h} to ${V}`)),o&&o(`[VERSIONING] Applied iOS buildNumber ${h} to ${V}
303
- `)}let F=(r||"default").replace(/[^a-zA-Z0-9-_]/g,"_"),D=b.join(de.homedir(),`Library/Developer/Xcode/DerivedData/${A.nameLower}`,F);y.mkdirSync(D,{recursive:!0});let j=_n(I),N=b.join(D,".mach-env-hash"),T=b.join(D,"Build"),R=y.existsSync(N)?y.readFileSync(N,"utf-8").trim():"";if(y.existsSync(T)){let V=R&&R!==j?"Build environment changed \u2014 clearing iOS DerivedData build products.":R?"Clearing iOS DerivedData build products to force a fresh JS bundle.":"DerivedData has no environment stamp \u2014 clearing iOS build products.";P.info(S.dim(V)),y.rmSync(T,{recursive:!0,force:!0})}if(y.writeFileSync(N,j),zt(process.cwd()),e.simulator){let V=fo(l,d,f,C,v),q=V||"generic/platform=iOS Simulator",ye=["-destination",q];P.info(S.dim(V?`Building for simulator (Scheme: ${C}, Config: ${v}, Destination: ${q})...`:`Building for simulator (Scheme: ${C}, Config: ${v}, Destination: ${q})...`));let Ae=[d?"-workspace":"-project",d||f,"-scheme",C,"-configuration",v,"-sdk","iphonesimulator",...ye,"-derivedDataPath",D,...w,"COMPILER_INDEX_STORE_ENABLE=NO","CODE_SIGNING_ALLOWED=NO","CODE_SIGNING_REQUIRED=NO","ONLY_ACTIVE_ARCH=NO","EXCLUDED_ARCHS=","SUPPORTED_PLATFORMS=iphonesimulator"];try{await Ct(Ae,l,I,o,s)}catch($){if(!po($))throw $;uo(D),zt(process.cwd()),await Ct(Ae,l,I,o,s)}let re=b.join(D,"Build/Products",`${v}-iphonesimulator`),te=yo(re,C,e),ae=b.basename(te,".app"),ie=tt(b.join(te,"Info.plist"),"CFBundleIdentifier")||"unknown bundle",De=Ln(te,h||void 0)[0].buildNumber,W=ti(te),k=ni(te),E=b.join(re,`${ae}_simulator.zip`);return P.info(S.dim(`Selected simulator app: ${b.relative(re,te)} (${ie}, build ${De})`)),P.info(S.dim(`Simulator executable architecture: ${W}`)),P.info(S.dim(`Simulator executable platform: ${k.split(`
304
- `).find($=>/\bplatform\b/i.test($))?.trim()||"IOSSIMULATOR"}`)),P.info(S.dim(`Creating simulator artifact: ${E}...`)),Pe(E),Te("zip",["-r",E,b.basename(te)],{cwd:b.dirname(te),stdio:"pipe"}),[E]}else{P.info(S.dim(`Archiving (Scheme: ${C}, Config: ${v})...`));let V=b.join(l,"build.xcarchive"),q=b.join(l,"export");y.rmSync(V,{recursive:!0,force:!0}),y.rmSync(q,{recursive:!0,force:!0});let ye=i.IOS_DIST_P12,Ae=i.IOS_PROVISIONING_PROFILE,re=i.IOS_P12_PASSWORD||"",te=[],ae,ie,K={isAppStore:!1,isDevelopment:!1};if(ye&&Ae){P.info(S.blue("\u{1F510} CI/CD Signing: Importing certificates..."));try{let J=`${A.buildPrefix}-${t}.keychain-db`,X=b.join(de.tmpdir(),J),pe=A.keychainPassword;L(`security create-keychain -p "${pe}" "${X}" 2>/dev/null || true`),L(`security set-keychain-settings -t 3600 -l "${X}"`),L(`security unlock-keychain -p "${pe}" "${X}"`);let Ve=b.join(de.tmpdir(),`cert-${t}.p12`),rt=Buffer.from(ye,"base64");y.writeFileSync(Ve,rt),P.info(S.dim(`P12 data size: ${rt.length} bytes, first bytes: ${rt.slice(0,4).toString("hex")}`)),(rt.length<100||rt[0]!==48)&&(P.warn(S.yellow("\u26A0\uFE0F P12 data looks corrupted or was not decrypted correctly.")),P.warn(S.yellow(" This usually means MACH_ENCRYPTION_KEY on the Remote API differs from when credentials were uploaded.")));let Bi=[re,"",A.keychainPassword],pn=!1;for(let fe of Bi)try{L(`security import "${Ve}" -k "${X}" -P "${fe}" -A -T /usr/bin/codesign -T /usr/bin/security`,{stdio:"pipe"}),pn=!0,P.info(S.dim(`\u2713 P12 imported successfully with password: ${fe?"[set]":"[empty]"}`));break}catch(ke){P.info(S.dim(` P12 import attempt with password ${fe?`"${fe.substring(0,3)}..."`:"[empty]"} failed: ${ke.message?.split(`
305
- `)[0]||"unknown"}`))}if(!pn)throw new Error("Failed to import P12.");y.unlinkSync(Ve),L(`security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${pe}" "${X}"`);let Di=L("security list-keychains -d user",{encoding:"utf-8"}).split(`
306
- `).map(fe=>fe.trim().replace(/^"|"$/g,"")).filter(fe=>fe.length>0),Vi=[X,...Di].map(fe=>`"${fe}"`).join(" ");L(`security list-keychains -d user -s ${Vi}`),L(`security default-keychain -s "${X}"`);let Rt=b.join(de.homedir(),"Library/MobileDevice/Provisioning Profiles");y.mkdirSync(Rt,{recursive:!0});let un=Buffer.from(Ae,"base64"),xt=b.join(Rt,`${A.nameLower}-temp-${t}.mobileprovision`);y.writeFileSync(xt,un);let $t=un.toString("utf-8"),mn=/<key>get-task-allow<\/key>\s*<true\/>/.test($t);K={isAppStore:!$t.includes("<key>ProvisionedDevices</key>")&&!mn,isDevelopment:mn};try{let ke=L(`security cms -D -i "${xt}"`,{encoding:"utf-8"}).match(/<key>UUID<\/key>\s*<string>([^<]+)<\/string>/);ie=ke?ke[1]:void 0}catch{let ke=$t.match(/<key>UUID<\/key>\s*<string>([^<]+)<\/string>/);ie=ke?ke[1]:void 0}ie||(P.warn("Could not extract UUID from provisioning profile. Using fallback."),ie=`${A.nameLower}-${t}`);let Ft=b.join(Rt,`${ie}.mobileprovision`);y.existsSync(Ft)&&y.unlinkSync(Ft),y.renameSync(xt,Ft);try{let fe=L(`security find-identity -v -p codesigning "${X}"`,{encoding:"utf-8"}),ke=Array.from(fe.matchAll(/"((?:Apple|iPhone) (?:Distribution|Developer|Development)[^"]*)"/g),ot=>ot[1]),fn=K.isDevelopment?ke.find(ot=>/\b(Development|Developer)\b/.test(ot)):ke.find(ot=>/\bDistribution\b/.test(ot)),gn=ke[0];(fn||gn)&&(ae=fn||gn,P.info(S.blue(`Identity auto-detected from keychain: "${ae}"`)))}catch{}ae||(ae=K.isDevelopment?"Apple Development":"Apple Distribution",P.info(S.blue(`Identity fallback (profile heuristic): "${ae}"`))),P.info(S.dim(`Profile type: ${K.isDevelopment?"Development":K.isAppStore?"App Store":"Ad-Hoc"}`)),P.info(S.dim(`Identity Detection: get-task-allow=${K.isDevelopment}, Selected Identity="${ae}"`)),te.push("CODE_SIGN_STYLE=Manual"),te.push(`CODE_SIGN_IDENTITY="${ae}"`),te.push(`PROVISIONING_PROFILE_SPECIFIER=${ie}`),e.iosTeamId&&te.push(`DEVELOPMENT_TEAM=${e.iosTeamId}`)}catch(J){throw P.error(`Signing setup failed: ${J.message}`),J}}else te.push("-allowProvisioningUpdates"),e.iosTeamId&&te.push(`DEVELOPMENT_TEAM=${e.iosTeamId}`);c&&await c("archive"),P.info(S.blue(`Archive detected Identity: "${ae}"`)),P.info(S.blue(`Archive detected UUID: "${ie}"`)),await Ct(["archive",d?"-workspace":"-project",d||f,"-scheme",C,"-configuration",v,"-archivePath",V,"-derivedDataPath",D,...w,...te],l,I,o,s);let De=He(b.join(V,"Products","Applications"),[".app"]);for(let J of De)for(let X of Ln(J,h||void 0))P.info(S.dim(`Validated iOS CFBundleVersion ${X.buildNumber} in ${b.basename(X.bundlePath)}`));let W;ie?(K.isAppStore?W="app-store":K.isDevelopment?W="development":W="ad-hoc",P.info(S.blue(`Export method from profile: "${W}"`))):(W=e.distribution==="store"?"app-store":e.distribution==="internal"?"ad-hoc":"development",P.warn(S.yellow(`No profile UUID detected. Export method from distribution flag: "${W}"`)));let k=e.iosExportMethod||W,E=e.iosBundleIdentifier||nt("ios"),$=b.join(l,"ExportOptions.plist"),B=`<?xml version="1.0" encoding="UTF-8"?>
301
+ \u2717 Local build failed: ${N.message}`)),await d("failed",{error:N.message,endTime:Date.now()}),N)}},wo=async(e,t,n={},i,r)=>{let o=I.existsSync("android/gradlew")?"android/gradlew":I.existsSync("gradlew")?"./gradlew":null;if(!o)throw new Error("Could not find gradlew. Is this an Android project?");let s=e.developmentClient?"assembleDebug":"assembleRelease";!e.developmentClient&&e.distribution==="store"?s="bundleRelease":!e.developmentClient&&e.distribution==="internal"&&(s="assembleRelease");let a=e.buildCommand||s;P.info(S.blue(`Running Android build: ${a}...`));let c=o.includes("android/")?"android":".",l=(o.includes("android/"),"./gradlew"),p=[a],d=pt(e.framework),f={...n,...d.localAndroidEnv(e,t),MACH_APP_NAME:e.appName||e.name||"App"},y=e.resolvedVersionCode||n.ANDROID_VERSION_CODE,g=y?Re(y,"resolved MACH build assignment"):null;g&&(p.push(`-Pandroid.injected.version.code=${g}`),f.ANDROID_VERSION_CODE=g,P.info(S.green(`\u2713 Applying Android versionCode ${g}`)));for(let _ of["app/build","build",".cxx"]){let C=b.join(c,_);I.existsSync(C)&&I.rmSync(C,{recursive:!0,force:!0})}zt(process.cwd()),await Oe(l,p,c,f,i,r);let h=b.join(c,"app/build/outputs"),w=He(h,[".apk",".aab"]);if(g&&w.length===0)throw new Error(`Android build produced no APK or AAB to verify against MACH versionCode ${g}.`);if(g)for(let _ of w){let C=Yt(_,g);P.info(S.dim(`Validated Android versionCode ${C} in ${b.basename(_)}`)),i?.(`[ANDROID VALID] ${b.basename(_)} versionCode ${C} matches MACH assignment
302
+ `)}return w},vo=async(e,t,n,i={},r,o,s,a,c)=>{if(process.platform!=="darwin")throw new Error("iOS builds can only be run on macOS.");let l=b.resolve(process.cwd(),I.existsSync("ios")?"ios":".");zn(l);let p=I.readdirSync(l),d=p.find(F=>F.endsWith(".xcworkspace")),f=p.find(F=>F.endsWith(".xcodeproj")),y=jt(i,n,e);ri(l,y,o);let g=e.resolvedBuildNumber||y.BUILD_NUMBER||y.CURRENT_PROJECT_VERSION,h=ut(g);if(g&&!h)throw new Error(`Invalid iOS build number: "${g}". Apple requires one to three period-separated integers. Fix the Dashboard secret or remove it so Mach can use its auto build number.`);let w=h?[`BUILD_NUMBER=${h}`,`CURRENT_PROJECT_VERSION=${h}`,`INFOPLIST_KEY_CFBundleVersion=${h}`]:[];if(h&&(y.BUILD_NUMBER=h,y.CURRENT_PROJECT_VERSION=h,P.info(S.dim(`Using iOS build number: ${h}`))),!d&&!f)throw new Error("Could not find Xcode workspace or project in ios/ directory.");try{let F=L("xcode-select -p").toString().trim();P.info(S.dim(`Using Xcode at: ${F}`))}catch{P.warn(S.dim("Could not detect Xcode path."))}P.info(S.blue("Running iOS build via xcodebuild..."));let _=d?d.replace(".xcworkspace",""):f?.replace(".xcodeproj",""),C=e.iosScheme||_||e.scheme,v=e.developmentClient?"Debug":e.iosConfiguration||"Release",x;try{if(h){x=Bn(l,h,{workspace:d,project:f,scheme:C,configuration:v});let V=x.plistPaths.length>0?`${x.plistPaths.length} Xcode target Info.plist file(s)`:"generated Info.plist build settings";P.info(S.green(`\u2713 Applied iOS buildNumber ${h} to ${V}`)),o&&o(`[VERSIONING] Applied iOS buildNumber ${h} to ${V}
303
+ `)}let F=(r||"default").replace(/[^a-zA-Z0-9-_]/g,"_"),D=b.join(de.homedir(),`Library/Developer/Xcode/DerivedData/${A.nameLower}`,F);I.mkdirSync(D,{recursive:!0});let j=_n(y),N=b.join(D,".mach-env-hash"),T=b.join(D,"Build"),R=I.existsSync(N)?I.readFileSync(N,"utf-8").trim():"";if(I.existsSync(T)){let V=R&&R!==j?"Build environment changed \u2014 clearing iOS DerivedData build products.":R?"Clearing iOS DerivedData build products to force a fresh JS bundle.":"DerivedData has no environment stamp \u2014 clearing iOS build products.";P.info(S.dim(V)),I.rmSync(T,{recursive:!0,force:!0})}if(I.writeFileSync(N,j),zt(process.cwd()),e.simulator){let V=fo(l,d,f,C,v),q=V||"generic/platform=iOS Simulator",ye=["-destination",q];P.info(S.dim(V?`Building for simulator (Scheme: ${C}, Config: ${v}, Destination: ${q})...`:`Building for simulator (Scheme: ${C}, Config: ${v}, Destination: ${q})...`));let Ae=[d?"-workspace":"-project",d||f,"-scheme",C,"-configuration",v,"-sdk","iphonesimulator",...ye,"-derivedDataPath",D,...w,"COMPILER_INDEX_STORE_ENABLE=NO","CODE_SIGNING_ALLOWED=NO","CODE_SIGNING_REQUIRED=NO","ONLY_ACTIVE_ARCH=NO","EXCLUDED_ARCHS=","SUPPORTED_PLATFORMS=iphonesimulator"];try{await Ct(Ae,l,y,o,s)}catch($){if(!po($))throw $;uo(D),zt(process.cwd()),await Ct(Ae,l,y,o,s)}let re=b.join(D,"Build/Products",`${v}-iphonesimulator`),te=yo(re,C,e),ae=b.basename(te,".app"),ie=tt(b.join(te,"Info.plist"),"CFBundleIdentifier")||"unknown bundle",De=Ln(te,h||void 0)[0].buildNumber,W=ti(te),k=ni(te),E=b.join(re,`${ae}_simulator.zip`);return P.info(S.dim(`Selected simulator app: ${b.relative(re,te)} (${ie}, build ${De})`)),P.info(S.dim(`Simulator executable architecture: ${W}`)),P.info(S.dim(`Simulator executable platform: ${k.split(`
304
+ `).find($=>/\bplatform\b/i.test($))?.trim()||"IOSSIMULATOR"}`)),P.info(S.dim(`Creating simulator artifact: ${E}...`)),Pe(E),Te("zip",["-r",E,b.basename(te)],{cwd:b.dirname(te),stdio:"pipe"}),[E]}else{P.info(S.dim(`Archiving (Scheme: ${C}, Config: ${v})...`));let V=b.join(l,"build.xcarchive"),q=b.join(l,"export");I.rmSync(V,{recursive:!0,force:!0}),I.rmSync(q,{recursive:!0,force:!0});let ye=i.IOS_DIST_P12,Ae=i.IOS_PROVISIONING_PROFILE,re=i.IOS_P12_PASSWORD||"",te=[],ae,ie,K={isAppStore:!1,isDevelopment:!1};if(ye&&Ae){P.info(S.blue("\u{1F510} CI/CD Signing: Importing certificates..."));try{let J=`${A.buildPrefix}-${t}.keychain-db`,X=b.join(de.tmpdir(),J),pe=A.keychainPassword;L(`security create-keychain -p "${pe}" "${X}" 2>/dev/null || true`),L(`security set-keychain-settings -t 3600 -l "${X}"`),L(`security unlock-keychain -p "${pe}" "${X}"`);let Ve=b.join(de.tmpdir(),`cert-${t}.p12`),rt=Buffer.from(ye,"base64");I.writeFileSync(Ve,rt),P.info(S.dim(`P12 data size: ${rt.length} bytes, first bytes: ${rt.slice(0,4).toString("hex")}`)),(rt.length<100||rt[0]!==48)&&(P.warn(S.yellow("\u26A0\uFE0F P12 data looks corrupted or was not decrypted correctly.")),P.warn(S.yellow(" This usually means MACH_ENCRYPTION_KEY on the Remote API differs from when credentials were uploaded.")));let Bi=[re,"",A.keychainPassword],pn=!1;for(let fe of Bi)try{L(`security import "${Ve}" -k "${X}" -P "${fe}" -A -T /usr/bin/codesign -T /usr/bin/security`,{stdio:"pipe"}),pn=!0,P.info(S.dim(`\u2713 P12 imported successfully with password: ${fe?"[set]":"[empty]"}`));break}catch(ke){P.info(S.dim(` P12 import attempt with password ${fe?`"${fe.substring(0,3)}..."`:"[empty]"} failed: ${ke.message?.split(`
305
+ `)[0]||"unknown"}`))}if(!pn)throw new Error("Failed to import P12.");I.unlinkSync(Ve),L(`security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${pe}" "${X}"`);let Di=L("security list-keychains -d user",{encoding:"utf-8"}).split(`
306
+ `).map(fe=>fe.trim().replace(/^"|"$/g,"")).filter(fe=>fe.length>0),Vi=[X,...Di].map(fe=>`"${fe}"`).join(" ");L(`security list-keychains -d user -s ${Vi}`),L(`security default-keychain -s "${X}"`);let Rt=b.join(de.homedir(),"Library/MobileDevice/Provisioning Profiles");I.mkdirSync(Rt,{recursive:!0});let un=Buffer.from(Ae,"base64"),xt=b.join(Rt,`${A.nameLower}-temp-${t}.mobileprovision`);I.writeFileSync(xt,un);let $t=un.toString("utf-8"),mn=/<key>get-task-allow<\/key>\s*<true\/>/.test($t);K={isAppStore:!$t.includes("<key>ProvisionedDevices</key>")&&!mn,isDevelopment:mn};try{let ke=L(`security cms -D -i "${xt}"`,{encoding:"utf-8"}).match(/<key>UUID<\/key>\s*<string>([^<]+)<\/string>/);ie=ke?ke[1]:void 0}catch{let ke=$t.match(/<key>UUID<\/key>\s*<string>([^<]+)<\/string>/);ie=ke?ke[1]:void 0}ie||(P.warn("Could not extract UUID from provisioning profile. Using fallback."),ie=`${A.nameLower}-${t}`);let Ft=b.join(Rt,`${ie}.mobileprovision`);I.existsSync(Ft)&&I.unlinkSync(Ft),I.renameSync(xt,Ft);try{let fe=L(`security find-identity -v -p codesigning "${X}"`,{encoding:"utf-8"}),ke=Array.from(fe.matchAll(/"((?:Apple|iPhone) (?:Distribution|Developer|Development)[^"]*)"/g),ot=>ot[1]),fn=K.isDevelopment?ke.find(ot=>/\b(Development|Developer)\b/.test(ot)):ke.find(ot=>/\bDistribution\b/.test(ot)),gn=ke[0];(fn||gn)&&(ae=fn||gn,P.info(S.blue(`Identity auto-detected from keychain: "${ae}"`)))}catch{}ae||(ae=K.isDevelopment?"Apple Development":"Apple Distribution",P.info(S.blue(`Identity fallback (profile heuristic): "${ae}"`))),P.info(S.dim(`Profile type: ${K.isDevelopment?"Development":K.isAppStore?"App Store":"Ad-Hoc"}`)),P.info(S.dim(`Identity Detection: get-task-allow=${K.isDevelopment}, Selected Identity="${ae}"`)),te.push("CODE_SIGN_STYLE=Manual"),te.push(`CODE_SIGN_IDENTITY="${ae}"`),te.push(`PROVISIONING_PROFILE_SPECIFIER=${ie}`),e.iosTeamId&&te.push(`DEVELOPMENT_TEAM=${e.iosTeamId}`)}catch(J){throw P.error(`Signing setup failed: ${J.message}`),J}}else te.push("-allowProvisioningUpdates"),e.iosTeamId&&te.push(`DEVELOPMENT_TEAM=${e.iosTeamId}`);c&&await c("archive"),P.info(S.blue(`Archive detected Identity: "${ae}"`)),P.info(S.blue(`Archive detected UUID: "${ie}"`)),await Ct(["archive",d?"-workspace":"-project",d||f,"-scheme",C,"-configuration",v,"-archivePath",V,"-derivedDataPath",D,...w,...te],l,y,o,s);let De=He(b.join(V,"Products","Applications"),[".app"]);for(let J of De)for(let X of Ln(J,h||void 0))P.info(S.dim(`Validated iOS CFBundleVersion ${X.buildNumber} in ${b.basename(X.bundlePath)}`));let W;ie?(K.isAppStore?W="app-store":K.isDevelopment?W="development":W="ad-hoc",P.info(S.blue(`Export method from profile: "${W}"`))):(W=e.distribution==="store"?"app-store":e.distribution==="internal"?"ad-hoc":"development",P.warn(S.yellow(`No profile UUID detected. Export method from distribution flag: "${W}"`)));let k=e.iosExportMethod||W,E=e.iosBundleIdentifier||nt("ios"),$=b.join(l,"ExportOptions.plist"),B=`<?xml version="1.0" encoding="UTF-8"?>
307
307
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
308
308
  <plist version="1.0">
309
309
  <dict>
@@ -323,25 +323,25 @@ ${s.join(`
323
323
  <string>${ie}</string>
324
324
  </dict>`:""}
325
325
  </dict>
326
- </plist>`;if(y.writeFileSync($,B),process.env[`${A.envPrefix}DEBUG`]&&P.info(S.magenta(`[${A.nameUpper}_DEBUG] ExportOptions.plist:
326
+ </plist>`;if(I.writeFileSync($,B),process.env[`${A.envPrefix}DEBUG`]&&P.info(S.magenta(`[${A.nameUpper}_DEBUG] ExportOptions.plist:
327
327
  ${B}`)),c&&await c("export"),P.info(S.blue(`Exporting with Bundle ID: "${E}"`)),P.info(S.blue(`Exporting with Method: "${k}"`)),o){o(S.magenta(`
328
328
  [DIAGNOSTIC] Checking available signing identities...
329
329
  `));try{let J=L("security find-identity -v -p codesigning",{encoding:"utf-8"});o(S.magenta(`${J}
330
330
  `))}catch(J){o(S.red(`[DIAGNOSTIC] Failed to list identities: ${J.message}
331
- `))}}await Ct(["-exportArchive","-archivePath",V,"-exportPath",q,"-exportOptionsPlist",$],l,I,o,s),c&&await c("validate");let Y=He(q,[".ipa"]);for(let J of Y)try{L(`unzip -t "${J}"`,{stdio:"pipe"});let X=ii(J,h||void 0);o&&o(`[IPA VALID] ${b.basename(J)} \u2014 archive integrity OK
331
+ `))}}await Ct(["-exportArchive","-archivePath",V,"-exportPath",q,"-exportOptionsPlist",$],l,y,o,s),c&&await c("validate");let z=He(q,[".ipa"]);for(let J of z)try{L(`unzip -t "${J}"`,{stdio:"pipe"});let X=ii(J,h||void 0);o&&o(`[IPA VALID] ${b.basename(J)} \u2014 archive integrity OK
332
332
  `),o&&o(`[IPA VALID] CFBundleVersion ${X}
333
333
  `)}catch(X){let pe=`IPA validation failed for ${b.basename(J)}: ${X.message||"archive may be corrupt"}`;throw o&&o(`[IPA CORRUPT] ${pe}
334
- `),new Error(pe)}return Y}}finally{x?.restore()}},nt=e=>{try{let t=b.join(process.cwd(),A.configFileName);if(y.existsSync(t)){let n=JSON.parse(y.readFileSync(t,"utf-8"));if(e==="android"&&n.android?.package)return n.android.package;if(e==="ios"&&n.ios?.bundleIdentifier)return n.ios.bundleIdentifier}if(e==="android"){let n=["android/app/build.gradle","app/build.gradle","build.gradle"];for(let i of n)if(y.existsSync(i)){let o=y.readFileSync(i,"utf-8").match(/applicationId\s+['"]([^'"]+)['"]/);if(o)return o[1]}}else{let n=b.resolve(process.cwd(),y.existsSync("ios")?"ios":"."),i=He(n,["Info.plist"]).filter(s=>!s.includes("/Pods/")&&!s.includes("/build/")&&!s.includes("/DerivedData/"));i.sort((s,a)=>a.split("/").length-s.split("/").length);for(let s of i){let c=y.readFileSync(s,"utf-8").match(/<key>CFBundleIdentifier<\/key>\s*<string>([^<]+)<\/string>/);if(c&&!c[1].includes("$"))return c[1]}let r=He(n,[".xcodeproj"]);if(r.length>0){let s=b.join(r[0],"project.pbxproj");if(y.existsSync(s)){let c=y.readFileSync(s,"utf-8").match(/PRODUCT_BUNDLE_IDENTIFIER\s*=\s*"?([^";\s]+)"?;/);if(c)return c[1]}}let o=["app.json","app.config.json","app.config.js","app.config.ts"];for(let s of o)if(y.existsSync(s)){let c=y.readFileSync(s,"utf-8").match(/"bundleIdentifier":\s*"([^"]+)"/);if(c)return c[1]}}}catch{return null}return null},Eo=()=>{try{return L("emulator -version",{stdio:"ignore"}),"emulator"}catch{let t=de.homedir(),n=[b.join(t,"Library/Android/sdk/emulator/emulator"),b.join(t,"Android/Sdk/emulator/emulator"),"/usr/local/lib/android/sdk/emulator/emulator"];for(let i of n)if(y.existsSync(i))return i}return"emulator"},Po=async(e,t)=>{let n=St();try{if(L("adb devices").toString().split(`
334
+ `),new Error(pe)}return z}}finally{x?.restore()}},nt=e=>{try{let t=b.join(process.cwd(),A.configFileName);if(I.existsSync(t)){let n=JSON.parse(I.readFileSync(t,"utf-8"));if(e==="android"&&n.android?.package)return n.android.package;if(e==="ios"&&n.ios?.bundleIdentifier)return n.ios.bundleIdentifier}if(e==="android"){let n=["android/app/build.gradle","app/build.gradle","build.gradle"];for(let i of n)if(I.existsSync(i)){let o=I.readFileSync(i,"utf-8").match(/applicationId\s+['"]([^'"]+)['"]/);if(o)return o[1]}}else{let n=b.resolve(process.cwd(),I.existsSync("ios")?"ios":"."),i=He(n,["Info.plist"]).filter(s=>!s.includes("/Pods/")&&!s.includes("/build/")&&!s.includes("/DerivedData/"));i.sort((s,a)=>a.split("/").length-s.split("/").length);for(let s of i){let c=I.readFileSync(s,"utf-8").match(/<key>CFBundleIdentifier<\/key>\s*<string>([^<]+)<\/string>/);if(c&&!c[1].includes("$"))return c[1]}let r=He(n,[".xcodeproj"]);if(r.length>0){let s=b.join(r[0],"project.pbxproj");if(I.existsSync(s)){let c=I.readFileSync(s,"utf-8").match(/PRODUCT_BUNDLE_IDENTIFIER\s*=\s*"?([^";\s]+)"?;/);if(c)return c[1]}}let o=["app.json","app.config.json","app.config.js","app.config.ts"];for(let s of o)if(I.existsSync(s)){let c=I.readFileSync(s,"utf-8").match(/"bundleIdentifier":\s*"([^"]+)"/);if(c)return c[1]}}}catch{return null}return null},Eo=()=>{try{return L("emulator -version",{stdio:"ignore"}),"emulator"}catch{let t=de.homedir(),n=[b.join(t,"Library/Android/sdk/emulator/emulator"),b.join(t,"Android/Sdk/emulator/emulator"),"/usr/local/lib/android/sdk/emulator/emulator"];for(let i of n)if(I.existsSync(i))return i}return"emulator"},Po=async(e,t)=>{let n=St();try{if(L("adb devices").toString().split(`
335
335
  `).slice(1).map(s=>s.trim()).filter(s=>s.length>0&&!s.startsWith("*")).map(s=>s.split(" ")[0]).length===0){P.warn(S.yellow("No Android devices or emulators found."));let s=Eo(),a=[];try{a=L(`${s} -list-avds`).toString().split(`
336
336
  `).filter(c=>c.trim().length>0)}catch{}if(a.length>0){let c=await Qt({message:"Select an emulator to launch:",options:a.map(d=>({value:d,label:d}))});if(wt(c))return;n.start(`Launching emulator ${c}...`),Hn(s,["-avd",c],{detached:!0,stdio:"ignore"}).unref();let l=0,p=!1;for(;l<60;){try{if(L("adb shell getprop sys.boot_completed",{stdio:"pipe"}).toString().trim()==="1"){p=!0;break}}catch{}await new Promise(d=>setTimeout(d,2e3)),l++}if(!p)throw n.stop("Emulator launch timed out."),new Error("Emulator launch timed out. Please try launching it manually.");n.stop("Emulator launched.")}else throw new Error("No devices found and no emulators available to launch. (Make sure Android SDK is installed)")}n.start("Installing APK on device..."),await Oe("adb",["install","-r",e],process.cwd(),{},t),n.stop("Installation complete.");let o=nt("android");if(o){P.info(S.blue(`\u{1F680} Launching ${o}...`));try{L(`adb shell dumpsys package ${o}`).toString().split(`
337
337
  `).find(c=>c.includes("android.intent.action.MAIN")&&c.includes("android.intent.category.LAUNCHER"))?L(`adb shell monkey -p ${o} -c android.intent.category.LAUNCHER 1`,{stdio:"ignore"}):L(`adb shell monkey -p ${o} -c android.intent.category.LAUNCHER 1`,{stdio:"ignore"})}catch{P.warn("Could not auto-launch app. You may need to open it manually.")}}}catch(i){n.stop("Installation failed."),P.error(S.red(`Failed to install APK: ${i.message}`))}},No=async(e,t,n)=>{let i=St();try{if(!L("xcrun simctl list devices booted").toString().includes("(Booted)")){P.warn(S.yellow("No iOS Simulator is currently booted."));let o=L("xcrun simctl list devices --json").toString(),s=JSON.parse(o).devices,a=[];Object.keys(s).forEach(d=>{s[d].forEach(f=>{f.isAvailable&&a.push({...f,runtime:d})})});let c=await Qt({message:"Select a simulator to launch:",options:a.map(d=>({value:d.udid,label:`${d.name} (${d.runtime.split(".").pop()})`}))});if(wt(c))return;i.start(`Booting ${c}...`),L(`xcrun simctl boot ${c}`),L(`open -a Simulator --args -CurrentDeviceUDID ${c}`);let l=0,p=!1;for(;l<30;){try{if(L("xcrun simctl list devices booted").toString().includes(c)){p=!0;break}}catch{}await new Promise(d=>setTimeout(d,2e3)),l++}if(!p)throw i.stop("Simulator boot timed out."),new Error("Simulator boot timed out.");i.stop("Simulator booted.")}i.start("Installing on iOS Simulator..."),ti(e),ni(e),await Oe("xcrun",["simctl","install","booted",e],process.cwd(),{},n),i.stop("Installation complete."),P.info(S.blue(`\u{1F680} Launching ${t}...`)),await Oe("xcrun",["simctl","launch","booted",t],process.cwd(),{},n)}catch(r){i.stop("Installation failed."),P.error(S.red(`Failed to install on Simulator: ${r.message}`))}},ko=async(e,t,n)=>{let i=St();i.start("Scanning for connected iOS devices...");try{let r=L("xcrun devicectl list devices --json-output -").toString(),s=(JSON.parse(r).result?.devices||[]).filter(c=>c.connectionProperties?.transportType==="wired"||c.connectionProperties?.transportType==="localNetwork");if(s.length===0)throw i.stop("No connected iOS devices found."),new Error("Please connect your iPhone via USB or ensure it is on the same Wi-Fi for wireless debugging.");let a=s[0].identifier;if(s.length>1){i.stop();let c=await Qt({message:"Select a device to install on:",options:s.map(l=>({value:l.identifier,label:`${l.deviceProperties?.name||l.name||l.model?.name} (${l.model?.name||"iPhone"}) - ${l.identifier}`}))});if(wt(c))return;a=c,i.start(`Installing on ${a}...`)}else i.message(`Installing on ${s[0].model.name}...`);await Oe("xcrun",["devicectl","device","install","app","--device",a,e],process.cwd(),{},n),i.stop("Installation complete."),P.info(S.blue(`\u{1F680} Launching ${t}...`)),await Oe("xcrun",["devicectl","device","launch","app","--device",a,t],process.cwd(),{},n)}catch(r){i.stop("Installation failed."),P.error(S.red(`Failed to install on device: ${r.message}`)),P.info(S.dim('Make sure your device is unlocked and "Developer Mode" is enabled in Settings -> Privacy & Security.'))}};import{createRequire as Ro}from"module";var xo=Ro(import.meta.url),$o=xo("../package.json"),en=String($o.version||"0.0.0");var li="https://mach-api.securejs.in",_o=["google-services.json","android/app/google-services.json"],oi="0.1.4";function To(){return me.join(process.cwd(),A.configFileName)}function Et(){let e=In();if(!e?.projectId)throw new Error(`No linked MACH project. Run \`${A.nameLower} link\` first.`);return e}function di(e){oe.writeFileSync(To(),`${JSON.stringify(e,null,2)}
338
- `)}function Oo(){return tn(me.join(process.cwd(),"package.json"))}function tn(e){if(!oe.existsSync(e))return null;try{return JSON.parse(oe.readFileSync(e,"utf8"))}catch{return null}}function Bo(e){let t=Oo();return!!(t?.dependencies?.[e]||t?.devDependencies?.[e])}function nn(e){let t=process.cwd(),n=tn(me.join(t,"node_modules",...e.split("/"),"package.json"));if(typeof n?.version=="string")return n.version;let r=tn(me.join(t,"package-lock.json"))?.packages?.[`node_modules/${e}`]?.version;return typeof r=="string"?r:void 0}function Do(e,t){let n=o=>o.replace(/^v/,"").split(/[.-]/).slice(0,3).map(s=>Number.parseInt(s,10)||0),i=n(e),r=n(t);for(let o=0;o<3;o+=1)if(i[o]!==r[o])return i[o]>r[o]?1:-1;return 0}function si(e,t){let n=nn(e);return!Bo(e)||!n||Do(n,t)<0}function Vo(e,t=!1){let n=process.cwd();return oe.existsSync(me.join(n,"pnpm-lock.yaml"))?{command:"pnpm",args:["add",...t?["-D"]:[],e],label:`pnpm add ${t?"-D ":""}${e}`}:oe.existsSync(me.join(n,"yarn.lock"))?{command:"yarn",args:["add",...t?["-D"]:[],e],label:`yarn add ${t?"-D ":""}${e}`}:oe.existsSync(me.join(n,"bun.lock"))||oe.existsSync(me.join(n,"bun.lockb"))?{command:"bun",args:["add",...t?["-d"]:[],e],label:`bun add ${t?"-d ":""}${e}`}:{command:"npm",args:["install",...t?["--save-dev"]:["--save"],"--no-audit","--no-fund",e],label:`npm install ${t?"--save-dev ":"--save "}${e} --no-audit --no-fund`}}function ai(e,t=!1){let n=Vo(e,t);console.log(Q.dim(`Installing dependency: ${n.label}`));let i=Fo(n.command,n.args,{cwd:process.cwd(),stdio:"inherit",timeout:12e4,env:{...process.env,NPM_CONFIG_AUDIT:"false",NPM_CONFIG_FUND:"false"}});return i.signal==="SIGTERM"?{ok:!1,note:`${n.label} timed out after 120s. Run it manually, or re-run \`${A.nameLower} push setup --skip-install\` to only generate files.`}:i.error||i.status!==0?{ok:!1,note:`${n.label} failed${i.error?`: ${i.error.message}`:` with code ${i.status}`}.`}:{ok:!0,note:`Installed with ${n.label}.`}}function Wo(e,t){let n=[];if(t)return n.push("Dependency installation skipped."),n;if(si("@radhya/mach-push-react-native",oi)){let i=ai(`@radhya/mach-push-react-native@${oi}`);if(!i.ok)throw new Error(`${i.note} No application files were wired.`);n.push(i.note)}else n.push(`@radhya/mach-push-react-native is already current (${nn("@radhya/mach-push-react-native")}).`);if(e==="expo")if(si("@radhya/mach",en)){let i=ai(`@radhya/mach@${en}`,!0);if(!i.ok)throw new Error(`${i.note} No Expo configuration was changed.`);n.push(i.note)}else n.push(`@radhya/mach is already current for the Expo config (${nn("@radhya/mach")}).`);return n}function Zo(e,t){return e||t||["google-services.json","android/app/google-services.json"].find(n=>oe.existsSync(me.join(process.cwd(),n)))}function pi(e){let t={enabled:!0};return e.appId&&e.publishableKey&&(t.appId=e.appId,t.publishableKey=e.publishableKey),e.apiUrl&&e.apiUrl!==li&&(t.apiUrl=e.apiUrl),e.environment&&e.environment!=="production"&&(t.environment=e.environment),e.googleServicesFile&&!_o.includes(e.googleServicesFile)&&(t.googleServicesFile=e.googleServicesFile),t}function Mo(e){return e==="development"?"development":"production"}function ui(e){let t=process.cwd(),n=e==="ios"?"bundleIdentifier":"package";for(let i of["app.json","app.config.json"]){let r=me.join(t,i);if(oe.existsSync(r))try{let o=JSON.parse(oe.readFileSync(r,"utf8")),a=(o.expo&&typeof o.expo=="object"?o.expo:o)?.[e]?.[n];if(typeof a=="string"&&a.trim())return a.trim()}catch{}}for(let i of["app.config.ts","app.config.js"]){let r=me.join(t,i);if(!oe.existsSync(r))continue;let s=oe.readFileSync(r,"utf8").match(new RegExp(`${n}\\s*:\\s*['"]([^'"]+)['"]`));if(s?.[1])return s[1]}}function mi(e,t){return t||We(e)||ui("ios")||nt("ios")||void 0}function fi(e,t){return t||Je(e)||ui("android")||nt("android")||void 0}function Go(e,t){let n=oe.readFileSync(e,"utf8");if(n.includes(t))return"already";let i=/(^[ \t]*)plugins\s*:\s*\[([\s\S]*?)\]/m.exec(n);if(!i||i.index===void 0)return"manual";let r=n.includes(`\r
338
+ `)}function Oo(){return tn(me.join(process.cwd(),"package.json"))}function tn(e){if(!oe.existsSync(e))return null;try{return JSON.parse(oe.readFileSync(e,"utf8"))}catch{return null}}function Bo(e){let t=Oo();return!!(t?.dependencies?.[e]||t?.devDependencies?.[e])}function nn(e){let t=process.cwd(),n=tn(me.join(t,"node_modules",...e.split("/"),"package.json"));if(typeof n?.version=="string")return n.version;let r=tn(me.join(t,"package-lock.json"))?.packages?.[`node_modules/${e}`]?.version;return typeof r=="string"?r:void 0}function Do(e,t){let n=o=>o.replace(/^v/,"").split(/[.-]/).slice(0,3).map(s=>Number.parseInt(s,10)||0),i=n(e),r=n(t);for(let o=0;o<3;o+=1)if(i[o]!==r[o])return i[o]>r[o]?1:-1;return 0}function si(e,t){let n=nn(e);return!Bo(e)||!n||Do(n,t)<0}function Vo(e,t=!1){let n=process.cwd();return oe.existsSync(me.join(n,"pnpm-lock.yaml"))?{command:"pnpm",args:["add",...t?["-D"]:[],e],label:`pnpm add ${t?"-D ":""}${e}`}:oe.existsSync(me.join(n,"yarn.lock"))?{command:"yarn",args:["add",...t?["-D"]:[],e],label:`yarn add ${t?"-D ":""}${e}`}:oe.existsSync(me.join(n,"bun.lock"))||oe.existsSync(me.join(n,"bun.lockb"))?{command:"bun",args:["add",...t?["-d"]:[],e],label:`bun add ${t?"-d ":""}${e}`}:{command:"npm",args:["install",...t?["--save-dev"]:["--save"],"--no-audit","--no-fund",e],label:`npm install ${t?"--save-dev ":"--save "}${e} --no-audit --no-fund`}}function ai(e,t=!1){let n=Vo(e,t);console.log(Y.dim(`Installing dependency: ${n.label}`));let i=Fo(n.command,n.args,{cwd:process.cwd(),stdio:"inherit",timeout:12e4,env:{...process.env,NPM_CONFIG_AUDIT:"false",NPM_CONFIG_FUND:"false"}});return i.signal==="SIGTERM"?{ok:!1,note:`${n.label} timed out after 120s. Run it manually, or re-run \`${A.nameLower} push setup --skip-install\` to only generate files.`}:i.error||i.status!==0?{ok:!1,note:`${n.label} failed${i.error?`: ${i.error.message}`:` with code ${i.status}`}.`}:{ok:!0,note:`Installed with ${n.label}.`}}function Wo(e,t){let n=[];if(t)return n.push("Dependency installation skipped."),n;if(si("@radhya/mach-push-react-native",oi)){let i=ai(`@radhya/mach-push-react-native@${oi}`);if(!i.ok)throw new Error(`${i.note} No application files were wired.`);n.push(i.note)}else n.push(`@radhya/mach-push-react-native is already current (${nn("@radhya/mach-push-react-native")}).`);if(e==="expo")if(si("@radhya/mach",en)){let i=ai(`@radhya/mach@${en}`,!0);if(!i.ok)throw new Error(`${i.note} No Expo configuration was changed.`);n.push(i.note)}else n.push(`@radhya/mach is already current for the Expo config (${nn("@radhya/mach")}).`);return n}function Zo(e,t){return e||t||["google-services.json","android/app/google-services.json"].find(n=>oe.existsSync(me.join(process.cwd(),n)))}function pi(e){let t={enabled:!0};return e.appId&&e.publishableKey&&(t.appId=e.appId,t.publishableKey=e.publishableKey),e.apiUrl&&e.apiUrl!==li&&(t.apiUrl=e.apiUrl),e.environment&&e.environment!=="production"&&(t.environment=e.environment),e.googleServicesFile&&!_o.includes(e.googleServicesFile)&&(t.googleServicesFile=e.googleServicesFile),t}function Mo(e){return e==="development"?"development":"production"}function ui(e){let t=process.cwd(),n=e==="ios"?"bundleIdentifier":"package";for(let i of["app.json","app.config.json"]){let r=me.join(t,i);if(oe.existsSync(r))try{let o=JSON.parse(oe.readFileSync(r,"utf8")),a=(o.expo&&typeof o.expo=="object"?o.expo:o)?.[e]?.[n];if(typeof a=="string"&&a.trim())return a.trim()}catch{}}for(let i of["app.config.ts","app.config.js"]){let r=me.join(t,i);if(!oe.existsSync(r))continue;let s=oe.readFileSync(r,"utf8").match(new RegExp(`${n}\\s*:\\s*['"]([^'"]+)['"]`));if(s?.[1])return s[1]}}function mi(e,t){return t||We(e)||ui("ios")||nt("ios")||void 0}function fi(e,t){return t||Je(e)||ui("android")||nt("android")||void 0}function Go(e,t){let n=oe.readFileSync(e,"utf8");if(n.includes(t))return"already";let i=/(^[ \t]*)plugins\s*:\s*\[([\s\S]*?)\]/m.exec(n);if(!i||i.index===void 0)return"manual";let r=n.includes(`\r
339
339
  `)?`\r
340
340
  `:`
341
341
  `,o=i[1]||"",s=i[2]||"",a=s.match(/\r?\n([ \t]+)\S/)?.[1]||`${o} `,c=s.trim().length===0?`${r}${a}'${t}',${r}${o}`:`${r}${a}'${t}',${s}`,l=i[0].indexOf("["),p=`${i[0].slice(0,l+1)}${c}]`;return oe.writeFileSync(e,`${n.slice(0,i.index)}${p}${n.slice(i.index+i[0].length)}`),"inserted"}function gi(){let e="@radhya/mach/expo-plugin",t=["app.config.ts","app.config.js"].find(c=>oe.existsSync(me.join(process.cwd(),c)));if(t){let c=Go(me.join(process.cwd(),t),e);return c==="inserted"?`${t} now includes ${e}.`:c==="already"?`${t} already includes ${e}.`:`Add "${e}" to the plugins array in ${t}; MACH could not safely edit its computed configuration.`}let n=["app.config.json","app.json"].find(c=>oe.existsSync(me.join(process.cwd(),c)));if(!n)return`Add "${e}" to the Expo plugins array.`;let i=me.join(process.cwd(),n),r=JSON.parse(oe.readFileSync(i,"utf8")),o=r.expo&&typeof r.expo=="object"?r.expo:r,s=Array.isArray(o.plugins)?o.plugins:[];return s.some(c=>(Array.isArray(c)?c[0]:c)===e)?`${n} already includes ${e}.`:(o.plugins=[...s,e],oe.writeFileSync(i,`${JSON.stringify(r,null,2)}
342
- `),`${n} now includes ${e}.`)}async function hi(e){let t=Et(),n=e.app||t.push?.appId,i=e.environment||t.push?.environment||"production";if(n)return{config:t,appId:n,environment:i};let{data:r}=await Z.get(`/projects/${t.projectId}/push/overview?days=1`),s=(r?.apps||[]).filter(a=>a.status!=="disabled").sort((a,c)=>(c.updatedAt||0)-(a.updatedAt||0))[0]?.appId;if(!s)throw new Error(`Push is not configured. Run \`${A.nameLower} push setup\` first.`);return{config:t,appId:s,environment:i}}function ci(e){let t=me.resolve(e);if(!oe.existsSync(t))throw new Error(`File not found: ${t}`);return t}function gt(e){let t=e?.response?.data?.message||e?.message||"Unknown error";console.error(Q.red(t)),process.exitCode=1}async function Xc(e){let t=vt();try{let n=Et();if(_t(n)==="flutter")throw new Error("MACH Push currently supports Expo and bare React Native. Flutter push support is planned for a later release.");let r=mi(n,e.iosBundle),o=fi(n,e.androidPackage);if(!r&&!o)throw new Error(`Add ios.bundleIdentifier or android.package to ${A.configFileName}, or pass --ios-bundle/--android-package.`);t.start("Creating MACH Push app..."),await Z.post(`/projects/${n.projectId}/push/apps`,{name:e.name||n.name||"Mobile app",iosBundleId:r,androidPackageName:o});let s=e.environment||"production";n.push=pi({environment:s,googleServicesFile:e.googleServicesFile}),di(n);let a=n.framework==="expo"?gi():void 0;t.stop(Q.green("MACH Push app created.")),console.log(["",`${Q.bold("Client config:")} ${A.configFileName} \u2192 push`,"","Install the mobile SDK:"," npm install @radhya/mach-push-react-native",...n.framework==="expo"?[" npm install --save-dev @radhya/mach",` ${a}`," Run npx expo prebuild."]:[],"",`Next: run \`${A.nameLower} credentials\` and choose Push Notifications.`].join(`
343
- `))}catch(n){t.stop(Q.red("MACH Push setup failed.")),gt(n)}}async function jc(e){let t=vt();try{let n=Et(),i=_t(n);if(i==="flutter")throw new Error("MACH Push currently supports Expo and bare React Native. Flutter push support is planned for a later release.");let r=mi(n,e.iosBundle),o=fi(n,e.androidPackage);if(!r&&!o)throw new Error(`Add ios.bundleIdentifier or android.package to ${A.configFileName}, or pass --ios-bundle/--android-package.`);let s;t.start("Checking the MACH Push app...");let l=((await Z.get(`/projects/${n.projectId}/push/overview?days=1`)).data?.apps||[]).filter(v=>v.status!=="disabled").sort((v,x)=>(x.updatedAt||0)-(v.updatedAt||0)).find(v=>(!r||v.iosBundleId===r)&&(!o||v.androidPackageName===o));if(l)s=l.appId,t.stop(Q.green("Existing MACH Push app linked."));else{let{data:v}=await Z.post(`/projects/${n.projectId}/push/apps`,{name:e.name||n.name||"Mobile app",iosBundleId:r,androidPackageName:o});s=v.app.appId,t.stop(Q.green("MACH Push app created."))}if(!s)throw new Error("MACH Push did not return a usable application.");let p=n.push,d=e.environment||p?.environment||"production",f=p?.apiUrl||li,I=Zo(e.googleServicesFile,p?.googleServicesFile);n.push=pi({apiUrl:f,environment:d,googleServicesFile:I}),di(n);let g=Wo(i,!!e.skipInstall),h=i==="expo"?gi():void 0;if(h?.startsWith('Add "'))throw new Error(h);let w={projectId:n.projectId,apiUrl:f,environment:d},_=Nn(process.cwd(),i,w);if(!_.entryFile)throw new Error(_.notes[0]||"MACH could not locate the application entry point.");let C=i==="expo"?{written:[],notes:[]}:Rn(process.cwd(),{iosBundleId:r,iosEnvironment:Mo(d),googleServicesFile:I});console.log(["",Q.green.bold("MACH Push basic setup is ready."),`${Q.bold("Framework:")} ${i}`,`${Q.bold("Client config:")} ${A.configFileName} \u2192 push`,`${Q.bold("Automatic startup:")} ${_.entryFile||"manual entry import required"}`,`${Q.bold("Customize callbacks:")} ${_.editableFile||"see the setup notes below"}`,"",...g.map(v=>`\u2022 ${v}`),...h?[`\u2022 ${h}`]:[],..._.notes.map(v=>`\u2022 ${v}`),...C.notes.map(v=>`\u2022 ${v}`),...[..._.written,...C.written].map(v=>`\u2022 Updated ${v}.`),"",`Next: run \`${A.nameLower} credentials\` and choose Push Notifications, then create one new native build.`].join(`
344
- `))}catch(n){t.stop(Q.red("MACH Push setup failed.")),gt(n)}}async function Pt(e,t){let n=vt();try{let{config:i,appId:r,environment:o}=await hi(t),s;if(e==="apns"){if(!t.teamId||!t.keyId)throw new Error("APNs requires --team-id and --key-id.");let a=t.privateKey||(t.file?oe.readFileSync(ci(t.file),"utf8"):"");if(!a)throw new Error("APNs requires --file or a generated private key.");let c=t.bundleId||We(i);if(!c)throw new Error("APNs requires --bundle-id.");s={environment:o,teamId:t.teamId,keyId:t.keyId,bundleId:c,privateKey:a}}else{let a=t.serviceAccount||(t.file?JSON.parse(oe.readFileSync(ci(t.file),"utf8")):void 0);if(!a)throw new Error("FCM requires --file or a generated service account.");s={serviceAccount:a}}n.start(`Configuring ${e.toUpperCase()}...`),await Z.put(`/projects/${i.projectId}/push/apps/${r}/credentials/${e}`,s),n.stop(Q.green(`${e.toUpperCase()} is ready.`))}catch(i){n.stop(Q.red(`${e.toUpperCase()} setup failed.`)),gt(i)}}async function Lc(e){let t=vt();try{let{config:n,appId:i,environment:r}=await hi(e),o=e.all?{all:!0,platform:e.platform}:e.token?.length?{machPushTokens:e.token}:e.user?.length?{externalUserIds:e.user}:null;if(!o)throw new Error("Choose --token, --user, or --all.");let s;if(e.data){let p=JSON.parse(e.data);if(!p||typeof p!="object"||Array.isArray(p))throw new Error("--data must be a JSON object.");s=Object.fromEntries(Object.entries(p).map(([d,f])=>[d,String(f)]))}let a=e.badge===void 0?void 0:Number(e.badge),c=e.ttl===void 0?void 0:Number(e.ttl);t.start("Queueing notification...");let{data:l}=await Z.post(`/projects/${n.projectId}/push/send`,{appId:i,environment:r,target:o,notification:{title:e.title,body:e.body,data:s},options:{sound:e.sound,badge:a,ttlSeconds:c,collapseKey:e.collapseKey,androidChannelId:e.androidChannelId}});t.stop(Q.green(`Notification queued: ${l.requestId}`))}catch(n){t.stop(Q.red("Notification was not queued.")),gt(n)}}async function Hc(e){try{let t=Et(),n=Math.min(Math.max(Number(e.days||30),1),90),{data:i}=await Z.get(`/projects/${t.projectId}/push/overview?days=${n}`),r=i.totals,o=r.requested>0?`${(r.accepted/r.requested*100).toFixed(1)}%`:"\u2014";console.log([`${Q.bold("Active devices:")} ${i.activeDevices}`,`${Q.bold("Queued requests:")} ${r.queuedRequests}`,`${Q.bold("Requested:")} ${r.requested}`,`${Q.bold("Provider accepted:")} ${r.accepted}`,`${Q.bold("Failed:")} ${r.failed}`,`${Q.bold("Retried:")} ${r.retried}`,`${Q.bold("Invalid devices:")} ${r.invalidDevices}`,`${Q.bold("Acceptance:")} ${o}`].join(`
342
+ `),`${n} now includes ${e}.`)}async function hi(e){let t=Et(),n=e.app||t.push?.appId,i=e.environment||t.push?.environment||"production";if(n)return{config:t,appId:n,environment:i};let{data:r}=await Z.get(`/projects/${t.projectId}/push/overview?days=1`),s=(r?.apps||[]).filter(a=>a.status!=="disabled").sort((a,c)=>(c.updatedAt||0)-(a.updatedAt||0))[0]?.appId;if(!s)throw new Error(`Push is not configured. Run \`${A.nameLower} push setup\` first.`);return{config:t,appId:s,environment:i}}function ci(e){let t=me.resolve(e);if(!oe.existsSync(t))throw new Error(`File not found: ${t}`);return t}function gt(e){let t=e?.response?.data?.message||e?.message||"Unknown error";console.error(Y.red(t)),process.exitCode=1}async function Xc(e){let t=vt();try{let n=Et();if(_t(n)==="flutter")throw new Error("MACH Push currently supports Expo and bare React Native. Flutter push support is planned for a later release.");let r=mi(n,e.iosBundle),o=fi(n,e.androidPackage);if(!r&&!o)throw new Error(`Add ios.bundleIdentifier or android.package to ${A.configFileName}, or pass --ios-bundle/--android-package.`);t.start("Creating MACH Push app..."),await Z.post(`/projects/${n.projectId}/push/apps`,{name:e.name||n.name||"Mobile app",iosBundleId:r,androidPackageName:o});let s=e.environment||"production";n.push=pi({environment:s,googleServicesFile:e.googleServicesFile}),di(n);let a=n.framework==="expo"?gi():void 0;t.stop(Y.green("MACH Push app created.")),console.log(["",`${Y.bold("Client config:")} ${A.configFileName} \u2192 push`,"","Install the mobile SDK:"," npm install @radhya/mach-push-react-native",...n.framework==="expo"?[" npm install --save-dev @radhya/mach",` ${a}`," Run npx expo prebuild."]:[],"",`Next: run \`${A.nameLower} credentials\` and choose Push Notifications.`].join(`
343
+ `))}catch(n){t.stop(Y.red("MACH Push setup failed.")),gt(n)}}async function jc(e){let t=vt();try{let n=Et(),i=_t(n);if(i==="flutter")throw new Error("MACH Push currently supports Expo and bare React Native. Flutter push support is planned for a later release.");let r=mi(n,e.iosBundle),o=fi(n,e.androidPackage);if(!r&&!o)throw new Error(`Add ios.bundleIdentifier or android.package to ${A.configFileName}, or pass --ios-bundle/--android-package.`);let s;t.start("Checking the MACH Push app...");let l=((await Z.get(`/projects/${n.projectId}/push/overview?days=1`)).data?.apps||[]).filter(v=>v.status!=="disabled").sort((v,x)=>(x.updatedAt||0)-(v.updatedAt||0)).find(v=>(!r||v.iosBundleId===r)&&(!o||v.androidPackageName===o));if(l)s=l.appId,t.stop(Y.green("Existing MACH Push app linked."));else{let{data:v}=await Z.post(`/projects/${n.projectId}/push/apps`,{name:e.name||n.name||"Mobile app",iosBundleId:r,androidPackageName:o});s=v.app.appId,t.stop(Y.green("MACH Push app created."))}if(!s)throw new Error("MACH Push did not return a usable application.");let p=n.push,d=e.environment||p?.environment||"production",f=p?.apiUrl||li,y=Zo(e.googleServicesFile,p?.googleServicesFile);n.push=pi({apiUrl:f,environment:d,googleServicesFile:y}),di(n);let g=Wo(i,!!e.skipInstall),h=i==="expo"?gi():void 0;if(h?.startsWith('Add "'))throw new Error(h);let w={projectId:n.projectId,apiUrl:f,environment:d},_=Nn(process.cwd(),i,w);if(!_.entryFile)throw new Error(_.notes[0]||"MACH could not locate the application entry point.");let C=i==="expo"?{written:[],notes:[]}:Rn(process.cwd(),{iosBundleId:r,iosEnvironment:Mo(d),googleServicesFile:y});console.log(["",Y.green.bold("MACH Push basic setup is ready."),`${Y.bold("Framework:")} ${i}`,`${Y.bold("Client config:")} ${A.configFileName} \u2192 push`,`${Y.bold("Automatic startup:")} ${_.entryFile||"manual entry import required"}`,`${Y.bold("Customize callbacks:")} ${_.editableFile||"see the setup notes below"}`,"",...g.map(v=>`\u2022 ${v}`),...h?[`\u2022 ${h}`]:[],..._.notes.map(v=>`\u2022 ${v}`),...C.notes.map(v=>`\u2022 ${v}`),...[..._.written,...C.written].map(v=>`\u2022 Updated ${v}.`),"",`Next: run \`${A.nameLower} credentials\` and choose Push Notifications, then create one new native build.`].join(`
344
+ `))}catch(n){t.stop(Y.red("MACH Push setup failed.")),gt(n)}}async function Pt(e,t){let n=vt();try{let{config:i,appId:r,environment:o}=await hi(t),s;if(e==="apns"){if(!t.teamId||!t.keyId)throw new Error("APNs requires --team-id and --key-id.");let a=t.privateKey||(t.file?oe.readFileSync(ci(t.file),"utf8"):"");if(!a)throw new Error("APNs requires --file or a generated private key.");let c=t.bundleId||We(i);if(!c)throw new Error("APNs requires --bundle-id.");s={environment:o,teamId:t.teamId,keyId:t.keyId,bundleId:c,privateKey:a}}else{let a=t.serviceAccount||(t.file?JSON.parse(oe.readFileSync(ci(t.file),"utf8")):void 0);if(!a)throw new Error("FCM requires --file or a generated service account.");s={serviceAccount:a}}n.start(`Configuring ${e.toUpperCase()}...`),await Z.put(`/projects/${i.projectId}/push/apps/${r}/credentials/${e}`,s),n.stop(Y.green(`${e.toUpperCase()} is ready.`))}catch(i){n.stop(Y.red(`${e.toUpperCase()} setup failed.`)),gt(i)}}async function Lc(e){let t=vt(),n=!1;try{let{config:i,appId:r,environment:o}=await hi(e),s=e.all?{all:!0,platform:e.platform}:e.token?.length?{machPushTokens:e.token}:e.user?.length?{externalUserIds:e.user}:null;if(!s)throw new Error('Choose --token, --user, or --all. Example: mach push send --all --title "Hello" --body "World"');let a;if(e.data){let d=JSON.parse(e.data);if(!d||typeof d!="object"||Array.isArray(d))throw new Error("--data must be a JSON object.");a=Object.fromEntries(Object.entries(d).map(([f,y])=>[f,String(y)]))}let c=e.badge===void 0?void 0:Number(e.badge),l=e.ttl===void 0?void 0:Number(e.ttl);t.start("Queueing notification..."),n=!0;let{data:p}=await Z.post(`/projects/${i.projectId}/push/send`,{appId:r,environment:o,target:s,notification:{title:e.title,body:e.body,data:a},options:{sound:e.sound,badge:c,ttlSeconds:l,collapseKey:e.collapseKey,androidChannelId:e.androidChannelId}});t.stop(Y.green(`Notification queued: ${p.requestId}`))}catch(i){n?t.stop(Y.red("Notification was not queued.")):console.error(Y.red("Notification was not queued.")),gt(i)}}async function Hc(e){try{let t=Et(),n=Math.min(Math.max(Number(e.days||30),1),90),{data:i}=await Z.get(`/projects/${t.projectId}/push/overview?days=${n}`),r=i.totals,o=r.requested>0?`${(r.accepted/r.requested*100).toFixed(1)}%`:"\u2014";console.log([`${Y.bold("Active devices:")} ${i.activeDevices}`,`${Y.bold("Queued requests:")} ${r.queuedRequests}`,`${Y.bold("Requested:")} ${r.requested}`,`${Y.bold("Provider accepted:")} ${r.accepted}`,`${Y.bold("Failed:")} ${r.failed}`,`${Y.bold("Retried:")} ${r.retried}`,`${Y.bold("Invalid devices:")} ${r.invalidDevices}`,`${Y.bold("Acceptance:")} ${o}`].join(`
345
345
  `))}catch(t){gt(t)}}import ki from"axios";import m from"chalk";import{execSync as Ie,spawnSync as Ne}from"child_process";import{createRequire as Lo}from"module";import Nt from"crypto";import O from"fs";import G from"path";import yt from"os";import Ho from"adm-zip";var Ko=Lo(import.meta.url);ki.defaults.proxy=!1;function an(e,t){if(!O.existsSync(e))return;let n=O.readdirSync(e);for(let i of n){let r=G.join(e,i);if(O.statSync(r).isDirectory()){let s=an(r,t);if(s)return s}else if(t.test(i))return r}}var Be=e=>String(e||"").trim().toLowerCase().replace(/_/g,"-"),yi=e=>String(e||"unknown").trim().replace(/[^a-zA-Z0-9._-]/g,"_")||"unknown",Jo=(e,t)=>`ios-certificates/${yi(e)}/${yi(t)}/`;function Yo(e){return"'"+e.replace(/'/g,"'\\''")+"'"}function Ii(...e){let t=e.join(`
346
346
  `).split(/\r?\n/).map(n=>n.trim()).filter(Boolean);return t.length>0?t.slice(-8).join(`
347
347
  `):void 0}function zo(e,t,n){let i=Ne(e,t,{env:n,encoding:"utf-8"});if(!(i.error||i.status!==0))return(i.stdout||i.stderr||"").trim()||void 0}function Qo(e,t,n,i,r=!1){let o=[`${e} match ${t}`];return n&&o.push(`--app_identifier "${n}"`),i&&o.push(`--profile_name "${i}"`),r&&(t==="adhoc"||t==="development")&&o.push("--force_for_new_devices"),o.join(" ")}function qo(e){let t=e?.match(/ruby\s+(\d+)\.(\d+)/);return t?{major:Number(t[1]),minor:Number(t[2])}:null}function es(e,t,n){let i=qo(e);return i?i.major!==t?i.major<t:i.minor<n:!1}function rn(e){let t=process.env.HOME||yt.homedir(),n=process.env.FASTLANE_GEM_HOME||G.join(t,".local/share/fastlane/3.4.0"),i=[process.env.FASTLANE_BINARY,"/usr/local/bin/fastlane","/opt/homebrew/bin/fastlane","/usr/local/Cellar/fastlane/2.227.0/libexec/bin/fastlane","/opt/homebrew/Cellar/fastlane/2.227.0/libexec/bin/fastlane",G.join(n,"bin/fastlane"),"fastlane"].filter(Boolean);for(let r of i){if(r.includes("/")&&!O.existsSync(r))continue;let o=Ne(r,["--version"],{env:e,stdio:"ignore"});if(!o.error&&o.status===0)return{command:r,shellCommand:Yo(r),env:e}}return null}function ts(e){if(process.env.MACH_SKIP_FASTLANE_INSTALL==="1")return{ok:!1,detail:"Automatic install skipped because MACH_SKIP_FASTLANE_INSTALL=1."};let t=Ne("gem",["--version"],{env:e,encoding:"utf-8"});if(t.error||t.status!==0)return{ok:!1,detail:Ii(t.stdout,t.stderr)||"RubyGems is not available."};let n=zo("ruby",["-v"],e);if(es(n,3,2))return{ok:!1,detail:[n?`Detected Ruby: ${n}`:void 0,"The latest fastlane dependency tree now requires Ruby >= 3.2.","Mach skipped automatic gem install because macOS system Ruby is too old for it."].filter(Boolean).join(`
@@ -354,14 +354,14 @@ ${n.detail}`:void 0,"Recommended fix: brew install fastlane","Alternative: insta
354
354
  `)?n:`${n}
355
355
  `,"utf8")),o.writeZip(i),i},$i=e=>{let t=e.toLowerCase();return t==="production"||t==="prod"||t.includes("store")||t.endsWith("-production")||t.endsWith("-prod")},ps=e=>{let t=e.toLowerCase();return t==="staging"||t==="stage"||t.includes("preview")||t.includes("adhoc")||t.includes("ad-hoc")||t.endsWith("-staging")||t.endsWith("-stage")},us=(e,t)=>{let n=Ke(e,t)||{},i=Be(n.distribution),r=Be(n.iosExportMethod||n.ios?.exportMethod),o=Be(n.environment);return r==="app-store"||i==="store"?"store":r==="development"||i==="development"?"development":r==="ad-hoc"||r==="adhoc"||i==="ad-hoc"||i==="adhoc"||i==="internal"?"adhoc":o==="production"||o==="store"?"store":o==="development"||o==="dev"?"development":o==="staging"||o==="stage"||o==="preview"?"adhoc":$i(t)?"store":ps(t)?"adhoc":"development"},ms=(e,t)=>{let n=Ke(e,t)||{},i=Be(n.distribution),r=Be(n.environment);return i==="store"||r==="production"||r==="store"||$i(t)?"store":"internal"},fs=["development","preview","production"],gs="U27F4V844T",on=null;function kt(){return on||(on=Ko("@expo/apple-utils")),on}function vi(e){let t=n=>n.replace(/^.*The password is only used to authenticate with Apple and never stored on Expo servers.*(?:\r?\n)?/gm,"").replace(/^.*Learn more\..*(?:\r?\n)?/gm,"");if(typeof e=="string")return t(e);if(Buffer.isBuffer(e)){let n=e.toString("utf-8"),i=t(n);return i===n?e:Buffer.from(i,"utf-8")}return e}async function hs(e){let t=process.stdout.write.bind(process.stdout),n=process.stderr.write.bind(process.stderr);process.stdout.write=(i,...r)=>t(vi(i),...r),process.stderr.write=(i,...r)=>n(vi(i),...r);try{return await e()}finally{process.stdout.write=t,process.stderr.write=n}}function Fi(e){return O.existsSync(G.resolve(e))?void 0:"File not found"}function ys(){try{let e=`./${A.configFileName}`;return O.existsSync(e)?JSON.parse(O.readFileSync(e,"utf-8")):{}}catch{return{}}}function Is(e,t){let n=String(e.name||t||"Mobile app").trim().replace(/\s+/g," ")||"Mobile app",i=new Date,r=[i.getFullYear(),String(i.getMonth()+1).padStart(2,"0"),String(i.getDate()).padStart(2,"0")].join(""),o=Nt.randomBytes(2).toString("hex").toUpperCase(),s=` ${r}-${o}`;return`${`MACH Push ${n}`.slice(0,Math.max(1,50-s.length))}${s}`}async function As(e){let t=e.submit?.production?.ios?.appleId||e.submit?.preview?.ios?.appleId||e.submit?.development?.ios?.appleId,n=await he({message:"Apple ID (for Apple Developer Portal):",initialValue:t,validate:i=>i.includes("@")?void 0:"Enter a valid Apple ID email"});return M(n)&&(H("Operation cancelled"),process.exit(0)),n}async function bs(e){let t=await ht({message:`Apple password for ${e} (used only for Apple login, not stored):`,validate:n=>n.trim()?void 0:"Password is required"});return M(t)&&(H("Operation cancelled"),process.exit(0)),t}function Cs(e){return(Array.isArray(e?.services)?e.services:[]).some(n=>n?.id===gs||/apple push notification|apns/i.test(String(n?.name||"")))}async function Ss(e){let{Keys:t}=kt(),n=Ue();try{n.start("Fetching existing APNs keys from Apple...");let i=await t.getKeysAsync(e),o=(await Promise.all(i.map(async s=>{try{return await t.getKeyInfoAsync(e,{id:s.id})}catch{return s}}))).filter(Cs);return n.stop(m.green(`Found ${o.length} APNs key${o.length===1?"":"s"}.`)),o}catch(i){throw n.stop(m.red("Could not fetch APNs keys from Apple.")),i}}async function ws(e){let{Keys:t}=kt(),i=(await Ss(e)).filter(c=>c.canRevoke!==!1);if(i.length===0)return u.warn(m.yellow("No revokable APNs keys were found for this Apple team.")),!1;let r=await ve({message:"Select an APNs key to revoke:",options:i.map(c=>({value:c.id,label:`${c.name||"Untitled APNs key"} (${c.id})`,hint:c.canDownload?"APNs key, private key may still be downloadable":"APNs key"}))});M(r)&&(H("Operation cancelled"),process.exit(0));let o=i.find(c=>c.id===r);u.warn(m.yellow("Revoking this key can break push notifications for any service currently using it."));let s=await ln({message:`Revoke "${o?.name||"Untitled APNs key"}" (${r})? This cannot be undone.`,initialValue:!1});if(M(s)&&(H("Operation cancelled"),process.exit(0)),!s)return u.info(m.dim("APNs key was not revoked.")),!1;let a=Ue();try{return a.start(`Revoking APNs key ${r}...`),await t.revokeKeyAsync(e,{id:r}),a.stop(m.green(`Revoked APNs key ${r}.`)),!0}catch(c){throw a.stop(m.red(`Could not revoke APNs key ${r}.`)),c}}async function vs(e,t){let{Keys:n}=kt(),i=0;for(;;){let r=t(),o=Ue();try{o.start(`Creating APNs auth key (${r})...`);let s=await n.createKeyAsync(e,{name:r,isApns:!0});o.message("Downloading APNs private key...");let a=await n.downloadKeyAsync(e,{id:s.id});if(!a)throw new Error("Apple did not return the APNs private key.");return o.stop(m.green(`APNs key generated: ${s.id}`)),{keyId:s.id,keyName:r,privateKey:a}}catch(s){if(o.stop(m.red("APNs key generation failed.")),Ps(s)&&i<3){i+=1,u.warn(m.yellow("Apple says that APNs key name already exists. Retrying with a new generated name..."));continue}if(!_i(s))throw s;Ti(s);let a=await ve({message:"Apple APNs key limit reached. What do you want to do?",options:[{value:"revoke",label:"List and revoke an existing APNs key",hint:"Then Mach will create a new key"},{value:"retry",label:"Try creating again"},{value:"exit",label:"Exit"}]});if((M(a)||a==="exit")&&(H("Operation cancelled"),process.exit(0)),a==="revoke"&&await ws(e))continue}}}async function Es(e,t){let n=await As(e);try{let i=await bs(n),{Auth:r}=kt();u.info(m.dim("Signing in to Apple Developer Portal..."));let o=await hs(()=>r.loginAsync({username:n,password:i},{autoResolveProvider:!0})),s=String(o?.context?.teamId||"").trim().toUpperCase(),a=await vs(o.context,()=>Is(e,t));return{keyId:a.keyId,teamId:s,privateKey:a.privateKey}}catch(i){throw u.error(m.red("APNs key generation failed.")),i}}function _i(e){let t=[e?.message,e?.response?.data,e?.cause?.message].filter(Boolean).join(`
356
356
  `);return/maximum allowed number.*keys/i.test(t)||/already reached the maximum/i.test(t)}function Ps(e){let t=[e?.message,e?.response?.data,e?.cause?.message].filter(Boolean).join(`
357
- `);return/another key with same name exists/i.test(t)||/same name already exists/i.test(t)}function Ti(e){if(u.warn(m.yellow(e?.message||"Could not generate APNs key automatically.")),_i(e)){u.info(m.dim("Apple rejected the request because this team is already at its APNs auth-key limit.")),u.info(m.dim("If you saved an existing .p8 file, upload it here. If not, delete an unused APNs key in Apple Developer, then generate again.")),u.info(m.dim("Apple only lets you download an APNs .p8 private key when the key is first created."));return}u.info(m.dim("You can upload an existing .p8 key, retry generation, or exit and try again later."))}async function sn(){let e=await ve({message:"Where should Mach save this APNs key?",options:[{value:"all",label:"All environments",hint:"Recommended \u2014 one APNs key works for sandbox and production"},{value:"development",label:"Development only"},{value:"preview",label:"Preview only"},{value:"production",label:"Production only"}]});return M(e)&&(H("Operation cancelled"),process.exit(0)),e==="all"?fs:[e]}async function Ns(e,t,n,i){let r=i.teamId||e.teamId;if(!r){let o=await he({message:"Apple Team ID:",validate:s=>/^[A-Z0-9]{10}$/i.test(s.trim())?void 0:"Team ID must be exactly 10 letters/numbers"});M(o)&&(H("Operation cancelled"),process.exit(0)),r=o.trim().toUpperCase()}for(let o of t)await Pt("apns",{...e,environment:o,privateKey:i.privateKey,teamId:r,keyId:i.keyId,bundleId:n})}async function Ei(e,t,n){let i=await he({message:"Path to APNs auth key (.p8):",validate:Fi});M(i)&&(H("Operation cancelled"),process.exit(0));let r=await he({message:"Apple Team ID:",initialValue:e.teamId,validate:s=>s.trim()?void 0:"Team ID is required"});M(r)&&(H("Operation cancelled"),process.exit(0));let o=await he({message:"APNs Key ID:",initialValue:e.keyId,validate:s=>s.trim()?void 0:"Key ID is required"});M(o)&&(H("Operation cancelled"),process.exit(0));for(let s of t)await Pt("apns",{...e,environment:s,file:i,teamId:r,keyId:o,bundleId:n})}async function ks(e){let t=ys(),n=e.bundleId||We(t)||t.push?.iosBundleId;for(;;){let i=await ve({message:"How do you want to configure APNs?",options:[{value:"generate",label:"Generate new APNs key with Apple",hint:"Mach creates, downloads once, and uploads it securely"},{value:"upload",label:"Upload existing .p8 key",hint:"Use a key you already downloaded from Apple"}]});if(M(i)&&(H("Operation cancelled"),process.exit(0)),i==="upload"){let r=await sn();await Ei(e,r,n);return}try{let r=await Es(t,n),o=await sn();await Ns(e,o,n,r);return}catch(r){Ti(r);let o=await ve({message:"APNs key was not created. What do you want to do?",options:[{value:"upload",label:"Upload existing .p8 key"},{value:"retry",label:"Try generating again"},{value:"exit",label:"Exit"}]});if((M(o)||o==="exit")&&(H("Operation cancelled"),process.exit(0)),o==="upload"){let s=await sn();await Ei(e,s,n);return}}}}async function Rs(e){let t=await he({message:"Path to Firebase service account JSON:",validate:Fi});M(t)&&(H("Operation cancelled"),process.exit(0));let n;try{n=JSON.parse(O.readFileSync(t,"utf8"))}catch(i){H(`Invalid Firebase service account JSON: ${i.message}`),process.exit(1)}await Pt("fcm",{...e,serviceAccount:n})}async function xs(e,t){if(t==="ios"){await ks(e);return}await Rs(e)}function $s(e,t,n){let i=O.readFileSync(n,"utf8"),r=Math.floor(Date.now()/1e3),o=Buffer.from(JSON.stringify({alg:"ES256",kid:e,typ:"JWT"})).toString("base64url"),s=Buffer.from(JSON.stringify({iss:t,iat:r,exp:r+1200,aud:"appstoreconnect-v1"})).toString("base64url"),a=`${o}.${s}`,c=Nt.createSign("SHA256");c.update(a);let l=c.sign({key:i,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${a}.${l}`}async function Fs(e,t,n,i){let r=$s(t,n,i),o=(await import("axios")).default;for(let s of e)try{await o.post("https://api.appstoreconnect.apple.com/v1/devices",{data:{type:"devices",attributes:{name:s.name,udid:s.udid,platform:"IOS"}}},{headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),u.info(m.dim(` \u2713 Registered: ${s.name}`))}catch(a){let c=a.response?.data?.errors;c?.some(p=>p.code==="ENTITY_ERROR.ATTRIBUTE.INVALID.DUPLICATE"||p.detail?.toLowerCase().includes("already registered")||p.detail?.toLowerCase().includes("already exists"))?u.info(m.dim(` Already on Portal: ${s.name}`)):u.warn(m.yellow(` Could not register ${s.name}: ${c?.[0]?.detail||a.message}`))}}var _s=async e=>{Uo(m.bgCyan.black(A.cliTag("Credentials")));let t=await ve({message:"Select platform:",options:[{value:"ios",label:"iOS"},{value:"android",label:"Android"}]});M(t)&&(H("Operation cancelled"),process.exit(0));let n=await ve({message:"What do you want to do?",options:[{value:"setup",label:"Build Credentials (Certs/Profiles)",hint:"Manage everything needed to build your project"},{value:"download",label:"Download credentials (credentials.json)",hint:"Sync credentials from Dashboard to local project"},{value:"service",label:"App Store Connect API Key (Magic)",hint:"Manage your API Key for automated submission"},{value:"push",label:"Push Notifications",hint:t==="ios"?"Upload APNs key":"Upload Firebase service account"},{value:"back",label:"Go back"},{value:"exit",label:"Exit"}].filter(i=>(t==="android"&&i.value==="service"&&(i.label="Google Service Account (JSON)"),!0))});if((M(n)||n==="exit")&&(H("Operation cancelled"),process.exit(0)),n==="back")return _s(e);n==="setup"?await Ts({...e,platform:t}):n==="download"?await Ms({...e,platform:t}):n==="service"?await En({...e,platform:t}):n==="push"&&await xs(e,t),Xo(m.green("Done!"))},Ts=async e=>{let t=Ue(),n=e.platform,i=e.profile;if(!i){let a=await ve({message:"Select credential type:",options:[{value:"development",label:"Development",hint:"Local testing & simulators"},{value:"staging",label:"Ad Hoc / Staging",hint:"Internal distribution & device testing"},{value:"production",label:"Production / App Store",hint:"App Store & Play Store submission"}]});M(a)&&(H("Operation cancelled"),process.exit(0)),i=a}let r=`./${A.configFileName}`;if(!O.existsSync(r)){u.error(`No ${A.configFileName} found. Run \`${A.nameLower} init\` or \`${A.nameLower} link\` first.`);return}let o=JSON.parse(O.readFileSync(r,"utf-8")),{projectId:s}=o;if(!s){u.error(`${A.configFileName} is missing projectId.`);return}if(e.awsProfile&&u.warn(m.yellow(`Ignoring --aws-profile. Authenticating with ${A.name} Cloud...`)),u.info(m.dim(`Setting up credentials for: ${i}`)),n==="ios")await Os(s,i,e,o);else{let a=ms(o,i);await Vs(s,i,a,e,o)}};async function Os(e,t,n,i){let r=n.bundleId;if(!r){let c=i.submit?.[t]?.ios?.bundleIdentifier||i.submit?.[t]?.ios?.bundleId||We(i,t),l=[];try{let d=(await Z.get(`/credentials/${e}`)).data.credentials||[];l=[...new Set(d.filter(f=>f.platform==="ios"&&f.bundleId&&f.bundleId!=="*").map(f=>f.bundleId))]}catch{}if(c&&!l.includes(c)&&l.unshift(c),l.length>0){let p=[...l.map(f=>({value:f,label:f,hint:f===c?"from config":void 0})),{value:"__new__",label:"+ Enter a new Bundle ID"}],d=await ve({message:"Which Bundle ID are you setting up credentials for?",options:p});if(M(d)&&(H("Operation cancelled"),process.exit(0)),d==="__new__"){let f=await he({message:"iOS Bundle ID (e.g. com.example.app):",placeholder:"com.example.app",validate:I=>I.includes(".")?void 0:"Please enter a valid Bundle ID"});M(f)&&(H("Operation cancelled"),process.exit(0)),r=f}else r=d}else{let p=await he({message:"iOS Bundle ID (e.g. com.example.app):",placeholder:"com.example.app",validate:d=>d.includes(".")?void 0:"Please enter a valid Bundle ID"});M(p)&&(H("Operation cancelled"),process.exit(0)),r=p}}u.info(m.dim(`Bundle ID: ${r}`));let o=us(i,t),s=i.submit?.production?.ios?.appleId;s&&u.info(m.dim(`Using Apple ID from config: ${s}`)),await Ds(e,r,t,o,o==="store"?"appstore":o==="adhoc"?"adhoc":"development",n,i,s)}async function Bs(e){let t="MATCH_ENCRYPTION_PASSPHRASE";try{let s=((await Z.get(`/projects/${e}/secrets/export?env=development`)).data.secrets||{})[t];if(s&&!s.includes("[Decryption Failed]"))return u.info(m.dim("Using existing encryption passphrase from Dashboard")),u.info(m.cyan(`MATCH_PASSWORD: ${s}`)),s;if(s&&s.includes("[Decryption Failed]")){u.warn(m.yellow("\u26A0\uFE0F Existing MATCH_PASSWORD could not be decrypted (encryption key changed).")),u.info(m.dim("Generating a fresh passphrase and cleaning old certificates..."));let a=Nt.randomBytes(32).toString("base64");try{await Z.post(`/projects/${e}/secrets`,{key:t,value:a,type:"managed",description:"Encryption passphrase for iOS certificates (fastlane match)",visibility:"secret"}),u.success(m.green("\u2713 New encryption passphrase generated and saved"))}catch{}try{await Z.post("/credentials/clean-match-storage",{projectId:e}),u.success(m.green("\u2713 Cleaned old certificates from storage"))}catch{}return a}}catch(r){u.info(m.dim(`Could not fetch existing passphrase from Dashboard: ${r.message}`))}let n=await ve({message:"No active encryption passphrase found on Dashboard. What would you like to do?",options:[{value:"generate",label:"Generate a new secure passphrase",hint:"Safe for first-time setup"},{value:"enter",label:"Enter existing passphrase manually",hint:"Required if you already have certs in S3"},{value:"cancel",label:"Cancel",hint:"Quit"}]});if((M(n)||n==="cancel")&&(H("Operation cancelled"),process.exit(0)),n==="enter"){let r=await ht({message:"Enter your MATCH_PASSWORD (encryption passphrase):",validate:s=>s.length>0?void 0:"Passphrase is required"});M(r)&&(H("Operation cancelled"),process.exit(0));let o=r;try{await Z.post(`/projects/${e}/secrets`,{key:t,value:o,type:"managed",description:"Encryption passphrase for iOS certificates (fastlane match)"}),u.success(m.green("\u2713 Saved passphrase to Dashboard"))}catch{}return o}let i=Nt.randomBytes(32).toString("base64");try{await Z.post(`/projects/${e}/secrets`,{key:t,value:i,type:"managed",description:"Encryption passphrase for iOS certificates (fastlane match)",visibility:"secret"}),u.success(m.green("\u2713 Generated and saved encryption passphrase to Dashboard")),u.info(m.cyan(`MATCH_PASSWORD: ${i}`))}catch(r){u.warn(m.yellow(`Could not save passphrase to Dashboard: ${r.message}`))}return i}async function Ds(e,t,n,i,r,o,s,a){let c=Ue(),l=!1,p=h=>{c.start(h),l=!0},d=h=>{l&&(c.stop(h),l=!1)};u.info(m.blue("Configuring iOS certificate management..."));let f,I=st(s,n),g=I;if(!a){let h=await he({message:"Apple ID (for Apple Developer Portal):",placeholder:"your-email@example.com",validate:w=>w.includes("@")?void 0:"Please enter a valid email"});M(h)&&(H("Operation cancelled"),process.exit(0)),a=h}try{let h=await Bs(e),w="",_="";try{let R=await Z.post("/credentials/build-server-token",{projectId:e});R.data.status==="success"&&R.data.credentials&&(process.env.AWS_ACCESS_KEY_ID=R.data.credentials.accessKeyId,process.env.AWS_SECRET_ACCESS_KEY=R.data.credentials.secretAccessKey,R.data.credentials.sessionToken&&(process.env.AWS_SESSION_TOKEN=R.data.credentials.sessionToken),_=R.data.credentials.region||"ap-south-1",w=R.data.credentials.bucket||A.bucketPrefix,process.env.AWS_REGION=_,delete process.env.AWS_PROFILE)}catch(R){throw u.error(`Failed to authenticate with ${A.name} Cloud.`),R}if(!w||!_){u.error(`Failed to resolve S3 configuration from ${A.name} Cloud.`);return}let C=o.teamId||I.teamId||s.submit?.production?.ios?.appleTeamId;if(!C)try{let V=(await Z.get(`/projects/${e}/secrets`)).data.secrets?.find(q=>q.key==="APPLE_TEAM_ID");V&&(C=V.value,u.info(m.dim(`Using Team ID from Dashboard: ${C}`)))}catch{}C&&C===s.submit?.production?.ios?.appleTeamId&&u.info(m.dim(`Using Apple Team ID from config: ${C}`));let v=await at({appleId:a,config:s,profile:n,initialTeam:{...I,teamId:C,developerTeamId:I.developerTeamId||C},promptToPersistConfig:!C,saveTeamId:C?void 0:R=>Pi(e,R)});if(!v?.teamId)return;C=v.teamId;let x={...I,...v,teamId:C,developerTeamId:v.developerTeamId||I.developerTeamId||C};g=x;let F=Jo(e,C);u.info(m.dim(`Using match storage prefix: ${F}`));let D=await os(),j={...D.env};process.env.CI||delete j.CI,p(`Preparing ${r} certificate sync...`),d("Starting certificate sync...");let N=`${A.buildPrefix}-${C}.keychain-db`,T=A.keychainPassword;try{let V=`${process.env.HOME||"/Users/"+(process.env.USER||A.nameLower)}/Library/Keychains/${N}`;u.info(m.dim(`Ensuring keychain exists: ${N}`));try{Ie(`security create-keychain -p ${T} ${N} 2>/dev/null || true`),Ie(`security unlock-keychain -p ${T} ${N}`),Ie(`security set-keychain-settings ${N}`);let W=Ie("security list-keychains -d user").toString();if(!W.includes(N)){u.info(m.dim(`Adding ${N} to search list`));let E=[...W.replace(/"/g,"").split(`
358
- `).map($=>$.trim()).filter($=>$.length>0),V].join(" ");Ie(`security list-keychains -d user -s ${E}`)}}catch(W){u.warn(m.dim("Keychain setup warning (non-critical): "+W.message))}let q,ye;try{let k=((await Z.get(`/credentials/${e}`)).data.credentials||[]).find(E=>E.type==="asc_api_key"&&E.issuerId);if(k){let E=await Z.get(`/credentials/${k.credentialId}/download`,{params:{projectId:e,format:"raw"}});if(E.data.downloadUrl){let B=await(await import("axios")).default.get(E.data.downloadUrl,{responseType:"arraybuffer"}),Y=G.join(yt.tmpdir(),`mach-asc-${Date.now()}`);O.mkdirSync(Y,{recursive:!0}),f=G.join(Y,`AuthKey_${k.keyId}.p8`),O.writeFileSync(f,Buffer.from(B.data)),q=k.keyId,ye=k.issuerId,u.success(m.green("\u2713 ASC API key loaded \u2014 no 2FA required for Portal operations"))}}}catch(W){u.warn(m.dim(`Could not load ASC API key: ${W.message}. Will fall back to Apple ID auth.`))}u.info(m.dim("Generating secure P12 export password..."));let Ae=Oi();u.success(m.green("\u2713 Secure P12 password generated."));let re={...j,AWS_REGION:process.env.AWS_REGION||"ap-south-1",AWS_ACCESS_KEY_ID:process.env.AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY:process.env.AWS_SECRET_ACCESS_KEY,SSL_CERT_FILE:"/etc/ssl/cert.pem",AWS_CA_BUNDLE:"/etc/ssl/cert.pem",FASTLANE_SSL_CA_CERT:"/etc/ssl/cert.pem",MATCH_PASSWORD:h,FASTLANE_USER:a,FASTLANE_SKIP_UPDATE_CHECK:"1",FASTLANE_TEAM_ID:C,MATCH_KEYCHAIN_NAME:V,MATCH_KEYCHAIN_PASSWORD:T,TERM:process.env.TERM||"xterm-256color",SHELL:process.env.SHELL||"/bin/zsh",MATCH_OUTPUT_PATH:G.join(process.cwd(),"temp_match"),MATCH_STORAGE_MODE:"s3",MATCH_S3_REGION:_,MATCH_S3_BUCKET:w,MATCH_S3_OBJECT_PREFIX:F,MATCH_USERNAME:a,MATCH_APP_IDENTIFIER:t,MATCH_TYPE:r,[`${A.envPrefix}P12_PASSWORD`]:Ae,...f&&q&&ye?{APP_STORE_CONNECT_API_KEY_KEY_ID:q,APP_STORE_CONNECT_API_KEY_ISSUER_ID:ye,APP_STORE_CONNECT_API_KEY_KEY_FILEPATH:f,FASTLANE_SKIP_2FA:"1"}:{}};if(o.force){u.warn(m.yellow(`
359
- \u26A0\uFE0F Force flag detected: Hard resetting ${r} certificates...`)),u.info(m.dim("Detected decryption failure loop. Clearing remote storage directly to allow fresh generation.")),u.info(m.cyan(`Current MATCH_PASSWORD: ${h}`)),u.info(m.dim(`Cleaning match storage for Team ID: ${C}...`));try{(await Z.post("/credentials/clean-match-storage",{projectId:e,teamId:C,storagePrefix:F})).data.status==="success"&&u.success(m.green(`\u2713 Cleared S3 storage for Team ID: ${C}`))}catch(W){u.warn(m.yellow(`S3 cleanup via API failed: ${W.message}`)),u.info(m.dim("Continuing to attempt standard nuke..."))}try{Ie(`${D.shellCommand} match nuke ${r} --skip_confirmation`,{stdio:"inherit",cwd:process.cwd(),env:re}),u.success(m.green(`\u2713 Nuked existing ${r} credentials`))}catch{u.warn(m.yellow("Standard nuke failed (likely due to password mismatch).")),u.info(m.dim("Since S3 was cleared manually, proceeding to generation..."))}}let te=r==="adhoc"||r==="development";if(r==="adhoc"||r==="development")try{u.info(m.blue("Fetching registered devices..."));let k=(await Z.get("/devices",C?{params:{teamId:C}}:void 0)).data.devices||[];if(C)try{let E=await Z.get("/devices",{params:{teamId:"LEGACY"}}),$=new Map;for(let B of[...k,...E.data.devices||[]])$.set(B.udid,B);k=Array.from($.values())}catch{}if(k.length===0)u.warn(m.yellow("No registered devices found. Profile will only include devices already on the Apple Developer Portal.")),u.info(m.dim(`Register devices with: ${A.nameLower} device register`));else{let{multiselect:E}=await import("@clack/prompts"),$=await E({message:`Select devices to include in the ${r} profile:`,options:k.map(B=>({value:B.udid,label:`${B.name} (${B.udid.substring(0,12)}...)`,hint:B.model||B.platform})),initialValues:k.map(B=>B.udid)});if(!M($)&&$.length>0){let B=k.filter(Y=>$.includes(Y.udid));if(u.info(m.blue(`Registering ${B.length} device(s) on Apple Developer Portal...`)),C&&await Promise.all(B.filter(Y=>!Y.teamId).map(Y=>Z.post("/devices",{udid:Y.udid,name:Y.name,platform:"ios",addedVia:Y.addedVia||"cli",teamId:C,teamName:x.teamName}).catch(()=>{}))),f&&q&&ye)await Fs(B,q,ye,f);else{u.info(m.dim("You will be prompted for a 2FA code once \u2014 type it and press Enter."));for(let Y of B){let J=Y.name.replace(/"/g,'\\"');Ne(`${D.shellCommand} run register_device name:"${J}" udid:"${Y.udid}"`,{shell:!0,env:re,stdio:"inherit",cwd:process.cwd()})}}u.info(m.green("\u2713 Device registration complete.")),te=!0}}}catch(W){u.warn(m.yellow(`Could not fetch registered devices: ${W.message}`)),u.info(m.dim("Continuing without explicit device registration."))}try{let W=`${A.nameLower} ${r} ${t}`,k=Qo(D.shellCommand,r,t,W,te);te&&u.info(m.dim(`Refreshing ${r} provisioning profile when device list changes (--force_for_new_devices).`));let E=Ne(k,{shell:!0,cwd:process.cwd(),env:re,stdio:"inherit",encoding:"utf-8"});if(E.status!==0){u.warn(m.yellow(`
357
+ `);return/another key with same name exists/i.test(t)||/same name already exists/i.test(t)}function Ti(e){if(u.warn(m.yellow(e?.message||"Could not generate APNs key automatically.")),_i(e)){u.info(m.dim("Apple rejected the request because this team is already at its APNs auth-key limit.")),u.info(m.dim("If you saved an existing .p8 file, upload it here. If not, delete an unused APNs key in Apple Developer, then generate again.")),u.info(m.dim("Apple only lets you download an APNs .p8 private key when the key is first created."));return}u.info(m.dim("You can upload an existing .p8 key, retry generation, or exit and try again later."))}async function sn(){let e=await ve({message:"Where should Mach save this APNs key?",options:[{value:"all",label:"All environments",hint:"Recommended \u2014 one APNs key works for sandbox and production"},{value:"development",label:"Development only"},{value:"preview",label:"Preview only"},{value:"production",label:"Production only"}]});return M(e)&&(H("Operation cancelled"),process.exit(0)),e==="all"?fs:[e]}async function Ns(e,t,n,i){let r=i.teamId||e.teamId;if(!r){let o=await he({message:"Apple Team ID:",validate:s=>/^[A-Z0-9]{10}$/i.test(s.trim())?void 0:"Team ID must be exactly 10 letters/numbers"});M(o)&&(H("Operation cancelled"),process.exit(0)),r=o.trim().toUpperCase()}for(let o of t)await Pt("apns",{...e,environment:o,privateKey:i.privateKey,teamId:r,keyId:i.keyId,bundleId:n})}async function Ei(e,t,n){let i=await he({message:"Path to APNs auth key (.p8):",validate:Fi});M(i)&&(H("Operation cancelled"),process.exit(0));let r=await he({message:"Apple Team ID:",initialValue:e.teamId,validate:s=>s.trim()?void 0:"Team ID is required"});M(r)&&(H("Operation cancelled"),process.exit(0));let o=await he({message:"APNs Key ID:",initialValue:e.keyId,validate:s=>s.trim()?void 0:"Key ID is required"});M(o)&&(H("Operation cancelled"),process.exit(0));for(let s of t)await Pt("apns",{...e,environment:s,file:i,teamId:r,keyId:o,bundleId:n})}async function ks(e){let t=ys(),n=e.bundleId||We(t)||t.push?.iosBundleId;for(;;){let i=await ve({message:"How do you want to configure APNs?",options:[{value:"generate",label:"Generate new APNs key with Apple",hint:"Mach creates, downloads once, and uploads it securely"},{value:"upload",label:"Upload existing .p8 key",hint:"Use a key you already downloaded from Apple"}]});if(M(i)&&(H("Operation cancelled"),process.exit(0)),i==="upload"){let r=await sn();await Ei(e,r,n);return}try{let r=await Es(t,n),o=await sn();await Ns(e,o,n,r);return}catch(r){Ti(r);let o=await ve({message:"APNs key was not created. What do you want to do?",options:[{value:"upload",label:"Upload existing .p8 key"},{value:"retry",label:"Try generating again"},{value:"exit",label:"Exit"}]});if((M(o)||o==="exit")&&(H("Operation cancelled"),process.exit(0)),o==="upload"){let s=await sn();await Ei(e,s,n);return}}}}async function Rs(e){let t=await he({message:"Path to Firebase service account JSON:",validate:Fi});M(t)&&(H("Operation cancelled"),process.exit(0));let n;try{n=JSON.parse(O.readFileSync(t,"utf8"))}catch(i){H(`Invalid Firebase service account JSON: ${i.message}`),process.exit(1)}await Pt("fcm",{...e,serviceAccount:n})}async function xs(e,t){if(t==="ios"){await ks(e);return}await Rs(e)}function $s(e,t,n){let i=O.readFileSync(n,"utf8"),r=Math.floor(Date.now()/1e3),o=Buffer.from(JSON.stringify({alg:"ES256",kid:e,typ:"JWT"})).toString("base64url"),s=Buffer.from(JSON.stringify({iss:t,iat:r,exp:r+1200,aud:"appstoreconnect-v1"})).toString("base64url"),a=`${o}.${s}`,c=Nt.createSign("SHA256");c.update(a);let l=c.sign({key:i,dsaEncoding:"ieee-p1363"}).toString("base64url");return`${a}.${l}`}async function Fs(e,t,n,i){let r=$s(t,n,i),o=(await import("axios")).default;for(let s of e)try{await o.post("https://api.appstoreconnect.apple.com/v1/devices",{data:{type:"devices",attributes:{name:s.name,udid:s.udid,platform:"IOS"}}},{headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),u.info(m.dim(` \u2713 Registered: ${s.name}`))}catch(a){let c=a.response?.data?.errors;c?.some(p=>p.code==="ENTITY_ERROR.ATTRIBUTE.INVALID.DUPLICATE"||p.detail?.toLowerCase().includes("already registered")||p.detail?.toLowerCase().includes("already exists"))?u.info(m.dim(` Already on Portal: ${s.name}`)):u.warn(m.yellow(` Could not register ${s.name}: ${c?.[0]?.detail||a.message}`))}}var _s=async e=>{Uo(m.bgCyan.black(A.cliTag("Credentials")));let t=await ve({message:"Select platform:",options:[{value:"ios",label:"iOS"},{value:"android",label:"Android"}]});M(t)&&(H("Operation cancelled"),process.exit(0));let n=await ve({message:"What do you want to do?",options:[{value:"setup",label:"Build Credentials (Certs/Profiles)",hint:"Manage everything needed to build your project"},{value:"download",label:"Download credentials (credentials.json)",hint:"Sync credentials from Dashboard to local project"},{value:"service",label:"App Store Connect API Key (Magic)",hint:"Manage your API Key for automated submission"},{value:"push",label:"Push Notifications",hint:t==="ios"?"Upload APNs key":"Upload Firebase service account"},{value:"back",label:"Go back"},{value:"exit",label:"Exit"}].filter(i=>(t==="android"&&i.value==="service"&&(i.label="Google Service Account (JSON)"),!0))});if((M(n)||n==="exit")&&(H("Operation cancelled"),process.exit(0)),n==="back")return _s(e);n==="setup"?await Ts({...e,platform:t}):n==="download"?await Ms({...e,platform:t}):n==="service"?await En({...e,platform:t}):n==="push"&&await xs(e,t),Xo(m.green("Done!"))},Ts=async e=>{let t=Ue(),n=e.platform,i=e.profile;if(!i){let a=await ve({message:"Select credential type:",options:[{value:"development",label:"Development",hint:"Local testing & simulators"},{value:"staging",label:"Ad Hoc / Staging",hint:"Internal distribution & device testing"},{value:"production",label:"Production / App Store",hint:"App Store & Play Store submission"}]});M(a)&&(H("Operation cancelled"),process.exit(0)),i=a}let r=`./${A.configFileName}`;if(!O.existsSync(r)){u.error(`No ${A.configFileName} found. Run \`${A.nameLower} init\` or \`${A.nameLower} link\` first.`);return}let o=JSON.parse(O.readFileSync(r,"utf-8")),{projectId:s}=o;if(!s){u.error(`${A.configFileName} is missing projectId.`);return}if(e.awsProfile&&u.warn(m.yellow(`Ignoring --aws-profile. Authenticating with ${A.name} Cloud...`)),u.info(m.dim(`Setting up credentials for: ${i}`)),n==="ios")await Os(s,i,e,o);else{let a=ms(o,i);await Vs(s,i,a,e,o)}};async function Os(e,t,n,i){let r=n.bundleId;if(!r){let c=i.submit?.[t]?.ios?.bundleIdentifier||i.submit?.[t]?.ios?.bundleId||We(i,t),l=[];try{let d=(await Z.get(`/credentials/${e}`)).data.credentials||[];l=[...new Set(d.filter(f=>f.platform==="ios"&&f.bundleId&&f.bundleId!=="*").map(f=>f.bundleId))]}catch{}if(c&&!l.includes(c)&&l.unshift(c),l.length>0){let p=[...l.map(f=>({value:f,label:f,hint:f===c?"from config":void 0})),{value:"__new__",label:"+ Enter a new Bundle ID"}],d=await ve({message:"Which Bundle ID are you setting up credentials for?",options:p});if(M(d)&&(H("Operation cancelled"),process.exit(0)),d==="__new__"){let f=await he({message:"iOS Bundle ID (e.g. com.example.app):",placeholder:"com.example.app",validate:y=>y.includes(".")?void 0:"Please enter a valid Bundle ID"});M(f)&&(H("Operation cancelled"),process.exit(0)),r=f}else r=d}else{let p=await he({message:"iOS Bundle ID (e.g. com.example.app):",placeholder:"com.example.app",validate:d=>d.includes(".")?void 0:"Please enter a valid Bundle ID"});M(p)&&(H("Operation cancelled"),process.exit(0)),r=p}}u.info(m.dim(`Bundle ID: ${r}`));let o=us(i,t),s=i.submit?.production?.ios?.appleId;s&&u.info(m.dim(`Using Apple ID from config: ${s}`)),await Ds(e,r,t,o,o==="store"?"appstore":o==="adhoc"?"adhoc":"development",n,i,s)}async function Bs(e){let t="MATCH_ENCRYPTION_PASSPHRASE";try{let s=((await Z.get(`/projects/${e}/secrets/export?env=development`)).data.secrets||{})[t];if(s&&!s.includes("[Decryption Failed]"))return u.info(m.dim("Using existing encryption passphrase from Dashboard")),u.info(m.cyan(`MATCH_PASSWORD: ${s}`)),s;if(s&&s.includes("[Decryption Failed]")){u.warn(m.yellow("\u26A0\uFE0F Existing MATCH_PASSWORD could not be decrypted (encryption key changed).")),u.info(m.dim("Generating a fresh passphrase and cleaning old certificates..."));let a=Nt.randomBytes(32).toString("base64");try{await Z.post(`/projects/${e}/secrets`,{key:t,value:a,type:"managed",description:"Encryption passphrase for iOS certificates (fastlane match)",visibility:"secret"}),u.success(m.green("\u2713 New encryption passphrase generated and saved"))}catch{}try{await Z.post("/credentials/clean-match-storage",{projectId:e}),u.success(m.green("\u2713 Cleaned old certificates from storage"))}catch{}return a}}catch(r){u.info(m.dim(`Could not fetch existing passphrase from Dashboard: ${r.message}`))}let n=await ve({message:"No active encryption passphrase found on Dashboard. What would you like to do?",options:[{value:"generate",label:"Generate a new secure passphrase",hint:"Safe for first-time setup"},{value:"enter",label:"Enter existing passphrase manually",hint:"Required if you already have certs in S3"},{value:"cancel",label:"Cancel",hint:"Quit"}]});if((M(n)||n==="cancel")&&(H("Operation cancelled"),process.exit(0)),n==="enter"){let r=await ht({message:"Enter your MATCH_PASSWORD (encryption passphrase):",validate:s=>s.length>0?void 0:"Passphrase is required"});M(r)&&(H("Operation cancelled"),process.exit(0));let o=r;try{await Z.post(`/projects/${e}/secrets`,{key:t,value:o,type:"managed",description:"Encryption passphrase for iOS certificates (fastlane match)"}),u.success(m.green("\u2713 Saved passphrase to Dashboard"))}catch{}return o}let i=Nt.randomBytes(32).toString("base64");try{await Z.post(`/projects/${e}/secrets`,{key:t,value:i,type:"managed",description:"Encryption passphrase for iOS certificates (fastlane match)",visibility:"secret"}),u.success(m.green("\u2713 Generated and saved encryption passphrase to Dashboard")),u.info(m.cyan(`MATCH_PASSWORD: ${i}`))}catch(r){u.warn(m.yellow(`Could not save passphrase to Dashboard: ${r.message}`))}return i}async function Ds(e,t,n,i,r,o,s,a){let c=Ue(),l=!1,p=h=>{c.start(h),l=!0},d=h=>{l&&(c.stop(h),l=!1)};u.info(m.blue("Configuring iOS certificate management..."));let f,y=st(s,n),g=y;if(!a){let h=await he({message:"Apple ID (for Apple Developer Portal):",placeholder:"your-email@example.com",validate:w=>w.includes("@")?void 0:"Please enter a valid email"});M(h)&&(H("Operation cancelled"),process.exit(0)),a=h}try{let h=await Bs(e),w="",_="";try{let R=await Z.post("/credentials/build-server-token",{projectId:e});R.data.status==="success"&&R.data.credentials&&(process.env.AWS_ACCESS_KEY_ID=R.data.credentials.accessKeyId,process.env.AWS_SECRET_ACCESS_KEY=R.data.credentials.secretAccessKey,R.data.credentials.sessionToken&&(process.env.AWS_SESSION_TOKEN=R.data.credentials.sessionToken),_=R.data.credentials.region||"ap-south-1",w=R.data.credentials.bucket||A.bucketPrefix,process.env.AWS_REGION=_,delete process.env.AWS_PROFILE)}catch(R){throw u.error(`Failed to authenticate with ${A.name} Cloud.`),R}if(!w||!_){u.error(`Failed to resolve S3 configuration from ${A.name} Cloud.`);return}let C=o.teamId||y.teamId||s.submit?.production?.ios?.appleTeamId;if(!C)try{let V=(await Z.get(`/projects/${e}/secrets`)).data.secrets?.find(q=>q.key==="APPLE_TEAM_ID");V&&(C=V.value,u.info(m.dim(`Using Team ID from Dashboard: ${C}`)))}catch{}C&&C===s.submit?.production?.ios?.appleTeamId&&u.info(m.dim(`Using Apple Team ID from config: ${C}`));let v=await at({appleId:a,config:s,profile:n,initialTeam:{...y,teamId:C,developerTeamId:y.developerTeamId||C},promptToPersistConfig:!C,saveTeamId:C?void 0:R=>Pi(e,R)});if(!v?.teamId)return;C=v.teamId;let x={...y,...v,teamId:C,developerTeamId:v.developerTeamId||y.developerTeamId||C};g=x;let F=Jo(e,C);u.info(m.dim(`Using match storage prefix: ${F}`));let D=await os(),j={...D.env};process.env.CI||delete j.CI,p(`Preparing ${r} certificate sync...`),d("Starting certificate sync...");let N=`${A.buildPrefix}-${C}.keychain-db`,T=A.keychainPassword;try{let V=`${process.env.HOME||"/Users/"+(process.env.USER||A.nameLower)}/Library/Keychains/${N}`;u.info(m.dim(`Ensuring keychain exists: ${N}`));try{Ie(`security create-keychain -p ${T} ${N} 2>/dev/null || true`),Ie(`security unlock-keychain -p ${T} ${N}`),Ie(`security set-keychain-settings ${N}`);let W=Ie("security list-keychains -d user").toString();if(!W.includes(N)){u.info(m.dim(`Adding ${N} to search list`));let E=[...W.replace(/"/g,"").split(`
358
+ `).map($=>$.trim()).filter($=>$.length>0),V].join(" ");Ie(`security list-keychains -d user -s ${E}`)}}catch(W){u.warn(m.dim("Keychain setup warning (non-critical): "+W.message))}let q,ye;try{let k=((await Z.get(`/credentials/${e}`)).data.credentials||[]).find(E=>E.type==="asc_api_key"&&E.issuerId);if(k){let E=await Z.get(`/credentials/${k.credentialId}/download`,{params:{projectId:e,format:"raw"}});if(E.data.downloadUrl){let B=await(await import("axios")).default.get(E.data.downloadUrl,{responseType:"arraybuffer"}),z=G.join(yt.tmpdir(),`mach-asc-${Date.now()}`);O.mkdirSync(z,{recursive:!0}),f=G.join(z,`AuthKey_${k.keyId}.p8`),O.writeFileSync(f,Buffer.from(B.data)),q=k.keyId,ye=k.issuerId,u.success(m.green("\u2713 ASC API key loaded \u2014 no 2FA required for Portal operations"))}}}catch(W){u.warn(m.dim(`Could not load ASC API key: ${W.message}. Will fall back to Apple ID auth.`))}u.info(m.dim("Generating secure P12 export password..."));let Ae=Oi();u.success(m.green("\u2713 Secure P12 password generated."));let re={...j,AWS_REGION:process.env.AWS_REGION||"ap-south-1",AWS_ACCESS_KEY_ID:process.env.AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY:process.env.AWS_SECRET_ACCESS_KEY,SSL_CERT_FILE:"/etc/ssl/cert.pem",AWS_CA_BUNDLE:"/etc/ssl/cert.pem",FASTLANE_SSL_CA_CERT:"/etc/ssl/cert.pem",MATCH_PASSWORD:h,FASTLANE_USER:a,FASTLANE_SKIP_UPDATE_CHECK:"1",FASTLANE_TEAM_ID:C,MATCH_KEYCHAIN_NAME:V,MATCH_KEYCHAIN_PASSWORD:T,TERM:process.env.TERM||"xterm-256color",SHELL:process.env.SHELL||"/bin/zsh",MATCH_OUTPUT_PATH:G.join(process.cwd(),"temp_match"),MATCH_STORAGE_MODE:"s3",MATCH_S3_REGION:_,MATCH_S3_BUCKET:w,MATCH_S3_OBJECT_PREFIX:F,MATCH_USERNAME:a,MATCH_APP_IDENTIFIER:t,MATCH_TYPE:r,[`${A.envPrefix}P12_PASSWORD`]:Ae,...f&&q&&ye?{APP_STORE_CONNECT_API_KEY_KEY_ID:q,APP_STORE_CONNECT_API_KEY_ISSUER_ID:ye,APP_STORE_CONNECT_API_KEY_KEY_FILEPATH:f,FASTLANE_SKIP_2FA:"1"}:{}};if(o.force){u.warn(m.yellow(`
359
+ \u26A0\uFE0F Force flag detected: Hard resetting ${r} certificates...`)),u.info(m.dim("Detected decryption failure loop. Clearing remote storage directly to allow fresh generation.")),u.info(m.cyan(`Current MATCH_PASSWORD: ${h}`)),u.info(m.dim(`Cleaning match storage for Team ID: ${C}...`));try{(await Z.post("/credentials/clean-match-storage",{projectId:e,teamId:C,storagePrefix:F})).data.status==="success"&&u.success(m.green(`\u2713 Cleared S3 storage for Team ID: ${C}`))}catch(W){u.warn(m.yellow(`S3 cleanup via API failed: ${W.message}`)),u.info(m.dim("Continuing to attempt standard nuke..."))}try{Ie(`${D.shellCommand} match nuke ${r} --skip_confirmation`,{stdio:"inherit",cwd:process.cwd(),env:re}),u.success(m.green(`\u2713 Nuked existing ${r} credentials`))}catch{u.warn(m.yellow("Standard nuke failed (likely due to password mismatch).")),u.info(m.dim("Since S3 was cleared manually, proceeding to generation..."))}}let te=r==="adhoc"||r==="development";if(r==="adhoc"||r==="development")try{u.info(m.blue("Fetching registered devices..."));let k=(await Z.get("/devices",C?{params:{teamId:C}}:void 0)).data.devices||[];if(C)try{let E=await Z.get("/devices",{params:{teamId:"LEGACY"}}),$=new Map;for(let B of[...k,...E.data.devices||[]])$.set(B.udid,B);k=Array.from($.values())}catch{}if(k.length===0)u.warn(m.yellow("No registered devices found. Profile will only include devices already on the Apple Developer Portal.")),u.info(m.dim(`Register devices with: ${A.nameLower} device register`));else{let{multiselect:E}=await import("@clack/prompts"),$=await E({message:`Select devices to include in the ${r} profile:`,options:k.map(B=>({value:B.udid,label:`${B.name} (${B.udid.substring(0,12)}...)`,hint:B.model||B.platform})),initialValues:k.map(B=>B.udid)});if(!M($)&&$.length>0){let B=k.filter(z=>$.includes(z.udid));if(u.info(m.blue(`Registering ${B.length} device(s) on Apple Developer Portal...`)),C&&await Promise.all(B.filter(z=>!z.teamId).map(z=>Z.post("/devices",{udid:z.udid,name:z.name,platform:"ios",addedVia:z.addedVia||"cli",teamId:C,teamName:x.teamName}).catch(()=>{}))),f&&q&&ye)await Fs(B,q,ye,f);else{u.info(m.dim("You will be prompted for a 2FA code once \u2014 type it and press Enter."));for(let z of B){let J=z.name.replace(/"/g,'\\"');Ne(`${D.shellCommand} run register_device name:"${J}" udid:"${z.udid}"`,{shell:!0,env:re,stdio:"inherit",cwd:process.cwd()})}}u.info(m.green("\u2713 Device registration complete.")),te=!0}}}catch(W){u.warn(m.yellow(`Could not fetch registered devices: ${W.message}`)),u.info(m.dim("Continuing without explicit device registration."))}try{let W=`${A.nameLower} ${r} ${t}`,k=Qo(D.shellCommand,r,t,W,te);te&&u.info(m.dim(`Refreshing ${r} provisioning profile when device list changes (--force_for_new_devices).`));let E=Ne(k,{shell:!0,cwd:process.cwd(),env:re,stdio:"inherit",encoding:"utf-8"});if(E.status!==0){u.warn(m.yellow(`
360
360
  Certificate sync failed. Attempting to create App ID and retry...`));try{Ie(`${D.shellCommand} produce --app_identifier "${t}" --app_name "${t}" --skip_itc`,{stdio:"inherit",env:re}),u.success(m.green("\u2713 App ID created successfully")),u.info(m.blue("Retrying certificate sync...")),E=Ne(k,{shell:!0,cwd:process.cwd(),env:re,stdio:"inherit",encoding:"utf-8"})}catch{}if(E.status!==0)throw new Error("fastlane match failed")}}catch(W){u.warn(m.yellow(`
361
361
  Sync failed. This often happens if the encryption passphrase (MATCH_PASSWORD) is incorrect or session expired.`)),u.info(m.cyan(`Failed MATCH_PASSWORD was: ${h}`));let k=await ve({message:"What would you like to do?",options:[{value:"retry_password",label:"Retry with a different MATCH_PASSWORD",hint:"Manually enter the decryption passphrase"},{value:"check_portal",label:"Check Apple Portal (Resolve certificate limits)",hint:"See if you have too many certificates"},{value:"manual",label:"Fallback to manual upload",hint:"Provide .p12 and .mobileprovision files"},{value:"cancel",label:"Cancel",hint:"Go back"}]});if(M(k)||k==="cancel")throw W;if(k==="retry_password"){u.info(m.dim(`
362
362
  You are overriding the dashboard passphrase for this session.`));let E=await ht({message:"Enter the correct MATCH_PASSWORD for this project:"});if(E&&!M(E)){h=E,u.info(m.blue("Retrying with provided passphrase...")),u.info(m.cyan(`New MATCH_PASSWORD: ${h}`));let $={...re,MATCH_PASSWORD:h};if(Ne(`${D.shellCommand} match ${r}`,{shell:!0,stdio:"inherit",cwd:process.cwd(),env:$}).status===0)await Z.post(`/projects/${e}/secrets`,{key:"MATCH_ENCRYPTION_PASSPHRASE",value:h,description:"Encryption passphrase for iOS certificates (fastlane match)",visibility:"secret"}),u.success(m.green("\u2713 Dashboard passphrase updated.")),u.info(m.cyan(`MATCH_PASSWORD: ${h}`));else throw new Error("Sync failed again with provided passphrase.")}else throw W}else if(k==="check_portal")try{let E=await cn(re,r,D.shellCommand);if(E.length>0){if(u.info(m.dim(`Found ${E.length} existing ${r} certificates on the portal.`)),await Us(r,re,e,D.shellCommand,E)&&(u.info(m.blue("Retrying certificate sync...")),Ne(`${D.shellCommand} match ${r}`,{shell:!0,stdio:"inherit",cwd:process.cwd(),env:re}).status!==0))throw new Error("Retry failed")}else throw u.error(m.red("No existing certificates found on portal to resolve.")),W}catch(E){throw u.warn(m.dim(`Portal check warning: ${E.message}`)),W}else throw W}u.success(m.green("\u2713 Certificates fetched and synced"));let ae=G.join(process.cwd(),"temp_match"),ie=G.join(ae,`${A.fastlanePrefix}_export.p12`),K=an(ae,/\.mobileprovision$/);try{let k=`${process.env.HOME||"/Users/"+(process.env.USER||A.nameLower)}/Library/Keychains/${N}`;O.existsSync(ae)||O.mkdirSync(ae,{recursive:!0}),u.info(m.dim("Exporting certificate from keychain for dashboard upload..."));let E=Ie(`security find-identity -v -p codesigning "${k}"`,{encoding:"utf-8"});u.info(m.dim(`Identities in keychain:
363
363
  ${E.trim()}`)),Ie(`security export -k "${k}" -t identities -f pkcs12 -o "${ie}" -P ""`,{stdio:"ignore"});try{let $=Ie(`openssl pkcs12 -in "${ie}" -nokeys -passin pass: -legacy 2>/dev/null || openssl pkcs12 -in "${ie}" -nokeys -passin pass: 2>/dev/null`,{encoding:"utf-8"});if(!$.includes(C))throw new Error(`Exported P12 does not contain identity for team ${C}. Found: ${$.substring(0,200)}`);u.success(m.green(`\u2713 P12 verified \u2014 contains correct team identity (${C})`))}catch($){throw new Error(`P12 verification failed: ${$.message}`)}}catch{u.warn(m.dim("Could not export certificate from keychain."))}o.teamId&&!C&&await Pi(e,o.teamId);let De=O.existsSync(ie)?ie:an(ae,/\.p12$/);if(De&&K){let W,k;try{let E=await cn(re,r,D.shellCommand);E.length>0&&(W=E[0].expires,k=E[0].id)}catch{u.warn(m.dim("Could not fetch expiration date or ID for dashboard record."))}await it(e,De,"ios_cert",t,i,void 0,W,o.teamId||C,k,Ae,void 0,void 0,x.teamId,x.teamName,x.developerTeamId,x.appStoreConnectTeamId,x.providerId,x.providerName),await it(e,K,"ios_profile",t,i,void 0,W,o.teamId||C,void 0,void 0,void 0,void 0,x.teamId,x.teamName,x.developerTeamId,x.appStoreConnectTeamId,x.providerId,x.providerName),u.success(m.green("\u2713 Both iOS certificate and provisioning profile uploaded successfully"));try{O.existsSync("./temp_match")&&O.rmSync("./temp_match",{recursive:!0,force:!0})}catch{}}else u.warn(m.yellow("Certificates generated but not found in expected location.")),u.info(m.dim("Falling back to manual upload...")),await Ni(e,t,i,g)}catch(R){d("Certificate fetch failed"),u.error(m.red(`Error: ${R.message}`)),u.info(m.dim("Falling back to manual upload...")),await Ni(e,t,i,g)}}catch(h){d("iOS setup failed"),u.error(m.red(`Error: ${h.message}`))}finally{if(f)try{O.rmSync(G.dirname(f),{recursive:!0,force:!0})}catch{}}}async function Pi(e,t){try{await Z.post(`/projects/${e}/secrets`,{key:"APPLE_TEAM_ID",value:t,description:"Apple Developer Team ID (used for iOS signing)"}),u.success(m.green(`\u2713 Saved Team ID ${t} to Dashboard`))}catch(n){u.warn(m.yellow(`Could not save Team ID to Dashboard: ${n.message}`))}}async function Ni(e,t,n,i={}){u.info(m.yellow(`
364
- Manual Upload Mode`)),u.info("Please provide your certificate and provisioning profile:");let r=await he({message:"Path to .p12 certificate file:",validate:a=>O.existsSync(a)?void 0:"File not found"});M(r)&&(H("Operation cancelled"),process.exit(0));let o=await he({message:"Path to .mobileprovision file:",validate:a=>O.existsSync(a)?void 0:"File not found"});M(o)&&(H("Operation cancelled"),process.exit(0));let s=Ue();s.start(`Uploading to ${A.name} Dashboard...`);try{await it(e,r,"ios_cert",t,n,void 0,void 0,i.teamId,void 0,void 0,void 0,void 0,i.teamId,i.teamName,i.developerTeamId||i.teamId,i.appStoreConnectTeamId,i.providerId,i.providerName),await it(e,o,"ios_profile",t,n,void 0,void 0,i.teamId,void 0,void 0,void 0,void 0,i.teamId,i.teamName,i.developerTeamId||i.teamId,i.appStoreConnectTeamId,i.providerId,i.providerName),s.stop("Upload complete"),u.success(m.green("\u2713 iOS credentials uploaded successfully"))}catch(a){throw s.stop("Upload failed"),a}}async function Vs(e,t,n,i,r){let o=Ue();u.step(m.blue("Android Credential Setup"));let s=i.bundleId;if(!s){let d=Je(r,t),f=[];try{let g=(await Z.get(`/credentials/${e}`)).data.credentials||[];f=[...new Set(g.filter(h=>h.platform==="android"&&h.bundleId&&h.bundleId!=="*").map(h=>h.bundleId))]}catch{}if(d&&!f.includes(d)&&f.unshift(d),f.length>0){let I=[...f.map(h=>({value:h,label:h,hint:h===d?"from config":void 0})),{value:"__new__",label:"+ Enter a new Package Name"}],g=await ve({message:"Which Package Name are you setting up credentials for?",options:I});if(M(g)&&(H("Operation cancelled"),process.exit(0)),g==="__new__"){let h=await he({message:"Android Package Name (e.g. com.example.app):",placeholder:"com.example.app",validate:w=>w.includes(".")?void 0:"Please enter a valid package name"});M(h)&&(H("Operation cancelled"),process.exit(0)),s=h}else s=g}else{let I=await he({message:"Android Package Name (e.g. com.example.app):",placeholder:"com.example.app",validate:g=>g.includes(".")?void 0:"Please enter a valid package name"});M(I)&&(H("Operation cancelled"),process.exit(0)),s=I}}try{let I=((await Z.get(`/credentials/${e}`)).data.credentials||[]).find(g=>g.platform==="android"&&g.distributionType===n&&g.bundleId===s);if(I){u.warn(m.yellow(`\u26A0\uFE0F Existing Android credentials found for ${n}`));let g=await he({message:"What would you like to do? (use/new/cancel)",validate:h=>{let w=h.toLowerCase();if(!(w==="use"||w==="new"||w==="cancel"))return"Please type: use, new, or cancel"}});if(M(g)||g.toLowerCase()==="cancel")return;if(g.toLowerCase()==="use"){u.success(m.green("\u2713 Using existing credentials."));return}await Z.delete(`/credentials/${I.credentialId}?projectId=${e}`)}}catch{}let a="./android/app/my-release-key.jks";if(O.existsSync(a)){let d=await ln({message:"Upload existing keystore?"});if(d&&!M(d)){let f=await he({message:"Key alias:",initialValue:"my-key-alias"});if(M(f))return;let I=await ht({message:"Keystore password:"});if(M(I))return;let g=await ht({message:"Key password (leave blank if same as keystore password):"});if(M(g))return;let h=g.trim()||I;await it(e,a,"android_keystore",s,n,f,void 0,void 0,void 0,void 0,I,h),u.success(m.green("\u2713 Keystore uploaded"));return}}u.info(m.blue("Generating new Android keystore..."));let c=i.keyAlias||`${A.nameLower}-${Gs()}`,l=Oi(),p=`./${A.nameLower}-${t}.jks`;O.existsSync(p)&&O.unlinkSync(p),o.start("Generating keystore...");try{let d=l.replace(/'/g,"'\\''");Ie(`keytool -genkeypair -v -keystore "${p}" -alias "${c}" -keyalg RSA -keysize 2048 -validity 10000 -storepass '${d}' -keypass '${d}' -dname "CN=${A.name} Build, OU=Mobile, O=Company, L=City, S=State, C=US"`,{stdio:"inherit"}),o.stop("Keystore generated"),await it(e,p,"android_keystore",s,n,c,void 0,void 0,void 0,void 0,l,l),u.success(m.green("\u2713 Android credentials uploaded successfully")),u.info(m.cyan(`Key Alias: ${c}`))}catch(d){throw o.stop("Generation failed"),new Error(`Keystore generation failed: ${d.message}`)}}var Ws=e=>new Promise(t=>setTimeout(t,e));function Zs(e){return/ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|ECONNABORTED|socket hang up|network|timeout|temporar/i.test(e)||/API_ERROR:\s*(408|409|425|429|5\d\d)/i.test(e)}async function it(e,t,n,i,r,o,s,a,c,l,p,d,f,I,g,h,w,_){let C=G.basename(t);u.info(m.dim(`Uploading ${C} (Isolated process)...`));let v=new URL(import.meta.url),x=G.dirname(v.pathname),D=[G.join(x,"commands","isolated-upload.js"),e,t,n,i,r,o||"undefined",s||"undefined",a||"undefined",c||"undefined",l||"undefined",p||"undefined",d||"undefined",f||"undefined",I||"undefined",g||"undefined",h||"undefined",w||"undefined",_||"undefined"],j="",N=5;for(let T=1;T<=N;T++){let R=Ne("node",D,{stdio:"pipe",encoding:"utf-8",env:{...process.env,AT_CLI_ISOLATED:"1"}});if(R.status===0&&R.stdout.includes("SUCCESS")){u.info(m.dim(`\u2713 ${C} uploaded and registered.`));return}if(R.status===0){u.warn(m.yellow(`Isolated upload finished but success not confirmed: ${R.stdout}`));return}if(j=(R.stderr||R.stdout||R.error?.message||"Unknown isolated upload failure").trim(),!Zs(j)||T>=N)throw u.error(m.red(`Isolated Upload Failed: ${j}`)),new Error(j);let q=Math.min(3e4,1500*Math.pow(2,T-1));u.warn(m.yellow(`Upload failed with a transient error. Retrying ${C} in ${Math.round(q/1e3)}s... (${T}/${N})`)),await Ws(q)}throw new Error(j||"Unknown isolated upload failure")}async function Ms(e){let t=Ue(),n=e.platform,i=`./${A.configFileName}`;if(!O.existsSync(i)){u.error(`No ${A.configFileName} found. Run \`${A.nameLower} init\` or \`${A.nameLower} link\` first.`);return}let r=JSON.parse(O.readFileSync(i,"utf-8")),{projectId:o}=r;if(!o){u.error(`${A.configFileName} is missing projectId.`);return}try{t.start("Fetching project secrets...");let a=(await Z.get(`/projects/${o}/secrets/export?env=all`)).data.secrets||{};t.stop("Secrets fetched and merged."),t.start("Fetching credentials...");let l=(await Z.get(`/credentials/${o}`)).data.credentials||[];t.stop(`Found ${l.length} metadata records.`);let p=l.filter(g=>g.platform===n);if(p.length===0){u.info(`No ${n} credentials found on Dashboard.`);return}let d="./credentials.json",f={};if(O.existsSync(d))try{f=JSON.parse(O.readFileSync(d,"utf-8"))}catch{u.warn("Could not parse existing credentials.json, creating a new one.")}f[n]||(f[n]={});let I=G.join(process.cwd(),"credentials",n);O.existsSync(I)||O.mkdirSync(I,{recursive:!0});for(let g of p){t.start(`Downloading ${g.type} (${g.distributionType})...`);try{let h=await Z.get(`/credentials/${g.credentialId}/download`,{params:{projectId:o,format:"raw"}});if(h.data.status==="success"&&h.data.downloadUrl){let w=G.join(process.cwd(),"credentials",n,g.distributionType);O.existsSync(w)||O.mkdirSync(w,{recursive:!0});let _=g.s3Key?.split(".").pop()||(g.type.includes("keystore")?"jks":g.type.includes("cert")?"p12":"mobileprovision"),C=`${g.type}.${_}`,v=G.join(w,C),x=await ki.get(h.data.downloadUrl,{responseType:"arraybuffer"});O.writeFileSync(v,Buffer.from(x.data));let F=G.join("credentials",n,g.distributionType,C),D="",j="",N={alias:"",keystorePassword:"",keyPassword:""};if(n==="ios"&&g.type==="ios_cert"||n==="android"&&g.type==="android_keystore"){let T=await as(o,n,g);if(n==="ios"&&g.type==="ios_cert"&&_.toLowerCase()==="p12"){if(D=ls(T,a),D){let R=wi(v,`${G.basename(v,G.extname(v))}-password.txt`,D);j=G.join("credentials",n,g.distributionType,G.basename(R))}}else if(n==="android"&&g.type==="android_keystore"&&(N=ds(T,a),N.keystorePassword||N.keyPassword)){let R=[N.alias?`keyAlias=${N.alias}`:void 0,N.keystorePassword?`keystorePassword=${N.keystorePassword}`:void 0,N.keyPassword?`keyPassword=${N.keyPassword}`:void 0].filter(Boolean).join(`
364
+ Manual Upload Mode`)),u.info("Please provide your certificate and provisioning profile:");let r=await he({message:"Path to .p12 certificate file:",validate:a=>O.existsSync(a)?void 0:"File not found"});M(r)&&(H("Operation cancelled"),process.exit(0));let o=await he({message:"Path to .mobileprovision file:",validate:a=>O.existsSync(a)?void 0:"File not found"});M(o)&&(H("Operation cancelled"),process.exit(0));let s=Ue();s.start(`Uploading to ${A.name} Dashboard...`);try{await it(e,r,"ios_cert",t,n,void 0,void 0,i.teamId,void 0,void 0,void 0,void 0,i.teamId,i.teamName,i.developerTeamId||i.teamId,i.appStoreConnectTeamId,i.providerId,i.providerName),await it(e,o,"ios_profile",t,n,void 0,void 0,i.teamId,void 0,void 0,void 0,void 0,i.teamId,i.teamName,i.developerTeamId||i.teamId,i.appStoreConnectTeamId,i.providerId,i.providerName),s.stop("Upload complete"),u.success(m.green("\u2713 iOS credentials uploaded successfully"))}catch(a){throw s.stop("Upload failed"),a}}async function Vs(e,t,n,i,r){let o=Ue();u.step(m.blue("Android Credential Setup"));let s=i.bundleId;if(!s){let d=Je(r,t),f=[];try{let g=(await Z.get(`/credentials/${e}`)).data.credentials||[];f=[...new Set(g.filter(h=>h.platform==="android"&&h.bundleId&&h.bundleId!=="*").map(h=>h.bundleId))]}catch{}if(d&&!f.includes(d)&&f.unshift(d),f.length>0){let y=[...f.map(h=>({value:h,label:h,hint:h===d?"from config":void 0})),{value:"__new__",label:"+ Enter a new Package Name"}],g=await ve({message:"Which Package Name are you setting up credentials for?",options:y});if(M(g)&&(H("Operation cancelled"),process.exit(0)),g==="__new__"){let h=await he({message:"Android Package Name (e.g. com.example.app):",placeholder:"com.example.app",validate:w=>w.includes(".")?void 0:"Please enter a valid package name"});M(h)&&(H("Operation cancelled"),process.exit(0)),s=h}else s=g}else{let y=await he({message:"Android Package Name (e.g. com.example.app):",placeholder:"com.example.app",validate:g=>g.includes(".")?void 0:"Please enter a valid package name"});M(y)&&(H("Operation cancelled"),process.exit(0)),s=y}}try{let y=((await Z.get(`/credentials/${e}`)).data.credentials||[]).find(g=>g.platform==="android"&&g.distributionType===n&&g.bundleId===s);if(y){u.warn(m.yellow(`\u26A0\uFE0F Existing Android credentials found for ${n}`));let g=await he({message:"What would you like to do? (use/new/cancel)",validate:h=>{let w=h.toLowerCase();if(!(w==="use"||w==="new"||w==="cancel"))return"Please type: use, new, or cancel"}});if(M(g)||g.toLowerCase()==="cancel")return;if(g.toLowerCase()==="use"){u.success(m.green("\u2713 Using existing credentials."));return}await Z.delete(`/credentials/${y.credentialId}?projectId=${e}`)}}catch{}let a="./android/app/my-release-key.jks";if(O.existsSync(a)){let d=await ln({message:"Upload existing keystore?"});if(d&&!M(d)){let f=await he({message:"Key alias:",initialValue:"my-key-alias"});if(M(f))return;let y=await ht({message:"Keystore password:"});if(M(y))return;let g=await ht({message:"Key password (leave blank if same as keystore password):"});if(M(g))return;let h=g.trim()||y;await it(e,a,"android_keystore",s,n,f,void 0,void 0,void 0,void 0,y,h),u.success(m.green("\u2713 Keystore uploaded"));return}}u.info(m.blue("Generating new Android keystore..."));let c=i.keyAlias||`${A.nameLower}-${Gs()}`,l=Oi(),p=`./${A.nameLower}-${t}.jks`;O.existsSync(p)&&O.unlinkSync(p),o.start("Generating keystore...");try{let d=l.replace(/'/g,"'\\''");Ie(`keytool -genkeypair -v -keystore "${p}" -alias "${c}" -keyalg RSA -keysize 2048 -validity 10000 -storepass '${d}' -keypass '${d}' -dname "CN=${A.name} Build, OU=Mobile, O=Company, L=City, S=State, C=US"`,{stdio:"inherit"}),o.stop("Keystore generated"),await it(e,p,"android_keystore",s,n,c,void 0,void 0,void 0,void 0,l,l),u.success(m.green("\u2713 Android credentials uploaded successfully")),u.info(m.cyan(`Key Alias: ${c}`))}catch(d){throw o.stop("Generation failed"),new Error(`Keystore generation failed: ${d.message}`)}}var Ws=e=>new Promise(t=>setTimeout(t,e));function Zs(e){return/ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|ECONNABORTED|socket hang up|network|timeout|temporar/i.test(e)||/API_ERROR:\s*(408|409|425|429|5\d\d)/i.test(e)}async function it(e,t,n,i,r,o,s,a,c,l,p,d,f,y,g,h,w,_){let C=G.basename(t);u.info(m.dim(`Uploading ${C} (Isolated process)...`));let v=new URL(import.meta.url),x=G.dirname(v.pathname),D=[G.join(x,"commands","isolated-upload.js"),e,t,n,i,r,o||"undefined",s||"undefined",a||"undefined",c||"undefined",l||"undefined",p||"undefined",d||"undefined",f||"undefined",y||"undefined",g||"undefined",h||"undefined",w||"undefined",_||"undefined"],j="",N=5;for(let T=1;T<=N;T++){let R=Ne("node",D,{stdio:"pipe",encoding:"utf-8",env:{...process.env,AT_CLI_ISOLATED:"1"}});if(R.status===0&&R.stdout.includes("SUCCESS")){u.info(m.dim(`\u2713 ${C} uploaded and registered.`));return}if(R.status===0){u.warn(m.yellow(`Isolated upload finished but success not confirmed: ${R.stdout}`));return}if(j=(R.stderr||R.stdout||R.error?.message||"Unknown isolated upload failure").trim(),!Zs(j)||T>=N)throw u.error(m.red(`Isolated Upload Failed: ${j}`)),new Error(j);let q=Math.min(3e4,1500*Math.pow(2,T-1));u.warn(m.yellow(`Upload failed with a transient error. Retrying ${C} in ${Math.round(q/1e3)}s... (${T}/${N})`)),await Ws(q)}throw new Error(j||"Unknown isolated upload failure")}async function Ms(e){let t=Ue(),n=e.platform,i=`./${A.configFileName}`;if(!O.existsSync(i)){u.error(`No ${A.configFileName} found. Run \`${A.nameLower} init\` or \`${A.nameLower} link\` first.`);return}let r=JSON.parse(O.readFileSync(i,"utf-8")),{projectId:o}=r;if(!o){u.error(`${A.configFileName} is missing projectId.`);return}try{t.start("Fetching project secrets...");let a=(await Z.get(`/projects/${o}/secrets/export?env=all`)).data.secrets||{};t.stop("Secrets fetched and merged."),t.start("Fetching credentials...");let l=(await Z.get(`/credentials/${o}`)).data.credentials||[];t.stop(`Found ${l.length} metadata records.`);let p=l.filter(g=>g.platform===n);if(p.length===0){u.info(`No ${n} credentials found on Dashboard.`);return}let d="./credentials.json",f={};if(O.existsSync(d))try{f=JSON.parse(O.readFileSync(d,"utf-8"))}catch{u.warn("Could not parse existing credentials.json, creating a new one.")}f[n]||(f[n]={});let y=G.join(process.cwd(),"credentials",n);O.existsSync(y)||O.mkdirSync(y,{recursive:!0});for(let g of p){t.start(`Downloading ${g.type} (${g.distributionType})...`);try{let h=await Z.get(`/credentials/${g.credentialId}/download`,{params:{projectId:o,format:"raw"}});if(h.data.status==="success"&&h.data.downloadUrl){let w=G.join(process.cwd(),"credentials",n,g.distributionType);O.existsSync(w)||O.mkdirSync(w,{recursive:!0});let _=g.s3Key?.split(".").pop()||(g.type.includes("keystore")?"jks":g.type.includes("cert")?"p12":"mobileprovision"),C=`${g.type}.${_}`,v=G.join(w,C),x=await ki.get(h.data.downloadUrl,{responseType:"arraybuffer"});O.writeFileSync(v,Buffer.from(x.data));let F=G.join("credentials",n,g.distributionType,C),D="",j="",N={alias:"",keystorePassword:"",keyPassword:""};if(n==="ios"&&g.type==="ios_cert"||n==="android"&&g.type==="android_keystore"){let T=await as(o,n,g);if(n==="ios"&&g.type==="ios_cert"&&_.toLowerCase()==="p12"){if(D=ls(T,a),D){let R=wi(v,`${G.basename(v,G.extname(v))}-password.txt`,D);j=G.join("credentials",n,g.distributionType,G.basename(R))}}else if(n==="android"&&g.type==="android_keystore"&&(N=ds(T,a),N.keystorePassword||N.keyPassword)){let R=[N.alias?`keyAlias=${N.alias}`:void 0,N.keystorePassword?`keystorePassword=${N.keystorePassword}`:void 0,N.keyPassword?`keyPassword=${N.keyPassword}`:void 0].filter(Boolean).join(`
365
365
  `),V=wi(v,`${G.basename(v,G.extname(v))}-passwords.txt`,R);j=G.join("credentials",n,g.distributionType,G.basename(V))}}if(n==="android")g.type==="android_keystore"&&(f.android.keystore={keystorePath:F,keystorePassword:N.keystorePassword,keyAlias:N.alias,keyPassword:N.keyPassword},j&&(f.android.keystore.keystoreArchivePath=j));else if(n==="ios"){let T=g.distributionType==="store"?"production":g.distributionType==="adhoc"?"staging":"development";f.ios[T]||(f.ios[T]={}),g.type==="ios_cert"?(f.ios[T].certificatePath=F,f.ios[T].certificatePassword=D,j&&(f.ios[T].certificateArchivePath=j)):g.type==="ios_profile"&&(f.ios[T].provisioningProfilePath=F)}t.stop(`\u2713 ${g.type} (${g.distributionType}) saved${j?" with password archive":""}.`)}}catch(h){let w=h.response?.data?.message||h.message;t.stop(m.dim(`- Skipped ${g.type} (${g.distributionType}): ${w}`))}}O.writeFileSync(d,JSON.stringify(f,null,2)),u.success(m.green("\u2713 Local credentials.json updated.")),jo("Credentials have been synced to your local machine. Ensure credentials.json and credentials/ is added to your .gitignore.","Sync Complete")}catch(s){t.stop(m.red("Sync failed.")),u.error(`Error: ${s.message}`)}}function Oi(){let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+=",t="";for(let n=0;n<24;n++)t+=e.charAt(Math.floor(Math.random()*e.length));return t}function Gs(e=8){let t="abcdefghijklmnopqrstuvwxyz0123456789",n="";for(let i=0;i<e;i++)n+=t.charAt(Math.floor(Math.random()*t.length));return n}async function Us(e,t,n,i,r){let o=r||await cn(t,e,i);if(!o||o.length===0)return!1;let s=await ve({message:"Select a certificate to revoke:",options:[...o.map(a=>({value:`revoke:${a.id}`,label:`Revoke: ${a.name} (${a.expires})`})),{value:"nuke",label:"Revoke All"},{value:"cancel",label:"Cancel"}]});return M(s)||s==="cancel"?!1:s==="nuke"?(Ie(`${i} match nuke ${e}`,{stdio:"inherit",cwd:process.cwd(),env:t}),!0):typeof s=="string"&&s.startsWith("revoke:")?(await Xs(t,s.split(":")[1],i),!0):!1}async function cn(e,t,n){let i=t==="development"?"development":"distribution",r=`
366
366
  lane :${A.fastlanePrefix}_list_certs do
367
367
  require 'spaceship'
@@ -1 +1 @@
1
- import{G as a,H as b,I as c}from"./chunk-PJTV6XTO.js";import"./chunk-S64YFTRR.js";export{a as credentialsMainCommand,b as credentialsSetupCommand,c as downloadCredentialsCommand};
1
+ import{G as a,H as b,I as c}from"./chunk-6S5J2ITE.js";import"./chunk-S64YFTRR.js";export{a as credentialsMainCommand,b as credentialsSetupCommand,c as downloadCredentialsCommand};
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{A as et,B as So,C as Eo,D as Bi,E as Io,F as wo,H as jt,a as ft,b as fo,c as mo,d as Li,e as go,f as ho,g as Cn,h as Tn,i as kn,j as Mi,k as Ui,l as Nn,m as xn,n as yo,o as Fi,p as It,q as wt,r as $e,s as bo,t as mt,u as ce,v as Ie,w as Ln,x as Mn,y as vt,z as Ao}from"./chunk-PJTV6XTO.js";import{a as m,b as uo,c as be,d as po,e as Et,f as Qe,g as He,h as $}from"./chunk-S64YFTRR.js";import{Command as eg,Option as Te}from"commander";import{configDotenv as tg}from"dotenv";import{intro as X,outro as nd}from"@clack/prompts";import J from"chalk";import{text as vo,confirm as ad,spinner as ld,isCancel as ji,cancel as Ht,note as dd,outro as cd}from"@clack/prompts";import Gt from"chalk";async function _o(){try{let e=await vo({message:"Enter Bucket Name:",placeholder:"e.g. my-app-dev",validate(r){if(r.length===0)return"Bucket name is required"}});ji(e)&&(Ht("Operation cancelled."),process.exit(0));let t=await vo({message:"Enter Region:",initialValue:"ap-south-1"});ji(t)&&(Ht("Operation cancelled."),process.exit(0));let n=await ad({message:"Do you want to create a CloudFront Distribution for this bucket?",initialValue:!0});ji(n)&&(Ht("Operation cancelled."),process.exit(0));let i=ld();i.start("Setting up hosting infrastructure...");try{let r=await $.post("/hosting/setup",{bucketName:e,region:t,createCloudFront:n});if(r.data.status!=="success")throw new Error(r.data.message||"Hosting setup failed");i.stop("Hosting setup complete!");let o=r.data,s=`Bucket Name: ${Gt.cyan(o.bucketName)}
2
+ import{A as et,B as So,C as Eo,D as Bi,E as Io,F as wo,H as jt,a as ft,b as fo,c as mo,d as Li,e as go,f as ho,g as Cn,h as Tn,i as kn,j as Mi,k as Ui,l as Nn,m as xn,n as yo,o as Fi,p as It,q as wt,r as $e,s as bo,t as mt,u as ce,v as Ie,w as Ln,x as Mn,y as vt,z as Ao}from"./chunk-6S5J2ITE.js";import{a as m,b as uo,c as be,d as po,e as Et,f as Qe,g as He,h as $}from"./chunk-S64YFTRR.js";import{Command as eg,Option as Te}from"commander";import{configDotenv as tg}from"dotenv";import{intro as X,outro as nd}from"@clack/prompts";import J from"chalk";import{text as vo,confirm as ad,spinner as ld,isCancel as ji,cancel as Ht,note as dd,outro as cd}from"@clack/prompts";import Gt from"chalk";async function _o(){try{let e=await vo({message:"Enter Bucket Name:",placeholder:"e.g. my-app-dev",validate(r){if(r.length===0)return"Bucket name is required"}});ji(e)&&(Ht("Operation cancelled."),process.exit(0));let t=await vo({message:"Enter Region:",initialValue:"ap-south-1"});ji(t)&&(Ht("Operation cancelled."),process.exit(0));let n=await ad({message:"Do you want to create a CloudFront Distribution for this bucket?",initialValue:!0});ji(n)&&(Ht("Operation cancelled."),process.exit(0));let i=ld();i.start("Setting up hosting infrastructure...");try{let r=await $.post("/hosting/setup",{bucketName:e,region:t,createCloudFront:n});if(r.data.status!=="success")throw new Error(r.data.message||"Hosting setup failed");i.stop("Hosting setup complete!");let o=r.data,s=`Bucket Name: ${Gt.cyan(o.bucketName)}
3
3
  `;s+=`Region: ${Gt.cyan(o.region)}
4
4
  `,s+=`S3 Website URL: ${Gt.blue(o.s3WebsiteUrl)}`,o.cloudFrontId&&(s+=`
5
5
 
@@ -1766,5 +1766,5 @@ module.exports = function withMachDeepLinks(config) {
1766
1766
  Running expo prebuild for deeper analysis...`));try{Fm("npx expo prebuild --no-install",{cwd:e,stdio:"pipe"})}catch{return $n.warn(_e.yellow("Prebuild failed \u2014 skipping manifest/plist checks.")),o}}else if(!l)return t.json||$n.info(_e.dim(`
1767
1767
  Skipping manifest/plist checks \u2014 no android/ios dirs. Use --prebuild to generate them.`)),o;for(let d of r){let c=Gl();c.start(_e.dim(`Running ${d.label}...`));try{let u=Date.now(),f=await d.fn(e,t);f.durationMs=Date.now()-u,o.push(f);let p=f.findings.length;c.stop(p>0?_e.yellow(`${d.label} \u2014 ${p} finding(s)`):_e.green(`${d.label} \u2014 clean`))}catch(u){c.stop(_e.red(`${d.label} \u2014 error`)),o.push({category:d.category,label:d.label,findings:[],durationMs:0,error:u.message})}}}return o}import fe from"chalk";import{log as le}from"@clack/prompts";var Mt={critical:fe.bgRed.white.bold,high:fe.red.bold,medium:fe.yellow.bold,low:fe.blue,info:fe.dim},Ci={critical:0,high:1,medium:2,low:3,info:4};function jm(e,t){if(!t)return!0;let n=Ci[t];return n===void 0?!0:Ci[e]<=n}function Wl(e,t){let n=0,i={critical:0,high:0,medium:0,low:0,info:0};for(let s of e){let a=s.findings.filter(d=>jm(d.severity,t));if(a.length===0&&!s.error)continue;if(le.info(""),le.info(fe.bold(` ${s.label}`)+fe.dim(` ${a.length} finding(s)`)),le.info(fe.dim(" "+"\u2500".repeat(60))),s.error){le.error(fe.red(` Error: ${s.error}`));continue}let l=[...a].sort((d,c)=>Ci[d.severity]-Ci[c.severity]);for(let d of l){let c=Mt[d.severity](` ${d.severity.toUpperCase()} `);le.info(` ${c} ${fe.bold(d.id)} ${d.title}`),le.info(fe.dim(` ${d.description}`)),d.file&&le.info(fe.dim(` File: ${d.file}${d.line?`:${d.line}`:""}`)),le.info(fe.cyan(` Fix: ${d.recommendation}`)),le.info(""),i[d.severity]++,n++}}le.info(""),le.info(fe.bold(" Summary")),le.info(fe.dim(" "+"\u2500".repeat(60))),le.info(` Total: ${fe.bold(String(n))} finding(s)`),le.info(` ${Mt.critical(` ${i.critical} Critical `)} ${Mt.high(` ${i.high} High `)} ${Mt.medium(` ${i.medium} Medium `)} ${Mt.low(` ${i.low} Low `)} ${Mt.info(` ${i.info} Info `)}`);let r=i.critical>0,o=i.high>0;r||o?(le.info(""),le.error(fe.red.bold(` FAIL \u2014 ${i.critical} critical, ${i.high} high issue(s) found`))):n>0?(le.info(""),le.warn(fe.yellow(" PASS (with warnings) \u2014 no critical or high issues"))):(le.info(""),le.success(fe.green.bold(" PASS \u2014 no issues found")))}function ql(e,t){let n=e.flatMap(r=>r.findings),i={};for(let r of Object.values(Pe))i[r]=n.filter(o=>o.severity===r).length;return{version:"1.0.0",timestamp:new Date().toISOString(),project:t.name||"unknown",projectVersion:t.version||"0.0.0",summary:{total:n.length,...i},passed:i.critical===0&&i.high===0,checks:e.map(r=>({category:r.category,label:r.label,findingCount:r.findings.length,durationMs:r.durationMs,error:r.error||null})),findings:n}}import{log as de,spinner as Hm}from"@clack/prompts";import ie from"chalk";import Ze from"fs";import Gm from"os";import Ut from"path";import{execSync as Vm}from"child_process";var Jl=16384,zm=1,Km=Buffer.from([127,69,76,70]);async function Yl(e){de.info(ie.bold.underline("16KB Page Alignment Check")),console.log("");let t=Ut.resolve(e);if(!Ze.existsSync(t))return de.error(ie.red(`APK file not found: ${t}`)),!1;if(!t.endsWith(".apk"))return de.error(ie.red("The provided file is not an APK file.")),!1;let n=Hm();n.start("Extracting and analyzing native libraries...");let i=Ze.mkdtempSync(Ut.join(Gm.tmpdir(),"mach-16kb-"));try{try{Vm(`unzip -o -q "${t}" "lib/arm64-v8a/*.so" "lib/x86_64/*.so" -d "${i}" 2>/dev/null`,{encoding:"utf-8",maxBuffer:50*1024*1024})}catch{}let r=Xl(Ut.join(i,"lib"));if(r.length===0)return n.stop("Analysis complete."),de.info(ie.yellow("No arm64-v8a or x86_64 native libraries found in the APK.")),de.info(ie.dim("16KB alignment check only applies to arm64-v8a and x86_64 architectures.")),!0;let o=[];for(let l of r){let d=Ut.relative(i,l),c=qm(d),u=Ut.basename(l),f=Wm(l);f!==null&&o.push({name:u,filePath:d,arch:c,align:f,compatible:f>=Jl})}if(n.stop("Analysis complete."),o.length===0)return de.info(ie.yellow("No valid ELF shared libraries found.")),!0;let s=o.filter(l=>!l.compatible),a=o.filter(l=>l.compatible);if(de.info(ie.dim(`Checked ${o.length} native librar${o.length===1?"y":"ies"}
1768
1768
  `)),s.length>0){de.info(ie.red.bold(`Incompatible libraries:
1769
- `));for(let l of s)de.error(ie.red(`${ie.bold(l.name)} ${ie.dim(`(${l.arch})`)}`)),de.info(ie.dim(` PT_LOAD alignment: 2**${Math.log2(l.align)} (${l.align} bytes, needs 2**14 = ${Jl})`))}return a.length>0&&(console.log(""),de.success(ie.green(`${a.length} librar${a.length===1?"y":"ies"} correctly aligned (2**14 or higher).`))),console.log(""),s.length===0?(de.success(ie.green.bold("ELF Verification Successful. APK is 16KB compatible.")),!0):(de.error(ie.red.bold(`Found ${s.length} unaligned lib${s.length===1?"":"s"} (arm64-v8a/x86_64 libs need to be aligned).`)),console.log(""),de.info(ie.yellow("To fix this:")),de.info(ie.dim(" 1. Rebuild with NDK r28+ which defaults to 16KB page alignment")),de.info(ie.dim(" 2. Or set -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON in CMake")),de.info(ie.dim(" 3. Update third-party libraries that ship prebuilt .so files")),de.info(ie.dim(" 4. After rebuilding: zipalign -p -f -v 16 input.apk output.apk")),console.log(""),de.info(ie.dim("Reference: https://developer.android.com/guide/practices/page-sizes")),!1)}catch(r){return n.stop("Analysis failed."),de.error(ie.red(`Failed to analyze APK: ${r.message}`)),!1}finally{try{Ze.rmSync(i,{recursive:!0,force:!0})}catch{}}}function Wm(e){let t=Ze.openSync(e,"r");try{let n=Buffer.alloc(64);if(Ze.readSync(t,n,0,64,0),!n.subarray(0,4).equals(Km))return null;let i=n[4]===2,r=n[5]===1,o=(f,p)=>r?f.readUInt16LE(p):f.readUInt16BE(p),s=(f,p)=>r?f.readUInt32LE(p):f.readUInt32BE(p),a=(f,p)=>Number(r?f.readBigUInt64LE(p):f.readBigUInt64BE(p)),l,d,c;i?(l=a(n,32),d=o(n,54),c=o(n,56)):(l=s(n,28),d=o(n,42),c=o(n,44));let u=null;for(let f=0;f<c;f++){let p=Buffer.alloc(d);if(Ze.readSync(t,p,0,d,l+f*d),s(p,0)!==zm)continue;let h;i?h=a(p,48):h=s(p,28),h>0&&(u===null||h<u)&&(u=h)}return u??0}catch{return null}finally{Ze.closeSync(t)}}function Xl(e){let t=[];if(!Ze.existsSync(e))return t;let n=Ze.readdirSync(e,{withFileTypes:!0});for(let i of n){let r=Ut.join(e,i.name);i.isDirectory()?t.push(...Xl(r)):i.name.endsWith(".so")&&t.push(r)}return t}function qm(e){return e.includes("arm64-v8a")?"arm64-v8a":e.includes("x86_64")?"x86_64":"unknown"}var ed=async e=>{if(be()||(Ce.error(Be.red(`You are not logged in. Run \`${m.nameLower} login\` first.`)),process.exit(1)),e.apk){await Xm(e);return}let n=process.cwd(),i=Ti.join(n,"package.json");Rn.existsSync(i)||(Ce.error(Be.red("No package.json found. Run this command from a project root.")),process.exit(1));let r=JSON.parse(Rn.readFileSync(i,"utf-8")),o=!!(r.dependencies?.expo||r.devDependencies?.expo);e.json||(Ce.info(Be.dim(`Project: ${r.name||"unknown"} v${r.version||"0.0.0"}`)),Ce.info(Be.dim(`Type: ${o?"Expo":"Bare React Native"}`)),Ce.info(""));let s={json:e.json,fix:e.fix,category:e.category,severity:e.severity,prebuild:e.prebuild},a=await Kl(n,s);e.json?console.log(JSON.stringify(ql(a,r),null,2)):Wl(a,e.severity);let l=a.some(c=>c.findings.some(u=>u.severity==="critical")),d=a.some(c=>c.findings.some(u=>u.severity==="high"));(l||d)&&process.exit(1)},Zl=["16kb"];async function Xm(e){let t=e.category?.toLowerCase();t&&!Zl.includes(t)&&(Ce.error(Be.red(`Unknown APK check category: "${t}"`)),Ce.info(Be.dim(`Available APK checks: ${Zl.join(", ")}`)),process.exit(1));let n=await Zm(e.apk);n||process.exit(1);let i=!t,r=!1;(i||t==="16kb")&&(await Yl(n)||(r=!0)),r&&process.exit(1)}async function Zm(e){if(e.startsWith("build:")){let n=e.slice(6);return await Qm(n)}if(e.startsWith("http://")||e.startsWith("https://"))return await td(e);let t=Ti.resolve(e);return Rn.existsSync(t)?t:(Ce.error(Be.red(`APK file not found: ${t}`)),null)}async function Qm(e){let t=Ql();t.start(`Fetching APK from build ${e}...`);try{let n=await $.get(`/build/${e}`);if(n.data.status!=="success")throw new Error(n.data.message);let i=n.data.build;if(!i)throw new Error("Build not found");let r=i.artifacts?.find(o=>o.type?o.type==="apk":o.name?.endsWith(".apk")||o.url?.includes(".apk"));return!r||!r.url?(t.stop("No APK artifact found"),Ce.error(Be.red("This build does not have an APK artifact.")),Ce.info(Be.dim("Make sure the build produced an APK (not just an AAB).")),null):(t.stop(`Found build: ${i.buildId||e}`),await td(r.url))}catch(n){return t.stop("Failed to fetch build"),Ce.error(Be.red(n.message)),null}}async function td(e){let t=Ql();t.start("Downloading APK...");try{let n=Rn.mkdtempSync(Ti.join(Jm.tmpdir(),`${m.nameLower}-audit-`)),i=Ti.join(n,"app.apk"),r=await Ym.get(e,{responseType:"arraybuffer"});Rn.writeFileSync(i,r.data);let o=(r.data.length/(1024*1024)).toFixed(1);return t.stop(`Downloaded APK (${o} MB)`),i}catch(n){return t.stop("Download failed"),Ce.error(Be.red(`Failed to download APK: ${n.message}`)),null}}var ng=console.log;console.log=()=>{};tg();console.log=ng;X(J.bgCyan.black(m.cliTag("Production Build Orchestrator")));var On=(e,t=[])=>t.concat(e),M=new eg;M.name(m.nameLower).description(`${m.name} CLI: Powerful Cloud Infrastructure Tools`).version(et).option("-y, --yes","Automatically answer yes to all prompts",!1).option("--quiet","Suppress non-essential output",!1);M.command("agent").description("Manage local device discovery agent for the Install Hub (port 7070)").argument("[action]","start, run, install, status, restart, stop, or uninstall","start").action(async e=>{await ha(e)});M.command("host").description("Setup AWS S3 static hosting and CloudFront").action(async()=>{X(J.bgCyan.black(m.cliTag("Hosting"))),await _o()});M.command("sitemap").description("Generate sitemap.xml from Expo Router app structure").option("-o, --output <path>","Output path for sitemap.xml","./public/sitemap.xml").action(async e=>{X(J.bgCyan.black(m.cliTag("Sitemap Generator"))),await Do(e)});M.command("build").description("Run a build on a cloud provider (AWS Spot Instances)").argument("[platform]","Target platform (android, ios)").option("--platform <os>","Target platform alias (android, ios) [Optional]").option("--repo <url>","Git Repository URL").option("--branch <name>","Git Branch").option("--ami <id>","AMI ID").option("--bucket <name>","S3 Bucket for artifacts").option("--region <region>","AWS Region").option("--aws-profile <name>","AWS Credentials Profile").option("-p, --build-profile <name>","Build Profile (e.g. production, staging)").option("--profile <name>","Build Profile (alias for --build-profile)").option("--dry-run","Generate User Data script without launching").option("--keep-instance","Do not terminate the instance after build").option("--subnet <id>","VPC Subnet ID to launch the instance in").option("--security-group <id>","VPC Security Group ID to use").option("--ssh-host <host>","Remote host for iOS build (SSH)").option("--ssh-user <user>","SSH username for remote host").option("--ssh-key <path>","Path to private SSH key for remote host").option("--ios-scheme <scheme>","iOS Scheme to build").option("--ios-team-id <id>","Apple Development Team ID").option("--ios-configuration <config>","Xcode configuration (Release/Debug)").option("--ios-export-method <method>","Export method (ad-hoc, app-store, development, enterprise)").option("--ios-api-key-id <id>","App Store Connect API Key ID").option("--ios-api-key-issuer <id>","App Store Connect API Key Issuer ID").option("--ios-api-key-path <path>","Path to App Store Connect API Key (.p8) file").option("--simulator","Build for iOS Simulator (no signing required)").addOption(new Te("--build-id <id>","Internal build ID").hideHelp()).addOption(new Te("--project-id <id>","Internal project ID").hideHelp()).addOption(new Te("--fail-only","Internal: mark an existing build failed").hideHelp()).addOption(new Te("--error <message>","Internal failure message").hideHelp()).option("--local","Run build on local machine").option("--auto-version","Assign the next Android versionCode or iOS buildNumber from Mach").option("--auto-submit","Submit this build after it completes successfully").option("--submit-track <track>","Google Play track to use with --auto-submit").option("--submit-release-status <status>","Google Play release status to use with --auto-submit").option("--submit-rollout <fraction>","Google Play staged rollout fraction to use with --auto-submit").option("--submit-changes-not-sent-for-review","Commit Google Play changes without automatically sending them for review when using --auto-submit").option("--submit-credential-id <id>","Service credential ID to use with --auto-submit").option("--submit-json-output <path>","Write auto-submit metadata JSON to a file for CI/CD").option("--verbose","Enable verbose logging").option("--json-output <path>","Write build metadata JSON to a file for CI/CD").option("--maestro","Queue a managed Maestro test run after a successful build").option("--maestro-flows <path>","Maestro flow file or directory (default: .maestro)").option("--maestro-device <device>","iOS simulator model or identifier (default: iPhone 17 Pro; managed Android uses Pixel 6)").option("--maestro-retries <n>","Retries for the Maestro run","1").option("--maestro-record","Enable screen recording where supported").option("--maestro-use-build-source","Use Maestro flows from the build source snapshot instead of uploading local flows").option("--maestro-env <name>","Forward an environment variable to the managed Maestro runner; repeat or comma-separate names",On,[]).option("-y, --yes","Automatically answer yes to all prompts",!1).option("--quiet","Suppress non-essential output",!1).action(async(e,t)=>{let n=M.opts();t.yes=t.yes||n.yes,t.quiet=t.quiet||n.quiet,t.platform=e||t.platform,t.buildProfile=t.profile||t.buildProfile,t.quiet||X(J.bgCyan.black(m.cliTag("Cloud Build"))),await Jn(t)});M.command("maestro").description("Run Maestro tests locally or with the managed Mach runner").option("--platform <os>","Target platform (android/ios)").option("-p, --profile <name>","Build profile to resolve when using --latest","production").option("--latest","Use the latest successful build for the platform/profile").option("--build-id <id>","Use a specific Mach build ID").option("--build-url <url>","Use a Mach build URL").option("--artifact-url <url>","Use a direct APK or iOS simulator app artifact URL").option("--local","Run Maestro on a connected local emulator/device instead of the managed runner").option("--maestro-flows <path>","Maestro flow file or directory (default: .maestro)").option("--maestro-device <device>","iOS simulator model or identifier (default: iPhone 17 Pro; managed Android uses Pixel 6)").option("--maestro-retries <n>","Retries for the Maestro run","1").option("--maestro-record","Enable screen recording where supported").option("--maestro-use-build-source","Use Maestro flows from the build source snapshot instead of uploading local flows").option("--maestro-env <name>","Forward an environment variable to the managed Maestro runner; repeat or comma-separate names",On,[]).option("--wait","Wait for managed Maestro completion and exit non-zero on failure").option("--wait-timeout <minutes>","Maximum minutes to wait for managed Maestro completion","60").option("--wait-interval <seconds>","Polling interval while waiting for managed Maestro completion","15").option("--json-output <path>","Write test run metadata JSON to a file for CI/CD").addOption(new Te("--local-runner","Internal: execute a managed Maestro run on this machine").hideHelp()).addOption(new Te("--test-run-id <id>","Internal test run ID").hideHelp()).addOption(new Te("--project-id <id>","Internal project ID").hideHelp()).addOption(new Te("--runner-token <token>","Internal runner token").hideHelp()).action(async e=>{X(J.bgCyan.black(m.cliTag("Maestro Testing"))),await Qo(e)});var Ft=e=>e.option("--platform <os>","Target platform: ios, android, or all","all").option("--channel <name>","OTA channel (for example: production, staging)").option("--branch <name>","Alias for --channel").option("--runtime-version <version>","Runtime version override").option("--message <text>","Release note/message for this OTA update").option("--framework <name>","Framework override: expo or react-native").option("--engine <name>","OTA engine override (currently expo-updates)").option("--url <url>","Mach OTA update URL override").option("--install-plugin","Install @radhya/mach locally for the Expo config plugin").option("--skip-install","Do not install local Expo plugin dependency").option("--update-id <id>","OTA update id for rollback/promote").option("--json","Print JSON output"),Bt=M.command("ota").description("Setup, publish, verify, and manage Mach OTA updates");Ft(Bt.command("setup").description("Configure OTA for this project")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Setup"))),await at("setup",{...e,yes:e.yes||t.yes})});Ft(Bt.command("publish").description("Publish an OTA update")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Publish"))),await at("publish",{...e,yes:e.yes||t.yes})});Ft(Bt.command("verify").description("Verify OTA configuration")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Verify"))),await at("verify",{...e,yes:e.yes||t.yes})});Ft(Bt.command("list").description("List OTA updates for the linked project")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Updates"))),await at("list",{...e,yes:e.yes||t.yes})});Ft(Bt.command("rollback").description("Roll back an OTA update")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Rollback"))),await at("rollback",{...e,yes:e.yes||t.yes})});Ft(Bt.command("promote").description("Promote an OTA update")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Promote"))),await at("promote",{...e,yes:e.yes||t.yes})});M.command("submit").description("Automated Store Submission (App Store / Google Play)").option("--platform <os>","Target platform (ios/android)").option("-p, --profile <name>","Build/submission profile to submit from (e.g. production, preprod)").option("--track <track>","Google Play Track (internal, alpha, beta, production)").option("--release-status <status>","Google Play release status (completed, draft, halted, inProgress)").option("--rollout <fraction>","Google Play staged rollout fraction for inProgress releases (example: 0.1)").option("--changes-not-sent-for-review","Commit Google Play changes without automatically sending them for review").option("--ssh-host <host>","Remote macOS host for iOS submission").option("--ssh-user <user>","SSH username for remote iOS submission").option("--ssh-key <path>","Path to private SSH key for remote iOS submission").option("--credential-id <id>","Service credential ID to use when multiple submission credentials exist").option("--local","Run submission on this machine (internal runner mode for iOS)").addOption(new Te("--submit-id <id>","Internal submission ID").hideHelp()).addOption(new Te("--project-id <id>","Internal project ID").hideHelp()).addOption(new Te("--package-name <name>","Internal Android package name").hideHelp()).addOption(new Te("--bundle-id <id>","Internal iOS bundle identifier").hideHelp()).option("--json-output <path>","Write submission metadata JSON to a file for CI/CD").option("--latest","Use the latest successful build for submission").option("--build-id <id>","Use a specific build ID for submission").action(async e=>{let t=M.opts();e.quiet=e.quiet||t.quiet,e.yes=e.yes||t.yes,X(J.bgCyan.black(m.cliTag("Store Submission"))),await Vn(e)});M.command("login").description(`Login to ${m.name} Dashboard`).action(async()=>{X(J.bgCyan.black(m.cliTag("Login"))),await Sa()});M.command("logout").description(`Logout from ${m.name} on this machine`).action(async()=>{X(J.bgCyan.black(m.cliTag("Logout"))),await Ea()});M.command("link").description(`Link local directory to a ${m.name} Project`).action(async()=>{X(J.bgCyan.black(m.cliTag("Link Project"))),await wa()});M.command("me").description("Display currently logged in user details").action(async()=>{await Wa()});M.command("init").description(`Create a new ${m.name} Project`).action(async()=>{X(J.bgCyan.black(m.cliTag("Init Project"))),await va()});M.command("env").description("Manage Environment Variables").argument("<action>","Action to perform: set, list, pull, download, or export").argument("[args...]","Key=Value pairs for set action").option("-e, --environment <name>","Environment to pull/download","development").option("-o, --out <file>","Output file for pull/download",".env.local").option("--overwrite","Overwrite output file if it already exists").action(async(e,t,n)=>{X(J.bgCyan.black(m.cliTag("Env Manager"))),await $a(e,t,n)});M.command("start").description("Start the development server (Metro)").option("-p, --build-profile <name>","Build profile (e.g. development, staging)","development").option("--tunnel","Use ngrok tunnel").option("--lan","Use LAN IP").option("--localhost","Use localhost").option("-c, --clear","Clear Metro cache").option("--port <number>","Port to listen on").option("--ios","Start on iOS").option("--android","Start on Android").option("--web","Start on Web").action(async e=>{X(J.bgCyan.black(m.cliTag("Dev Server"))),await Ja(e)});var Dn=M.command("push").description("Configure and send provider-direct APNs/FCM notifications");Dn.command("setup").description("Install and wire a working default push experience").option("--name <name>","Push app display name").option("--ios-bundle <id>","iOS bundle identifier").option("--android-package <name>","Android package name").option("-e, --environment <name>","development, preview, or production").option("--google-services-file <path>","Android google-services.json path").option("--skip-install","Generate setup without installing SDK dependencies").action(Eo);Dn.command("init").description("Create only the server-side push app (advanced)").option("--name <name>","Push app display name").option("--ios-bundle <id>","iOS bundle identifier").option("--android-package <name>","Android package name").option("-e, --environment <name>","development, preview, or production","production").option("--google-services-file <path>","Expo Android google-services.json path").action(So);var id=Dn.command("credentials").description("Configure provider credentials");id.command("apns").description("Configure an Apple APNs .p8 authentication key").requiredOption("--file <path>","APNs .p8 file").requiredOption("--team-id <id>","Apple Developer team ID").requiredOption("--key-id <id>","APNs key ID").option("--bundle-id <id>","iOS bundle identifier").option("--app <id>","MACH Push app ID").option("-e, --environment <name>","development, preview, or production").action(e=>Bi("apns",e));id.command("fcm").description("Configure a Firebase service-account JSON file").requiredOption("--file <path>","Firebase service-account JSON").option("--app <id>","MACH Push app ID").option("-e, --environment <name>","Deprecated; accepted for compatibility because FCM credentials are package-wide").action(e=>Bi("fcm",e));Dn.command("send").description("Queue one transient push notification").requiredOption("--title <text>","Notification title").requiredOption("--body <text>","Notification body").option("--app <id>","MACH Push app ID").option("-e, --environment <name>","development, preview, or production").option("--token <token>","MACH push token; repeatable",On,[]).option("--user <id>","Application user ID; repeatable",On,[]).option("--all","Send to all active devices").option("--platform <platform>","Limit --all to ios or android").option("--data <json>","String-to-string custom data JSON").option("--sound <name>","Provider sound name").option("--badge <number>","iOS badge count").option("--ttl <seconds>","Provider time-to-live").option("--collapse-key <key>","Provider collapse key").option("--android-channel-id <id>","Android notification channel").action(Io);Dn.command("status").description("Show aggregate push delivery counters").option("--days <number>","Statistics range, 1-90","30").action(wo);M.command("config").description("Show resolved configuration for a profile").option("-p, --profile <name>","Build profile to resolve","development").option("--json","Output as JSON").action(async e=>{await Ya(e)});var rd=M.command("version").description("Show or seed DB-owned native version counters"),od=e=>e.requiredOption("--platform <os>","Target platform: ios or android").option("-p, --profile <name>","Build profile used to resolve package/bundle scope","production").option("--scope <value>","Counter scope override, usually package name or bundle identifier").option("--package <name>","Android package override").option("--bundle-id <id>","iOS bundle identifier override").option("--json","Print JSON output");od(rd.command("show").description("Show the current native version counter")).action(async e=>{X(J.bgCyan.black(m.cliTag("Version Counter"))),await no("show",e)});od(rd.command("seed").description("Seed the native version counter for an existing app").argument("[value]","Latest already-used value; the next build uses value + 1").option("--value <number>","Latest already-used value; the next build uses value + 1").option("--force","Allow lowering an existing counter")).action(async(e,t)=>{X(J.bgCyan.black(m.cliTag("Version Counter"))),await no("seed",{...t,value:t.value??e})});var sd=M.command("deeplink").description("Configure and verify app links, universal links, and URI schemes");sd.command("setup").description("Generate deep link config, hosted association files, and Expo plugin support").option("--domain <domain>","Associated domain, e.g. app.example.com").option("--base-url <url>","Base URL, e.g. https://app.example.com").option("-p, --profile <name>","Profile used for build/submit overrides").option("--platform <platform>","ios, android, or all").option("--framework <framework>","expo or react-native").option("--scheme <scheme>","URI scheme, e.g. myapp").option("--ios-bundle-id <id>","iOS bundle identifier").option("--android-package <name>","Android package name").option("--apple-team-id <id>","Apple Developer Team ID").option("--app-store-id <id>","App Store app ID for Smart App Banner").option("--android-fingerprint <sha256>","Android SHA256 signing certificate fingerprint; repeatable",On,[]).option("--output <dir>","Directory for hosted files, e.g. public or deep-links").option("--install-plugin","Install @radhya/mach locally so Expo can use the packaged config plugin").option("--no-install-plugin","Do not install @radhya/mach for Expo projects; use the local plugin fallback if the package is missing").option("-y, --yes","Automatically answer yes to prompts",!1).action(async e=>{let t=M.opts();e.yes=e.yes||t.yes,X(J.bgCyan.black(m.cliTag("Deep Links"))),await bl(e)});sd.command("verify").description("Verify local and optionally live deep link configuration").option("-p, --profile <name>","Profile used for build/submit overrides").option("--live","Check hosted files over HTTPS").option("--android-device","Print Android device verification commands").action(async e=>{X(J.bgCyan.black(m.cliTag("Deep Link Verify"))),await Al(e)});M.command("credentials").description("Unified, interactive credential management (iOS/Android)").option("-p, --profile <name>","Build profile (production, staging, development)").option("--force","Force recreate certificates (nuke existing on Apple Portal)",!1).action(async e=>{let{credentialsMainCommand:t}=await import("./credentials-7RCDD7VB.js");await t(e)});M.command("credentials:setup").description("Automated credential provisioning (iOS/Android) [Legacy]").requiredOption("--platform <os>","Platform: ios or android").option("--profile <name>","Build profile (production, staging, development)").option("--bundle-id <id>","Bundle ID / Package Name (optional, auto-detected)").option("--team-id <id>","Apple Team ID (iOS only)").option("--key-alias <alias>","Android keystore alias (optional, auto-generated)").option("--aws-profile <name>","AWS Credentials Profile (for S3 storage)").option("--force","Force recreate certificates (nuke existing on Apple Portal)",!1).action(async e=>{X(J.bgCyan.black(m.cliTag("Credentials Setup"))),await jt(e),nd(J.green("Done!"))});M.command("credentials:service").description("Upload Service Credentials (ASC API Key / Google Service JSON) [Legacy]").requiredOption("--platform <os>","Platform: ios or android").option("--file <path>","Path to credential file (.p8 or .json)").option("--issuer-id <id>","ASC API Key Issuer ID (iOS only)").option("--key-id <id>","ASC API Key ID (iOS only)").option("--bundle-id <id>","Bundle identifier / Android package name to attach this service credential to").option("--package-name <name>","Android package name to attach this service credential to").option("-p, --profile <name>","Build profile to resolve package/bundle identifier from config").action(async e=>{X(J.bgCyan.black(m.cliTag("Service Credentials"))),await Ao(e),nd(J.green("Done!"))});var so=M.command("device").description("Manage registered iOS test devices");so.command("register").description("Register a connected iOS device or enter UDID manually").option("--udid <udid>","Device UDID (skip auto-detection)").option("--name <name>","Device name").option("--team-id <id>","Apple Developer Team ID for this device").action(async e=>{await Ii("register",e)});so.command("list").description("List all registered devices").option("--team-id <id>","Filter by Apple Developer Team ID").action(async e=>{await Ii("list",e)});so.command("remove").description("Remove a registered device").option("--udid <udid>","Device UDID to remove").option("--team-id <id>","Apple Developer Team ID for this device").action(async e=>{await Ii("remove",e)});M.command("audit").description("Run automated security audit on the project or APK").option("--apk <path>","Path to APK file (runs APK diagnostics like 16KB alignment)").option("--json","Output results as JSON (for CI/CD)").option("--fix","Auto-apply fixes where possible").option("--category <name>","Run only a specific check category (e.g. 16kb, permissions, secrets)").option("--severity <level>","Minimum severity to display (critical, high, medium, low, info)").option("--prebuild","Run expo prebuild for deeper manifest/plist analysis").action(async e=>{X(J.bgCyan.black(m.cliTag(e.apk?"APK Audit":"Security Audit"))),await ed(e)});var ig=new Set(["login","logout","agent"]);M.hook("preAction",(e,t)=>{let n=t.name(),i=t.opts?.()||{};n==="maestro"&&(i.local||i.localRunner)||t.parent?.name()!=="deeplink"&&(ig.has(n)||Et())});M.on("command:*",()=>{console.error(`Invalid command: %s
1769
+ `));for(let l of s)de.error(ie.red(`${ie.bold(l.name)} ${ie.dim(`(${l.arch})`)}`)),de.info(ie.dim(` PT_LOAD alignment: 2**${Math.log2(l.align)} (${l.align} bytes, needs 2**14 = ${Jl})`))}return a.length>0&&(console.log(""),de.success(ie.green(`${a.length} librar${a.length===1?"y":"ies"} correctly aligned (2**14 or higher).`))),console.log(""),s.length===0?(de.success(ie.green.bold("ELF Verification Successful. APK is 16KB compatible.")),!0):(de.error(ie.red.bold(`Found ${s.length} unaligned lib${s.length===1?"":"s"} (arm64-v8a/x86_64 libs need to be aligned).`)),console.log(""),de.info(ie.yellow("To fix this:")),de.info(ie.dim(" 1. Rebuild with NDK r28+ which defaults to 16KB page alignment")),de.info(ie.dim(" 2. Or set -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON in CMake")),de.info(ie.dim(" 3. Update third-party libraries that ship prebuilt .so files")),de.info(ie.dim(" 4. After rebuilding: zipalign -p -f -v 16 input.apk output.apk")),console.log(""),de.info(ie.dim("Reference: https://developer.android.com/guide/practices/page-sizes")),!1)}catch(r){return n.stop("Analysis failed."),de.error(ie.red(`Failed to analyze APK: ${r.message}`)),!1}finally{try{Ze.rmSync(i,{recursive:!0,force:!0})}catch{}}}function Wm(e){let t=Ze.openSync(e,"r");try{let n=Buffer.alloc(64);if(Ze.readSync(t,n,0,64,0),!n.subarray(0,4).equals(Km))return null;let i=n[4]===2,r=n[5]===1,o=(f,p)=>r?f.readUInt16LE(p):f.readUInt16BE(p),s=(f,p)=>r?f.readUInt32LE(p):f.readUInt32BE(p),a=(f,p)=>Number(r?f.readBigUInt64LE(p):f.readBigUInt64BE(p)),l,d,c;i?(l=a(n,32),d=o(n,54),c=o(n,56)):(l=s(n,28),d=o(n,42),c=o(n,44));let u=null;for(let f=0;f<c;f++){let p=Buffer.alloc(d);if(Ze.readSync(t,p,0,d,l+f*d),s(p,0)!==zm)continue;let h;i?h=a(p,48):h=s(p,28),h>0&&(u===null||h<u)&&(u=h)}return u??0}catch{return null}finally{Ze.closeSync(t)}}function Xl(e){let t=[];if(!Ze.existsSync(e))return t;let n=Ze.readdirSync(e,{withFileTypes:!0});for(let i of n){let r=Ut.join(e,i.name);i.isDirectory()?t.push(...Xl(r)):i.name.endsWith(".so")&&t.push(r)}return t}function qm(e){return e.includes("arm64-v8a")?"arm64-v8a":e.includes("x86_64")?"x86_64":"unknown"}var ed=async e=>{if(be()||(Ce.error(Be.red(`You are not logged in. Run \`${m.nameLower} login\` first.`)),process.exit(1)),e.apk){await Xm(e);return}let n=process.cwd(),i=Ti.join(n,"package.json");Rn.existsSync(i)||(Ce.error(Be.red("No package.json found. Run this command from a project root.")),process.exit(1));let r=JSON.parse(Rn.readFileSync(i,"utf-8")),o=!!(r.dependencies?.expo||r.devDependencies?.expo);e.json||(Ce.info(Be.dim(`Project: ${r.name||"unknown"} v${r.version||"0.0.0"}`)),Ce.info(Be.dim(`Type: ${o?"Expo":"Bare React Native"}`)),Ce.info(""));let s={json:e.json,fix:e.fix,category:e.category,severity:e.severity,prebuild:e.prebuild},a=await Kl(n,s);e.json?console.log(JSON.stringify(ql(a,r),null,2)):Wl(a,e.severity);let l=a.some(c=>c.findings.some(u=>u.severity==="critical")),d=a.some(c=>c.findings.some(u=>u.severity==="high"));(l||d)&&process.exit(1)},Zl=["16kb"];async function Xm(e){let t=e.category?.toLowerCase();t&&!Zl.includes(t)&&(Ce.error(Be.red(`Unknown APK check category: "${t}"`)),Ce.info(Be.dim(`Available APK checks: ${Zl.join(", ")}`)),process.exit(1));let n=await Zm(e.apk);n||process.exit(1);let i=!t,r=!1;(i||t==="16kb")&&(await Yl(n)||(r=!0)),r&&process.exit(1)}async function Zm(e){if(e.startsWith("build:")){let n=e.slice(6);return await Qm(n)}if(e.startsWith("http://")||e.startsWith("https://"))return await td(e);let t=Ti.resolve(e);return Rn.existsSync(t)?t:(Ce.error(Be.red(`APK file not found: ${t}`)),null)}async function Qm(e){let t=Ql();t.start(`Fetching APK from build ${e}...`);try{let n=await $.get(`/build/${e}`);if(n.data.status!=="success")throw new Error(n.data.message);let i=n.data.build;if(!i)throw new Error("Build not found");let r=i.artifacts?.find(o=>o.type?o.type==="apk":o.name?.endsWith(".apk")||o.url?.includes(".apk"));return!r||!r.url?(t.stop("No APK artifact found"),Ce.error(Be.red("This build does not have an APK artifact.")),Ce.info(Be.dim("Make sure the build produced an APK (not just an AAB).")),null):(t.stop(`Found build: ${i.buildId||e}`),await td(r.url))}catch(n){return t.stop("Failed to fetch build"),Ce.error(Be.red(n.message)),null}}async function td(e){let t=Ql();t.start("Downloading APK...");try{let n=Rn.mkdtempSync(Ti.join(Jm.tmpdir(),`${m.nameLower}-audit-`)),i=Ti.join(n,"app.apk"),r=await Ym.get(e,{responseType:"arraybuffer"});Rn.writeFileSync(i,r.data);let o=(r.data.length/(1024*1024)).toFixed(1);return t.stop(`Downloaded APK (${o} MB)`),i}catch(n){return t.stop("Download failed"),Ce.error(Be.red(`Failed to download APK: ${n.message}`)),null}}var ng=console.log;console.log=()=>{};tg();console.log=ng;X(J.bgCyan.black(m.cliTag("Production Build Orchestrator")));var On=(e,t=[])=>t.concat(e),M=new eg;M.name(m.nameLower).description(`${m.name} CLI: Powerful Cloud Infrastructure Tools`).version(et).option("-y, --yes","Automatically answer yes to all prompts",!1).option("--quiet","Suppress non-essential output",!1);M.command("agent").description("Manage local device discovery agent for the Install Hub (port 7070)").argument("[action]","start, run, install, status, restart, stop, or uninstall","start").action(async e=>{await ha(e)});M.command("host").description("Setup AWS S3 static hosting and CloudFront").action(async()=>{X(J.bgCyan.black(m.cliTag("Hosting"))),await _o()});M.command("sitemap").description("Generate sitemap.xml from Expo Router app structure").option("-o, --output <path>","Output path for sitemap.xml","./public/sitemap.xml").action(async e=>{X(J.bgCyan.black(m.cliTag("Sitemap Generator"))),await Do(e)});M.command("build").description("Run a build on a cloud provider (AWS Spot Instances)").argument("[platform]","Target platform (android, ios)").option("--platform <os>","Target platform alias (android, ios) [Optional]").option("--repo <url>","Git Repository URL").option("--branch <name>","Git Branch").option("--ami <id>","AMI ID").option("--bucket <name>","S3 Bucket for artifacts").option("--region <region>","AWS Region").option("--aws-profile <name>","AWS Credentials Profile").option("-p, --build-profile <name>","Build Profile (e.g. production, staging)").option("--profile <name>","Build Profile (alias for --build-profile)").option("--dry-run","Generate User Data script without launching").option("--keep-instance","Do not terminate the instance after build").option("--subnet <id>","VPC Subnet ID to launch the instance in").option("--security-group <id>","VPC Security Group ID to use").option("--ssh-host <host>","Remote host for iOS build (SSH)").option("--ssh-user <user>","SSH username for remote host").option("--ssh-key <path>","Path to private SSH key for remote host").option("--ios-scheme <scheme>","iOS Scheme to build").option("--ios-team-id <id>","Apple Development Team ID").option("--ios-configuration <config>","Xcode configuration (Release/Debug)").option("--ios-export-method <method>","Export method (ad-hoc, app-store, development, enterprise)").option("--ios-api-key-id <id>","App Store Connect API Key ID").option("--ios-api-key-issuer <id>","App Store Connect API Key Issuer ID").option("--ios-api-key-path <path>","Path to App Store Connect API Key (.p8) file").option("--simulator","Build for iOS Simulator (no signing required)").addOption(new Te("--build-id <id>","Internal build ID").hideHelp()).addOption(new Te("--project-id <id>","Internal project ID").hideHelp()).addOption(new Te("--fail-only","Internal: mark an existing build failed").hideHelp()).addOption(new Te("--error <message>","Internal failure message").hideHelp()).option("--local","Run build on local machine").option("--auto-version","Assign the next Android versionCode or iOS buildNumber from Mach").option("--auto-submit","Submit this build after it completes successfully").option("--submit-track <track>","Google Play track to use with --auto-submit").option("--submit-release-status <status>","Google Play release status to use with --auto-submit").option("--submit-rollout <fraction>","Google Play staged rollout fraction to use with --auto-submit").option("--submit-changes-not-sent-for-review","Commit Google Play changes without automatically sending them for review when using --auto-submit").option("--submit-credential-id <id>","Service credential ID to use with --auto-submit").option("--submit-json-output <path>","Write auto-submit metadata JSON to a file for CI/CD").option("--verbose","Enable verbose logging").option("--json-output <path>","Write build metadata JSON to a file for CI/CD").option("--maestro","Queue a managed Maestro test run after a successful build").option("--maestro-flows <path>","Maestro flow file or directory (default: .maestro)").option("--maestro-device <device>","iOS simulator model or identifier (default: iPhone 17 Pro; managed Android uses Pixel 6)").option("--maestro-retries <n>","Retries for the Maestro run","1").option("--maestro-record","Enable screen recording where supported").option("--maestro-use-build-source","Use Maestro flows from the build source snapshot instead of uploading local flows").option("--maestro-env <name>","Forward an environment variable to the managed Maestro runner; repeat or comma-separate names",On,[]).option("-y, --yes","Automatically answer yes to all prompts",!1).option("--quiet","Suppress non-essential output",!1).action(async(e,t)=>{let n=M.opts();t.yes=t.yes||n.yes,t.quiet=t.quiet||n.quiet,t.platform=e||t.platform,t.buildProfile=t.profile||t.buildProfile,t.quiet||X(J.bgCyan.black(m.cliTag("Cloud Build"))),await Jn(t)});M.command("maestro").description("Run Maestro tests locally or with the managed Mach runner").option("--platform <os>","Target platform (android/ios)").option("-p, --profile <name>","Build profile to resolve when using --latest","production").option("--latest","Use the latest successful build for the platform/profile").option("--build-id <id>","Use a specific Mach build ID").option("--build-url <url>","Use a Mach build URL").option("--artifact-url <url>","Use a direct APK or iOS simulator app artifact URL").option("--local","Run Maestro on a connected local emulator/device instead of the managed runner").option("--maestro-flows <path>","Maestro flow file or directory (default: .maestro)").option("--maestro-device <device>","iOS simulator model or identifier (default: iPhone 17 Pro; managed Android uses Pixel 6)").option("--maestro-retries <n>","Retries for the Maestro run","1").option("--maestro-record","Enable screen recording where supported").option("--maestro-use-build-source","Use Maestro flows from the build source snapshot instead of uploading local flows").option("--maestro-env <name>","Forward an environment variable to the managed Maestro runner; repeat or comma-separate names",On,[]).option("--wait","Wait for managed Maestro completion and exit non-zero on failure").option("--wait-timeout <minutes>","Maximum minutes to wait for managed Maestro completion","60").option("--wait-interval <seconds>","Polling interval while waiting for managed Maestro completion","15").option("--json-output <path>","Write test run metadata JSON to a file for CI/CD").addOption(new Te("--local-runner","Internal: execute a managed Maestro run on this machine").hideHelp()).addOption(new Te("--test-run-id <id>","Internal test run ID").hideHelp()).addOption(new Te("--project-id <id>","Internal project ID").hideHelp()).addOption(new Te("--runner-token <token>","Internal runner token").hideHelp()).action(async e=>{X(J.bgCyan.black(m.cliTag("Maestro Testing"))),await Qo(e)});var Ft=e=>e.option("--platform <os>","Target platform: ios, android, or all","all").option("--channel <name>","OTA channel (for example: production, staging)").option("--branch <name>","Alias for --channel").option("--runtime-version <version>","Runtime version override").option("--message <text>","Release note/message for this OTA update").option("--framework <name>","Framework override: expo or react-native").option("--engine <name>","OTA engine override (currently expo-updates)").option("--url <url>","Mach OTA update URL override").option("--install-plugin","Install @radhya/mach locally for the Expo config plugin").option("--skip-install","Do not install local Expo plugin dependency").option("--update-id <id>","OTA update id for rollback/promote").option("--json","Print JSON output"),Bt=M.command("ota").description("Setup, publish, verify, and manage Mach OTA updates");Ft(Bt.command("setup").description("Configure OTA for this project")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Setup"))),await at("setup",{...e,yes:e.yes||t.yes})});Ft(Bt.command("publish").description("Publish an OTA update")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Publish"))),await at("publish",{...e,yes:e.yes||t.yes})});Ft(Bt.command("verify").description("Verify OTA configuration")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Verify"))),await at("verify",{...e,yes:e.yes||t.yes})});Ft(Bt.command("list").description("List OTA updates for the linked project")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Updates"))),await at("list",{...e,yes:e.yes||t.yes})});Ft(Bt.command("rollback").description("Roll back an OTA update")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Rollback"))),await at("rollback",{...e,yes:e.yes||t.yes})});Ft(Bt.command("promote").description("Promote an OTA update")).action(async e=>{let t=M.opts();X(J.bgCyan.black(m.cliTag("OTA Promote"))),await at("promote",{...e,yes:e.yes||t.yes})});M.command("submit").description("Automated Store Submission (App Store / Google Play)").option("--platform <os>","Target platform (ios/android)").option("-p, --profile <name>","Build/submission profile to submit from (e.g. production, preprod)").option("--track <track>","Google Play Track (internal, alpha, beta, production)").option("--release-status <status>","Google Play release status (completed, draft, halted, inProgress)").option("--rollout <fraction>","Google Play staged rollout fraction for inProgress releases (example: 0.1)").option("--changes-not-sent-for-review","Commit Google Play changes without automatically sending them for review").option("--ssh-host <host>","Remote macOS host for iOS submission").option("--ssh-user <user>","SSH username for remote iOS submission").option("--ssh-key <path>","Path to private SSH key for remote iOS submission").option("--credential-id <id>","Service credential ID to use when multiple submission credentials exist").option("--local","Run submission on this machine (internal runner mode for iOS)").addOption(new Te("--submit-id <id>","Internal submission ID").hideHelp()).addOption(new Te("--project-id <id>","Internal project ID").hideHelp()).addOption(new Te("--package-name <name>","Internal Android package name").hideHelp()).addOption(new Te("--bundle-id <id>","Internal iOS bundle identifier").hideHelp()).option("--json-output <path>","Write submission metadata JSON to a file for CI/CD").option("--latest","Use the latest successful build for submission").option("--build-id <id>","Use a specific build ID for submission").action(async e=>{let t=M.opts();e.quiet=e.quiet||t.quiet,e.yes=e.yes||t.yes,X(J.bgCyan.black(m.cliTag("Store Submission"))),await Vn(e)});M.command("login").description(`Login to ${m.name} Dashboard`).action(async()=>{X(J.bgCyan.black(m.cliTag("Login"))),await Sa()});M.command("logout").description(`Logout from ${m.name} on this machine`).action(async()=>{X(J.bgCyan.black(m.cliTag("Logout"))),await Ea()});M.command("link").description(`Link local directory to a ${m.name} Project`).action(async()=>{X(J.bgCyan.black(m.cliTag("Link Project"))),await wa()});M.command("me").description("Display currently logged in user details").action(async()=>{await Wa()});M.command("init").description(`Create a new ${m.name} Project`).action(async()=>{X(J.bgCyan.black(m.cliTag("Init Project"))),await va()});M.command("env").description("Manage Environment Variables").argument("<action>","Action to perform: set, list, pull, download, or export").argument("[args...]","Key=Value pairs for set action").option("-e, --environment <name>","Environment to pull/download","development").option("-o, --out <file>","Output file for pull/download",".env.local").option("--overwrite","Overwrite output file if it already exists").action(async(e,t,n)=>{X(J.bgCyan.black(m.cliTag("Env Manager"))),await $a(e,t,n)});M.command("start").description("Start the development server (Metro)").option("-p, --build-profile <name>","Build profile (e.g. development, staging)","development").option("--tunnel","Use ngrok tunnel").option("--lan","Use LAN IP").option("--localhost","Use localhost").option("-c, --clear","Clear Metro cache").option("--port <number>","Port to listen on").option("--ios","Start on iOS").option("--android","Start on Android").option("--web","Start on Web").action(async e=>{X(J.bgCyan.black(m.cliTag("Dev Server"))),await Ja(e)});var Dn=M.command("push").description("Configure and send provider-direct APNs/FCM notifications");Dn.command("setup").description("Install and wire a working default push experience").option("--name <name>","Push app display name").option("--ios-bundle <id>","iOS bundle identifier").option("--android-package <name>","Android package name").option("-e, --environment <name>","development, preview, or production").option("--google-services-file <path>","Android google-services.json path").option("--skip-install","Generate setup without installing SDK dependencies").action(Eo);Dn.command("init").description("Create only the server-side push app (advanced)").option("--name <name>","Push app display name").option("--ios-bundle <id>","iOS bundle identifier").option("--android-package <name>","Android package name").option("-e, --environment <name>","development, preview, or production","production").option("--google-services-file <path>","Expo Android google-services.json path").action(So);var id=Dn.command("credentials").description("Configure provider credentials");id.command("apns").description("Configure an Apple APNs .p8 authentication key").requiredOption("--file <path>","APNs .p8 file").requiredOption("--team-id <id>","Apple Developer team ID").requiredOption("--key-id <id>","APNs key ID").option("--bundle-id <id>","iOS bundle identifier").option("--app <id>","MACH Push app ID").option("-e, --environment <name>","development, preview, or production").action(e=>Bi("apns",e));id.command("fcm").description("Configure a Firebase service-account JSON file").requiredOption("--file <path>","Firebase service-account JSON").option("--app <id>","MACH Push app ID").option("-e, --environment <name>","Deprecated; accepted for compatibility because FCM credentials are package-wide").action(e=>Bi("fcm",e));Dn.command("send").description("Queue one transient push notification").requiredOption("--title <text>","Notification title").requiredOption("--body <text>","Notification body").option("--app <id>","MACH Push app ID").option("-e, --environment <name>","development, preview, or production").option("--token <token>","MACH push token; repeatable",On,[]).option("--user <id>","Application user ID; repeatable",On,[]).option("--all","Send to all active devices").option("--platform <platform>","Limit --all to ios or android").option("--data <json>","String-to-string custom data JSON").option("--sound <name>","Provider sound name").option("--badge <number>","iOS badge count").option("--ttl <seconds>","Provider time-to-live").option("--collapse-key <key>","Provider collapse key").option("--android-channel-id <id>","Android notification channel").action(Io);Dn.command("status").description("Show aggregate push delivery counters").option("--days <number>","Statistics range, 1-90","30").action(wo);M.command("config").description("Show resolved configuration for a profile").option("-p, --profile <name>","Build profile to resolve","development").option("--json","Output as JSON").action(async e=>{await Ya(e)});var rd=M.command("version").description("Show or seed DB-owned native version counters"),od=e=>e.requiredOption("--platform <os>","Target platform: ios or android").option("-p, --profile <name>","Build profile used to resolve package/bundle scope","production").option("--scope <value>","Counter scope override, usually package name or bundle identifier").option("--package <name>","Android package override").option("--bundle-id <id>","iOS bundle identifier override").option("--json","Print JSON output");od(rd.command("show").description("Show the current native version counter")).action(async e=>{X(J.bgCyan.black(m.cliTag("Version Counter"))),await no("show",e)});od(rd.command("seed").description("Seed the native version counter for an existing app").argument("[value]","Latest already-used value; the next build uses value + 1").option("--value <number>","Latest already-used value; the next build uses value + 1").option("--force","Allow lowering an existing counter")).action(async(e,t)=>{X(J.bgCyan.black(m.cliTag("Version Counter"))),await no("seed",{...t,value:t.value??e})});var sd=M.command("deeplink").description("Configure and verify app links, universal links, and URI schemes");sd.command("setup").description("Generate deep link config, hosted association files, and Expo plugin support").option("--domain <domain>","Associated domain, e.g. app.example.com").option("--base-url <url>","Base URL, e.g. https://app.example.com").option("-p, --profile <name>","Profile used for build/submit overrides").option("--platform <platform>","ios, android, or all").option("--framework <framework>","expo or react-native").option("--scheme <scheme>","URI scheme, e.g. myapp").option("--ios-bundle-id <id>","iOS bundle identifier").option("--android-package <name>","Android package name").option("--apple-team-id <id>","Apple Developer Team ID").option("--app-store-id <id>","App Store app ID for Smart App Banner").option("--android-fingerprint <sha256>","Android SHA256 signing certificate fingerprint; repeatable",On,[]).option("--output <dir>","Directory for hosted files, e.g. public or deep-links").option("--install-plugin","Install @radhya/mach locally so Expo can use the packaged config plugin").option("--no-install-plugin","Do not install @radhya/mach for Expo projects; use the local plugin fallback if the package is missing").option("-y, --yes","Automatically answer yes to prompts",!1).action(async e=>{let t=M.opts();e.yes=e.yes||t.yes,X(J.bgCyan.black(m.cliTag("Deep Links"))),await bl(e)});sd.command("verify").description("Verify local and optionally live deep link configuration").option("-p, --profile <name>","Profile used for build/submit overrides").option("--live","Check hosted files over HTTPS").option("--android-device","Print Android device verification commands").action(async e=>{X(J.bgCyan.black(m.cliTag("Deep Link Verify"))),await Al(e)});M.command("credentials").description("Unified, interactive credential management (iOS/Android)").option("-p, --profile <name>","Build profile (production, staging, development)").option("--force","Force recreate certificates (nuke existing on Apple Portal)",!1).action(async e=>{let{credentialsMainCommand:t}=await import("./credentials-SVICEIL5.js");await t(e)});M.command("credentials:setup").description("Automated credential provisioning (iOS/Android) [Legacy]").requiredOption("--platform <os>","Platform: ios or android").option("--profile <name>","Build profile (production, staging, development)").option("--bundle-id <id>","Bundle ID / Package Name (optional, auto-detected)").option("--team-id <id>","Apple Team ID (iOS only)").option("--key-alias <alias>","Android keystore alias (optional, auto-generated)").option("--aws-profile <name>","AWS Credentials Profile (for S3 storage)").option("--force","Force recreate certificates (nuke existing on Apple Portal)",!1).action(async e=>{X(J.bgCyan.black(m.cliTag("Credentials Setup"))),await jt(e),nd(J.green("Done!"))});M.command("credentials:service").description("Upload Service Credentials (ASC API Key / Google Service JSON) [Legacy]").requiredOption("--platform <os>","Platform: ios or android").option("--file <path>","Path to credential file (.p8 or .json)").option("--issuer-id <id>","ASC API Key Issuer ID (iOS only)").option("--key-id <id>","ASC API Key ID (iOS only)").option("--bundle-id <id>","Bundle identifier / Android package name to attach this service credential to").option("--package-name <name>","Android package name to attach this service credential to").option("-p, --profile <name>","Build profile to resolve package/bundle identifier from config").action(async e=>{X(J.bgCyan.black(m.cliTag("Service Credentials"))),await Ao(e),nd(J.green("Done!"))});var so=M.command("device").description("Manage registered iOS test devices");so.command("register").description("Register a connected iOS device or enter UDID manually").option("--udid <udid>","Device UDID (skip auto-detection)").option("--name <name>","Device name").option("--team-id <id>","Apple Developer Team ID for this device").action(async e=>{await Ii("register",e)});so.command("list").description("List all registered devices").option("--team-id <id>","Filter by Apple Developer Team ID").action(async e=>{await Ii("list",e)});so.command("remove").description("Remove a registered device").option("--udid <udid>","Device UDID to remove").option("--team-id <id>","Apple Developer Team ID for this device").action(async e=>{await Ii("remove",e)});M.command("audit").description("Run automated security audit on the project or APK").option("--apk <path>","Path to APK file (runs APK diagnostics like 16KB alignment)").option("--json","Output results as JSON (for CI/CD)").option("--fix","Auto-apply fixes where possible").option("--category <name>","Run only a specific check category (e.g. 16kb, permissions, secrets)").option("--severity <level>","Minimum severity to display (critical, high, medium, low, info)").option("--prebuild","Run expo prebuild for deeper manifest/plist analysis").action(async e=>{X(J.bgCyan.black(m.cliTag(e.apk?"APK Audit":"Security Audit"))),await ed(e)});var ig=new Set(["login","logout","agent"]);M.hook("preAction",(e,t)=>{let n=t.name(),i=t.opts?.()||{};n==="maestro"&&(i.local||i.localRunner)||t.parent?.name()!=="deeplink"&&(ig.has(n)||Et())});M.on("command:*",()=>{console.error(`Invalid command: %s
1770
1770
  See --help for a list of available commands.`,M.args.join(" ")),process.exit(1)});process.argv.slice(2).length||M.help();M.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radhya/mach",
3
- "version": "2.1.8",
3
+ "version": "2.1.9",
4
4
  "description": "Mach CLI: Cloud Build Orchestrator for React Native & Expo",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",