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
@@ -0,0 +1,458 @@
1
+ import { fileURLToPath, pathToFileURL } from "url"
2
+ import { dirname, resolve as resolvePath, join, extname } from "path"
3
+ import { readFileSync, existsSync, statSync } from "fs"
4
+ import { createRequire } from "module"
5
+ import { transformSync } from "esbuild"
6
+
7
+ const __filename = fileURLToPath(import.meta.url)
8
+ const __dirname = dirname(__filename)
9
+
10
+ // Cache for loaded aliases
11
+ let aliasCache = null
12
+
13
+ /**
14
+ * Load and resolve module aliases from both the consuming app and catalyst-core
15
+ */
16
+ function loadAliases() {
17
+ if (aliasCache) {
18
+ return aliasCache
19
+ }
20
+
21
+ const appRoot = process.env.src_path || process.cwd()
22
+
23
+ const appPackageJsonConfig = resolvePath(appRoot, "package.json")
24
+ const catalystPackageJsonConfig = resolvePath(__dirname, "../../package.json")
25
+
26
+ let appModuleAliases = {}
27
+ let catalystModuleAliases = {}
28
+
29
+ // Read aliases from consuming application's package.json
30
+ try {
31
+ const appPackageJsonContent = readFileSync(appPackageJsonConfig, "utf8")
32
+ const appPackageJson = JSON.parse(appPackageJsonContent)
33
+ appModuleAliases = appPackageJson._moduleAliases || {}
34
+ } catch (error) {
35
+ // Silently fail if app package.json doesn't exist or is invalid
36
+ }
37
+
38
+ // Read aliases from catalyst-core's package.json
39
+ try {
40
+ const catalystPackageJsonContent = readFileSync(catalystPackageJsonConfig, "utf8")
41
+ const catalystPackageJson = JSON.parse(catalystPackageJsonContent)
42
+ catalystModuleAliases = catalystPackageJson._moduleAliases || {}
43
+ } catch (error) {
44
+ // Silently fail if catalyst package.json doesn't exist or is invalid
45
+ }
46
+
47
+ // Application aliases take precedence over catalyst-core aliases
48
+ const allAliases = { ...catalystModuleAliases, ...appModuleAliases }
49
+
50
+ // Convert aliases to resolved paths
51
+ aliasCache = {}
52
+ for (const [alias, aliasPath] of Object.entries(allAliases)) {
53
+ if (aliasPath && typeof aliasPath === "string") {
54
+ try {
55
+ // All aliases resolve relative to consuming project root (src_path)
56
+ const resolvedPath = resolvePath(appRoot, ...aliasPath.split("/"))
57
+ aliasCache[alias] = resolvedPath
58
+ } catch (error) {
59
+ console.warn(`Failed to resolve alias ${alias}:`, error.message)
60
+ }
61
+ }
62
+ }
63
+
64
+ return aliasCache
65
+ }
66
+
67
+ /**
68
+ * Try to resolve a path by applying common JS/TS/ESM extensions and index fallbacks.
69
+ * This brings resolution closer to webpack-style behavior for extensionless imports.
70
+ */
71
+ function resolveWithExtensions(basePath) {
72
+ // Exact match — but only if it's a file, not a directory
73
+ if (existsSync(basePath) && statSync(basePath).isFile()) {
74
+ return basePath
75
+ }
76
+
77
+ const extensions = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".scss"]
78
+
79
+ // Try with common extensions (for extensionless imports)
80
+ for (const ext of extensions) {
81
+ const candidate = `${basePath}${ext}`
82
+ if (existsSync(candidate)) {
83
+ return candidate
84
+ }
85
+ }
86
+
87
+ // Try replacing the existing extension (e.g. .js → .jsx, .ts → .tsx)
88
+ // This handles webpack-style resolution where .js imports can resolve to .jsx files
89
+ const currentExt = extname(basePath)
90
+ if (currentExt) {
91
+ const withoutExt = basePath.slice(0, -currentExt.length)
92
+ for (const ext of extensions) {
93
+ if (ext === currentExt) continue
94
+ const candidate = `${withoutExt}${ext}`
95
+ if (existsSync(candidate)) {
96
+ return candidate
97
+ }
98
+ }
99
+ }
100
+
101
+ // Try index files inside a directory
102
+ for (const ext of extensions) {
103
+ const candidate = join(basePath, `index${ext}`)
104
+ if (existsSync(candidate)) {
105
+ return candidate
106
+ }
107
+ }
108
+
109
+ return null
110
+ }
111
+
112
+ /**
113
+ * Resolve an import specifier using aliases
114
+ */
115
+ function resolveAlias(specifier, parentURL) {
116
+ const aliases = loadAliases()
117
+
118
+ // Check if specifier starts with any alias
119
+ for (const [alias, aliasPath] of Object.entries(aliases)) {
120
+ if (specifier.startsWith(alias + "/") || specifier === alias) {
121
+ const remainingPath = specifier === alias ? "" : specifier.slice(alias.length + 1)
122
+ const rawResolvedPath = join(aliasPath, remainingPath)
123
+ const finalResolvedPath = resolveWithExtensions(rawResolvedPath)
124
+
125
+ if (finalResolvedPath) {
126
+ return resolvePath(finalResolvedPath)
127
+ }
128
+ }
129
+ }
130
+
131
+ return null
132
+ }
133
+
134
+ /**
135
+ * Try to resolve a relative specifier by computing the absolute path from the
136
+ * parent module and running it through extension / index resolution.
137
+ */
138
+ function resolveRelative(specifier, parentURL) {
139
+ if (!parentURL) return null
140
+ try {
141
+ const parentPath = fileURLToPath(parentURL)
142
+ const parentDir = dirname(parentPath)
143
+ const absolutePath = resolvePath(parentDir, specifier)
144
+ return resolveWithExtensions(absolutePath)
145
+ } catch {
146
+ return null
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Resolve a bare specifier (e.g. "@tata1mg/synapse/utils") using CJS resolution
152
+ * rules via createRequire. CJS require.resolve handles extensionless imports,
153
+ * directory/index resolution, and package.json "main" fields automatically.
154
+ */
155
+ function resolveBareSpecifier(specifier, parentURL) {
156
+ if (!parentURL) return null
157
+ try {
158
+ const req = createRequire(parentURL)
159
+ const resolved = req.resolve(specifier)
160
+ return resolved
161
+ } catch {
162
+ return null
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Node.js loader hook for resolving modules
168
+ */
169
+ export async function resolve(specifier, context, defaultResolve) {
170
+ try {
171
+ // 1. Try alias resolution first
172
+ const aliasResolved = resolveAlias(specifier, context.parentURL)
173
+ if (aliasResolved) {
174
+ const fileURL = pathToFileURL(aliasResolved).href
175
+ const ext = extname(aliasResolved)
176
+ // Node's default resolver can't handle .jsx/.tsx — shortCircuit directly
177
+ if (ext === ".jsx" || ext === ".tsx") {
178
+ return { url: fileURL, shortCircuit: true }
179
+ }
180
+ return await defaultResolve(fileURL, context)
181
+ }
182
+
183
+ // 2. For relative imports, try extension / directory index resolution
184
+ // before handing off to Node's strict ESM resolver.
185
+ if (specifier.startsWith("./") || specifier.startsWith("../")) {
186
+ const resolved = resolveRelative(specifier, context.parentURL)
187
+ if (resolved) {
188
+ return {
189
+ url: pathToFileURL(resolved).href,
190
+ shortCircuit: true,
191
+ }
192
+ }
193
+ }
194
+
195
+ // 3. Default resolver
196
+ return await defaultResolve(specifier, context)
197
+ } catch (error) {
198
+ if (error.code === "ERR_UNSUPPORTED_DIR_IMPORT" || error.code === "ERR_MODULE_NOT_FOUND") {
199
+ // 4a. For relative imports, retry with extension / directory resolution
200
+ if (specifier.startsWith("./") || specifier.startsWith("../")) {
201
+ const resolved = resolveRelative(specifier, context.parentURL)
202
+ if (resolved) {
203
+ return {
204
+ url: pathToFileURL(resolved).href,
205
+ shortCircuit: true,
206
+ }
207
+ }
208
+ }
209
+
210
+ // 4b. For bare specifiers (node_modules), fall back to CJS require.resolve
211
+ const cjsResolved = resolveBareSpecifier(specifier, context.parentURL)
212
+ if (cjsResolved) {
213
+ return {
214
+ url: pathToFileURL(cjsResolved).href,
215
+ shortCircuit: true,
216
+ }
217
+ }
218
+ }
219
+ throw error
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Walk up from a directory to find the nearest package.json and return its parsed content.
225
+ */
226
+ function findNearestPackageType(dir) {
227
+ while (dir !== dirname(dir)) {
228
+ const pkgPath = join(dir, "package.json")
229
+ if (existsSync(pkgPath)) {
230
+ try {
231
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"))
232
+ return pkg.type || "commonjs"
233
+ } catch {
234
+ return "commonjs"
235
+ }
236
+ }
237
+ dir = dirname(dir)
238
+ }
239
+ return "commonjs"
240
+ }
241
+
242
+ /**
243
+ * Check if a file is a CJS module based on extension and nearest package.json.
244
+ */
245
+ function isCjsModule(filePath) {
246
+ const ext = extname(filePath)
247
+ if (ext === ".mjs") return false
248
+ if (ext === ".cjs") return true
249
+ return findNearestPackageType(dirname(filePath)) !== "module"
250
+ }
251
+
252
+ const VALID_IDENTIFIER_RE = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/
253
+ const JS_RESERVED = new Set([
254
+ "break",
255
+ "case",
256
+ "catch",
257
+ "continue",
258
+ "debugger",
259
+ "default",
260
+ "delete",
261
+ "do",
262
+ "else",
263
+ "finally",
264
+ "for",
265
+ "function",
266
+ "if",
267
+ "in",
268
+ "instanceof",
269
+ "new",
270
+ "return",
271
+ "switch",
272
+ "this",
273
+ "throw",
274
+ "try",
275
+ "typeof",
276
+ "var",
277
+ "void",
278
+ "while",
279
+ "with",
280
+ "class",
281
+ "const",
282
+ "enum",
283
+ "export",
284
+ "extends",
285
+ "import",
286
+ "super",
287
+ "implements",
288
+ "interface",
289
+ "let",
290
+ "package",
291
+ "private",
292
+ "protected",
293
+ "public",
294
+ "static",
295
+ "yield",
296
+ ])
297
+
298
+ function isValidExportName(name) {
299
+ return VALID_IDENTIFIER_RE.test(name) && !JS_RESERVED.has(name) && name !== "default"
300
+ }
301
+
302
+ // Loader-scoped require for discovering CJS exports
303
+ const loaderRequire = createRequire(import.meta.url)
304
+
305
+ const CJS_PATTERN = /\b(module\.exports\b|exports\.\w+\s*=)/
306
+ const REQUIRE_CALL_PATTERN = /\brequire\s*\(/
307
+
308
+ // Shim __dirname and __filename for ESM app files (these globals only exist in CJS)
309
+ const createDirnameShim = (source) => {
310
+ const hasFilename = /\b(?:const|let|var)\s+__filename\b/.test(source)
311
+ const hasDirname = /\b(?:const|let|var)\s+__dirname\b/.test(source)
312
+ if (hasFilename && hasDirname) return ""
313
+
314
+ return [
315
+ !hasFilename && `import { fileURLToPath as __node_loader_fileURLToPath } from "url";`,
316
+ !hasDirname && `import { dirname as __node_loader_dirname } from "path";`,
317
+ !hasFilename && `const __filename = __node_loader_fileURLToPath(import.meta.url);`,
318
+ !hasDirname && `const __dirname = __node_loader_dirname(__filename);`,
319
+ ]
320
+ .filter(Boolean)
321
+ .join("\n")
322
+ }
323
+
324
+ // Shim require for ESM app files that still import legacy CJS dependencies.
325
+ const createRequireShim = (source) => {
326
+ if (!REQUIRE_CALL_PATTERN.test(source)) return ""
327
+ if (/\b(?:const|let|var)\s+require\b/.test(source) || /\bfunction\s+require\b/.test(source)) return ""
328
+
329
+ return [
330
+ `import { createRequire as __node_loader_createRequire } from "module";`,
331
+ `const require = __node_loader_createRequire(import.meta.url);`,
332
+ ].join("\n")
333
+ }
334
+
335
+ /**
336
+ * Generate an ESM wrapper for a CJS file using createRequire.
337
+ * Discovers named exports by executing the module via require().
338
+ */
339
+ function generateCjsWrapper(filePath, url) {
340
+ const mod = loaderRequire(filePath)
341
+ const exportNames = Object.keys(mod).filter(isValidExportName)
342
+
343
+ return [
344
+ `import { createRequire as __createRequire } from "module";`,
345
+ `const __require = __createRequire(${JSON.stringify(url)});`,
346
+ `const __mod = __require(${JSON.stringify(filePath)});`,
347
+ `export default __mod;`,
348
+ ...exportNames.map((name) => `export const ${name} = __mod[${JSON.stringify(name)}];`),
349
+ ].join("\n")
350
+ }
351
+
352
+ /**
353
+ * Node.js loader hook for transforming source code.
354
+ * - Wraps CJS modules (node_modules and app files) as ESM so named imports work.
355
+ * - Transpiles JSX in .js/.js app files so Node can execute them.
356
+ */
357
+ export async function load(url, context, defaultLoad) {
358
+ // Only transform file:// URLs (skip node: builtins, data: urls, etc.)
359
+ if (!url.startsWith("file://")) {
360
+ return defaultLoad(url, context)
361
+ }
362
+
363
+ const filePath = fileURLToPath(url)
364
+ const ext = extname(filePath)
365
+
366
+ if (ext !== ".js" && ext !== ".jsx" && ext !== ".cjs") {
367
+ return defaultLoad(url, context)
368
+ }
369
+
370
+ const isNodeModule = filePath.includes("/node_modules/")
371
+
372
+ // --- CJS detection and wrapping ---
373
+ // For node_modules: check via package.json "type" field
374
+ // For app files: check source content (because package.json may say "module"
375
+ // but the file may still use CJS syntax during migration)
376
+ if (ext === ".cjs" || (isNodeModule && isCjsModule(filePath))) {
377
+ try {
378
+ const source = generateCjsWrapper(filePath, url)
379
+ return { format: "module", source, shortCircuit: true }
380
+ } catch {
381
+ return defaultLoad(url, context)
382
+ }
383
+ }
384
+
385
+ // For non-node_modules .js/.js files, read source to detect CJS or JSX
386
+ if (!isNodeModule) {
387
+ const source = readFileSync(filePath, "utf8")
388
+
389
+ // If source uses CJS module.exports/exports, wrap it in an ESM shim.
390
+ // We can't use createRequire here because the file lives in a "type":"module"
391
+ // package — Node's CJS require refuses to load it. Instead, we wrap the
392
+ // source inline so that `module.exports` becomes the default export.
393
+ if (CJS_PATTERN.test(source)) {
394
+ const shimmed = [
395
+ createRequireShim(source),
396
+ createDirnameShim(source),
397
+ `var module = { exports: {} };`,
398
+ `var exports = module.exports;`,
399
+ source,
400
+ `export default module.exports;`,
401
+ ].join("\n")
402
+
403
+ // Run through esbuild in case the CJS file also has JSX
404
+ try {
405
+ const result = transformSync(shimmed, {
406
+ loader: "jsx",
407
+ format: "esm",
408
+ sourcefile: filePath,
409
+ target: "node20",
410
+ })
411
+ return { format: "module", source: result.code, shortCircuit: true }
412
+ } catch {
413
+ // If esbuild fails, return the shimmed source as-is
414
+ return { format: "module", source: shimmed, shortCircuit: true }
415
+ }
416
+ }
417
+
418
+ // ESM app files: prepend __dirname/__filename shim + JSX transform
419
+ {
420
+ const transformed = `${createRequireShim(source)}\n${createDirnameShim(source)}\n${source}`
421
+ try {
422
+ const result = transformSync(transformed, {
423
+ loader: "jsx",
424
+ format: "esm",
425
+ sourcefile: filePath,
426
+ target: "node20",
427
+ })
428
+ return {
429
+ format: "module",
430
+ source: result.code,
431
+ shortCircuit: true,
432
+ }
433
+ } catch {
434
+ // If esbuild fails, return with just the shim
435
+ return { format: "module", source: transformed, shortCircuit: true }
436
+ }
437
+ }
438
+ }
439
+
440
+ // .jsx files in node_modules still need esbuild transformation
441
+ // since Node.js cannot natively handle the .jsx extension
442
+ if (ext === ".jsx") {
443
+ const source = readFileSync(filePath, "utf8")
444
+ try {
445
+ const result = transformSync(source, {
446
+ loader: "jsx",
447
+ format: "esm",
448
+ sourcefile: filePath,
449
+ target: "node20",
450
+ })
451
+ return { format: "module", source: result.code, shortCircuit: true }
452
+ } catch {
453
+ return { format: "module", source, shortCircuit: true }
454
+ }
455
+ }
456
+
457
+ return defaultLoad(url, context)
458
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @description generate assets url according to enviorment
3
+ * @returns returns path required for loading assets according to enviorment
4
+ */
5
+ export const imageUrl = () => {
6
+ const { PUBLIC_STATIC_ASSET_URL, PUBLIC_STATIC_ASSET_PATH } = process.env
7
+ let publicPath = `${PUBLIC_STATIC_ASSET_URL}${PUBLIC_STATIC_ASSET_PATH}`
8
+ const imagePath = `${publicPath}images/`
9
+ return imagePath
10
+ }
11
+
12
+ /**
13
+ * @description generate assets font url according to enviorment
14
+ * @returns returns path required for loading fonts according to enviorment
15
+ */
16
+ export const fontUrl = () => {
17
+ const { PUBLIC_STATIC_ASSET_URL, PUBLIC_STATIC_ASSET_PATH } = process.env
18
+ let publicPath = `${PUBLIC_STATIC_ASSET_URL}${PUBLIC_STATIC_ASSET_PATH}`
19
+ const fontPath = `${publicPath}fonts/`
20
+ return fontPath
21
+ }
@@ -0,0 +1,130 @@
1
+ import loadEnvironmentVariables from "../scripts/loadEnvironmentVariables.js"
2
+ loadEnvironmentVariables()
3
+ import { defineConfig } from "vite"
4
+ import baseConfig, { getClientEnvVariables } from "./vite.config.js"
5
+ import path from "path"
6
+ import { manifestCategorizationPlugin } from "./manifest-categorization-plugin.js"
7
+ import { injectCacheKeyPlugin } from "./inject-cache-key-plugin.js"
8
+ import { loadCustomViteConfig } from "./loadCustomViteConfig.js"
9
+
10
+ const createClientConfig = async () => {
11
+ const customViteConfig = await loadCustomViteConfig()
12
+
13
+ return {
14
+ ...baseConfig,
15
+ mode: "production",
16
+ base: `${process.env.PUBLIC_STATIC_ASSET_URL || ""}${process.env.PUBLIC_STATIC_ASSET_PATH || "/"}`,
17
+
18
+ plugins: [
19
+ ...(baseConfig.plugins || []),
20
+ manifestCategorizationPlugin({
21
+ outputFile: "asset-categories.json",
22
+ publicPath: `${process.env.PUBLIC_STATIC_ASSET_URL}${process.env.PUBLIC_STATIC_ASSET_PATH}/client/assets/`,
23
+ }),
24
+ injectCacheKeyPlugin(),
25
+ ...(customViteConfig?.clientPlugins || []),
26
+ ],
27
+
28
+ build: {
29
+ target: "esnext",
30
+ minify: "esbuild",
31
+ sourcemap: false,
32
+ manifest: true,
33
+ ssrManifest: true,
34
+ outDir: path.join(process.env.src_path, process.env.BUILD_OUTPUT_PATH || "build"),
35
+
36
+ // cssCodeSplit: true (default) — each chunk gets its own CSS file.
37
+ // Since ALL CSS is served via external <link> tags (never inlined),
38
+ // per-chunk CSS is fine — more files but each is small and cacheable.
39
+
40
+ rollupOptions: {
41
+ input: {
42
+ main: path.join(process.env.src_path, "client/index.js"),
43
+ },
44
+ output: {
45
+ format: "es",
46
+ entryFileNames: (chunkInfo) => {
47
+ return chunkInfo.name === "server"
48
+ ? "server/[name].js"
49
+ : "client/assets/[name]-[hash].js"
50
+ },
51
+ chunkFileNames: "client/assets/[name]-[hash].js",
52
+ assetFileNames: (assetInfo) => {
53
+ const extType = assetInfo.name.split(".").pop()
54
+ if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
55
+ return "client/assets/images/[name]-[hash][extname]"
56
+ }
57
+ if (/woff2?|eot|ttf|otf/i.test(extType)) {
58
+ return "client/assets/fonts/[name]-[hash][extname]"
59
+ }
60
+ if (/css/i.test(extType)) {
61
+ return "client/assets/css/[name]-[hash][extname]"
62
+ }
63
+ return "client/assets/[name]-[hash][extname]"
64
+ },
65
+
66
+ // Each manual chunk gets its own [hash] from chunkFileNames,
67
+ // so a change in one group does not bust caches for the others.
68
+ // Keep CSS out of manual chunks so cssCodeSplit works correctly.
69
+ manualChunks(id) {
70
+ if (/\.(css|scss|sass|less|styl)(\?.*)?$/.test(id)) {
71
+ return undefined
72
+ }
73
+ if (!/[\\/]node_modules[\\/]/.test(id)) {
74
+ return undefined
75
+ }
76
+ if (
77
+ /[\\/]node_modules[\\/](react|react-dom|scheduler|react-fast-compare|react-side-effect|react-helmet-async)[\\/]/.test(
78
+ id
79
+ )
80
+ ) {
81
+ return "vendor-react"
82
+ }
83
+ if (/[\\/]node_modules[\\/](react-router(?:-dom|-config)?|history)[\\/]/.test(id)) {
84
+ return "vendor-router"
85
+ }
86
+ if (/[\\/]node_modules[\\/]axios[\\/]/.test(id)) {
87
+ return "vendor-network"
88
+ }
89
+ if (/[\\/]node_modules[\\/]lottie[^\\/]*[\\/]/.test(id)) {
90
+ return "vendor-lottie"
91
+ }
92
+ if (
93
+ /[\\/]node_modules[\\/](react-google-recaptcha|react-async-script|react-dfp)[\\/]/.test(
94
+ id
95
+ )
96
+ ) {
97
+ return "vendor-ads"
98
+ }
99
+ if (
100
+ /[\\/]node_modules[\\/](react-loadable-visibility|react-detect-offline|normalize\.css)[\\/]/.test(
101
+ id
102
+ )
103
+ ) {
104
+ return "vendor-ui"
105
+ }
106
+ if (/[\\/]node_modules[\\/]catalyst-core[\\/]/.test(id)) {
107
+ return "app"
108
+ }
109
+ // Other node_modules → let Vite pack them with the chunks that use them.
110
+ return undefined
111
+ },
112
+ },
113
+ },
114
+
115
+ modulePreload: false,
116
+ chunkSizeWarningLimit: 2000,
117
+ },
118
+ esbuild: {
119
+ legalComments: "none",
120
+ },
121
+
122
+ define: {
123
+ ...getClientEnvVariables(),
124
+ __DEV__: false,
125
+ "process.env.NODE_ENV": JSON.stringify("production"),
126
+ },
127
+ }
128
+ }
129
+
130
+ export default defineConfig(createClientConfig)