nx-react-native-cli 2.6.11 → 2.7.0

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.
package/lib/index.cjs CHANGED
@@ -61,7 +61,7 @@ ${m.description}`:"";return`${[a,v,b].filter(Boolean).join(" ")}
61
61
  ${C}${T}${F}${N2.default.cursorHide}`});var b1=O(require("node:readline"),1),j=O(d1(),1),ml=O(m1(),1),E1=O(Ha(),1),F1=O(Et(),1),v1={set:(e,r="",t)=>{let n=e;r.split(".").forEach((i,u,o)=>{i==="__proto__"||i==="constructor"||(u===o.length-1?n[i]=t:i in n||(n[i]={}),n=n[i])})},get:(e,r="",t)=>{let n=u=>String.prototype.split.call(r,u).filter(Boolean).reduce((o,a)=>o!=null?o[a]:o,e),i=n(/[,[\]]+?/)||n(/[,.[\]]+?/);return i===void 0||i===e?t:i}};function Dl(e,r,t){if(r in e){let n=e[r];if(typeof n=="function")return(0,j.from)((0,ml.default)(n)(t).then(i=>Object.assign(e,{[r]:i})))}return(0,j.of)(e)}var hl=class extends Error{isTtyError=!0};function ES(e={}){e.skipTTYChecks=e.skipTTYChecks===void 0?!0:e.skipTTYChecks;let r=e.input||process.stdin;if(!e.skipTTYChecks&&!r.isTTY)throw new hl("Prompts can not be meaningfully rendered in non-TTY environments");let t=new E1.default;return t.pipe(e.output||process.stdout),{terminal:!0,...e,input:r,output:t}}function FS(e){return Object.values(e).every(r=>typeof r=="object"&&!Array.isArray(r)&&r!=null)}function _S(e){return e.prototype&&"run"in e.prototype&&typeof e.prototype.run=="function"}var Dn=class{prompts;answers={};process=j.EMPTY;onClose;opt;rl;constructor(r,t){this.opt=t,this.prompts=r}run(r,t){this.answers=typeof t=="object"?{...t}:{};let n;Array.isArray(r)?n=(0,j.from)(r):(0,j.isObservable)(r)?n=r:FS(r)?n=(0,j.from)(Object.entries(r).map(([u,o])=>Object.assign({},o,{name:u}))):n=(0,j.from)([r]),this.process=n.pipe((0,j.concatMap)(u=>this.processQuestion(u)));let i=(0,j.lastValueFrom)(this.process.pipe((0,j.reduce)((u,o)=>(v1.set(u,o.name,o.answer),u),this.answers))).then(()=>this.onCompletion(),u=>this.onError(u));return Object.assign(i,{ui:this})}onCompletion(){return this.close(),this.answers}onError(r){return this.close(),Promise.reject(r)}processQuestion(r){return r={...r},(0,j.defer)(()=>(0,j.of)(r).pipe((0,j.concatMap)(this.setDefaultType),(0,j.concatMap)(this.filterIfRunnable),(0,j.concatMap)(n=>Dl(n,"message",this.answers)),(0,j.concatMap)(n=>Dl(n,"default",this.answers)),(0,j.concatMap)(n=>Dl(n,"choices",this.answers)),(0,j.concatMap)(n=>("choices"in n&&(n.choices=n.choices.map(i=>typeof i=="string"?{name:i,value:i}:i)),(0,j.of)(n))),(0,j.concatMap)(n=>this.fetchAnswer(n))))}fetchAnswer(r){let t=this.prompts[r.type];if(t==null)throw new Error(`Prompt for type ${r.type} not found`);return _S(t)?(0,j.defer)(()=>{let n=b1.default.createInterface(ES(this.opt));n.resume();let i=()=>{n.removeListener("SIGINT",this.onForceClose),n.setPrompt(""),n.output.unmute(),n.output.write(F1.default.cursorShow),n.output.end(),n.close()};this.onClose=i,this.rl=n,process.on("exit",this.onForceClose),n.on("SIGINT",this.onForceClose);let u=new t(r,n,this.answers);return(0,j.from)(u.run().then(o=>(i(),this.onClose=void 0,this.rl=void 0,{name:r.name,answer:o})))}):(0,j.defer)(()=>(0,j.from)(t(r,this.opt).then(n=>({name:r.name,answer:n}))))}onForceClose=()=>{this.close(),process.kill(process.pid,"SIGINT"),console.log("")};close=()=>{process.removeListener("exit",this.onForceClose),typeof this.onClose=="function"&&this.onClose()};setDefaultType=r=>(this.prompts[r.type]||(r.type="input"),(0,j.defer)(()=>(0,j.of)(r)));filterIfRunnable=r=>{if(r.askAnswered!==!0&&v1.get(this.answers,r.name)!==void 0)return j.EMPTY;let{when:t}=r;return t===!1?j.EMPTY:typeof t!="function"?(0,j.of)(r):(0,j.defer)(()=>(0,j.from)((0,ml.default)(t)(this.answers).then(n=>{if(n)return r})).pipe((0,j.filter)(n=>n!=null)))}};var _1={input:zs,select:zi,list:zi,number:Ks,confirm:Gs,rawlist:Zs,expand:Xs,checkbox:ts,password:ec,editor:Hs};function y1(e){function r(t,n){let i=new Dn(r.prompts,e);try{return i.run(t,n)}catch(u){let o=Promise.reject(u);return Object.assign(o,{ui:i})}}return r.prompts={..._1},r.registerPrompt=function(t,n){return r.prompts[t]=n,this},r.restoreDefaultPrompts=function(){r.prompts={..._1}},r}var vl=y1();function yS(e,r){vl.registerPrompt(e,r)}function gS(){vl.restoreDefaultPrompts()}var CS={prompt:vl,ui:{Prompt:Dn},createPromptModule:y1,registerPrompt:yS,restoreDefaultPrompts:gS,Separator:ae},ri=CS;var ui=O(require("node:process"),1);var _l=O(require("node:process"),1);var k1=O(require("node:process"),1),T1=O(A1(),1),M1=O(P1(),1),AS=(0,T1.default)(()=>{(0,M1.default)(()=>{k1.default.stderr.write("\x1B[?25h")},{alwaysLast:!0})}),I1=AS;var la=!1,bn={};bn.show=(e=_l.default.stderr)=>{e.isTTY&&(la=!1,e.write("\x1B[?25h"))};bn.hide=(e=_l.default.stderr)=>{e.isTTY&&(I1(),la=!0,e.write("\x1B[?25l"))};bn.toggle=(e,r)=>{e!==void 0&&(la=e),la?bn.show(r):bn.hide(r)};var yl=bn;var oi=O(Ei(),1);var Se=O(require("node:process"),1);function gl(){return Se.default.platform!=="win32"?Se.default.env.TERM!=="linux":!!Se.default.env.CI||!!Se.default.env.WT_SESSION||!!Se.default.env.TERMINUS_SUBLIME||Se.default.env.ConEmuTask==="{cmd::Cmder}"||Se.default.env.TERM_PROGRAM==="Terminus-Sublime"||Se.default.env.TERM_PROGRAM==="vscode"||Se.default.env.TERM==="xterm-256color"||Se.default.env.TERM==="alacritty"||Se.default.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var OS={info:z.blue("\u2139"),success:z.green("\u2714"),warning:z.yellow("\u26A0"),error:z.red("\u2716")},SS={info:z.blue("i"),success:z.green("\u221A"),warning:z.yellow("\u203C"),error:z.red("\xD7")},BS=gl()?OS:SS,ni=BS;function Cl({onlyFirst:e=!1}={}){let r=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(r,e?void 0:"g")}var qS=Cl();function ii(e){if(typeof e!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``);return e.replace(qS,"")}function R1(e){return e===161||e===164||e===167||e===168||e===170||e===173||e===174||e>=176&&e<=180||e>=182&&e<=186||e>=188&&e<=191||e===198||e===208||e===215||e===216||e>=222&&e<=225||e===230||e>=232&&e<=234||e===236||e===237||e===240||e===242||e===243||e>=247&&e<=250||e===252||e===254||e===257||e===273||e===275||e===283||e===294||e===295||e===299||e>=305&&e<=307||e===312||e>=319&&e<=322||e===324||e>=328&&e<=331||e===333||e===338||e===339||e===358||e===359||e===363||e===462||e===464||e===466||e===468||e===470||e===472||e===474||e===476||e===593||e===609||e===708||e===711||e>=713&&e<=715||e===717||e===720||e>=728&&e<=731||e===733||e===735||e>=768&&e<=879||e>=913&&e<=929||e>=931&&e<=937||e>=945&&e<=961||e>=963&&e<=969||e===1025||e>=1040&&e<=1103||e===1105||e===8208||e>=8211&&e<=8214||e===8216||e===8217||e===8220||e===8221||e>=8224&&e<=8226||e>=8228&&e<=8231||e===8240||e===8242||e===8243||e===8245||e===8251||e===8254||e===8308||e===8319||e>=8321&&e<=8324||e===8364||e===8451||e===8453||e===8457||e===8467||e===8470||e===8481||e===8482||e===8486||e===8491||e===8531||e===8532||e>=8539&&e<=8542||e>=8544&&e<=8555||e>=8560&&e<=8569||e===8585||e>=8592&&e<=8601||e===8632||e===8633||e===8658||e===8660||e===8679||e===8704||e===8706||e===8707||e===8711||e===8712||e===8715||e===8719||e===8721||e===8725||e===8730||e>=8733&&e<=8736||e===8739||e===8741||e>=8743&&e<=8748||e===8750||e>=8756&&e<=8759||e===8764||e===8765||e===8776||e===8780||e===8786||e===8800||e===8801||e>=8804&&e<=8807||e===8810||e===8811||e===8814||e===8815||e===8834||e===8835||e===8838||e===8839||e===8853||e===8857||e===8869||e===8895||e===8978||e>=9312&&e<=9449||e>=9451&&e<=9547||e>=9552&&e<=9587||e>=9600&&e<=9615||e>=9618&&e<=9621||e===9632||e===9633||e>=9635&&e<=9641||e===9650||e===9651||e===9654||e===9655||e===9660||e===9661||e===9664||e===9665||e>=9670&&e<=9672||e===9675||e>=9678&&e<=9681||e>=9698&&e<=9701||e===9711||e===9733||e===9734||e===9737||e===9742||e===9743||e===9756||e===9758||e===9792||e===9794||e===9824||e===9825||e>=9827&&e<=9829||e>=9831&&e<=9834||e===9836||e===9837||e===9839||e===9886||e===9887||e===9919||e>=9926&&e<=9933||e>=9935&&e<=9939||e>=9941&&e<=9953||e===9955||e===9960||e===9961||e>=9963&&e<=9969||e===9972||e>=9974&&e<=9977||e===9979||e===9980||e===9982||e===9983||e===10045||e>=10102&&e<=10111||e>=11094&&e<=11097||e>=12872&&e<=12879||e>=57344&&e<=63743||e>=65024&&e<=65039||e===65533||e>=127232&&e<=127242||e>=127248&&e<=127277||e>=127280&&e<=127337||e>=127344&&e<=127373||e===127375||e===127376||e>=127387&&e<=127404||e>=917760&&e<=917999||e>=983040&&e<=1048573||e>=1048576&&e<=1114109}function L1(e){return e===12288||e>=65281&&e<=65376||e>=65504&&e<=65510}function N1(e){return e>=4352&&e<=4447||e===8986||e===8987||e===9001||e===9002||e>=9193&&e<=9196||e===9200||e===9203||e===9725||e===9726||e===9748||e===9749||e>=9800&&e<=9811||e===9855||e===9875||e===9889||e===9898||e===9899||e===9917||e===9918||e===9924||e===9925||e===9934||e===9940||e===9962||e===9970||e===9971||e===9973||e===9978||e===9981||e===9989||e===9994||e===9995||e===10024||e===10060||e===10062||e>=10067&&e<=10069||e===10071||e>=10133&&e<=10135||e===10160||e===10175||e===11035||e===11036||e===11088||e===11093||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12287||e>=12289&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12591||e>=12593&&e<=12686||e>=12688&&e<=12771||e>=12783&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=94176&&e<=94180||e===94192||e===94193||e>=94208&&e<=100343||e>=100352&&e<=101589||e>=101632&&e<=101640||e>=110576&&e<=110579||e>=110581&&e<=110587||e===110589||e===110590||e>=110592&&e<=110882||e===110898||e>=110928&&e<=110930||e===110933||e>=110948&&e<=110951||e>=110960&&e<=111355||e===126980||e===127183||e===127374||e>=127377&&e<=127386||e>=127488&&e<=127490||e>=127504&&e<=127547||e>=127552&&e<=127560||e===127568||e===127569||e>=127584&&e<=127589||e>=127744&&e<=127776||e>=127789&&e<=127797||e>=127799&&e<=127868||e>=127870&&e<=127891||e>=127904&&e<=127946||e>=127951&&e<=127955||e>=127968&&e<=127984||e===127988||e>=127992&&e<=128062||e===128064||e>=128066&&e<=128252||e>=128255&&e<=128317||e>=128331&&e<=128334||e>=128336&&e<=128359||e===128378||e===128405||e===128406||e===128420||e>=128507&&e<=128591||e>=128640&&e<=128709||e===128716||e>=128720&&e<=128722||e>=128725&&e<=128727||e>=128732&&e<=128735||e===128747||e===128748||e>=128756&&e<=128764||e>=128992&&e<=129003||e===129008||e>=129292&&e<=129338||e>=129340&&e<=129349||e>=129351&&e<=129535||e>=129648&&e<=129660||e>=129664&&e<=129672||e>=129680&&e<=129725||e>=129727&&e<=129733||e>=129742&&e<=129755||e>=129760&&e<=129768||e>=129776&&e<=129784||e>=131072&&e<=196605||e>=196608&&e<=262141}function jS(e){if(!Number.isSafeInteger(e))throw new TypeError(`Expected a code point, got \`${typeof e}\`.`)}function $1(e,{ambiguousAsWide:r=!1}={}){return jS(e),L1(e)||N1(e)||r&&R1(e)?2:1}var W1=O(V1(),1),PS=new Intl.Segmenter,kS=/^\p{Default_Ignorable_Code_Point}$/u;function wl(e,r={}){if(typeof e!="string"||e.length===0)return 0;let{ambiguousIsNarrow:t=!0,countAnsiEscapeCodes:n=!1}=r;if(n||(e=ii(e)),e.length===0)return 0;let i=0,u={ambiguousAsWide:!t};for(let{segment:o}of PS.segment(e)){let a=o.codePointAt(0);if(!(a<=31||a>=127&&a<=159)&&!(a>=8203&&a<=8207||a===65279)&&!(a>=768&&a<=879||a>=6832&&a<=6911||a>=7616&&a<=7679||a>=8400&&a<=8447||a>=65056&&a<=65071)&&!(a>=55296&&a<=57343)&&!(a>=65024&&a<=65039)&&!kS.test(o)){if((0,W1.default)().test(o)){i+=2;continue}i+=$1(a,u)}}return i}function Al({stream:e=process.stdout}={}){return!!(e&&e.isTTY&&process.env.TERM!=="dumb"&&!("CI"in process.env))}var Re=O(require("node:process"),1);function Ol(){return Re.default.platform!=="win32"?Re.default.env.TERM!=="linux":!!Re.default.env.WT_SESSION||!!Re.default.env.TERMINUS_SUBLIME||Re.default.env.ConEmuTask==="{cmd::Cmder}"||Re.default.env.TERM_PROGRAM==="Terminus-Sublime"||Re.default.env.TERM_PROGRAM==="vscode"||Re.default.env.TERM==="xterm-256color"||Re.default.env.TERM==="alacritty"||Re.default.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var Le=O(require("node:process"),1),TS=3,Sl=class{#i=0;start(){this.#i++,this.#i===1&&this.#t()}stop(){if(this.#i<=0)throw new Error("`stop` called more times than `start`");this.#i--,this.#i===0&&this.#e()}#t(){Le.default.platform==="win32"||!Le.default.stdin.isTTY||(Le.default.stdin.setRawMode(!0),Le.default.stdin.on("data",this.#u),Le.default.stdin.resume())}#e(){Le.default.stdin.isTTY&&(Le.default.stdin.off("data",this.#u),Le.default.stdin.pause(),Le.default.stdin.setRawMode(!1))}#u(r){r[0]===TS&&Le.default.emit("SIGINT")}},MS=new Sl,Bl=MS;var IS=O(Ei(),1),ql=class{#i=0;#t=!1;#e=0;#u=0;#r;#o;#n;#x;#d;#c;#l;#f;#D;#a;#s;color;constructor(r){typeof r=="string"&&(r={text:r}),this.#r={color:"cyan",stream:ui.default.stderr,discardStdin:!0,hideCursor:!0,...r},this.color=this.#r.color,this.spinner=this.#r.spinner,this.#d=this.#r.interval,this.#n=this.#r.stream,this.#c=typeof this.#r.isEnabled=="boolean"?this.#r.isEnabled:Al({stream:this.#n}),this.#l=typeof this.#r.isSilent=="boolean"?this.#r.isSilent:!1,this.text=this.#r.text,this.prefixText=this.#r.prefixText,this.suffixText=this.#r.suffixText,this.indent=this.#r.indent,ui.default.env.NODE_ENV==="test"&&(this._stream=this.#n,this._isEnabled=this.#c,Object.defineProperty(this,"_linesToClear",{get(){return this.#i},set(t){this.#i=t}}),Object.defineProperty(this,"_frameIndex",{get(){return this.#u}}),Object.defineProperty(this,"_lineCount",{get(){return this.#e}}))}get indent(){return this.#f}set indent(r=0){if(!(r>=0&&Number.isInteger(r)))throw new Error("The `indent` option must be an integer from 0 and up");this.#f=r,this.#p()}get interval(){return this.#d??this.#o.interval??100}get spinner(){return this.#o}set spinner(r){if(this.#u=0,this.#d=void 0,typeof r=="object"){if(r.frames===void 0)throw new Error("The given spinner must have a `frames` property");this.#o=r}else if(!Ol())this.#o=oi.default.line;else if(r===void 0)this.#o=oi.default.dots;else if(r!=="default"&&oi.default[r])this.#o=oi.default[r];else throw new Error(`There is no built-in spinner named '${r}'. See https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json for a full list.`)}get text(){return this.#D}set text(r=""){this.#D=r,this.#p()}get prefixText(){return this.#a}set prefixText(r=""){this.#a=r,this.#p()}get suffixText(){return this.#s}set suffixText(r=""){this.#s=r,this.#p()}get isSpinning(){return this.#x!==void 0}#h(r=this.#a,t=" "){return typeof r=="string"&&r!==""?r+t:typeof r=="function"?r()+t:""}#m(r=this.#s,t=" "){return typeof r=="string"&&r!==""?t+r:typeof r=="function"?t+r():""}#p(){let r=this.#n.columns??80,t=this.#h(this.#a,"-"),n=this.#m(this.#s,"-"),i=" ".repeat(this.#f)+t+"--"+this.#D+"--"+n;this.#e=0;for(let u of ii(i).split(`
62
62
  `))this.#e+=Math.max(1,Math.ceil(wl(u,{countAnsiEscapeCodes:!0})/r))}get isEnabled(){return this.#c&&!this.#l}set isEnabled(r){if(typeof r!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#c=r}get isSilent(){return this.#l}set isSilent(r){if(typeof r!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#l=r}frame(){let{frames:r}=this.#o,t=r[this.#u];this.color&&(t=z[this.color](t)),this.#u=++this.#u%r.length;let n=typeof this.#a=="string"&&this.#a!==""?this.#a+" ":"",i=typeof this.text=="string"?" "+this.text:"",u=typeof this.#s=="string"&&this.#s!==""?" "+this.#s:"";return n+t+i+u}clear(){if(!this.#c||!this.#n.isTTY)return this;this.#n.cursorTo(0);for(let r=0;r<this.#i;r++)r>0&&this.#n.moveCursor(0,-1),this.#n.clearLine(1);return(this.#f||this.lastIndent!==this.#f)&&this.#n.cursorTo(this.#f),this.lastIndent=this.#f,this.#i=0,this}render(){return this.#l?this:(this.clear(),this.#n.write(this.frame()),this.#i=this.#e,this)}start(r){return r&&(this.text=r),this.#l?this:this.#c?this.isSpinning?this:(this.#r.hideCursor&&yl.hide(this.#n),this.#r.discardStdin&&ui.default.stdin.isTTY&&(this.#t=!0,Bl.start()),this.render(),this.#x=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#n.write(`- ${this.text}
63
63
  `),this)}stop(){return this.#c?(clearInterval(this.#x),this.#x=void 0,this.#u=0,this.clear(),this.#r.hideCursor&&yl.show(this.#n),this.#r.discardStdin&&ui.default.stdin.isTTY&&this.#t&&(Bl.stop(),this.#t=!1),this):this}succeed(r){return this.stopAndPersist({symbol:ni.success,text:r})}fail(r){return this.stopAndPersist({symbol:ni.error,text:r})}warn(r){return this.stopAndPersist({symbol:ni.warning,text:r})}info(r){return this.stopAndPersist({symbol:ni.info,text:r})}stopAndPersist(r={}){if(this.#l)return this;let t=r.prefixText??this.#a,n=this.#h(t," "),i=r.symbol??" ",u=r.text??this.text,o=typeof u=="string"?" "+u:"",a=r.suffixText??this.#s,s=this.#m(a," "),c=n+i+o+s+`
64
- `;return this.stop(),this.#n.write(c),this}};function _e(e){return new ql(e)}var z1=require("child_process"),Be=O(require("fs"),1),at=O(require("path"),1);var H1={dependencies:{"@gorhom/bottom-sheet":"5.2.8","@hookform/resolvers":"5.0.1","@react-native-community/datetimepicker":"8.6.0","@react-native-community/hooks":"100.1.0","@react-navigation/core":"7.4.0","@react-navigation/material-top-tabs":"7.2.13","@react-navigation/native-stack":"7.2.1","@react-navigation/native":"7.0.15","@react-navigation/stack":"7.1.2","@shopify/react-native-skia":"2.4.14","@tanstack/query-async-storage-persister":"5.67.3","@tanstack/query-core":"5.67.3","@tanstack/query-sync-storage-persister":"5.67.3","@tanstack/react-query-persist-client":"5.67.3","@tanstack/react-query":"5.67.3",axios:"1.13.2","babel-plugin-module-resolver":"5.0.2",dayjs:"1.11.19","jotai-optics":"0.4.0",jotai:"2.16.1","lodash-es":"4.17.22","react-hook-form":"7.56.4","react-native-dotenv":"3.4.11","react-native-gesture-handler":"2.29.1","react-native-get-random-values":"1.11.0","react-native-haptic-feedback":"2.3.3","react-native-keyboard-controller":"1.19.1","react-native-mmkv":"4.1.0","react-native-modal-datetime-picker":"18.0.0","react-native-modal":"14.0.0-rc.1","react-native-nitro-modules":"0.32.0","react-native-pager-view":"6.8.0","react-native-reanimated":"4.2.1","react-native-safe-area-context":"5.6.0","react-native-screens":"4.19.0","react-native-simple-toast":"3.3.2","react-native-turbo-image":"1.22.1","react-native-url-polyfill":"2.0.0","react-native-worklets":"0.7.1","react-native":"0.83.1",react:"19.2.0",tailwindcss:"3.4.16",twrnc:"4.16.0",uuid:"11.1.0","zod-validation-error":"3.4.0",zod:"3.24.2",zustand:"5.0.5"}};var G1={devDependencies:{"@babel/core":"7.25.2","@babel/eslint-parser":"7.23.10","@babel/preset-env":"7.25.3","@babel/preset-react":"7.27.1","@babel/runtime":"7.25.0","@react-native-community/cli-platform-android":"20.0.0","@react-native-community/cli-platform-ios":"20.0.0","@react-native-community/cli":"20.0.0","@react-native/babel-preset":"0.83.1","@react-native/eslint-config":"0.83.1","@react-native/metro-config":"0.83.1","@react-native/typescript-config":"0.83.1","@swc-node/register":"~1.8.0","@tanstack/eslint-plugin-query":"5.91.2","@testing-library/jest-native":"5.4.3","@testing-library/react-native":"12.5.1","@types/jest":"29.5.13","@types/jwt-encode":"1.0.3","@types/lodash-es":"4.17.12","@types/react-native-vector-icons":"6.4.18","@types/react-test-renderer":"19.1.0","@types/react":"19.2.0","@typescript-eslint/eslint-plugin":"^6.13.2","@typescript-eslint/parser":"^6.21.0","babel-jest":"29.6.3","babel-plugin-module-resolver":"5.0.2","eslint-config-airbnb-typescript":"^17.1.0","eslint-config-prettier":"10.1.8","eslint-import-resolver-typescript":"^3.8.5","eslint-plugin-ft-flow":"2.0.3","eslint-plugin-import":"^2.31.0","eslint-plugin-jest":"27.9.0","eslint-plugin-prettier":"^5.2.3","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-perf":"^3.3.3","eslint-plugin-react":"^7.32.2","eslint-plugin-sonarjs":"0.25.1","eslint-plugin-sort-destructure-keys":"^2.0.0","eslint-plugin-sort-keys-fix":"^1.1.2","eslint-plugin-tailwindcss":"^3.18.0","eslint-plugin-testing-library":"6.2.2",eslint:"8.57.0",husky:"9.1.7","jest-environment-jsdom":"30.1.2",jest:"29.6.3","prettier-plugin-tailwindcss":"^0.6.11",prettier:"3.3.2","react-native-dotenv":"3.4.11","react-native-svg-transformer":"1.3.0","react-native-svg":"15.15.1","react-test-renderer":"19.2.0",typescript:"5.8.3"}};function fa(){return __dirname}var pe=(e,r)=>{(0,z1.execSync)(`cd ${e} && ${r}`,{stdio:"inherit"})},te=(e,r,t,n)=>{let i=at.default.join(fa(),`../templates/${t}/${r}`);!Be.default.existsSync(i)&&n&&(i=at.default.join(fa(),`../templates/${n}/${r}`)),Be.default.copyFile(i,e,u=>{if(u){console.error(`Error copying file: ${u.message}`);return}})},Ne=(e,r,t,n)=>{let i=at.default.join(fa(),`../templates/${t}/${r}`);!Be.default.existsSync(i)&&n&&(i=at.default.join(fa(),`../templates/${n}/${r}`)),Be.default.cpSync(i,e,{recursive:!0},u=>{if(u){console.error(`Error copying file: ${u.message}`);return}})},jl=e=>{Be.default.rmSync(e,{recursive:!0,force:!0},r=>{if(r){console.error(`Error removing directory: ${r.message}`);return}})},ai=e=>{Be.default.rmSync(e,{recursive:!0,force:!0},r=>{if(r){console.error(`Error removing file: ${r.message}`);return}})},Pl=e=>{let r={doctor:"npx nx react-native doctor",android:"cd apps/mobile && npm run run-android","android:connect":"cd apps/mobile && npm run android:connect","check-env:mobile":"./check-env.sh apps/mobile/.env apps/mobile/.env.template",ios:"cd apps/mobile && npm run run-ios",clean:"./clean-generated-outputs.sh","create-env":"printenv > ","lint:all":"npx nx run-many -t lint -p mobile --parallel=1 --skip-nx-cache","lint:mobile":"npx nx run mobile:lint --skip-nx-cache","mobile-android":"cd apps/mobile && npm run run-android","mobile-ios":"cd apps/mobile && npm run run-ios",prepare:"husky install","serve:mobile":"cd apps/mobile && npm start","serve:all":"npx nx run-many -t serve -p mobile --parallel=1 --skip-nx-cache",xcode:"cd apps/mobile && npm run xcode","touch-xcode":"cd apps/mobile && npm run touch-xcode","setup-fastlane":"cd apps/mobile && npm run setup-fastlane","deploy-android:dev":"cd apps/mobile && npm run deploy-android:dev","deploy-ios:dev":"cd apps/mobile && npm run deploy-ios:dev","ios-certificates":"cd apps/mobile && npm run ios-certificates","pod-install":"cd apps/mobile && npm run pod-install-conditional","react-native-asset":"cd apps/mobile && npx react-native-asset"},t=at.default.join(e,"package.json"),n=JSON.parse(Be.default.readFileSync(t,"utf8"));n.dependencies={...n.dependencies,...H1.dependencies},n.devDependencies={...n.devDependencies,...G1.devDependencies},n.scripts={...n.scripts,...r},Be.default.writeFileSync(t,JSON.stringify(n,null,2))},K1=e=>{let r=at.default.join(e,"nx.json");if(!Be.default.existsSync(r))return;let t=JSON.parse(Be.default.readFileSync(r,"utf-8"));t.tui={...t.tui||{},enabled:!1},Be.default.writeFileSync(r,JSON.stringify(t,null,2))},kl=(e,r)=>{let t=_e({text:"Configuring iOS Dev scheme and build configurations...",color:"cyan"}).start();try{pe(e,"bundle check || bundle install"),pe(e,"bundle exec ruby ./scripts/setup-ios-dev-scheme.rb"),t.succeed(r.success("iOS Dev scheme and build configurations configured successfully"))}catch(n){throw t.fail(r.error("Failed to configure iOS Dev scheme and build configurations")),n}};var NS="2.6.11",De="21.2.2",E={title:z.bold.cyan,subtitle:z.cyan,success:z.bold.green,info:z.bold.blue,warning:z.hex("#FFA500").bold,error:z.bold.red,highlight:z.bold.magenta,command:z.yellow.italic,path:z.green.underline,step:e=>z.bgCyan.black(` STEP ${e} `),emoji:{rocket:"\u{1F680}",check:"\u2705",warning:"\u26A0\uFE0F",star:"\u2B50",sparkles:"\u2728",tools:"\u{1F6E0}\uFE0F",mobile:"\u{1F4F1}",folder:"\u{1F4C1}",code:"\u{1F4BB}"}},J1=()=>{console.log(`
64
+ `;return this.stop(),this.#n.write(c),this}};function _e(e){return new ql(e)}var z1=require("child_process"),Be=O(require("fs"),1),at=O(require("path"),1);var H1={dependencies:{"@gorhom/bottom-sheet":"5.2.8","@hookform/resolvers":"5.0.1","@react-native-community/datetimepicker":"8.6.0","@react-native-community/hooks":"100.1.0","@react-navigation/core":"7.4.0","@react-navigation/material-top-tabs":"7.2.13","@react-navigation/native-stack":"7.2.1","@react-navigation/native":"7.0.15","@react-navigation/stack":"7.1.2","@shopify/react-native-skia":"2.4.14","@tanstack/query-async-storage-persister":"5.67.3","@tanstack/query-core":"5.67.3","@tanstack/query-sync-storage-persister":"5.67.3","@tanstack/react-query-persist-client":"5.67.3","@tanstack/react-query":"5.67.3",axios:"1.13.2","babel-plugin-module-resolver":"5.0.2",dayjs:"1.11.19","jotai-optics":"0.4.0",jotai:"2.16.1","lodash-es":"4.17.22","react-hook-form":"7.56.4","react-native-dotenv":"3.4.11","react-native-gesture-handler":"2.29.1","react-native-get-random-values":"1.11.0","react-native-haptic-feedback":"2.3.3","react-native-keyboard-controller":"1.19.1","react-native-mmkv":"4.1.0","react-native-modal-datetime-picker":"18.0.0","react-native-modal":"14.0.0-rc.1","react-native-nitro-modules":"0.32.0","react-native-pager-view":"6.8.0","react-native-reanimated":"4.2.1","react-native-safe-area-context":"5.6.0","react-native-screens":"4.19.0","react-native-simple-toast":"3.3.2","react-native-turbo-image":"1.22.1","react-native-url-polyfill":"2.0.0","react-native-worklets":"0.7.1","react-native":"0.83.1",react:"19.2.0",tailwindcss:"3.4.16",twrnc:"4.16.0",uuid:"11.1.0","zod-validation-error":"3.4.0",zod:"3.24.2",zustand:"5.0.5"}};var G1={devDependencies:{"@babel/core":"7.25.2","@babel/eslint-parser":"7.23.10","@babel/preset-env":"7.25.3","@babel/preset-react":"7.27.1","@babel/runtime":"7.25.0","@react-native-community/cli-platform-android":"20.0.0","@react-native-community/cli-platform-ios":"20.0.0","@react-native-community/cli":"20.0.0","@react-native/babel-preset":"0.83.1","@react-native/eslint-config":"0.83.1","@react-native/metro-config":"0.83.1","@react-native/typescript-config":"0.83.1","@swc-node/register":"~1.8.0","@tanstack/eslint-plugin-query":"5.91.2","@testing-library/jest-native":"5.4.3","@testing-library/react-native":"12.5.1","@types/jest":"29.5.13","@types/jwt-encode":"1.0.3","@types/lodash-es":"4.17.12","@types/react-native-vector-icons":"6.4.18","@types/react-test-renderer":"19.1.0","@types/react":"19.2.0","@typescript-eslint/eslint-plugin":"^6.13.2","@typescript-eslint/parser":"^6.21.0","babel-jest":"29.6.3","babel-plugin-module-resolver":"5.0.2","eslint-config-airbnb-typescript":"^17.1.0","eslint-config-prettier":"10.1.8","eslint-import-resolver-typescript":"^3.8.5","eslint-plugin-ft-flow":"2.0.3","eslint-plugin-import":"^2.31.0","eslint-plugin-jest":"27.9.0","eslint-plugin-prettier":"^5.2.3","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-react-perf":"^3.3.3","eslint-plugin-react":"^7.32.2","eslint-plugin-sonarjs":"0.25.1","eslint-plugin-sort-destructure-keys":"^2.0.0","eslint-plugin-sort-keys-fix":"^1.1.2","eslint-plugin-tailwindcss":"^3.18.0","eslint-plugin-testing-library":"6.2.2",eslint:"8.57.0",husky:"9.1.7","jest-environment-jsdom":"30.1.2",jest:"29.6.3","prettier-plugin-tailwindcss":"^0.6.11",prettier:"3.3.2","react-native-dotenv":"3.4.11","react-native-svg-transformer":"1.3.0","react-native-svg":"15.15.1","react-test-renderer":"19.2.0",typescript:"5.8.3"}};function fa(){return __dirname}var pe=(e,r)=>{(0,z1.execSync)(`cd ${e} && ${r}`,{stdio:"inherit"})},te=(e,r,t,n)=>{let i=at.default.join(fa(),`../templates/${t}/${r}`);!Be.default.existsSync(i)&&n&&(i=at.default.join(fa(),`../templates/${n}/${r}`)),Be.default.copyFile(i,e,u=>{if(u){console.error(`Error copying file: ${u.message}`);return}})},Ne=(e,r,t,n)=>{let i=at.default.join(fa(),`../templates/${t}/${r}`);!Be.default.existsSync(i)&&n&&(i=at.default.join(fa(),`../templates/${n}/${r}`)),Be.default.cpSync(i,e,{recursive:!0},u=>{if(u){console.error(`Error copying file: ${u.message}`);return}})},jl=e=>{Be.default.rmSync(e,{recursive:!0,force:!0},r=>{if(r){console.error(`Error removing directory: ${r.message}`);return}})},ai=e=>{Be.default.rmSync(e,{recursive:!0,force:!0},r=>{if(r){console.error(`Error removing file: ${r.message}`);return}})},Pl=e=>{let r={doctor:"npx nx react-native doctor",android:"npx nx run-android mobile","android:connect":"adb reverse tcp:8081 tcp:8081","check-env:mobile":"./check-env.sh apps/mobile/.env apps/mobile/.env.template",ios:"npx nx run-ios mobile",clean:"./clean-generated-outputs.sh","lint:all":"npx nx run-many -t lint -p mobile --parallel=1 --skip-nx-cache","lint:mobile":"npx nx run mobile:lint --skip-nx-cache",prepare:"husky install","serve:mobile":"npx nx start mobile --skip-nx-cache","serve:all":"npx nx run-many -t serve -p mobile --parallel=1 --skip-nx-cache",xcode:"cd apps/mobile && ./ios-only.sh 'xed -b ios'","touch-xcode":"cd apps/mobile && ./ios-only.sh 'touch ios/.xcode.env'","setup-fastlane":"cd apps/mobile && rbenv local && bundle install && bundle update","deploy:mobile":"cd apps/mobile && ./deploy.sh","ios-certificates":"cd apps/mobile && ./ios-only.sh 'rbenv local && bundle install && bundle update && bundle exec fastlane ios certificates --env development'","pod-install":"npx nx pod-install mobile","pod-install:force":"npx nx pod-install:force mobile","list:ios-configurations":"cd apps/mobile && ./ios-only.sh 'cd ios && xcodebuild -list'","list:ios-devices":"cd apps/mobile && ./ios-only.sh 'xcrun xctrace list devices'","react-native-asset":"cd apps/mobile && npx react-native-asset"},t=at.default.join(e,"package.json"),n=JSON.parse(Be.default.readFileSync(t,"utf8"));n.dependencies={...n.dependencies,...H1.dependencies},n.devDependencies={...n.devDependencies,...G1.devDependencies},n.scripts={...n.scripts,...r},Be.default.writeFileSync(t,JSON.stringify(n,null,2))},K1=e=>{let r=at.default.join(e,"nx.json");if(!Be.default.existsSync(r))return;let t=JSON.parse(Be.default.readFileSync(r,"utf-8"));t.tui={...t.tui||{},enabled:!1},Be.default.writeFileSync(r,JSON.stringify(t,null,2))},kl=(e,r)=>{let t=_e({text:"Configuring iOS Dev scheme and build configurations...",color:"cyan"}).start();try{pe(e,"bundle check || bundle install"),pe(e,"bundle exec ruby ./scripts/setup-ios-dev-scheme.rb"),t.succeed(r.success("iOS Dev scheme and build configurations configured successfully"))}catch(n){throw t.fail(r.error("Failed to configure iOS Dev scheme and build configurations")),n}};var NS="2.7.0",De="21.2.2",E={title:z.bold.cyan,subtitle:z.cyan,success:z.bold.green,info:z.bold.blue,warning:z.hex("#FFA500").bold,error:z.bold.red,highlight:z.bold.magenta,command:z.yellow.italic,path:z.green.underline,step:e=>z.bgCyan.black(` STEP ${e} `),emoji:{rocket:"\u{1F680}",check:"\u2705",warning:"\u26A0\uFE0F",star:"\u2B50",sparkles:"\u2728",tools:"\u{1F6E0}\uFE0F",mobile:"\u{1F4F1}",folder:"\u{1F4C1}",code:"\u{1F4BB}"}},J1=()=>{console.log(`
65
65
  `),console.log(E.title("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557")),console.log(E.title("\u2551 \u2551")),console.log(E.title("\u2551 ")+E.highlight("NX REACT NATIVE CLI")+E.title(" \u2551")),console.log(E.title("\u2551 ")+E.subtitle("A powerful starter for React Native with NX")+E.title(" \u2551")),console.log(E.title("\u2551 \u2551")),console.log(E.title("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D")),console.log(`
66
66
  `)};yn.name("React Native Starter with NX").description("A starter script to create a new React Native project with NX").version(NS);yn.command("create [workspace_name] [bundle_id]").description("create nx workspace with react-native").option("--fresh","Create a fresh project without copying template files").option("--nx-version <version>","Specify Nx version to use",De).option("--package-manager <pm>","Package manager to use (yarn or npm)","yarn").option("--skip-install","Skip package install after adding dependencies").option("--skip-configs","Skip copying prettier, eslint, and husky configs").action(async(e,r,t)=>{J1(),e||(e=(await ri.prompt([{type:"input",name:"workspace_name",message:E.info("Enter the workspace name:")}])).workspace_name),r||(r=(await ri.prompt([{type:"input",name:"bundle_id",message:E.info("Enter the bundle ID: ex. org.reactjsnative.example")}])).bundle_id);let n=t.fresh||!1,i=t.nxVersion||De,u=t.packageManager||"yarn",o=t.skipInstall||!1,a=t.skipConfigs||!1,s=process.cwd(),c=`${s}/${e}`,x=`${c}/apps/mobile`;console.log(`
67
67
  ${E.step(1)} ${E.emoji.folder} ${E.success(`Creating Nx workspace in ${E.path(`./${e}`)}`)}`);let d=_e({text:"Setting up Nx workspace...",color:"cyan"}).start();(0,Y1.execSync)(`cd ${s} && npx create-nx-workspace@${i} --preset apps --workspaceType integrated --name ${e} --package-manager=${u} --interactive false --nxCloud skip`,{stdio:"inherit"}),K1(c),d.succeed(E.success("Nx workspace created successfully")),console.log(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx-react-native-cli",
3
- "version": "2.6.11",
3
+ "version": "2.7.0",
4
4
  "description": "A react native starter (with NX) cli script",
5
5
  "type": "module",
6
6
  "files": [
@@ -116,6 +116,7 @@ buck-out/
116
116
 
117
117
  # Ruby / CocoaPods
118
118
  **/ios/Pods/
119
+ **/ios/.pods-checksum
119
120
  **/vendor/bundle/
120
121
 
121
122
  # iOS build logs
@@ -7,14 +7,14 @@
7
7
  "// targets": "to see all targets run: nx show project mobile --web",
8
8
  "targets": {
9
9
  "check-env": {
10
- "executor": "nx:run-script",
10
+ "executor": "nx:run-commands",
11
11
  "options": {
12
- "script": "check-env:mobile"
12
+ "command": "./check-env.sh apps/mobile/.env apps/mobile/.env.template"
13
13
  }
14
14
  },
15
15
  "start": {
16
16
  "executor": "@nx/react-native:start",
17
- "dependsOn": ["check-env", "sync-deps", "pod-install"],
17
+ "dependsOn": ["check-env", "pod-install"],
18
18
  "options": {
19
19
  "port": 8081,
20
20
  "resetCache": true,
@@ -28,9 +28,11 @@
28
28
  }
29
29
  },
30
30
  "run-ios": {
31
- "executor": "@nx/react-native:run-ios",
31
+ "executor": "nx:run-commands",
32
32
  "dependsOn": ["pod-install"],
33
- "options": {}
33
+ "options": {
34
+ "command": "cd apps/mobile && ./run-ios.sh"
35
+ }
34
36
  },
35
37
  "bundle-ios": {
36
38
  "executor": "@nx/react-native:bundle",
@@ -43,12 +45,10 @@
43
45
  }
44
46
  },
45
47
  "run-android": {
46
- "executor": "@nx/react-native:run-android",
48
+ "executor": "nx:run-commands",
47
49
  "dependsOn": [],
48
50
  "options": {
49
- "appIdSuffix": "dev",
50
- "mode": "debug",
51
- "tasks": "installDevDebug"
51
+ "command": "cd apps/mobile && ./run-android.sh"
52
52
  }
53
53
  },
54
54
  "build-android": {
@@ -67,9 +67,15 @@
67
67
  "options": {}
68
68
  },
69
69
  "pod-install": {
70
- "executor": "nx:run-script",
70
+ "executor": "nx:run-commands",
71
71
  "options": {
72
- "script": "bundle:pod-install"
72
+ "command": "cd apps/mobile && ./pod-install.sh"
73
+ }
74
+ },
75
+ "pod-install:force": {
76
+ "executor": "nx:run-commands",
77
+ "options": {
78
+ "command": "cd apps/mobile && ./ios-only.sh 'cd ios && bundle install && bundle exec pod install --repo-update && cd .. && ./export-node-binary.sh'"
73
79
  }
74
80
  },
75
81
  "bundle-android": {
@@ -82,14 +88,6 @@
82
88
  "bundleOutput": "dist/apps/mobile/android/main.jsbundle"
83
89
  }
84
90
  },
85
- "sync-deps": {
86
- "executor": "@nx/react-native:sync-deps",
87
- "options": {}
88
- },
89
- "ensure-symlink": {
90
- "executor": "@nx/react-native:ensure-symlink",
91
- "options": {}
92
- },
93
91
  "lint": {
94
92
  "executor": "@nx/eslint:lint",
95
93
  "outputs": ["{options.outputFile}"],
@@ -116,6 +116,7 @@ buck-out/
116
116
 
117
117
  # Ruby / CocoaPods
118
118
  **/ios/Pods/
119
+ **/ios/.pods-checksum
119
120
  **/vendor/bundle/
120
121
 
121
122
  # iOS build logs
@@ -7,14 +7,14 @@
7
7
  "// targets": "to see all targets run: nx show project mobile --web",
8
8
  "targets": {
9
9
  "check-env": {
10
- "executor": "nx:run-script",
10
+ "executor": "nx:run-commands",
11
11
  "options": {
12
- "script": "check-env:mobile"
12
+ "command": "./check-env.sh apps/mobile/.env apps/mobile/.env.template"
13
13
  }
14
14
  },
15
15
  "start": {
16
16
  "executor": "@nx/react-native:start",
17
- "dependsOn": ["check-env", "sync-deps", "pod-install"],
17
+ "dependsOn": ["check-env", "pod-install"],
18
18
  "options": {
19
19
  "port": 8081,
20
20
  "resetCache": true,
@@ -28,9 +28,11 @@
28
28
  }
29
29
  },
30
30
  "run-ios": {
31
- "executor": "@nx/react-native:run-ios",
31
+ "executor": "nx:run-commands",
32
32
  "dependsOn": ["pod-install"],
33
- "options": {}
33
+ "options": {
34
+ "command": "cd apps/mobile && ./run-ios.sh"
35
+ }
34
36
  },
35
37
  "bundle-ios": {
36
38
  "executor": "@nx/react-native:bundle",
@@ -43,12 +45,10 @@
43
45
  }
44
46
  },
45
47
  "run-android": {
46
- "executor": "@nx/react-native:run-android",
48
+ "executor": "nx:run-commands",
47
49
  "dependsOn": [],
48
50
  "options": {
49
- "appIdSuffix": "dev",
50
- "mode": "debug",
51
- "tasks": "installDevDebug"
51
+ "command": "cd apps/mobile && ./run-android.sh"
52
52
  }
53
53
  },
54
54
  "build-android": {
@@ -67,9 +67,15 @@
67
67
  "options": {}
68
68
  },
69
69
  "pod-install": {
70
- "executor": "nx:run-script",
70
+ "executor": "nx:run-commands",
71
71
  "options": {
72
- "script": "bundle:pod-install"
72
+ "command": "cd apps/mobile && ./pod-install.sh"
73
+ }
74
+ },
75
+ "pod-install:force": {
76
+ "executor": "nx:run-commands",
77
+ "options": {
78
+ "command": "cd apps/mobile && ./ios-only.sh 'cd ios && bundle install && bundle exec pod install --repo-update && cd .. && ./export-node-binary.sh'"
73
79
  }
74
80
  },
75
81
  "bundle-android": {
@@ -82,14 +88,6 @@
82
88
  "bundleOutput": "dist/apps/mobile/android/main.jsbundle"
83
89
  }
84
90
  },
85
- "sync-deps": {
86
- "executor": "@nx/react-native:sync-deps",
87
- "options": {}
88
- },
89
- "ensure-symlink": {
90
- "executor": "@nx/react-native:ensure-symlink",
91
- "options": {}
92
- },
93
91
  "lint": {
94
92
  "executor": "@nx/eslint:lint",
95
93
  "outputs": ["{options.outputFile}"],
@@ -74,6 +74,7 @@ DerivedData
74
74
  # Android/IntelliJ
75
75
  #
76
76
  build/
77
+ .kotlin
77
78
  .idea
78
79
  .gradle
79
80
  local.properties
File without changes
@@ -0,0 +1,107 @@
1
+ #!/bin/bash
2
+ # Interactive deployment - picks platform, lane, and environment
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ FASTLANE_DIR="$SCRIPT_DIR/fastlane"
6
+
7
+ source "$SCRIPT_DIR/picker.sh"
8
+
9
+ # --- Platform selection ---
10
+ PLATFORMS=("ios" "android")
11
+ pick "Select a platform:" "${PLATFORMS[@]}" --key "deploy-platform"
12
+ SELECTED_PLATFORM="${PLATFORMS[$PICKED_INDEX]}"
13
+
14
+ # --- Lane selection (dynamically parsed from Fastfile) ---
15
+ LANES=$(python3 -c "
16
+ import re
17
+ with open('$FASTLANE_DIR/Fastfile') as f:
18
+ content = f.read()
19
+
20
+ # Find the platform block for the selected platform
21
+ pattern = r'platform\s+:$SELECTED_PLATFORM\s+do(.*?)^end'
22
+ match = re.search(pattern, content, re.DOTALL | re.MULTILINE)
23
+ if match:
24
+ block = match.group(1)
25
+ # Find all lane declarations
26
+ lanes = re.findall(r'lane\s+:(\w+)\s+do', block)
27
+ for lane in lanes:
28
+ print(lane)
29
+ ")
30
+
31
+ if [ -z "$LANES" ]; then
32
+ echo "No lanes found for platform: $SELECTED_PLATFORM"
33
+ exit 1
34
+ fi
35
+
36
+ LANE_ARRAY=()
37
+ while IFS= read -r line; do
38
+ [ -z "$line" ] && continue
39
+ LANE_ARRAY+=("$line")
40
+ done <<< "$LANES"
41
+
42
+ pick "Select a lane:" "${LANE_ARRAY[@]}" --key "deploy-lane-$SELECTED_PLATFORM"
43
+ SELECTED_LANE="${LANE_ARRAY[$PICKED_INDEX]}"
44
+
45
+ # --- Environment selection (dynamically from .env.* files) ---
46
+ ENV_ARRAY=()
47
+ for env_file in "$FASTLANE_DIR"/.env.*; do
48
+ [ -f "$env_file" ] || continue
49
+ env_name=$(basename "$env_file" | sed 's/^\.env\.//')
50
+ # Skip template
51
+ if [ "$env_name" = "template" ]; then
52
+ continue
53
+ fi
54
+ ENV_ARRAY+=("$env_name")
55
+ done
56
+
57
+ if [ ${#ENV_ARRAY[@]} -eq 0 ]; then
58
+ echo ""
59
+ echo "No environment files found. Create at least one of:"
60
+ echo " fastlane/.env.development"
61
+ echo " fastlane/.env.staging"
62
+ echo " fastlane/.env.production"
63
+ exit 1
64
+ fi
65
+
66
+ pick "Select an environment:" "${ENV_ARRAY[@]}" --key "deploy-env"
67
+ SELECTED_ENV="${ENV_ARRAY[$PICKED_INDEX]}"
68
+
69
+ # --- Safeguard: check for local URLs in .env ---
70
+ APP_ENV="$SCRIPT_DIR/.env"
71
+ if [ -f "$APP_ENV" ]; then
72
+ if grep -qiE 'localhost|192\.168\.' "$APP_ENV"; then
73
+ echo ""
74
+ echo "Deployment aborted: apps/mobile/.env contains a local URL (localhost or 192.168.*)."
75
+ echo "Update your .env to point to the correct remote server before deploying."
76
+ exit 1
77
+ fi
78
+ fi
79
+
80
+ # --- Confirmation ---
81
+ echo ""
82
+ echo "Deploy summary:"
83
+ echo " Platform: $SELECTED_PLATFORM"
84
+ echo " Lane: $SELECTED_LANE"
85
+ if [ -n "$SELECTED_ENV" ]; then
86
+ echo " Environment: $SELECTED_ENV"
87
+ fi
88
+ echo ""
89
+
90
+ CONFIRM_ARRAY=("Yes" "No")
91
+ pick "Proceed with deployment?" "${CONFIRM_ARRAY[@]}"
92
+ if [ "$PICKED_INDEX" -ne 0 ]; then
93
+ echo "Deployment cancelled."
94
+ exit 0
95
+ fi
96
+
97
+ # --- Run fastlane ---
98
+ echo ""
99
+ FASTLANE_CMD="bundle exec fastlane $SELECTED_PLATFORM $SELECTED_LANE"
100
+ if [ -n "$SELECTED_ENV" ]; then
101
+ FASTLANE_CMD="$FASTLANE_CMD --env $SELECTED_ENV"
102
+ fi
103
+
104
+ echo "Running: $FASTLANE_CMD"
105
+ echo ""
106
+
107
+ cd "$SCRIPT_DIR" && $FASTLANE_CMD
@@ -1,82 +1,5 @@
1
1
  {
2
2
  "name": "mobile",
3
3
  "version": "0.0.1",
4
- "private": true,
5
- "scripts": {
6
- "android:connect": "adb reverse tcp:8081 tcp:8081",
7
- "start": "npx nx start mobile --skip-nx-cache",
8
- "run-ios": "./ios-only.sh npx nx run-ios mobile --skip-nx-cache --scheme=Dev --simulator='iPhone 16'",
9
- "run-android": "npx nx run-android mobile --skip-nx-cache",
10
- "ensure-symlink": "npx nx ensure-symlink mobile",
11
- "sync-deps": "npx nx sync-deps mobile",
12
- "pod-install": "./ios-only.sh npx nx pod-install mobile",
13
- "export-node-binary": "./export-node-binary.sh",
14
- "bundle:pod-install": "./ios-only.sh 'cd ios && bundle install && bundle exec pod install --repo-update && npm run export-node-binary'",
15
- "pre-build": "npm run ensure-symlink && npm run sync-deps && npm run pod-install-conditional",
16
- "list:ios-configurations": "./ios-only.sh 'cd ios && xcodebuild -list'",
17
- "list:ios-devices": "./ios-only.sh xcrun xctrace list devices",
18
- "xcode": "./ios-only.sh xed -b ios",
19
- "touch-xcode": "./ios-only.sh 'cd ios && touch .xcode.env'",
20
- "check-env:mobile": "cd ../.. && npm run check-env:mobile",
21
- "setup-fastlane": "rbenv local && bundle install && bundle update",
22
- "deploy-android:dev": "bundle exec fastlane android dev --env development",
23
- "deploy-ios:dev": "./ios-only.sh 'bundle exec fastlane ios dev --env development'",
24
- "ios-certificates": "./ios-only.sh 'npm run setup-fastlane && bundle exec fastlane ios certificates --env development'"
25
- },
26
- "dependencies": {
27
- "@gorhom/bottom-sheet": "*",
28
- "@hookform/resolvers": "*",
29
- "@react-native-community/datetimepicker": "*",
30
- "@react-native-community/hooks": "*",
31
- "@react-native/metro-config": "*",
32
- "@react-navigation/core": "*",
33
- "@react-navigation/material-top-tabs": "*",
34
- "@react-navigation/native-stack": "*",
35
- "@react-navigation/native": "*",
36
- "@react-navigation/routers": "*",
37
- "@react-navigation/stack": "*",
38
- "@shopify/react-native-skia": "*",
39
- "@tanstack/query-async-storage-persister": "*",
40
- "@tanstack/query-core": "*",
41
- "@tanstack/query-sync-storage-persister": "*",
42
- "@tanstack/react-query-persist-client": "*",
43
- "@tanstack/react-query": "*",
44
- "@testing-library/jest-native": "*",
45
- "@testing-library/react-native": "*",
46
- "axios": "*",
47
- "babel-plugin-module-resolver": "*",
48
- "dayjs": "*",
49
- "jotai-optics": "*",
50
- "jotai": "*",
51
- "lodash": "*",
52
- "metro-config": "*",
53
- "react-hook-form": "*",
54
- "react-native-dotenv": "*",
55
- "react-native-gesture-handler": "*",
56
- "react-native-get-random-values": "*",
57
- "react-native-haptic-feedback": "*",
58
- "react-native-keyboard-controller": "*",
59
- "react-native-mmkv": "*",
60
- "react-native-modal-datetime-picker": "*",
61
- "react-native-modal": "*",
62
- "react-native-nitro-modules": "*",
63
- "react-native-pager-view": "*",
64
- "react-native-reanimated": "*",
65
- "react-native-safe-area-context": "*",
66
- "react-native-screens": "*",
67
- "react-native-simple-toast": "*",
68
- "react-native-svg-transformer": "*",
69
- "react-native-svg": "*",
70
- "react-native-turbo-image": "*",
71
- "react-native-url-polyfill": "*",
72
- "react-native-worklets": "*",
73
- "react-native": "*",
74
- "react": "*",
75
- "tailwindcss": "*",
76
- "twrnc": "*",
77
- "uuid": "*",
78
- "zod-validation-error": "*",
79
- "zod": "*",
80
- "zustand": "*"
81
- }
4
+ "private": true
82
5
  }
@@ -0,0 +1,151 @@
1
+ #!/bin/bash
2
+ # Arrow key menu picker with scrolling and recent selection memory
3
+ # Usage: source picker.sh
4
+ # pick "Title" options_array # no memory
5
+ # pick "Title" options_array --key "cache-key" # remembers last pick
6
+
7
+ PICKER_CACHE_DIR="${HOME}/.cache/nxrn-picker"
8
+
9
+ pick() {
10
+ local title="$1"
11
+ shift
12
+
13
+ # Parse options and --key flag
14
+ local raw_options=()
15
+ local cache_key=""
16
+ while [ $# -gt 0 ]; do
17
+ if [ "$1" = "--key" ]; then
18
+ cache_key="$2"
19
+ shift 2
20
+ else
21
+ raw_options+=("$1")
22
+ shift
23
+ fi
24
+ done
25
+
26
+ local options=("${raw_options[@]}")
27
+ local count=${#options[@]}
28
+ local selected=0
29
+
30
+ # If cache key provided, sort last-used to top
31
+ local reordered_indices=()
32
+ if [ -n "$cache_key" ] && [ -f "$PICKER_CACHE_DIR/$cache_key" ]; then
33
+ local last_pick
34
+ last_pick=$(cat "$PICKER_CACHE_DIR/$cache_key")
35
+
36
+ # Find the last-used item and move it to front
37
+ local found_idx=-1
38
+ for i in "${!options[@]}"; do
39
+ if [ "${options[$i]}" = "$last_pick" ]; then
40
+ found_idx=$i
41
+ break
42
+ fi
43
+ done
44
+
45
+ if [ $found_idx -ge 0 ]; then
46
+ local new_options=("${options[$found_idx]}")
47
+ reordered_indices=($found_idx)
48
+ for i in "${!options[@]}"; do
49
+ if [ "$i" -ne $found_idx ]; then
50
+ new_options+=("${options[$i]}")
51
+ reordered_indices+=($i)
52
+ fi
53
+ done
54
+ options=("${new_options[@]}")
55
+ fi
56
+ fi
57
+
58
+ # If no reorder happened, build identity mapping
59
+ if [ ${#reordered_indices[@]} -eq 0 ]; then
60
+ for i in "${!options[@]}"; do
61
+ reordered_indices+=($i)
62
+ done
63
+ fi
64
+
65
+ # Max visible rows
66
+ local term_height=$(tput lines)
67
+ local max_visible=$((term_height - 4))
68
+ if [ $max_visible -gt $count ]; then
69
+ max_visible=$count
70
+ fi
71
+ if [ $max_visible -lt 3 ]; then
72
+ max_visible=3
73
+ fi
74
+
75
+ local scroll_offset=0
76
+
77
+ tput civis
78
+ trap 'tput cnorm' RETURN
79
+
80
+ draw_menu() {
81
+ for ((i = 0; i < max_visible; i++)); do
82
+ local idx=$((scroll_offset + i))
83
+ tput el
84
+ if [ "$idx" -eq $selected ]; then
85
+ echo -e " \033[7m> ${options[$idx]}\033[0m"
86
+ else
87
+ echo " ${options[$idx]}"
88
+ fi
89
+ done
90
+ tput el
91
+ if [ $count -gt $max_visible ]; then
92
+ echo -e " \033[2m[$((selected + 1))/$count]\033[0m"
93
+ else
94
+ echo ""
95
+ fi
96
+ }
97
+
98
+ echo ""
99
+ echo "$title"
100
+ draw_menu
101
+
102
+ local visible_lines=$((max_visible + 1))
103
+
104
+ while true; do
105
+ IFS= read -rsn1 key
106
+
107
+ if [[ "$key" == $'\x1b' ]]; then
108
+ read -rsn2 rest
109
+ key+="$rest"
110
+ fi
111
+
112
+ case "$key" in
113
+ $'\x1b[A' | k)
114
+ ((selected--))
115
+ if [ $selected -lt 0 ]; then
116
+ selected=$((count - 1))
117
+ scroll_offset=$((count - max_visible))
118
+ if [ $scroll_offset -lt 0 ]; then scroll_offset=0; fi
119
+ elif [ $selected -lt $scroll_offset ]; then
120
+ scroll_offset=$selected
121
+ fi
122
+ ;;
123
+ $'\x1b[B' | j)
124
+ ((selected++))
125
+ if [ $selected -ge $count ]; then
126
+ selected=0
127
+ scroll_offset=0
128
+ elif [ $selected -ge $((scroll_offset + max_visible)) ]; then
129
+ scroll_offset=$((selected - max_visible + 1))
130
+ fi
131
+ ;;
132
+ '')
133
+ break
134
+ ;;
135
+ esac
136
+
137
+ tput cuu $visible_lines
138
+ draw_menu
139
+ done
140
+
141
+ tput cnorm
142
+
143
+ # Save selection to cache
144
+ if [ -n "$cache_key" ]; then
145
+ mkdir -p "$PICKER_CACHE_DIR"
146
+ echo "${options[$selected]}" > "$PICKER_CACHE_DIR/$cache_key"
147
+ fi
148
+
149
+ # Map back to original index
150
+ PICKED_INDEX=${reordered_indices[$selected]}
151
+ }
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+ # Smart pod install - only runs when dependencies have changed
3
+ # Compares checksum of Podfile + root package.json deps against cached value
4
+
5
+ if [[ "$OSTYPE" != "darwin"* ]]; then
6
+ echo "Skipping pod install on non-macOS platform"
7
+ exit 0
8
+ fi
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
+ IOS_DIR="$SCRIPT_DIR/ios"
12
+ ROOT_DIR="$SCRIPT_DIR/../.."
13
+ CHECKSUM_FILE="$IOS_DIR/.pods-checksum"
14
+
15
+ # Generate checksum from files that affect pods
16
+ CURRENT_CHECKSUM=$(cat \
17
+ "$IOS_DIR/Podfile" \
18
+ "$ROOT_DIR/package.json" \
19
+ "$ROOT_DIR/yarn.lock" \
20
+ 2>/dev/null | shasum -a 256 | awk '{print $1}')
21
+
22
+ # Compare with cached checksum
23
+ if [ -f "$CHECKSUM_FILE" ]; then
24
+ CACHED_CHECKSUM=$(cat "$CHECKSUM_FILE")
25
+ if [ "$CURRENT_CHECKSUM" = "$CACHED_CHECKSUM" ]; then
26
+ echo "Pods up to date, skipping install."
27
+ exit 0
28
+ fi
29
+ fi
30
+
31
+ echo "Dependencies changed, running pod install..."
32
+ cd "$IOS_DIR" && bundle install && bundle exec pod install
33
+
34
+ if [ $? -eq 0 ]; then
35
+ echo "$CURRENT_CHECKSUM" > "$CHECKSUM_FILE"
36
+ cd "$SCRIPT_DIR" && ./export-node-binary.sh
37
+ else
38
+ echo "Pod install failed"
39
+ exit 1
40
+ fi
@@ -1,4 +1,19 @@
1
+ const rootPkg = require('../../package.json');
2
+
3
+ // Dynamically read all dependencies from the root package.json
4
+ // so autolinking discovers native modules without duplicating deps here.
5
+ const allDeps = Object.keys({
6
+ ...rootPkg.dependencies,
7
+ ...rootPkg.devDependencies,
8
+ });
9
+
10
+ const dependencies = {};
11
+ for (const dep of allDeps) {
12
+ dependencies[dep] = {};
13
+ }
14
+
1
15
  module.exports = {
16
+ dependencies,
2
17
  project: {
3
18
  ios: {},
4
19
  android: {},
@@ -0,0 +1,130 @@
1
+ #!/bin/bash
2
+ # Interactive Android launcher - picks variant and device
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ ANDROID_DIR="$SCRIPT_DIR/android"
6
+
7
+ source "$SCRIPT_DIR/picker.sh"
8
+
9
+ # --- Variant selection via gradle install tasks ---
10
+ echo ""
11
+ echo "Fetching build variants..."
12
+
13
+ INSTALL_TASKS=$(cd "$ANDROID_DIR" && ./gradlew app:tasks --group=install --quiet 2>/dev/null | grep "^install" | grep -vi "AndroidTest\|Optimized" | awk '{print $1}')
14
+
15
+ if [ -z "$INSTALL_TASKS" ]; then
16
+ echo "Could not read build variants from Gradle"
17
+ exit 1
18
+ fi
19
+
20
+ TASK_ARRAY=()
21
+ DISPLAY_ARRAY=()
22
+ while IFS= read -r line; do
23
+ [ -z "$line" ] && continue
24
+ TASK_ARRAY+=("$line")
25
+ DISPLAY_ARRAY+=("${line#install}")
26
+ done <<< "$INSTALL_TASKS"
27
+
28
+ pick "Select a build variant:" "${DISPLAY_ARRAY[@]}" --key "android-variant"
29
+ SELECTED_TASK="${TASK_ARRAY[$PICKED_INDEX]}"
30
+ SELECTED_VARIANT="${SELECTED_TASK#install}"
31
+
32
+ # Mode is the full variant name with first letter lowercased (e.g. devDebug, productionRelease)
33
+ MODE="$(tr '[:upper:]' '[:lower:]' <<< "${SELECTED_VARIANT:0:1}")${SELECTED_VARIANT:1}"
34
+
35
+ # Infer appIdSuffix from flavor (lowercase first char of variant minus build type)
36
+ FLAVOR=$(echo "$SELECTED_VARIANT" | sed -E 's/(Debug|Release)$//' | tr '[:upper:]' '[:lower:]')
37
+ APP_ID_SUFFIX=""
38
+ if [ "$FLAVOR" != "production" ] && [ -n "$FLAVOR" ]; then
39
+ APP_ID_SUFFIX="$FLAVOR"
40
+ fi
41
+
42
+ # --- Device selection (booted devices + shutdown AVDs) ---
43
+ DEVICE_ARRAY=()
44
+ DEVICE_IDS=()
45
+ DEVICE_TYPES=() # "booted" or "avd"
46
+
47
+ # Collect running devices/emulators
48
+ RUNNING_AVDS=()
49
+ DEVICES=$(adb devices -l 2>/dev/null | tail -n +2 | grep -v '^$')
50
+ if [ -n "$DEVICES" ]; then
51
+ while IFS= read -r line; do
52
+ [ -z "$line" ] && continue
53
+ SERIAL=$(echo "$line" | awk '{print $1}')
54
+ MODEL=$(echo "$line" | grep -o 'model:[^ ]*' | cut -d: -f2)
55
+
56
+ if echo "$SERIAL" | grep -q "emulator"; then
57
+ # Get AVD name for this running emulator
58
+ AVD_NAME=$(adb -s "$SERIAL" emu avd name 2>/dev/null | head -1 | tr -d '\r')
59
+ RUNNING_AVDS+=("$AVD_NAME")
60
+ LABEL="[Booted] $SERIAL${AVD_NAME:+ ($AVD_NAME)}"
61
+ else
62
+ LABEL="[Device] $SERIAL${MODEL:+ ($MODEL)}"
63
+ fi
64
+
65
+ DEVICE_ARRAY+=("$LABEL")
66
+ DEVICE_IDS+=("$SERIAL")
67
+ DEVICE_TYPES+=("booted")
68
+ done <<< "$DEVICES"
69
+ fi
70
+
71
+ # Collect shutdown AVDs
72
+ ALL_AVDS=$(emulator -list-avds 2>/dev/null)
73
+ if [ -n "$ALL_AVDS" ]; then
74
+ while IFS= read -r avd; do
75
+ [ -z "$avd" ] && continue
76
+ # Skip if already running
77
+ ALREADY_RUNNING=false
78
+ for running in "${RUNNING_AVDS[@]}"; do
79
+ if [ "$avd" = "$running" ]; then
80
+ ALREADY_RUNNING=true
81
+ break
82
+ fi
83
+ done
84
+ if [ "$ALREADY_RUNNING" = false ]; then
85
+ DEVICE_ARRAY+=("[Shutdown] $avd")
86
+ DEVICE_IDS+=("$avd")
87
+ DEVICE_TYPES+=("avd")
88
+ fi
89
+ done <<< "$ALL_AVDS"
90
+ fi
91
+
92
+ if [ ${#DEVICE_ARRAY[@]} -eq 0 ]; then
93
+ echo ""
94
+ echo "No Android devices or AVDs found."
95
+ exit 1
96
+ fi
97
+
98
+ pick "Select a device:" "${DEVICE_ARRAY[@]}" --key "android-device"
99
+ SELECTED_INDEX=$PICKED_INDEX
100
+ SELECTED_DEVICE="${DEVICE_IDS[$SELECTED_INDEX]}"
101
+
102
+ # Boot AVD if shutdown
103
+ if [ "${DEVICE_TYPES[$SELECTED_INDEX]}" = "avd" ]; then
104
+ echo ""
105
+ echo "Booting AVD: $SELECTED_DEVICE..."
106
+ emulator -avd "$SELECTED_DEVICE" -no-snapshot-load &>/dev/null &
107
+
108
+ # Wait for device to come online
109
+ echo "Waiting for device to boot..."
110
+ adb wait-for-device
111
+ # Wait for boot animation to finish
112
+ while [ "$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" != "1" ]; do
113
+ sleep 1
114
+ done
115
+ echo "Device booted."
116
+
117
+ # Get the serial of the newly booted emulator
118
+ SELECTED_DEVICE=$(adb devices | grep "emulator" | tail -1 | awk '{print $1}')
119
+ fi
120
+
121
+ echo ""
122
+ echo "Running: task=$SELECTED_TASK mode=$MODE device=$SELECTED_DEVICE"
123
+ echo ""
124
+
125
+ RN_ARGS="--tasks=$SELECTED_TASK --mode=$MODE --device=$SELECTED_DEVICE"
126
+ if [ -n "$APP_ID_SUFFIX" ]; then
127
+ RN_ARGS="$RN_ARGS --appIdSuffix=$APP_ID_SUFFIX"
128
+ fi
129
+
130
+ cd "$SCRIPT_DIR" && npx react-native run-android $RN_ARGS
@@ -0,0 +1,89 @@
1
+ #!/bin/bash
2
+ # Interactive iOS launcher - picks scheme and simulator
3
+
4
+ if [[ "$OSTYPE" != "darwin"* ]]; then
5
+ echo "iOS builds only work on macOS"
6
+ exit 1
7
+ fi
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
+ PROJECT_DIR="$SCRIPT_DIR/ios"
11
+
12
+ source "$SCRIPT_DIR/picker.sh"
13
+
14
+ # --- Scheme selection ---
15
+ SCHEMES=$(cd "$PROJECT_DIR" && xcodebuild -list -json 2>/dev/null | python3 -c "
16
+ import sys, json
17
+ data = json.load(sys.stdin)
18
+ for s in data.get('project', {}).get('schemes', []):
19
+ print(s)
20
+ ")
21
+
22
+ if [ -z "$SCHEMES" ]; then
23
+ echo "Could not read schemes from Xcode project"
24
+ exit 1
25
+ fi
26
+
27
+ SCHEME_ARRAY=()
28
+ while IFS= read -r line; do
29
+ SCHEME_ARRAY+=("$line")
30
+ done <<< "$SCHEMES"
31
+
32
+ pick "Select a scheme:" "${SCHEME_ARRAY[@]}" --key "ios-scheme"
33
+ SELECTED_SCHEME="${SCHEME_ARRAY[$PICKED_INDEX]}"
34
+
35
+ # --- Simulator selection (booted first, then by name, then iOS version desc) ---
36
+ SIMULATORS=$(xcrun simctl list devices available -j 2>/dev/null | python3 -c "
37
+ import sys, json, re
38
+
39
+ data = json.load(sys.stdin)
40
+ devices_list = []
41
+
42
+ for runtime, devices in data.get('devices', {}).items():
43
+ if 'iOS' not in runtime:
44
+ continue
45
+ ver_match = re.search(r'(\d+)[\-\.](\d+)', runtime)
46
+ if not ver_match:
47
+ continue
48
+ ver_major, ver_minor = int(ver_match.group(1)), int(ver_match.group(2))
49
+ ver = f'{ver_major}.{ver_minor}'
50
+ for d in devices:
51
+ is_booted = d['state'] == 'Booted'
52
+ devices_list.append((is_booted, d['name'], ver_major, ver_minor, ver))
53
+
54
+ # Parse model number from name (e.g. 'iPhone 16 Pro Max' -> 16)
55
+ def sort_key(x):
56
+ is_booted, name, ver_major, ver_minor, ver = x
57
+ is_iphone = name.startswith('iPhone')
58
+ model_match = re.search(r'(\d+)', name)
59
+ model_num = int(model_match.group(1)) if model_match else 0
60
+ # booted first, iPhone over iPad, highest model first, Pro Max > Pro > base, newest iOS first
61
+ return (not is_booted, not is_iphone, -model_num, name.count('Pro') == 0, 'Max' not in name, -ver_major, -ver_minor)
62
+
63
+ devices_list.sort(key=sort_key)
64
+
65
+ for is_booted, name, _, _, ver in devices_list:
66
+ prefix = '[Booted] ' if is_booted else ''
67
+ print(f'{prefix}{name} ({ver})')
68
+ ")
69
+
70
+ if [ -z "$SIMULATORS" ]; then
71
+ echo "No iOS simulators found"
72
+ exit 1
73
+ fi
74
+
75
+ SIM_ARRAY=()
76
+ while IFS= read -r line; do
77
+ SIM_ARRAY+=("$line")
78
+ done <<< "$SIMULATORS"
79
+
80
+ pick "Select a simulator:" "${SIM_ARRAY[@]}" --key "ios-simulator"
81
+ SELECTED_SIM="${SIM_ARRAY[$PICKED_INDEX]}"
82
+ # Strip [Booted] prefix to get "Name (version)"
83
+ SIM_NAME=$(echo "$SELECTED_SIM" | sed 's/^\[Booted\] //')
84
+
85
+ echo ""
86
+ echo "Running: scheme=$SELECTED_SCHEME simulator=$SIM_NAME"
87
+ echo ""
88
+
89
+ cd "$SCRIPT_DIR" && npx react-native run-ios --scheme="$SELECTED_SCHEME" --simulator="$SIM_NAME"
@@ -1,7 +1,14 @@
1
1
  /* eslint-disable no-magic-numbers */
2
2
  import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
3
3
  import React, { useCallback, useState } from 'react';
4
- import { Keyboard, Pressable, Modal as RNBuiltInModal, StyleProp, ViewStyle } from 'react-native';
4
+ import {
5
+ Keyboard,
6
+ Pressable,
7
+ Modal as RNBuiltInModal,
8
+ StyleProp,
9
+ View,
10
+ ViewStyle,
11
+ } from 'react-native';
5
12
  import RNModal from 'react-native-modal';
6
13
 
7
14
  import CONFIG from '@/config';
@@ -35,7 +42,12 @@ function IOSModal(props: ModalProps) {
35
42
  onBackButtonPress={onBackButtonPress}
36
43
  onBackdropPress={onBackdropPress}
37
44
  >
38
- <BottomSheetModalProvider>{children}</BottomSheetModalProvider>
45
+ <>
46
+ <Pressable style={tw`absolute h-full w-full`} onPress={onBackdropPress}>
47
+ <View style={tw`h-full w-full bg-black/60`} />
48
+ </Pressable>
49
+ <BottomSheetModalProvider>{children}</BottomSheetModalProvider>
50
+ </>
39
51
  </RNModal>
40
52
  );
41
53
  }
@@ -52,11 +64,12 @@ function AndroidModal(props: ModalProps) {
52
64
  visible={isVisible}
53
65
  onRequestClose={onBackButtonPress}
54
66
  >
55
- <Pressable style={tw`flex-1 bg-black/60`} onPress={onBackdropPress}>
56
- <Pressable style={tw`flex-1`}>
57
- <BottomSheetModalProvider>{children}</BottomSheetModalProvider>
67
+ <>
68
+ <Pressable style={tw`absolute h-full w-full`} onPress={onBackdropPress}>
69
+ <View style={tw`h-full w-full bg-black/60`} />
58
70
  </Pressable>
59
- </Pressable>
71
+ <BottomSheetModalProvider>{children}</BottomSheetModalProvider>
72
+ </>
60
73
  </RNBuiltInModal>
61
74
  );
62
75
  }
@@ -16,7 +16,7 @@ export function Typography(props: Props): JSX.Element {
16
16
  return (
17
17
  <RNText
18
18
  {...shouldTruncateTextProps}
19
- style={[tw`text-black-950 font-sans text-base font-normal`, style]}
19
+ style={[tw`font-sans text-base font-normal text-black`, style]}
20
20
  {...extraProps}
21
21
  />
22
22
  );
@@ -39,7 +39,7 @@ export function ScreenHeader(props: Props) {
39
39
  {extraActionComponent ? (
40
40
  extraActionComponent
41
41
  ) : (
42
- <GearIcon height={25} style={tw`text-black-950`} width={25} />
42
+ <GearIcon height={25} style={tw`text-black`} width={25} />
43
43
  )}
44
44
  </View>
45
45
  </TouchableOpacity>
@@ -34,6 +34,10 @@ rm -rf "$app_rn_node_modules_path"
34
34
  echo "Deleting $app_rn_ios_pods_path..."
35
35
  rm -rf "$app_rn_ios_pods_path"
36
36
 
37
+ app_rn_ios_pods_checksum="apps/$app_rn_name/ios/.pods-checksum"
38
+ echo "Deleting $app_rn_ios_pods_checksum..."
39
+ rm -f "$app_rn_ios_pods_checksum"
40
+
37
41
  echo "Deleting $app_rn_ios_build_path..."
38
42
  rm -rf "$app_rn_ios_build_path"
39
43