catalyst-core 0.2.0-beta.2 → 0.3.0-beta.1

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.
Files changed (184) hide show
  1. package/babel.native.config.cjs +8 -0
  2. package/bin/catalyst.js +49 -105
  3. package/changelog.md +8 -0
  4. package/dist/caching.js +1 -1
  5. package/dist/index.jsx +8 -0
  6. package/dist/logger.js +74 -3
  7. package/dist/native/androidProject/app/build.gradle.kts +1 -0
  8. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +143 -4
  9. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +26 -6
  10. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MetricsMonitor.kt +143 -17
  11. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +6 -0
  12. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/WebCacheManager.kt +26 -0
  13. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +56 -1
  14. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/KeyboardUtil.kt +48 -8
  15. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/PerfDeliveryState.kt +36 -0
  16. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/PerfEventBuffer.kt +289 -0
  17. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/ProfilerNavigationState.kt +13 -0
  18. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/ProfilerLifecycleTest.kt +51 -0
  19. package/dist/native/androidSetup.js +300 -8
  20. package/dist/native/bridge/WebBridge.js +481 -59
  21. package/dist/native/bridge/constants/NativeInterfaces.js +290 -44
  22. package/dist/native/bridge/errors.js +250 -26
  23. package/dist/native/bridge/hooks/index.js +125 -1
  24. package/dist/native/bridge/hooks/useCamera.js +347 -9
  25. package/dist/native/bridge/hooks/useDataProtection.js +200 -2
  26. package/dist/native/bridge/hooks/useDeviceInfo.js +71 -2
  27. package/dist/native/bridge/hooks/useFilePicker.js +429 -2
  28. package/dist/native/bridge/hooks/useGoogleSignIn.js +81 -1
  29. package/dist/native/bridge/hooks/useHapticFeedback.js +196 -1
  30. package/dist/native/bridge/hooks/useIntent.js +95 -1
  31. package/dist/native/bridge/hooks/useNativeTransition.js +202 -27
  32. package/dist/native/bridge/hooks/useNetworkStatus.js +84 -3
  33. package/dist/native/bridge/hooks/useNotification.js +318 -2
  34. package/dist/native/bridge/hooks/useSafeArea.js +84 -2
  35. package/dist/native/bridge/hooks/useVideoStream.js +434 -6
  36. package/dist/native/bridge/hooks/utils.js +27 -1
  37. package/dist/native/bridge/hooks.js +16 -1
  38. package/dist/native/bridge/perf/collectors/ApiCollector.js +85 -0
  39. package/dist/native/bridge/perf/collectors/CacheCollector.js +215 -0
  40. package/dist/native/bridge/perf/collectors/HookCollector.js +165 -0
  41. package/dist/native/bridge/perf/collectors/InsightsCollector.js +505 -0
  42. package/dist/native/bridge/perf/collectors/InteractionCollector.js +273 -0
  43. package/dist/native/bridge/perf/collectors/KeyboardCollector.js +124 -0
  44. package/dist/native/bridge/perf/collectors/NavigationCollector.js +294 -0
  45. package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +183 -0
  46. package/dist/native/bridge/perf/collectors/RenderCollector.js +284 -0
  47. package/dist/native/bridge/perf/collectors/ScrollCollector.js +111 -0
  48. package/dist/native/bridge/perf/collectors/ThreadCollector.js +111 -0
  49. package/dist/native/bridge/perf/core/constants.js +126 -0
  50. package/dist/native/bridge/perf/core/measure.js +189 -0
  51. package/dist/native/bridge/perf/core/session.js +100 -0
  52. package/dist/native/bridge/perf/core/store.js +554 -0
  53. package/dist/native/bridge/perf/core/summary.js +174 -0
  54. package/dist/native/bridge/perf/core/traceExport.js +240 -0
  55. package/dist/native/bridge/perf/core/waterfalls.js +146 -0
  56. package/dist/native/bridge/perf/index.js +402 -0
  57. package/dist/native/bridge/safeArea.js +53 -5
  58. package/dist/native/bridge/standardizedHooks.js +595 -82
  59. package/dist/native/bridge/useBaseHook.js +274 -38
  60. package/dist/native/bridge/utils/CameraUtils.js +201 -56
  61. package/dist/native/bridge/utils/FileObjectConverter.js +129 -18
  62. package/dist/native/bridge/utils/NativeBridge.js +425 -141
  63. package/dist/native/buildAndroid/assets.js +510 -13
  64. package/dist/native/buildAndroid/build.js +296 -19
  65. package/dist/native/buildAndroid/config.js +87 -1
  66. package/dist/native/buildAndroid/index.js +374 -1
  67. package/dist/native/buildAppAndroid.js +34 -2
  68. package/dist/native/buildAppIos.js +62 -2
  69. package/dist/native/buildIos/assets.js +609 -8
  70. package/dist/native/buildIos/build.js +639 -20
  71. package/dist/native/buildIos/config.js +294 -12
  72. package/dist/native/buildIos/index.js +343 -6
  73. package/dist/native/buildIos/plugins.js +343 -16
  74. package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +43 -0
  75. package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +28 -0
  76. package/dist/native/internal-plugins/device-info-plugin/manifest.json +19 -0
  77. package/dist/native/internalPluginUtils.js +232 -7
  78. package/dist/native/iosnativeWebView/Sources/Core/Constants/CatalystConstants.swift +19 -0
  79. package/dist/native/iosnativeWebView/Sources/Core/Constants/ConfigConstants.swift +4 -0
  80. package/dist/native/iosnativeWebView/Sources/Core/Utils/BootTimingUtility.swift +5 -1
  81. package/dist/native/iosnativeWebView/Sources/Core/Utils/CacheManager.swift +10 -0
  82. package/dist/native/iosnativeWebView/Sources/Core/Utils/DisplayLinkPerfMonitor.swift +89 -0
  83. package/dist/native/iosnativeWebView/Sources/Core/Utils/PerfEventBuffer.swift +373 -0
  84. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeFileHandler.swift +35 -1
  85. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +24 -11
  86. package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +9 -0
  87. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +126 -0
  88. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +75 -1
  89. package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeMessageValidatorTests.swift +13 -0
  90. package/dist/native/package.json +3 -0
  91. package/dist/native/plugin-bridge/PluginBridge.js +227 -1
  92. package/dist/native/pluginComposerAndroid.js +407 -23
  93. package/dist/native/pluginComposerIos.js +435 -11
  94. package/dist/native/renameAndroidProject.js +1094 -88
  95. package/dist/native/setupEmulatorIos.js +289 -22
  96. package/dist/native/setupServer.js +160 -19
  97. package/dist/native/terminalProgress.js +199 -11
  98. package/dist/native/utils.js +193 -15
  99. package/dist/offline/catalyst-sw.js +145 -1
  100. package/dist/offline/registerServiceWorker.js +33 -1
  101. package/dist/otel.js +375 -46
  102. package/dist/router/ClientRouter.js +14 -2
  103. package/dist/router/ServerRouter.js +9 -1
  104. package/dist/router.js +1 -1
  105. package/dist/scripts/build.js +112 -3
  106. package/dist/scripts/checkVersion.js +3 -1
  107. package/dist/scripts/cleanCache.js +30 -1
  108. package/dist/scripts/generateOfflineManifest.js +116 -1
  109. package/dist/scripts/loadEnvironmentVariables.js +32 -6
  110. package/dist/scripts/plugins.js +309 -1
  111. package/dist/scripts/preServerInit.js +13 -0
  112. package/dist/scripts/scriptUtils.js +54 -3
  113. package/dist/scripts/serve.js +51 -4
  114. package/dist/scripts/start.js +47 -10
  115. package/dist/scripts/validator.js +149 -1
  116. package/dist/sentry.cjs +127 -0
  117. package/dist/sentry.js +125 -5
  118. package/dist/server/expressServer.js +250 -5
  119. package/dist/server/manifestCache.js +36 -0
  120. package/dist/server/renderer/ChunkExtractor.js +144 -0
  121. package/dist/server/renderer/document/Body.jsx +59 -0
  122. package/dist/server/renderer/document/FastRefresh.jsx +20 -0
  123. package/dist/server/renderer/document/Head.jsx +60 -0
  124. package/dist/server/renderer/document/index.jsx +2 -0
  125. package/dist/server/renderer/extract.js +149 -31
  126. package/dist/server/renderer/handler.jsx +433 -0
  127. package/dist/server/renderer/index.js +8 -1
  128. package/dist/server/renderer/render.js +47 -0
  129. package/dist/server/utils/botDetectionMiddleware.js +29 -0
  130. package/dist/server/utils/cjsRequire.js +10 -0
  131. package/dist/server/utils/userAgentUtil.js +87 -9
  132. package/dist/server/utils/validator.js +164 -1
  133. package/dist/vite/FastRefresh.jsx +20 -0
  134. package/dist/vite/inject-cache-key-plugin.js +276 -0
  135. package/dist/vite/loadCustomViteConfig.js +22 -0
  136. package/dist/vite/manifest-categorization-plugin.js +455 -0
  137. package/dist/vite/node-loader.mjs +458 -0
  138. package/dist/vite/scssParams.js +21 -0
  139. package/dist/vite/vite.config.client.js +130 -0
  140. package/dist/vite/vite.config.js +422 -0
  141. package/dist/vite/vite.config.server.js +84 -0
  142. package/dist/web-router/components/MetaTag.jsx +34 -0
  143. package/dist/web-router/components/RouterDataProvider.jsx +332 -0
  144. package/dist/web-router/components/Split.jsx +200 -0
  145. package/dist/web-router/components/SplitInview.jsx +106 -0
  146. package/dist/web-router/components/SsrRequestContext.jsx +14 -0
  147. package/dist/web-router/context.jsx +12 -0
  148. package/dist/web-router/hooks.jsx +72 -0
  149. package/dist/web-router/types/components/MetaTag.d.ts +2 -0
  150. package/dist/web-router/types/components/RouterDataProvider.d.ts +95 -0
  151. package/dist/web-router/types/context.d.ts +14 -0
  152. package/dist/web-router/types/hooks.d.ts +1 -0
  153. package/dist/web-router/types/index.d.ts +3 -0
  154. package/dist/web-router/types/utils/metaDataUtils.d.ts +24 -0
  155. package/dist/web-router/utils/metaDataUtils.jsx +119 -0
  156. package/mcp_v2/conversion-tasks.json +35 -17
  157. package/mcp_v2/knowledge-base.json +124 -13
  158. package/mcp_v2/lib/helpers.js +10 -0
  159. package/mcp_v2/mcp.js +4 -4
  160. package/mcp_v2/package.json +1 -0
  161. package/mcp_v2/tools/build.js +116 -20
  162. package/mcp_v2/tools/conversion.js +106 -5
  163. package/mcp_v2/tools/tasks.js +18 -14
  164. package/package.json +35 -68
  165. package/babel.config.js +0 -32
  166. package/dist/index.js +0 -1
  167. package/dist/scripts/devBuild.js +0 -3
  168. package/dist/scripts/devServe.js +0 -3
  169. package/dist/scripts/loadScriptsBeforeServerStarts.js +0 -4
  170. package/dist/scripts/registerAliases.js +0 -6
  171. package/dist/server/renderer/document/Body.js +0 -11
  172. package/dist/server/renderer/document/Head.js +0 -9
  173. package/dist/server/renderer/document/index.js +0 -1
  174. package/dist/server/renderer/handler.js +0 -47
  175. package/dist/server/startServer.js +0 -57
  176. package/dist/webpack/babel-plugins/remove-client.plugin.js +0 -5
  177. package/dist/webpack/babel-plugins/remove-ssr.plugin.js +0 -5
  178. package/dist/webpack/babel.config.client.js +0 -1
  179. package/dist/webpack/babel.config.ssr.js +0 -1
  180. package/dist/webpack/base.babel.js +0 -7
  181. package/dist/webpack/development.client.babel.js +0 -10
  182. package/dist/webpack/production.client.babel.js +0 -4
  183. package/dist/webpack/production.ssr.babel.js +0 -8
  184. package/dist/webpack/scssParams.js +0 -9
@@ -1,19 +1,234 @@
1
- "use strict";var _child_process=require("child_process");var _fs=_interopRequireDefault(require("fs"));var _utils=require("./utils.js");var _TerminalProgress=_interopRequireDefault(require("./TerminalProgress.js"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}const configPath=`${process.env.PWD}/config/config.json`;const{setupServer}=require("./setupServer.js");const ITEMS_PER_PAGE=10;const steps={platform:"Check Platform Compatibility",config:"Initialize Configuration",simulator:"Configure iOS Simulator",launch:"Launch iOS Simulator",saveConfig:"Saving configuration",setupServer:"Setup Server"};const progressPaddingConfig={titlePaddingTop:2,titlePaddingBottom:1,stepPaddingLeft:4,stepSpacing:1,errorPaddingLeft:6,bottomMargin:2};const progress=new _TerminalProgress.default(steps,"Catalyst Universal Ios Setup",progressPaddingConfig);async function initializeConfig(){const configFile=_fs.default.readFileSync(configPath,"utf8");const config=JSON.parse(configFile);const{WEBVIEW_CONFIG}=config;if(!WEBVIEW_CONFIG||Object.keys(WEBVIEW_CONFIG).length===0){progress.log("WebView Config missing in "+configPath,"error");process.exit(1);}if(!WEBVIEW_CONFIG.ios){WEBVIEW_CONFIG.ios={};}return{WEBVIEW_CONFIG};}async function saveConfig(newConfig){try{// Read the existing config
2
- const existingConfigFile=_fs.default.readFileSync(configPath,"utf8");const existingConfig=JSON.parse(existingConfigFile);// Merge the new WEBVIEW_CONFIG with existing config
3
- const updatedConfig={...existingConfig,// Preserve all existing keys
4
- WEBVIEW_CONFIG:{...existingConfig.WEBVIEW_CONFIG,ios:newConfig.WEBVIEW_CONFIG.ios}// Update only WEBVIEW_CONFIG
5
- };// Save the merged config
6
- _fs.default.writeFileSync(configPath,JSON.stringify(updatedConfig,null,2));progress.log("Configuration saved successfully","success");}catch(error){progress.log("Failed to save configuration: "+error.message,"error");process.exit(1);}}async function setupIOSEnvironment(){try{progress.start("platform");if(process.platform!=="darwin"){progress.log("iOS Simulator is only available on macOS.");process.exit(1);}progress.complete("platform");progress.start("config");const{WEBVIEW_CONFIG}=await initializeConfig();progress.complete("config");progress.start("simulator");await configureSimulator(WEBVIEW_CONFIG);progress.complete("simulator");progress.start("launch");await launchIOSSimulator(WEBVIEW_CONFIG.ios.simulatorName);progress.complete("launch");progress.start("saveConfig");const config=await(0,_utils.validateAndCompleteConfig)("ios",configPath);progress.complete("saveConfig");progress.start("setupServer");await setupServer(configPath);progress.start("setupServer");progress.printTreeContent("Configuration Explanation",["WEBVIEW_CONFIG: Main configuration object for the WebView setup",{text:"port: Port number for the WebView server",indent:1,prefix:"├─ ",color:"gray"},{text:"ios: iOS-specific configuration",indent:1,prefix:"└─ ",color:"gray"},{text:"buildType: Build type (debug/release)",indent:2,prefix:"├─ ",color:"gray"},{text:"appBundleId: iOS application bundle identifier",indent:2,prefix:"├─ ",color:"gray"},{text:"simulatorName: Selected iOS simulator name",indent:2,prefix:"└─ ",color:"gray"}]);progress.printTreeContent("Final Configuration",[JSON.stringify(config,null,2)]);process.exit(0);}catch(error){if(progress.currentStep){progress.fail(progress.currentStep.id,error.message);}process.exit(1);}}async function displayPaginatedList(items,startIndex){const endIndex=Math.min(startIndex+ITEMS_PER_PAGE,items.length);for(let i=startIndex;i<endIndex;i++){console.log(`${i+1}. ${items[i]}`);}if(endIndex<items.length){console.log(`\nShowing ${startIndex+1}-${endIndex} of ${items.length} items`);console.log('Type "more" to see more items, or enter your selection: ');return true;}return false;}async function getRuntime(){const runtimesOutput=(0,_child_process.execSync)("xcrun simctl list runtimes -j").toString();const parsedRuntimes=JSON.parse(runtimesOutput).runtimes;const availableRuntime=parsedRuntimes.find(runtime=>runtime.isAvailable||runtime.availability==="(available)"||runtime.availability==="available");if(!availableRuntime){const runningSimulators=(0,_child_process.execSync)("xcrun simctl list devices booted").toString();if(runningSimulators.includes("(Booted)")&&parsedRuntimes.length>0){console.log(`Using runtime: ${parsedRuntimes[0].name}`);return parsedRuntimes[0];}console.error("No available iOS runtime found. Please install one through Xcode.");process.exit(1);}console.log(`Using runtime: ${availableRuntime.name}`);return availableRuntime;}async function configureSimulator(config){// If a simulator is already configured, skip the interactive picker
7
- if(config.ios.simulatorName){progress.log(`Using configured simulator: ${config.ios.simulatorName}`);return;}progress.pause();// Get the current runtime first
8
- const runtime=await getRuntime();// Get simulators specifically for this runtime
9
- const simulatorsJson=JSON.parse((0,_child_process.execSync)("xcrun simctl list devices -j").toString());const runtimeSimulators=simulatorsJson.devices[runtime.identifier]||[];// Filter for available simulators only
10
- const availableSimulators=runtimeSimulators.filter(sim=>sim.availability==="(available)"||sim.isAvailable).map(sim=>`${sim.name} (${sim.udid})`);if(availableSimulators.length===0){progress.log(`No available simulators found for runtime: ${runtime.name}`,"error");progress.resume();process.exit(1);return;}let startIndex=0;console.log(`\nAvailable simulators for ${runtime.name} (or type 'new' to create a new one):`);// eslint-disable-next-line no-constant-condition
11
- while(true){const hasMore=await displayPaginatedList(availableSimulators,startIndex);const simulatorChoice=await(0,_utils.promptUser)(hasMore?"":"\nEnter selection: ");if(simulatorChoice.toLowerCase()==="more"&&hasMore){startIndex+=ITEMS_PER_PAGE;continue;}if(simulatorChoice.toLowerCase()==="new"){const deviceTypes=JSON.parse((0,_child_process.execSync)("xcrun simctl list devicetypes --json").toString()).devicetypes;const simulatorName=await(0,_utils.promptUser)("Enter a name for the new simulator: ");// Use iPhone 15 Pro as default device type
12
- const defaultDevice=deviceTypes.find(dt=>dt.name.includes("iPhone 15 Pro"))||deviceTypes[0];try{(0,_utils.runCommand)(`xcrun simctl create "${simulatorName}" "${defaultDevice.identifier}" "${runtime.identifier}"`);console.log(`Simulator "${simulatorName}" created successfully.`);config.ios.simulatorName=simulatorName;}catch(error){console.log(`Failed to create simulator "${simulatorName}". Error: ${error.message}`);process.exit(1);}break;}else{const index=parseInt(simulatorChoice)-1;if(index>=0&&index<availableSimulators.length){const selectedSimulator=availableSimulators[index];// Extract only the simulator name without ID and state
13
- const simulatorName=selectedSimulator.split(" (")[0];config.ios.simulatorName=simulatorName;break;}else{console.log("Invalid selection. Please try again.");}}}progress.resume();await saveConfig({WEBVIEW_CONFIG:config});}// async function createDefaultSimulator(config, runtime) {
1
+ "use strict";
2
+
3
+ var _child_process = require("child_process");
4
+ var _fs = _interopRequireDefault(require("fs"));
5
+ var _utils = require("./utils.js");
6
+ var _TerminalProgress = _interopRequireDefault(require("./TerminalProgress.js"));
7
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
+ const configPath = `${process.env.PWD}/config/config.json`;
9
+ const {
10
+ setupServer
11
+ } = require("./setupServer.js");
12
+ const ITEMS_PER_PAGE = 10;
13
+ const steps = {
14
+ platform: "Check Platform Compatibility",
15
+ config: "Initialize Configuration",
16
+ simulator: "Configure iOS Simulator",
17
+ launch: "Launch iOS Simulator",
18
+ saveConfig: "Saving configuration",
19
+ setupServer: "Setup Server"
20
+ };
21
+ const progressPaddingConfig = {
22
+ titlePaddingTop: 2,
23
+ titlePaddingBottom: 1,
24
+ stepPaddingLeft: 4,
25
+ stepSpacing: 1,
26
+ errorPaddingLeft: 6,
27
+ bottomMargin: 2
28
+ };
29
+ const progress = new _TerminalProgress.default(steps, "Catalyst Universal Ios Setup", progressPaddingConfig);
30
+ async function initializeConfig() {
31
+ const configFile = _fs.default.readFileSync(configPath, "utf8");
32
+ const config = JSON.parse(configFile);
33
+ const {
34
+ WEBVIEW_CONFIG
35
+ } = config;
36
+ if (!WEBVIEW_CONFIG || Object.keys(WEBVIEW_CONFIG).length === 0) {
37
+ progress.log("WebView Config missing in " + configPath, "error");
38
+ process.exit(1);
39
+ }
40
+ if (!WEBVIEW_CONFIG.ios) {
41
+ WEBVIEW_CONFIG.ios = {};
42
+ }
43
+ return {
44
+ WEBVIEW_CONFIG
45
+ };
46
+ }
47
+ async function saveConfig(newConfig) {
48
+ try {
49
+ // Read the existing config
50
+ const existingConfigFile = _fs.default.readFileSync(configPath, "utf8");
51
+ const existingConfig = JSON.parse(existingConfigFile);
52
+
53
+ // Merge the new WEBVIEW_CONFIG with existing config
54
+ const updatedConfig = {
55
+ ...existingConfig,
56
+ // Preserve all existing keys
57
+ WEBVIEW_CONFIG: {
58
+ ...existingConfig.WEBVIEW_CONFIG,
59
+ ios: newConfig.WEBVIEW_CONFIG.ios
60
+ } // Update only WEBVIEW_CONFIG
61
+ };
62
+
63
+ // Save the merged config
64
+ _fs.default.writeFileSync(configPath, JSON.stringify(updatedConfig, null, 2));
65
+ progress.log("Configuration saved successfully", "success");
66
+ } catch (error) {
67
+ progress.log("Failed to save configuration: " + error.message, "error");
68
+ process.exit(1);
69
+ }
70
+ }
71
+ async function setupIOSEnvironment() {
72
+ try {
73
+ progress.start("platform");
74
+ if (process.platform !== "darwin") {
75
+ progress.log("iOS Simulator is only available on macOS.");
76
+ process.exit(1);
77
+ }
78
+ progress.complete("platform");
79
+ progress.start("config");
80
+ const {
81
+ WEBVIEW_CONFIG
82
+ } = await initializeConfig();
83
+ progress.complete("config");
84
+ progress.start("simulator");
85
+ await configureSimulator(WEBVIEW_CONFIG);
86
+ progress.complete("simulator");
87
+ progress.start("launch");
88
+ await launchIOSSimulator(WEBVIEW_CONFIG.ios.simulatorName);
89
+ progress.complete("launch");
90
+ progress.start("saveConfig");
91
+ const config = await (0, _utils.validateAndCompleteConfig)("ios", configPath);
92
+ progress.complete("saveConfig");
93
+ progress.start("setupServer");
94
+ await setupServer(configPath);
95
+ progress.start("setupServer");
96
+ progress.printTreeContent("Configuration Explanation", ["WEBVIEW_CONFIG: Main configuration object for the WebView setup", {
97
+ text: "port: Port number for the WebView server",
98
+ indent: 1,
99
+ prefix: "├─ ",
100
+ color: "gray"
101
+ }, {
102
+ text: "ios: iOS-specific configuration",
103
+ indent: 1,
104
+ prefix: "└─ ",
105
+ color: "gray"
106
+ }, {
107
+ text: "buildType: Build type (debug/release)",
108
+ indent: 2,
109
+ prefix: "├─ ",
110
+ color: "gray"
111
+ }, {
112
+ text: "appBundleId: iOS application bundle identifier",
113
+ indent: 2,
114
+ prefix: "├─ ",
115
+ color: "gray"
116
+ }, {
117
+ text: "simulatorName: Selected iOS simulator name",
118
+ indent: 2,
119
+ prefix: "└─ ",
120
+ color: "gray"
121
+ }]);
122
+ progress.printTreeContent("Final Configuration", [JSON.stringify(config, null, 2)]);
123
+ process.exit(0);
124
+ } catch (error) {
125
+ if (progress.currentStep) {
126
+ progress.fail(progress.currentStep.id, error.message);
127
+ }
128
+ process.exit(1);
129
+ }
130
+ }
131
+ async function displayPaginatedList(items, startIndex) {
132
+ const endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.length);
133
+ for (let i = startIndex; i < endIndex; i++) {
134
+ console.log(`${i + 1}. ${items[i]}`);
135
+ }
136
+ if (endIndex < items.length) {
137
+ console.log(`\nShowing ${startIndex + 1}-${endIndex} of ${items.length} items`);
138
+ console.log('Type "more" to see more items, or enter your selection: ');
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ async function getRuntime() {
144
+ const runtimesOutput = (0, _child_process.execSync)("xcrun simctl list runtimes -j").toString();
145
+ const parsedRuntimes = JSON.parse(runtimesOutput).runtimes;
146
+ const availableRuntime = parsedRuntimes.find(runtime => runtime.isAvailable || runtime.availability === "(available)" || runtime.availability === "available");
147
+ if (!availableRuntime) {
148
+ const runningSimulators = (0, _child_process.execSync)("xcrun simctl list devices booted").toString();
149
+ if (runningSimulators.includes("(Booted)") && parsedRuntimes.length > 0) {
150
+ console.log(`Using runtime: ${parsedRuntimes[0].name}`);
151
+ return parsedRuntimes[0];
152
+ }
153
+ console.error("No available iOS runtime found. Please install one through Xcode.");
154
+ process.exit(1);
155
+ }
156
+ console.log(`Using runtime: ${availableRuntime.name}`);
157
+ return availableRuntime;
158
+ }
159
+ async function configureSimulator(config) {
160
+ // If a simulator is already configured, skip the interactive picker
161
+ if (config.ios.simulatorName) {
162
+ progress.log(`Using configured simulator: ${config.ios.simulatorName}`);
163
+ return;
164
+ }
165
+ progress.pause();
166
+
167
+ // Get the current runtime first
168
+ const runtime = await getRuntime();
169
+
170
+ // Get simulators specifically for this runtime
171
+ const simulatorsJson = JSON.parse((0, _child_process.execSync)("xcrun simctl list devices -j").toString());
172
+ const runtimeSimulators = simulatorsJson.devices[runtime.identifier] || [];
173
+
174
+ // Filter for available simulators only
175
+ const availableSimulators = runtimeSimulators.filter(sim => sim.availability === "(available)" || sim.isAvailable).map(sim => `${sim.name} (${sim.udid})`);
176
+ if (availableSimulators.length === 0) {
177
+ progress.log(`No available simulators found for runtime: ${runtime.name}`, "error");
178
+ progress.resume();
179
+ process.exit(1);
180
+ return;
181
+ }
182
+ let startIndex = 0;
183
+ console.log(`\nAvailable simulators for ${runtime.name} (or type 'new' to create a new one):`);
184
+
185
+ // eslint-disable-next-line no-constant-condition
186
+ while (true) {
187
+ const hasMore = await displayPaginatedList(availableSimulators, startIndex);
188
+ const simulatorChoice = await (0, _utils.promptUser)(hasMore ? "" : "\nEnter selection: ");
189
+ if (simulatorChoice.toLowerCase() === "more" && hasMore) {
190
+ startIndex += ITEMS_PER_PAGE;
191
+ continue;
192
+ }
193
+ if (simulatorChoice.toLowerCase() === "new") {
194
+ const deviceTypes = JSON.parse((0, _child_process.execSync)("xcrun simctl list devicetypes --json").toString()).devicetypes;
195
+ const simulatorName = await (0, _utils.promptUser)("Enter a name for the new simulator: ");
196
+
197
+ // Use iPhone 15 Pro as default device type
198
+ const defaultDevice = deviceTypes.find(dt => dt.name.includes("iPhone 15 Pro")) || deviceTypes[0];
199
+ try {
200
+ (0, _utils.runCommand)(`xcrun simctl create "${simulatorName}" "${defaultDevice.identifier}" "${runtime.identifier}"`);
201
+ console.log(`Simulator "${simulatorName}" created successfully.`);
202
+ config.ios.simulatorName = simulatorName;
203
+ } catch (error) {
204
+ console.log(`Failed to create simulator "${simulatorName}". Error: ${error.message}`);
205
+ process.exit(1);
206
+ }
207
+ break;
208
+ } else {
209
+ const index = parseInt(simulatorChoice) - 1;
210
+ if (index >= 0 && index < availableSimulators.length) {
211
+ const selectedSimulator = availableSimulators[index];
212
+ // Extract only the simulator name without ID and state
213
+ const simulatorName = selectedSimulator.split(" (")[0];
214
+ config.ios.simulatorName = simulatorName;
215
+ break;
216
+ } else {
217
+ console.log("Invalid selection. Please try again.");
218
+ }
219
+ }
220
+ }
221
+ progress.resume();
222
+ await saveConfig({
223
+ WEBVIEW_CONFIG: config
224
+ });
225
+ }
226
+
227
+ // async function createDefaultSimulator(config, runtime) {
14
228
  // const deviceTypes = JSON.parse(execSync("xcrun simctl list devicetypes --json").toString()).devicetypes
15
229
  // const defaultDevice = deviceTypes.find((dt) => dt.name.includes("iPhone 15 Pro")) || deviceTypes[0]
16
230
  // const simulatorName = `Default ${defaultDevice.name.split(" (")[0]}`
231
+
17
232
  // try {
18
233
  // runCommand(
19
234
  // `xcrun simctl create "${simulatorName}" "${defaultDevice.identifier}" "${runtime.identifier}"`
@@ -26,13 +241,65 @@ const simulatorName=selectedSimulator.split(" (")[0];config.ios.simulatorName=si
26
241
  // process.exit(1)
27
242
  // }
28
243
  // }
29
- async function launchIOSSimulator(simulatorName){progress.log("Launching iOS Simulator...");try{// Get all simulators including both available and booted ones
30
- const allSimulatorInfo=(0,_child_process.execSync)("xcrun simctl list devices -j").toString();const simulatorsJson=JSON.parse(allSimulatorInfo);const runtimesOutput=(0,_child_process.execSync)("xcrun simctl list runtimes -j").toString();const availableRuntimeIds=new Set(JSON.parse(runtimesOutput).runtimes.filter(r=>r.isAvailable||r.availability==="(available)"||r.availability==="available").map(r=>r.identifier));// Search through all runtimes and their devices
31
- let foundSimulator=null;let foundSimulatorId=null;let isBooted=false;// Prefer devices under an available runtime; fall back to already-booted ones
32
- Object.entries(simulatorsJson.devices).forEach(([runtimeId,devices])=>{const isAvailableRuntime=availableRuntimeIds.has(runtimeId);devices.forEach(device=>{if(device.name===simulatorName){const alreadyBooted=device.state==="Booted";// Take this match if: no match yet, or this runtime is available and current isn't, or device is already booted
33
- if(!foundSimulator||isAvailableRuntime&&!foundSimulator._fromAvailableRuntime||alreadyBooted){foundSimulator={...device,_fromAvailableRuntime:isAvailableRuntime};foundSimulatorId=device.udid;isBooted=alreadyBooted;}}});});if(!foundSimulator){console.log(`Configured simulator "${simulatorName}" not found.`);return;}if(!isBooted){console.log(`Booting simulator: ${simulatorName}`);(0,_utils.runCommand)(`xcrun simctl boot ${foundSimulatorId}`);}else{console.log(`Simulator ${simulatorName} is already booted`);}// Open Simulator.app and focus
34
- progress.log("Opening Simulator.app...");(0,_utils.runCommand)("open -a Simulator");// Give the simulator a moment to open/focus
35
- await new Promise(resolve=>setTimeout(resolve,1000));// Activate the Simulator.app window to bring it to front
36
- (0,_utils.runCommand)("osascript -e 'tell application \"Simulator\" to activate'");console.log("iOS Simulator launched successfully.");}catch(error){console.error("Failed to launch iOS Simulator. Error:",error.message);}// process.exit(0);
37
- }// Execute the main setup
244
+
245
+ async function launchIOSSimulator(simulatorName) {
246
+ progress.log("Launching iOS Simulator...");
247
+ try {
248
+ // Get all simulators including both available and booted ones
249
+ const allSimulatorInfo = (0, _child_process.execSync)("xcrun simctl list devices -j").toString();
250
+ const simulatorsJson = JSON.parse(allSimulatorInfo);
251
+ const runtimesOutput = (0, _child_process.execSync)("xcrun simctl list runtimes -j").toString();
252
+ const availableRuntimeIds = new Set(JSON.parse(runtimesOutput).runtimes.filter(r => r.isAvailable || r.availability === "(available)" || r.availability === "available").map(r => r.identifier));
253
+
254
+ // Search through all runtimes and their devices
255
+ let foundSimulator = null;
256
+ let foundSimulatorId = null;
257
+ let isBooted = false;
258
+
259
+ // Prefer devices under an available runtime; fall back to already-booted ones
260
+ Object.entries(simulatorsJson.devices).forEach(([runtimeId, devices]) => {
261
+ const isAvailableRuntime = availableRuntimeIds.has(runtimeId);
262
+ devices.forEach(device => {
263
+ if (device.name === simulatorName) {
264
+ const alreadyBooted = device.state === "Booted";
265
+ // Take this match if: no match yet, or this runtime is available and current isn't, or device is already booted
266
+ if (!foundSimulator || isAvailableRuntime && !foundSimulator._fromAvailableRuntime || alreadyBooted) {
267
+ foundSimulator = {
268
+ ...device,
269
+ _fromAvailableRuntime: isAvailableRuntime
270
+ };
271
+ foundSimulatorId = device.udid;
272
+ isBooted = alreadyBooted;
273
+ }
274
+ }
275
+ });
276
+ });
277
+ if (!foundSimulator) {
278
+ console.log(`Configured simulator "${simulatorName}" not found.`);
279
+ return;
280
+ }
281
+ if (!isBooted) {
282
+ console.log(`Booting simulator: ${simulatorName}`);
283
+ (0, _utils.runCommand)(`xcrun simctl boot ${foundSimulatorId}`);
284
+ } else {
285
+ console.log(`Simulator ${simulatorName} is already booted`);
286
+ }
287
+
288
+ // Open Simulator.app and focus
289
+ progress.log("Opening Simulator.app...");
290
+ (0, _utils.runCommand)("open -a Simulator");
291
+
292
+ // Give the simulator a moment to open/focus
293
+ await new Promise(resolve => setTimeout(resolve, 1000));
294
+
295
+ // Activate the Simulator.app window to bring it to front
296
+ (0, _utils.runCommand)("osascript -e 'tell application \"Simulator\" to activate'");
297
+ console.log("iOS Simulator launched successfully.");
298
+ } catch (error) {
299
+ console.error("Failed to launch iOS Simulator. Error:", error.message);
300
+ }
301
+ // process.exit(0);
302
+ }
303
+
304
+ // Execute the main setup
38
305
  setupIOSEnvironment();
@@ -1,27 +1,168 @@
1
- "use strict";const{exec,execFile,execSync}=require("child_process");const fs=require("fs");/**
1
+ "use strict";
2
+
3
+ const {
4
+ exec,
5
+ execFile,
6
+ execSync
7
+ } = require("child_process");
8
+ const fs = require("fs");
9
+
10
+ /**
2
11
  * Get local IP address on macOS using ifconfig
3
- */function getLocalIPAddress(){try{const command=`ifconfig | grep "inet " | grep -v 127.0.0.1 | head -n 1 | awk '{print $2}'`;return execSync(command).toString().trim();}catch(error){console.warn("Could not get local IP, using localhost");return"localhost";}}/**
12
+ */
13
+ function getLocalIPAddress() {
14
+ try {
15
+ const command = `ifconfig | grep "inet " | grep -v 127.0.0.1 | head -n 1 | awk '{print $2}'`;
16
+ return execSync(command).toString().trim();
17
+ } catch (error) {
18
+ console.warn("Could not get local IP, using localhost");
19
+ return "localhost";
20
+ }
21
+ }
22
+
23
+ /**
4
24
  * Check if server is running on given port
5
- */async function isServerRunning(port){return new Promise(resolve=>{const normalizedPort=Number(port);if(!Number.isInteger(normalizedPort)||normalizedPort<1||normalizedPort>65535){resolve(false);return;}execFile("lsof",["-i",`:${normalizedPort}`],(error,stdout)=>{if(error){resolve(false);return;}resolve(stdout.includes("LISTEN"));});});}/**
25
+ */
26
+ async function isServerRunning(port) {
27
+ return new Promise(resolve => {
28
+ const normalizedPort = Number(port);
29
+ if (!Number.isInteger(normalizedPort) || normalizedPort < 1 || normalizedPort > 65535) {
30
+ resolve(false);
31
+ return;
32
+ }
33
+ execFile("lsof", ["-i", `:${normalizedPort}`], (error, stdout) => {
34
+ if (error) {
35
+ resolve(false);
36
+ return;
37
+ }
38
+ resolve(stdout.includes("LISTEN"));
39
+ });
40
+ });
41
+ }
42
+
43
+ /**
6
44
  * Start server in background using npm start
7
- */function startServerBackground(){console.log("Starting server in background...");const serverProcess=exec("npm start",{detached:true,stdio:"ignore"});if(serverProcess.pid){serverProcess.unref();// Allow parent to exit
8
- console.log("Server started in background");}}/**
45
+ */
46
+ function startServerBackground() {
47
+ console.log("Starting server in background...");
48
+ const serverProcess = exec("npm start", {
49
+ detached: true,
50
+ stdio: "ignore"
51
+ });
52
+ if (serverProcess.pid) {
53
+ serverProcess.unref(); // Allow parent to exit
54
+ console.log("Server started in background");
55
+ }
56
+ }
57
+
58
+ /**
9
59
  * Recursively replace localhost and different IPs with current local IP
10
- */function replaceIPInObject(obj,localIP,path=""){let updated=false;for(const[key,value]of Object.entries(obj)){const currentPath=path?`${path}.${key}`:key;if(typeof value==="string"){let newValue=value;let shouldUpdate=false;// Replace localhost with local IP
11
- if(value.includes("localhost")){newValue=value.replace(/localhost/g,localIP);shouldUpdate=true;}// Replace different IP addresses in URLs
12
- const urlPattern=/http:\/\/(\d+\.\d+\.\d+\.\d+)/g;const matches=[...value.matchAll(urlPattern)];for(const match of matches){if(match[1]!==localIP){newValue=newValue.replace(match[1],localIP);shouldUpdate=true;}}// Replace standalone IP addresses that are not localhost
13
- const ipPattern=/^(\d+\.\d+\.\d+\.\d+)$/;const ipMatch=value.match(ipPattern);if(ipMatch&&ipMatch[1]!==localIP){newValue=localIP;shouldUpdate=true;}if(shouldUpdate&&newValue!==value){console.log(`Updating ${currentPath}: ${value} -> ${newValue}`);obj[key]=newValue;updated=true;}}else if(typeof value==="object"&&value!==null){// Recursively process nested objects
14
- const nestedUpdated=replaceIPInObject(value,localIP,currentPath);updated=updated||nestedUpdated;}}return updated;}/**
60
+ */
61
+ function replaceIPInObject(obj, localIP, path = "") {
62
+ let updated = false;
63
+ for (const [key, value] of Object.entries(obj)) {
64
+ const currentPath = path ? `${path}.${key}` : key;
65
+ if (typeof value === "string") {
66
+ let newValue = value;
67
+ let shouldUpdate = false;
68
+
69
+ // Replace localhost with local IP
70
+ if (value.includes("localhost")) {
71
+ newValue = value.replace(/localhost/g, localIP);
72
+ shouldUpdate = true;
73
+ }
74
+
75
+ // Replace different IP addresses in URLs
76
+ const urlPattern = /http:\/\/(\d+\.\d+\.\d+\.\d+)/g;
77
+ const matches = [...value.matchAll(urlPattern)];
78
+ for (const match of matches) {
79
+ if (match[1] !== localIP) {
80
+ newValue = newValue.replace(match[1], localIP);
81
+ shouldUpdate = true;
82
+ }
83
+ }
84
+
85
+ // Replace standalone IP addresses that are not localhost
86
+ const ipPattern = /^(\d+\.\d+\.\d+\.\d+)$/;
87
+ const ipMatch = value.match(ipPattern);
88
+ if (ipMatch && ipMatch[1] !== localIP) {
89
+ newValue = localIP;
90
+ shouldUpdate = true;
91
+ }
92
+ if (shouldUpdate && newValue !== value) {
93
+ console.log(`Updating ${currentPath}: ${value} -> ${newValue}`);
94
+ obj[key] = newValue;
95
+ updated = true;
96
+ }
97
+ } else if (typeof value === "object" && value !== null) {
98
+ // Recursively process nested objects
99
+ const nestedUpdated = replaceIPInObject(value, localIP, currentPath);
100
+ updated = updated || nestedUpdated;
101
+ }
102
+ }
103
+ return updated;
104
+ }
105
+
106
+ /**
15
107
  * Update config.json with current local IP address
16
- */function updateConfigWithLocalIP(configPath,localIP){try{const config=JSON.parse(fs.readFileSync(configPath,"utf8"));// Recursively update all IP addresses in the config
17
- const updated=replaceIPInObject(config,localIP);// Write back if updated
18
- if(updated){fs.writeFileSync(configPath,JSON.stringify(config,null,2),"utf8");console.log("Configuration updated with current IP address");}else{console.log("No IP addresses needed updating in configuration");}return config;}catch(error){console.error("Error updating config:",error.message);throw error;}}/**
108
+ */
109
+ function updateConfigWithLocalIP(configPath, localIP) {
110
+ try {
111
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
112
+
113
+ // Recursively update all IP addresses in the config
114
+ const updated = replaceIPInObject(config, localIP);
115
+
116
+ // Write back if updated
117
+ if (updated) {
118
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
119
+ console.log("Configuration updated with current IP address");
120
+ } else {
121
+ console.log("No IP addresses needed updating in configuration");
122
+ }
123
+ return config;
124
+ } catch (error) {
125
+ console.error("Error updating config:", error.message);
126
+ throw error;
127
+ }
128
+ }
129
+
130
+ /**
19
131
  * Main function: Setup server with IP validation and background startup
20
132
  * @param {string} configPath - Path to config.json file
21
133
  * @returns {Promise<{serverURL: string, localIP: string, port: number}>}
22
- */async function setupServer(configPath){console.log("Setting up server...");// Get local IP
23
- const localIP=getLocalIPAddress();console.log(`Local IP: ${localIP}`);// Update config with current IP
24
- const config=updateConfigWithLocalIP(configPath,localIP);// Get port from config
25
- const port=config.WEBVIEW_CONFIG?.port||3005;const serverURL=`http://${localIP}:${port}`;// Check if server is running
26
- const running=await isServerRunning(port);if(!running){console.log(`Server not running on ${serverURL}, starting...`);startServerBackground();// Give it a moment to start
27
- await new Promise(resolve=>setTimeout(resolve,3000));}else{console.log(`Server already running on ${serverURL}`);}console.log(`Server setup complete: ${serverURL}`);return{serverURL,localIP,port};}module.exports={setupServer};
134
+ */
135
+ async function setupServer(configPath) {
136
+ console.log("Setting up server...");
137
+
138
+ // Get local IP
139
+ const localIP = getLocalIPAddress();
140
+ console.log(`Local IP: ${localIP}`);
141
+
142
+ // Update config with current IP
143
+ const config = updateConfigWithLocalIP(configPath, localIP);
144
+
145
+ // Get port from config
146
+ const port = config.WEBVIEW_CONFIG?.port || 3005;
147
+ const serverURL = `http://${localIP}:${port}`;
148
+
149
+ // Check if server is running
150
+ const running = await isServerRunning(port);
151
+ if (!running) {
152
+ console.log(`Server not running on ${serverURL}, starting...`);
153
+ startServerBackground();
154
+ // Give it a moment to start
155
+ await new Promise(resolve => setTimeout(resolve, 3000));
156
+ } else {
157
+ console.log(`Server already running on ${serverURL}`);
158
+ }
159
+ console.log(`Server setup complete: ${serverURL}`);
160
+ return {
161
+ serverURL,
162
+ localIP,
163
+ port
164
+ };
165
+ }
166
+ module.exports = {
167
+ setupServer
168
+ };