catalyst-core 0.2.0-beta.3 → 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.
- package/babel.native.config.cjs +8 -0
- package/bin/catalyst.js +49 -105
- package/changelog.md +8 -0
- package/dist/caching.js +1 -1
- package/dist/index.jsx +8 -0
- package/dist/logger.js +74 -3
- package/dist/native/androidSetup.js +300 -8
- package/dist/native/bridge/WebBridge.js +481 -59
- package/dist/native/bridge/constants/NativeInterfaces.js +290 -45
- package/dist/native/bridge/errors.js +250 -26
- package/dist/native/bridge/hooks/index.js +125 -1
- package/dist/native/bridge/hooks/useCamera.js +347 -9
- package/dist/native/bridge/hooks/useDataProtection.js +200 -2
- package/dist/native/bridge/hooks/useDeviceInfo.js +71 -2
- package/dist/native/bridge/hooks/useFilePicker.js +429 -2
- package/dist/native/bridge/hooks/useGoogleSignIn.js +81 -1
- package/dist/native/bridge/hooks/useHapticFeedback.js +196 -1
- package/dist/native/bridge/hooks/useIntent.js +95 -1
- package/dist/native/bridge/hooks/useNativeTransition.js +202 -27
- package/dist/native/bridge/hooks/useNetworkStatus.js +84 -3
- package/dist/native/bridge/hooks/useNotification.js +318 -2
- package/dist/native/bridge/hooks/useSafeArea.js +84 -2
- package/dist/native/bridge/hooks/useVideoStream.js +434 -6
- package/dist/native/bridge/hooks/utils.js +27 -1
- package/dist/native/bridge/hooks.js +16 -1
- package/dist/native/bridge/perf/collectors/ApiCollector.js +66 -3
- package/dist/native/bridge/perf/collectors/CacheCollector.js +186 -11
- package/dist/native/bridge/perf/collectors/HookCollector.js +141 -19
- package/dist/native/bridge/perf/collectors/InsightsCollector.js +481 -23
- package/dist/native/bridge/perf/collectors/InteractionCollector.js +245 -10
- package/dist/native/bridge/perf/collectors/KeyboardCollector.js +107 -8
- package/dist/native/bridge/perf/collectors/NavigationCollector.js +273 -32
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +178 -2
- package/dist/native/bridge/perf/collectors/RenderCollector.js +258 -14
- package/dist/native/bridge/perf/collectors/ScrollCollector.js +95 -9
- package/dist/native/bridge/perf/collectors/ThreadCollector.js +90 -6
- package/dist/native/bridge/perf/core/constants.js +103 -20
- package/dist/native/bridge/perf/core/measure.js +179 -30
- package/dist/native/bridge/perf/core/session.js +89 -23
- package/dist/native/bridge/perf/core/store.js +554 -1
- package/dist/native/bridge/perf/core/summary.js +174 -1
- package/dist/native/bridge/perf/core/traceExport.js +240 -1
- package/dist/native/bridge/perf/core/waterfalls.js +146 -1
- package/dist/native/bridge/perf/index.js +359 -38
- package/dist/native/bridge/safeArea.js +53 -5
- package/dist/native/bridge/standardizedHooks.js +595 -82
- package/dist/native/bridge/useBaseHook.js +274 -38
- package/dist/native/bridge/utils/CameraUtils.js +201 -56
- package/dist/native/bridge/utils/FileObjectConverter.js +129 -18
- package/dist/native/bridge/utils/NativeBridge.js +425 -141
- package/dist/native/buildAndroid/assets.js +510 -13
- package/dist/native/buildAndroid/build.js +296 -19
- package/dist/native/buildAndroid/config.js +87 -1
- package/dist/native/buildAndroid/index.js +374 -1
- package/dist/native/buildAppAndroid.js +34 -2
- package/dist/native/buildAppIos.js +62 -2
- package/dist/native/buildIos/assets.js +609 -8
- package/dist/native/buildIos/build.js +639 -20
- package/dist/native/buildIos/config.js +294 -12
- package/dist/native/buildIos/index.js +343 -6
- package/dist/native/buildIos/plugins.js +343 -16
- package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +43 -0
- package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +28 -0
- package/dist/native/internal-plugins/device-info-plugin/manifest.json +19 -0
- package/dist/native/internalPluginUtils.js +232 -7
- package/dist/native/package.json +3 -0
- package/dist/native/plugin-bridge/PluginBridge.js +227 -1
- package/dist/native/pluginComposerAndroid.js +407 -23
- package/dist/native/pluginComposerIos.js +435 -11
- package/dist/native/renameAndroidProject.js +1094 -88
- package/dist/native/setupEmulatorIos.js +289 -22
- package/dist/native/setupServer.js +160 -19
- package/dist/native/terminalProgress.js +199 -11
- package/dist/native/utils.js +193 -15
- package/dist/offline/catalyst-sw.js +145 -1
- package/dist/offline/registerServiceWorker.js +33 -1
- package/dist/otel.js +375 -46
- package/dist/router/ClientRouter.js +14 -2
- package/dist/router/ServerRouter.js +9 -1
- package/dist/router.js +1 -1
- package/dist/scripts/build.js +112 -3
- package/dist/scripts/checkVersion.js +3 -1
- package/dist/scripts/cleanCache.js +30 -1
- package/dist/scripts/generateOfflineManifest.js +116 -1
- package/dist/scripts/loadEnvironmentVariables.js +32 -6
- package/dist/scripts/plugins.js +309 -1
- package/dist/scripts/preServerInit.js +13 -0
- package/dist/scripts/scriptUtils.js +54 -3
- package/dist/scripts/serve.js +51 -4
- package/dist/scripts/start.js +47 -10
- package/dist/scripts/validator.js +149 -1
- package/dist/sentry.cjs +127 -0
- package/dist/sentry.js +125 -5
- package/dist/server/expressServer.js +250 -5
- package/dist/server/manifestCache.js +36 -0
- package/dist/server/renderer/ChunkExtractor.js +144 -0
- package/dist/server/renderer/document/Body.jsx +59 -0
- package/dist/server/renderer/document/FastRefresh.jsx +20 -0
- package/dist/server/renderer/document/Head.jsx +60 -0
- package/dist/server/renderer/document/index.jsx +2 -0
- package/dist/server/renderer/extract.js +149 -31
- package/dist/server/renderer/handler.jsx +433 -0
- package/dist/server/renderer/index.js +8 -1
- package/dist/server/renderer/render.js +47 -0
- package/dist/server/utils/botDetectionMiddleware.js +29 -0
- package/dist/server/utils/cjsRequire.js +10 -0
- package/dist/server/utils/userAgentUtil.js +87 -9
- package/dist/server/utils/validator.js +164 -1
- package/dist/vite/FastRefresh.jsx +20 -0
- package/dist/vite/inject-cache-key-plugin.js +276 -0
- package/dist/vite/loadCustomViteConfig.js +22 -0
- package/dist/vite/manifest-categorization-plugin.js +455 -0
- package/dist/vite/node-loader.mjs +458 -0
- package/dist/vite/scssParams.js +21 -0
- package/dist/vite/vite.config.client.js +130 -0
- package/dist/vite/vite.config.js +422 -0
- package/dist/vite/vite.config.server.js +84 -0
- package/dist/web-router/components/MetaTag.jsx +34 -0
- package/dist/web-router/components/RouterDataProvider.jsx +332 -0
- package/dist/web-router/components/Split.jsx +200 -0
- package/dist/web-router/components/SplitInview.jsx +106 -0
- package/dist/web-router/components/SsrRequestContext.jsx +14 -0
- package/dist/web-router/context.jsx +12 -0
- package/dist/web-router/hooks.jsx +72 -0
- package/dist/web-router/types/components/MetaTag.d.ts +2 -0
- package/dist/web-router/types/components/RouterDataProvider.d.ts +95 -0
- package/dist/web-router/types/context.d.ts +14 -0
- package/dist/web-router/types/hooks.d.ts +1 -0
- package/dist/web-router/types/index.d.ts +3 -0
- package/dist/web-router/types/utils/metaDataUtils.d.ts +24 -0
- package/dist/web-router/utils/metaDataUtils.jsx +119 -0
- package/mcp_v2/conversion-tasks.json +35 -17
- package/mcp_v2/knowledge-base.json +124 -13
- package/mcp_v2/lib/helpers.js +10 -0
- package/mcp_v2/mcp.js +4 -4
- package/mcp_v2/package.json +1 -0
- package/mcp_v2/tools/build.js +116 -20
- package/mcp_v2/tools/conversion.js +106 -5
- package/mcp_v2/tools/tasks.js +18 -14
- package/package.json +35 -68
- package/babel.config.js +0 -32
- package/dist/index.js +0 -1
- package/dist/scripts/devBuild.js +0 -3
- package/dist/scripts/devServe.js +0 -3
- package/dist/scripts/loadScriptsBeforeServerStarts.js +0 -4
- package/dist/scripts/registerAliases.js +0 -6
- package/dist/server/renderer/document/Body.js +0 -11
- package/dist/server/renderer/document/Head.js +0 -9
- package/dist/server/renderer/document/index.js +0 -1
- package/dist/server/renderer/handler.js +0 -47
- package/dist/server/startServer.js +0 -57
- package/dist/webpack/babel-plugins/remove-client.plugin.js +0 -5
- package/dist/webpack/babel-plugins/remove-ssr.plugin.js +0 -5
- package/dist/webpack/babel.config.client.js +0 -1
- package/dist/webpack/babel.config.ssr.js +0 -1
- package/dist/webpack/base.babel.js +0 -7
- package/dist/webpack/development.client.babel.js +0 -10
- package/dist/webpack/production.client.babel.js +0 -4
- package/dist/webpack/production.ssr.babel.js +0 -8
- package/dist/webpack/scssParams.js +0 -9
|
@@ -1,13 +1,236 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
// ─── Pure helpers (no ctx dependency) ────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
function isPlainObject(value) {
|
|
9
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
function deepEqual(left, right) {
|
|
12
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
13
|
+
}
|
|
14
|
+
function mergeStructuredValues(existing, incoming, fieldName) {
|
|
15
|
+
if (existing === undefined) return JSON.parse(JSON.stringify(incoming));
|
|
16
|
+
if (Array.isArray(existing) && Array.isArray(incoming)) {
|
|
17
|
+
const merged = [];
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
for (const value of [...existing, ...incoming]) {
|
|
20
|
+
const key = JSON.stringify(value);
|
|
21
|
+
if (seen.has(key)) continue;
|
|
22
|
+
seen.add(key);
|
|
23
|
+
merged.push(value);
|
|
24
|
+
}
|
|
25
|
+
return merged;
|
|
26
|
+
}
|
|
27
|
+
if (isPlainObject(existing) && isPlainObject(incoming)) {
|
|
28
|
+
const merged = {
|
|
29
|
+
...existing
|
|
30
|
+
};
|
|
31
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
32
|
+
merged[key] = mergeStructuredValues(merged[key], value, `${fieldName}.${key}`);
|
|
33
|
+
}
|
|
34
|
+
return merged;
|
|
35
|
+
}
|
|
36
|
+
if (deepEqual(existing, incoming)) return existing;
|
|
37
|
+
throw new Error(`Conflicting values for '${fieldName}' while composing iOS build metadata`);
|
|
38
|
+
}
|
|
39
|
+
function generateSwiftProperty(key, value, indent = " ") {
|
|
40
|
+
if (value === null || value === undefined) return `${indent}public static let ${key}: String? = nil`;
|
|
41
|
+
if (key === "cachePattern") {
|
|
42
|
+
if (typeof value === "string") return `${indent}public static let ${key}: [String] = ["${value}"]`;
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
const arrayValues = value.map(v => `"${v}"`).join(", ");
|
|
45
|
+
return `${indent}public static let ${key}: [String] = [${arrayValues}]`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (typeof value === "string") return `${indent}public static let ${key} = "${value}"`;
|
|
49
|
+
if (typeof value === "number") return `${indent}public static let ${key} = ${value}`;
|
|
50
|
+
if (typeof value === "boolean") return `${indent}public static let ${key} = ${value}`;
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
if (value.length === 0) return `${indent}public static let ${key}: [String] = []`;
|
|
53
|
+
const firstElement = value[0];
|
|
54
|
+
if (typeof firstElement === "string") {
|
|
55
|
+
const arrayValues = value.map(v => `"${v}"`).join(", ");
|
|
56
|
+
return `${indent}public static let ${key}: [String] = [${arrayValues}]`;
|
|
57
|
+
} else if (typeof firstElement === "number") {
|
|
58
|
+
const arrayType = Number.isInteger(firstElement) ? "Int" : "Double";
|
|
59
|
+
return `${indent}public static let ${key}: [${arrayType}] = [${value.join(", ")}]`;
|
|
60
|
+
} else if (typeof firstElement === "boolean") {
|
|
61
|
+
return `${indent}public static let ${key}: [Bool] = [${value.join(", ")}]`;
|
|
62
|
+
} else {
|
|
63
|
+
const arrayValues = value.map(v => `"${v}"`).join(", ");
|
|
64
|
+
return `${indent}public static let ${key}: [String] = [${arrayValues}]`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "object" && value !== null) {
|
|
68
|
+
let nestedContent = `${indent}public enum ${key.charAt(0).toUpperCase() + key.slice(1)} {\n`;
|
|
69
|
+
for (const [nestedKey, nestedValue] of Object.entries(value)) {
|
|
70
|
+
nestedContent += generateSwiftProperty(nestedKey, nestedValue, indent + " ") + "\n";
|
|
71
|
+
}
|
|
72
|
+
nestedContent += `${indent}}`;
|
|
73
|
+
return nestedContent;
|
|
74
|
+
}
|
|
75
|
+
return `${indent}public static let ${key} = "${value}"`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─── Module factory ───────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
module.exports = function createConfigPhase(ctx) {
|
|
81
|
+
const {
|
|
82
|
+
WEBVIEW_CONFIG,
|
|
83
|
+
iosConfig,
|
|
84
|
+
PROJECT_DIR,
|
|
85
|
+
url,
|
|
86
|
+
progress,
|
|
87
|
+
restoreManagedFileFromBaseline,
|
|
88
|
+
readPlistObject,
|
|
89
|
+
writePlistObject
|
|
90
|
+
} = ctx;
|
|
91
|
+
function mergeIntoTopLevelObject(target, source, fieldName) {
|
|
92
|
+
for (const [key, value] of Object.entries(source || {})) {
|
|
93
|
+
target[key] = mergeStructuredValues(target[key], value, `${fieldName}.${key}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function mergeUrlSchemes(plistObject, entries) {
|
|
97
|
+
const existing = Array.isArray(plistObject.CFBundleURLTypes) ? plistObject.CFBundleURLTypes : [];
|
|
98
|
+
const merged = existing.map(entry => ({
|
|
99
|
+
...entry,
|
|
100
|
+
CFBundleURLSchemes: Array.isArray(entry?.CFBundleURLSchemes) ? [...new Set(entry.CFBundleURLSchemes)] : []
|
|
101
|
+
}));
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
const targetName = entry.name || null;
|
|
104
|
+
let match = merged.find(item => item.CFBundleURLName === targetName);
|
|
105
|
+
if (!match) {
|
|
106
|
+
match = {
|
|
107
|
+
CFBundleURLName: targetName,
|
|
108
|
+
CFBundleURLSchemes: []
|
|
109
|
+
};
|
|
110
|
+
merged.push(match);
|
|
111
|
+
}
|
|
112
|
+
match.CFBundleURLSchemes = [...new Set([...match.CFBundleURLSchemes, ...entry.schemes])];
|
|
113
|
+
}
|
|
114
|
+
if (merged.length > 0) plistObject.CFBundleURLTypes = merged;
|
|
115
|
+
}
|
|
116
|
+
function mergeQuerySchemes(plistObject, schemes) {
|
|
117
|
+
const existing = Array.isArray(plistObject.LSApplicationQueriesSchemes) ? plistObject.LSApplicationQueriesSchemes : [];
|
|
118
|
+
const merged = [...new Set([...existing, ...schemes.filter(Boolean)])];
|
|
119
|
+
if (merged.length > 0) plistObject.LSApplicationQueriesSchemes = merged;
|
|
120
|
+
}
|
|
121
|
+
async function generateConfigConstants() {
|
|
122
|
+
progress.start("config");
|
|
123
|
+
try {
|
|
124
|
+
const appConfigPath = path.join(PROJECT_DIR,
|
|
125
|
+
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - PROJECT_DIR is the fixed generated iOS project directory.
|
|
126
|
+
"Sources", "Core", "Constants", "ConfigConstants.swift");
|
|
127
|
+
const appConfigDir = path.dirname(appConfigPath);
|
|
128
|
+
if (!fs.existsSync(appConfigDir)) fs.mkdirSync(appConfigDir, {
|
|
129
|
+
recursive: true
|
|
130
|
+
});
|
|
131
|
+
let configContent = `// This file is auto-generated. Do not edit.
|
|
5
132
|
import Foundation
|
|
6
133
|
|
|
7
134
|
public enum ConfigConstants {
|
|
8
|
-
public static let url = "${url}"`;
|
|
9
|
-
|
|
10
|
-
|
|
135
|
+
public static let url = "${url}"`;
|
|
136
|
+
const addedKeys = new Set();
|
|
137
|
+
if (WEBVIEW_CONFIG && typeof WEBVIEW_CONFIG === "object") {
|
|
138
|
+
for (const [key, value] of Object.entries(WEBVIEW_CONFIG)) {
|
|
139
|
+
if (key === "ios" || key === "android") continue;
|
|
140
|
+
if (key === "notifications") progress.log(`Processing notifications config: ${JSON.stringify(value)}`, "info");
|
|
141
|
+
configContent += "\n" + generateSwiftProperty(key, value);
|
|
142
|
+
addedKeys.add(key);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (iosConfig && typeof iosConfig === "object") {
|
|
146
|
+
configContent += "\n \n // iOS-specific configuration";
|
|
147
|
+
for (const [key, value] of Object.entries(iosConfig)) {
|
|
148
|
+
if (addedKeys.has(key)) continue;
|
|
149
|
+
configContent += "\n" + generateSwiftProperty(key, value);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (WEBVIEW_CONFIG.accessControl) {
|
|
153
|
+
const accessControl = WEBVIEW_CONFIG.accessControl;
|
|
154
|
+
configContent += `\n public static let accessControlEnabled = ${accessControl.enabled || false}`;
|
|
155
|
+
if (accessControl.allowedUrls && Array.isArray(accessControl.allowedUrls)) {
|
|
156
|
+
const allowedUrls = accessControl.allowedUrls.map(u => `"${u}"`).join(", ");
|
|
157
|
+
configContent += `\n public static let allowedUrls: [String] = [${allowedUrls}]`;
|
|
158
|
+
} else if (accessControl.allowedUrls && typeof accessControl.allowedUrls === "string") {
|
|
159
|
+
const allowedUrls = accessControl.allowedUrls.split(",").map(u => u.trim()).filter(u => u.length > 0).map(u => `"${u}"`).join(", ");
|
|
160
|
+
configContent += `\n public static let allowedUrls: [String] = [${allowedUrls}]`;
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
configContent += `\n public static let accessControlEnabled = false\n public static let allowedUrls: [String] = []`;
|
|
164
|
+
}
|
|
165
|
+
const splashConfig = WEBVIEW_CONFIG.splashScreen;
|
|
166
|
+
if (splashConfig) {
|
|
167
|
+
configContent += `\n\n // Splash Screen Configuration\n public static let splashScreenEnabled = true`;
|
|
168
|
+
configContent += splashConfig.duration ? `\n public static let splashScreenDuration: TimeInterval? = ${splashConfig.duration / 1000.0}` : `\n public static let splashScreenDuration: TimeInterval? = nil`;
|
|
169
|
+
configContent += splashConfig.backgroundColor ? `\n public static let splashScreenBackgroundColor = "${splashConfig.backgroundColor}"` : `\n public static let splashScreenBackgroundColor = "#ffffff"`;
|
|
170
|
+
configContent += `\n public static let splashScreenImageWidth: CGFloat = ${splashConfig.imageWidth || 120}`;
|
|
171
|
+
configContent += `\n public static let splashScreenImageHeight: CGFloat = ${splashConfig.imageHeight || 120}`;
|
|
172
|
+
configContent += `\n public static let splashScreenCornerRadius: CGFloat = ${splashConfig.cornerRadius || 20}`;
|
|
173
|
+
} else {
|
|
174
|
+
configContent += `\n\n // Splash Screen Configuration\n public static let splashScreenEnabled = false\n public static let splashScreenDuration: TimeInterval? = nil\n public static let splashScreenBackgroundColor = "#ffffff"\n public static let splashScreenImageWidth: CGFloat = 120\n public static let splashScreenImageHeight: CGFloat = 120\n public static let splashScreenCornerRadius: CGFloat = 20`;
|
|
175
|
+
}
|
|
176
|
+
if (!addedKeys.has("notifications")) {
|
|
177
|
+
progress.log("Notifications not found in config, adding default (false)", "info");
|
|
178
|
+
configContent += "\n public enum Notifications {\n public static let enabled = false\n }";
|
|
179
|
+
addedKeys.add("notifications");
|
|
180
|
+
} else {
|
|
181
|
+
progress.log("Notifications config was processed from WEBVIEW_CONFIG", "info");
|
|
182
|
+
}
|
|
183
|
+
if (!addedKeys.has("googleSignIn")) {
|
|
184
|
+
progress.log("Google Sign-In not found in config, adding defaults (disabled)", "info");
|
|
185
|
+
configContent += '\n public enum GoogleSignIn {\n public static let enabled = false\n public static let clientId = ""\n public static let iosClientId = ""\n }';
|
|
186
|
+
addedKeys.add("googleSignIn");
|
|
187
|
+
}
|
|
188
|
+
if (!addedKeys.has("profiler")) {
|
|
189
|
+
configContent += "\n public enum Profiler {\n public static let enabled = false\n }";
|
|
190
|
+
addedKeys.add("profiler");
|
|
191
|
+
}
|
|
192
|
+
if (!addedKeys.has("edgeToEdge")) {
|
|
193
|
+
progress.log("EdgeToEdge not found in config, adding default (false)", "info");
|
|
194
|
+
configContent += "\n public enum EdgeToEdge {\n public static let enabled = false\n }";
|
|
195
|
+
addedKeys.add("edgeToEdge");
|
|
196
|
+
} else {
|
|
197
|
+
progress.log("EdgeToEdge config was processed from WEBVIEW_CONFIG", "info");
|
|
198
|
+
}
|
|
199
|
+
if (!addedKeys.has("initial_url")) {
|
|
200
|
+
configContent += '\n public static let initial_url = ""';
|
|
201
|
+
addedKeys.add("initial_url");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Ensure appInfo always exists (default to empty string if not configured)
|
|
205
|
+
if (!addedKeys.has("appInfo")) {
|
|
206
|
+
configContent += '\n public static let appInfo = ""';
|
|
207
|
+
addedKeys.add("appInfo");
|
|
208
|
+
}
|
|
209
|
+
configContent += `\n}`;
|
|
210
|
+
fs.writeFileSync(appConfigPath, configContent, "utf8");
|
|
211
|
+
progress.log("Configuration constants generated successfully (SPM Package)", "success");
|
|
212
|
+
progress.complete("config");
|
|
213
|
+
} catch (error) {
|
|
214
|
+
progress.fail("config", error.message);
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function generateXCConfig() {
|
|
219
|
+
try {
|
|
220
|
+
const xconfigPath = path.join(PROJECT_DIR, "Configurations", "Shared.xcconfig"); // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
|
221
|
+
const configDir = path.dirname(xconfigPath);
|
|
222
|
+
if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, {
|
|
223
|
+
recursive: true
|
|
224
|
+
});
|
|
225
|
+
const bundleId = iosConfig.bundleIdentifier || iosConfig.appBundleId || "com.catalyst.framework.app";
|
|
226
|
+
const appName = iosConfig.appName || "Catalyst App";
|
|
227
|
+
const teamId = iosConfig.developmentTeam || "";
|
|
228
|
+
const swiftVersion = iosConfig.deployment?.swiftVersion || "5.9";
|
|
229
|
+
const deploymentTarget = iosConfig.deployment?.target || "17.0";
|
|
230
|
+
const marketingVersion = iosConfig.version ? `${iosConfig.version.major || 1}.${iosConfig.version.minor || 0}.${iosConfig.version.patch || 0}` : "1.0.0";
|
|
231
|
+
const buildNumber = iosConfig.version?.buildNumber || 1;
|
|
232
|
+
const provisioningProfile = iosConfig.provisioningProfile || "";
|
|
233
|
+
const xconfigContent = `// This file is auto-generated by buildAppIos.js. Do not edit.
|
|
11
234
|
//
|
|
12
235
|
// Shared configuration for both Debug and Release builds
|
|
13
236
|
// All values are dynamically injected from config.json
|
|
@@ -64,8 +287,67 @@ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES
|
|
|
64
287
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES
|
|
65
288
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
|
|
66
289
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
|
|
67
|
-
`;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
290
|
+
`;
|
|
291
|
+
fs.writeFileSync(xconfigPath, xconfigContent, "utf8");
|
|
292
|
+
console.log(`✅ Generated Shared.xcconfig with Swift ${swiftVersion}, iOS ${deploymentTarget}, Bundle ID: ${bundleId}`);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error(`❌ Failed to generate Shared.xcconfig: ${error.message}`);
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async function updateInfoPlist(pluginComposition = {}) {
|
|
299
|
+
const PROJECT_NAME = ctx.PROJECT_NAME;
|
|
300
|
+
const isGoogleSignInEnabled = ctx.isGoogleSignInEnabled;
|
|
301
|
+
const GOOGLE_SERVICES_FILENAME = "GoogleService-Info.plist";
|
|
302
|
+
const infoPlistPath = path.join(PROJECT_DIR, PROJECT_NAME, "Info.plist"); // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
|
303
|
+
const infoReleasePlistPath = path.join(PROJECT_DIR, PROJECT_NAME, "Info-Release.plist"); // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
|
304
|
+
const googleServicesPlistPath = path.join(PROJECT_DIR, PROJECT_NAME, GOOGLE_SERVICES_FILENAME); // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
|
305
|
+
const googleClientId = WEBVIEW_CONFIG.googleSignIn?.clientId || WEBVIEW_CONFIG.googleSignIn?.webClientId || "";
|
|
306
|
+
const iosClientId = WEBVIEW_CONFIG.googleSignIn?.iosClientId || "";
|
|
307
|
+
const googleServicesContent = fs.existsSync(googleServicesPlistPath) ? fs.readFileSync(googleServicesPlistPath, "utf8") : null;
|
|
308
|
+
const reversedClientIdFromServices = googleServicesContent ? (googleServicesContent.match(/<key>REVERSED_CLIENT_ID<\/key>\s*<string>([^<]+)<\/string>/) || [])[1] : null;
|
|
309
|
+
const clientIdFromServices = googleServicesContent ? (googleServicesContent.match(/<key>CLIENT_ID<\/key>\s*<string>([^<]+)<\/string>/) || [])[1] : null;
|
|
310
|
+
const computeReversed = value => !value ? "" : value.split(".").reverse().join(".");
|
|
311
|
+
const resolvedClientIdForScheme = iosClientId || googleClientId || clientIdFromServices || "";
|
|
312
|
+
const resolvedReversedClientId = reversedClientIdFromServices || computeReversed(resolvedClientIdForScheme);
|
|
313
|
+
if (isGoogleSignInEnabled && !resolvedReversedClientId) {
|
|
314
|
+
throw new Error("Google Sign-In enabled but no valid clientId found");
|
|
315
|
+
}
|
|
316
|
+
const plistTargets = [infoPlistPath, infoReleasePlistPath];
|
|
317
|
+
const pluginUrlSchemes = pluginComposition.urlSchemes || [];
|
|
318
|
+
const pluginQuerySchemes = pluginComposition.querySchemes || [];
|
|
319
|
+
const pluginInfoPlist = pluginComposition.infoPlist || {};
|
|
320
|
+
plistTargets.forEach(plistPath => {
|
|
321
|
+
if (!fs.existsSync(plistPath)) return;
|
|
322
|
+
restoreManagedFileFromBaseline(plistPath);
|
|
323
|
+
const plistObject = readPlistObject(plistPath);
|
|
324
|
+
plistObject.CFBundleDisplayName = iosConfig.appName || "Catalyst Application";
|
|
325
|
+
mergeIntoTopLevelObject(plistObject, pluginInfoPlist, "ios.infoPlist");
|
|
326
|
+
if (isGoogleSignInEnabled && resolvedReversedClientId) {
|
|
327
|
+
mergeUrlSchemes(plistObject, [{
|
|
328
|
+
name: "googleSignIn",
|
|
329
|
+
schemes: [resolvedReversedClientId]
|
|
330
|
+
}]);
|
|
331
|
+
mergeQuerySchemes(plistObject, ["google", resolvedReversedClientId]);
|
|
332
|
+
}
|
|
333
|
+
mergeUrlSchemes(plistObject, pluginUrlSchemes);
|
|
334
|
+
mergeQuerySchemes(plistObject, pluginQuerySchemes);
|
|
335
|
+
writePlistObject(plistPath, plistObject);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
async function updateEntitlements(pluginComposition = {}) {
|
|
339
|
+
const PROJECT_NAME = ctx.PROJECT_NAME;
|
|
340
|
+
const entitlementsPath = path.join(PROJECT_DIR, PROJECT_NAME, `${PROJECT_NAME}.entitlements`); // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
|
341
|
+
if (!fs.existsSync(entitlementsPath)) return;
|
|
342
|
+
restoreManagedFileFromBaseline(entitlementsPath);
|
|
343
|
+
const entitlementsObject = readPlistObject(entitlementsPath);
|
|
344
|
+
mergeIntoTopLevelObject(entitlementsObject, pluginComposition.entitlements || {}, "ios.entitlements");
|
|
345
|
+
writePlistObject(entitlementsPath, entitlementsObject);
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
generateConfigConstants,
|
|
349
|
+
generateXCConfig,
|
|
350
|
+
updateInfoPlist,
|
|
351
|
+
updateEntitlements
|
|
352
|
+
};
|
|
353
|
+
};
|