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

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 (167) 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/globals.d.ts +7 -0
  6. package/dist/index.jsx +8 -0
  7. package/dist/logger.js +74 -3
  8. package/dist/native/androidProject/app/build.gradle.kts +45 -4
  9. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +86 -0
  10. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +8 -0
  11. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +173 -13
  12. package/dist/native/androidProject/settings.gradle.kts +10 -0
  13. package/dist/native/androidSetup.js +300 -8
  14. package/dist/native/bridge/WebBridge.js +481 -59
  15. package/dist/native/bridge/constants/NativeInterfaces.js +304 -45
  16. package/dist/native/bridge/errors.js +250 -26
  17. package/dist/native/bridge/hooks/index.js +132 -1
  18. package/dist/native/bridge/hooks/useAI.js +94 -0
  19. package/dist/native/bridge/hooks/useCamera.js +347 -9
  20. package/dist/native/bridge/hooks/useDataProtection.js +200 -2
  21. package/dist/native/bridge/hooks/useDeviceInfo.js +71 -2
  22. package/dist/native/bridge/hooks/useFilePicker.js +429 -2
  23. package/dist/native/bridge/hooks/useGoogleSignIn.js +81 -1
  24. package/dist/native/bridge/hooks/useHapticFeedback.js +196 -1
  25. package/dist/native/bridge/hooks/useIntent.js +95 -1
  26. package/dist/native/bridge/hooks/useNativeTransition.js +202 -27
  27. package/dist/native/bridge/hooks/useNetworkStatus.js +84 -3
  28. package/dist/native/bridge/hooks/useNotification.js +318 -2
  29. package/dist/native/bridge/hooks/useSafeArea.js +84 -2
  30. package/dist/native/bridge/hooks/useVideoStream.js +434 -6
  31. package/dist/native/bridge/hooks/utils.js +27 -1
  32. package/dist/native/bridge/hooks.js +16 -1
  33. package/dist/native/bridge/perf/collectors/ApiCollector.js +66 -3
  34. package/dist/native/bridge/perf/collectors/CacheCollector.js +186 -11
  35. package/dist/native/bridge/perf/collectors/HookCollector.js +141 -19
  36. package/dist/native/bridge/perf/collectors/InsightsCollector.js +481 -23
  37. package/dist/native/bridge/perf/collectors/InteractionCollector.js +245 -10
  38. package/dist/native/bridge/perf/collectors/KeyboardCollector.js +107 -8
  39. package/dist/native/bridge/perf/collectors/NavigationCollector.js +273 -32
  40. package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +178 -2
  41. package/dist/native/bridge/perf/collectors/RenderCollector.js +258 -14
  42. package/dist/native/bridge/perf/collectors/ScrollCollector.js +95 -9
  43. package/dist/native/bridge/perf/collectors/ThreadCollector.js +90 -6
  44. package/dist/native/bridge/perf/core/constants.js +103 -20
  45. package/dist/native/bridge/perf/core/measure.js +179 -30
  46. package/dist/native/bridge/perf/core/session.js +89 -23
  47. package/dist/native/bridge/perf/core/store.js +554 -1
  48. package/dist/native/bridge/perf/core/summary.js +174 -1
  49. package/dist/native/bridge/perf/core/traceExport.js +240 -1
  50. package/dist/native/bridge/perf/core/waterfalls.js +146 -1
  51. package/dist/native/bridge/perf/index.js +359 -38
  52. package/dist/native/bridge/safeArea.js +53 -5
  53. package/dist/native/bridge/standardizedHooks.js +595 -82
  54. package/dist/native/bridge/useBaseHook.js +274 -38
  55. package/dist/native/bridge/utils/CameraUtils.js +201 -56
  56. package/dist/native/bridge/utils/FileObjectConverter.js +129 -18
  57. package/dist/native/bridge/utils/NativeBridge.js +425 -141
  58. package/dist/native/buildAndroid/assets.js +510 -13
  59. package/dist/native/buildAndroid/build.js +296 -19
  60. package/dist/native/buildAndroid/config.js +87 -1
  61. package/dist/native/buildAndroid/index.js +406 -1
  62. package/dist/native/buildAppAndroid.js +34 -2
  63. package/dist/native/buildAppIos.js +62 -2
  64. package/dist/native/buildIos/assets.js +609 -8
  65. package/dist/native/buildIos/build.js +639 -20
  66. package/dist/native/buildIos/config.js +294 -12
  67. package/dist/native/buildIos/index.js +343 -6
  68. package/dist/native/buildIos/plugins.js +343 -16
  69. package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +43 -0
  70. package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +28 -0
  71. package/dist/native/internal-plugins/device-info-plugin/manifest.json +19 -0
  72. package/dist/native/internalPluginUtils.js +232 -7
  73. package/dist/native/package.json +3 -0
  74. package/dist/native/plugin-bridge/PluginBridge.js +227 -1
  75. package/dist/native/pluginComposerAndroid.js +407 -23
  76. package/dist/native/pluginComposerIos.js +435 -11
  77. package/dist/native/renameAndroidProject.js +1094 -88
  78. package/dist/native/setupEmulatorIos.js +289 -22
  79. package/dist/native/setupServer.js +160 -19
  80. package/dist/native/terminalProgress.js +199 -11
  81. package/dist/native/utils.js +193 -15
  82. package/dist/offline/catalyst-sw.js +145 -1
  83. package/dist/offline/registerServiceWorker.js +33 -1
  84. package/dist/otel.js +375 -46
  85. package/dist/router/ClientRouter.js +14 -2
  86. package/dist/router/ServerRouter.js +9 -1
  87. package/dist/router.js +1 -1
  88. package/dist/scripts/build.js +112 -3
  89. package/dist/scripts/checkVersion.js +3 -1
  90. package/dist/scripts/cleanCache.js +30 -1
  91. package/dist/scripts/generateOfflineManifest.js +116 -1
  92. package/dist/scripts/loadEnvironmentVariables.js +32 -6
  93. package/dist/scripts/plugins.js +309 -1
  94. package/dist/scripts/preServerInit.js +13 -0
  95. package/dist/scripts/scriptUtils.js +54 -3
  96. package/dist/scripts/serve.js +51 -4
  97. package/dist/scripts/start.js +47 -10
  98. package/dist/scripts/validator.js +149 -1
  99. package/dist/sentry.cjs +127 -0
  100. package/dist/sentry.js +125 -5
  101. package/dist/server/expressServer.js +296 -5
  102. package/dist/server/manifestCache.js +36 -0
  103. package/dist/server/renderer/ChunkExtractor.js +144 -0
  104. package/dist/server/renderer/document/Body.jsx +59 -0
  105. package/dist/server/renderer/document/FastRefresh.jsx +20 -0
  106. package/dist/server/renderer/document/Head.jsx +60 -0
  107. package/dist/server/renderer/document/index.jsx +2 -0
  108. package/dist/server/renderer/extract.js +149 -31
  109. package/dist/server/renderer/handler.jsx +450 -0
  110. package/dist/server/renderer/index.js +8 -1
  111. package/dist/server/renderer/render.js +47 -0
  112. package/dist/server/utils/botDetectionMiddleware.js +29 -0
  113. package/dist/server/utils/cjsRequire.js +10 -0
  114. package/dist/server/utils/userAgentUtil.js +87 -9
  115. package/dist/server/utils/validator.js +164 -1
  116. package/dist/vite/FastRefresh.jsx +20 -0
  117. package/dist/vite/inject-cache-key-plugin.js +276 -0
  118. package/dist/vite/loadCustomViteConfig.js +22 -0
  119. package/dist/vite/manifest-categorization-plugin.js +455 -0
  120. package/dist/vite/node-loader.mjs +458 -0
  121. package/dist/vite/scssParams.js +21 -0
  122. package/dist/vite/vite.config.client.js +130 -0
  123. package/dist/vite/vite.config.js +498 -0
  124. package/dist/vite/vite.config.server.js +84 -0
  125. package/dist/web-router/components/MetaTag.jsx +34 -0
  126. package/dist/web-router/components/RouterDataProvider.jsx +332 -0
  127. package/dist/web-router/components/Split.jsx +200 -0
  128. package/dist/web-router/components/SplitInview.jsx +106 -0
  129. package/dist/web-router/components/SsrRequestContext.jsx +14 -0
  130. package/dist/web-router/context.jsx +12 -0
  131. package/dist/web-router/hooks.jsx +72 -0
  132. package/dist/web-router/types/components/MetaTag.d.ts +2 -0
  133. package/dist/web-router/types/components/RouterDataProvider.d.ts +95 -0
  134. package/dist/web-router/types/context.d.ts +14 -0
  135. package/dist/web-router/types/hooks.d.ts +1 -0
  136. package/dist/web-router/types/index.d.ts +3 -0
  137. package/dist/web-router/types/utils/metaDataUtils.d.ts +24 -0
  138. package/dist/web-router/utils/metaDataUtils.jsx +119 -0
  139. package/mcp_v2/conversion-tasks.json +35 -17
  140. package/mcp_v2/knowledge-base.json +176 -17
  141. package/mcp_v2/lib/helpers.js +10 -0
  142. package/mcp_v2/mcp.js +40 -8
  143. package/mcp_v2/package.json +1 -0
  144. package/mcp_v2/tools/build.js +161 -37
  145. package/mcp_v2/tools/conversion.js +106 -5
  146. package/mcp_v2/tools/tasks.js +18 -14
  147. package/package.json +35 -68
  148. package/babel.config.js +0 -32
  149. package/dist/index.js +0 -1
  150. package/dist/scripts/devBuild.js +0 -3
  151. package/dist/scripts/devServe.js +0 -3
  152. package/dist/scripts/loadScriptsBeforeServerStarts.js +0 -4
  153. package/dist/scripts/registerAliases.js +0 -6
  154. package/dist/server/renderer/document/Body.js +0 -11
  155. package/dist/server/renderer/document/Head.js +0 -9
  156. package/dist/server/renderer/document/index.js +0 -1
  157. package/dist/server/renderer/handler.js +0 -47
  158. package/dist/server/startServer.js +0 -57
  159. package/dist/webpack/babel-plugins/remove-client.plugin.js +0 -5
  160. package/dist/webpack/babel-plugins/remove-ssr.plugin.js +0 -5
  161. package/dist/webpack/babel.config.client.js +0 -1
  162. package/dist/webpack/babel.config.ssr.js +0 -1
  163. package/dist/webpack/base.babel.js +0 -7
  164. package/dist/webpack/development.client.babel.js +0 -10
  165. package/dist/webpack/production.client.babel.js +0 -4
  166. package/dist/webpack/production.ssr.babel.js +0 -8
  167. package/dist/webpack/scssParams.js +0 -9
@@ -1,7 +1,232 @@
1
- "use strict";const fs=require("fs");const path=require("path");function isDir(dirPath){return fs.existsSync(dirPath)&&fs.statSync(dirPath).isDirectory();}function mustBeNonEmptyString(value,fieldName,sourcePath){if(typeof value!=="string"||!value.trim()){throw new Error(`Invalid '${fieldName}' in ${sourcePath}`);}return value.trim();}function readStringArray(value,fieldName,sourcePath,{required=false,nonEmpty=false}={}){if(!Array.isArray(value)){if(required){throw new Error(`'${fieldName}' is required and must be an array in ${sourcePath}`);}return[];}const result=value.map(entry=>mustBeNonEmptyString(entry,`${fieldName}[]`,sourcePath));if(nonEmpty&&result.length===0){throw new Error(`'${fieldName}' is required and must be non-empty in ${sourcePath}`);}return result;}function readPlainObject(value,fieldName,sourcePath){if(value==null){return{};}if(!value||typeof value!=="object"||Array.isArray(value)){throw new Error(`'${fieldName}' must be an object in ${sourcePath}`);}return value;}function cloneJsonValue(value,fieldName,sourcePath){try{return JSON.parse(JSON.stringify(value));}catch(error){throw new Error(`'${fieldName}' must be JSON-serializable in ${sourcePath}`);}}function readIosUrlSchemes(value,fieldName,sourcePath){if(value==null){return[];}if(!Array.isArray(value)){throw new Error(`'${fieldName}' must be an array in ${sourcePath}`);}return value.map((entry,index)=>{const entryField=`${fieldName}[${index}]`;if(!entry||typeof entry!=="object"||Array.isArray(entry)){throw new Error(`'${entryField}' must be an object in ${sourcePath}`);}return{name:entry.name==null?null:mustBeNonEmptyString(entry.name,`${entryField}.name`,sourcePath),schemes:readStringArray(entry.schemes,`${entryField}.schemes`,sourcePath,{required:true,nonEmpty:true})};});}function readIosDependencies(value,fieldName,sourcePath){if(value==null){return[];}if(!Array.isArray(value)){throw new Error(`'${fieldName}' must be an array in ${sourcePath}`);}return value.map((entry,index)=>{const entryField=`${fieldName}[${index}]`;if(!entry||typeof entry!=="object"||Array.isArray(entry)){throw new Error(`'${entryField}' must be an object in ${sourcePath}`);}const url=mustBeNonEmptyString(entry.url,`${entryField}.url`,sourcePath);const packageIdentity=entry.package==null?derivePackageIdentityFromUrl(url,`${entryField}.url`,sourcePath):mustBeNonEmptyString(entry.package,`${entryField}.package`,sourcePath);const products=readStringArray(entry.products,`${entryField}.products`,sourcePath,{required:true,nonEmpty:true});if(new Set(products).size!==products.length){throw new Error(`Duplicate product(s) found in '${entryField}.products' in ${sourcePath}`);}const hasFrom=entry.from!=null;const hasExact=entry.exact!=null;if(hasFrom===hasExact){throw new Error(`'${entryField}' must define exactly one version requirement: 'from' or 'exact' in ${sourcePath}`);}return{url,package:packageIdentity,products,requirement:hasFrom?{type:"from",version:mustBeNonEmptyString(entry.from,`${entryField}.from`,sourcePath)}:{type:"exact",version:mustBeNonEmptyString(entry.exact,`${entryField}.exact`,sourcePath)}};});}function derivePackageIdentityFromUrl(url,fieldName,sourcePath){const sanitizedUrl=url.replace(/\/+$/,"");const packageIdentity=sanitizedUrl.split("/").pop()?.replace(/\.git$/,"");if(!packageIdentity){throw new Error(`Unable to derive package identity from '${fieldName}' in ${sourcePath}`);}return packageIdentity;}function parsePluginManifest(pluginDir){// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - pluginDir is discovered from the internal plugin root and the filename is fixed.
2
- const manifestPath=path.join(pluginDir,"manifest.json");if(!fs.existsSync(manifestPath)){return null;}let manifestContent;try{manifestContent=fs.readFileSync(manifestPath,"utf8");}catch(error){throw new Error(`Failed to read plugin manifest at ${manifestPath}: ${error.message}`);}let manifest;try{manifest=JSON.parse(manifestContent);}catch(error){throw new Error(`Invalid JSON in plugin manifest ${manifestPath}: ${error.message}`);}const id=mustBeNonEmptyString(manifest.id,"id",manifestPath);const configKey=mustBeNonEmptyString(manifest.configKey,"configKey",manifestPath);const platforms=readStringArray(manifest.platforms,"platforms",manifestPath,{required:true,nonEmpty:true});const androidConfig=platforms.includes("android")?manifest.android:null;const iosConfig=platforms.includes("ios")?manifest.ios:null;if(platforms.includes("android")&&(!androidConfig||typeof androidConfig!=="object")){throw new Error(`'android' config is required for plugin '${id}' in ${manifestPath}`);}if(platforms.includes("ios")&&(!iosConfig||typeof iosConfig!=="object")){throw new Error(`'ios' config is required for plugin '${id}' in ${manifestPath}`);}return{pluginDir,manifestPath,id,configKey,version:mustBeNonEmptyString(manifest.version,"version",manifestPath),displayName:mustBeNonEmptyString(manifest.displayName,"displayName",manifestPath),description:mustBeNonEmptyString(manifest.description,"description",manifestPath),category:mustBeNonEmptyString(manifest.category,"category",manifestPath),platforms,commands:readStringArray(manifest.commands,"commands",manifestPath,{required:true,nonEmpty:true}),android:androidConfig?{// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - pluginDir is discovered from the internal plugin root and the child directory is fixed.
3
- sourceDir:path.join(pluginDir,"android"),permissions:readStringArray(androidConfig.permissions,"android.permissions",manifestPath),dependencies:readStringArray(androidConfig.dependencies,"android.dependencies",manifestPath),className:mustBeNonEmptyString(androidConfig.className,"android.className",manifestPath)}:null,ios:iosConfig?{// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - pluginDir is discovered from the internal plugin root and the child directory is fixed.
4
- sourceDir:path.join(pluginDir,"ios"),dependencies:readIosDependencies(iosConfig.dependencies,"ios.dependencies",manifestPath),className:mustBeNonEmptyString(iosConfig.className,"ios.className",manifestPath),infoPlist:cloneJsonValue(readPlainObject(iosConfig.infoPlist,"ios.infoPlist",manifestPath),"ios.infoPlist",manifestPath),urlSchemes:readIosUrlSchemes(iosConfig.urlSchemes,"ios.urlSchemes",manifestPath),querySchemes:readStringArray(iosConfig.querySchemes,"ios.querySchemes",manifestPath),entitlements:cloneJsonValue(readPlainObject(iosConfig.entitlements,"ios.entitlements",manifestPath),"ios.entitlements",manifestPath),resources:readStringArray(iosConfig.resources,"ios.resources",manifestPath)}:null};}function discoverInternalPlugins(corePluginsRoot,log=()=>{}){if(!corePluginsRoot||!isDir(corePluginsRoot)){log(`No internal plugin directory found at ${corePluginsRoot||"<empty>"}`,"info");return[];}const plugins=[];const entries=fs.readdirSync(corePluginsRoot,{withFileTypes:true}).sort((left,right)=>left.name.localeCompare(right.name));for(const entry of entries){if(!entry.isDirectory()){continue;}// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - entry.name comes from readdirSync under the internal plugin root.
5
- const pluginDir=path.join(corePluginsRoot,entry.name);const parsed=parsePluginManifest(pluginDir);if(parsed){plugins.push(parsed);}}log(`Discovered ${plugins.length} internal plugin manifest(s)`,"info");return plugins;}function resolveInternalPluginsRoot(packageRoot){// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - These are fixed package-internal directories.
6
- const distPluginsPath=path.join(packageRoot,"dist","native","internal-plugins");// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - These are fixed package-internal directories.
7
- const srcPluginsPath=path.join(packageRoot,"src","native","internal-plugins");return fs.existsSync(distPluginsPath)?distPluginsPath:srcPluginsPath;}function resolvePluginConfig(WEBVIEW_CONFIG){const pluginConfig={};if(WEBVIEW_CONFIG.plugins!=null){if(typeof WEBVIEW_CONFIG.plugins!=="object"||Array.isArray(WEBVIEW_CONFIG.plugins)){throw new Error("'WEBVIEW_CONFIG.plugins' must be an object with boolean values");}for(const[key,value]of Object.entries(WEBVIEW_CONFIG.plugins)){if(typeof value!=="boolean"){throw new Error(`'WEBVIEW_CONFIG.plugins.${key}' must be boolean`);}pluginConfig[key]=value;}}return pluginConfig;}module.exports={discoverInternalPlugins,parsePluginManifest,resolvePluginConfig,resolveInternalPluginsRoot};
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ function isDir(dirPath) {
6
+ return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory();
7
+ }
8
+ function mustBeNonEmptyString(value, fieldName, sourcePath) {
9
+ if (typeof value !== "string" || !value.trim()) {
10
+ throw new Error(`Invalid '${fieldName}' in ${sourcePath}`);
11
+ }
12
+ return value.trim();
13
+ }
14
+ function readStringArray(value, fieldName, sourcePath, {
15
+ required = false,
16
+ nonEmpty = false
17
+ } = {}) {
18
+ if (!Array.isArray(value)) {
19
+ if (required) {
20
+ throw new Error(`'${fieldName}' is required and must be an array in ${sourcePath}`);
21
+ }
22
+ return [];
23
+ }
24
+ const result = value.map(entry => mustBeNonEmptyString(entry, `${fieldName}[]`, sourcePath));
25
+ if (nonEmpty && result.length === 0) {
26
+ throw new Error(`'${fieldName}' is required and must be non-empty in ${sourcePath}`);
27
+ }
28
+ return result;
29
+ }
30
+ function readPlainObject(value, fieldName, sourcePath) {
31
+ if (value == null) {
32
+ return {};
33
+ }
34
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
35
+ throw new Error(`'${fieldName}' must be an object in ${sourcePath}`);
36
+ }
37
+ return value;
38
+ }
39
+ function cloneJsonValue(value, fieldName, sourcePath) {
40
+ try {
41
+ return JSON.parse(JSON.stringify(value));
42
+ } catch (error) {
43
+ throw new Error(`'${fieldName}' must be JSON-serializable in ${sourcePath}`);
44
+ }
45
+ }
46
+ function readIosUrlSchemes(value, fieldName, sourcePath) {
47
+ if (value == null) {
48
+ return [];
49
+ }
50
+ if (!Array.isArray(value)) {
51
+ throw new Error(`'${fieldName}' must be an array in ${sourcePath}`);
52
+ }
53
+ return value.map((entry, index) => {
54
+ const entryField = `${fieldName}[${index}]`;
55
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
56
+ throw new Error(`'${entryField}' must be an object in ${sourcePath}`);
57
+ }
58
+ return {
59
+ name: entry.name == null ? null : mustBeNonEmptyString(entry.name, `${entryField}.name`, sourcePath),
60
+ schemes: readStringArray(entry.schemes, `${entryField}.schemes`, sourcePath, {
61
+ required: true,
62
+ nonEmpty: true
63
+ })
64
+ };
65
+ });
66
+ }
67
+ function readIosDependencies(value, fieldName, sourcePath) {
68
+ if (value == null) {
69
+ return [];
70
+ }
71
+ if (!Array.isArray(value)) {
72
+ throw new Error(`'${fieldName}' must be an array in ${sourcePath}`);
73
+ }
74
+ return value.map((entry, index) => {
75
+ const entryField = `${fieldName}[${index}]`;
76
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
77
+ throw new Error(`'${entryField}' must be an object in ${sourcePath}`);
78
+ }
79
+ const url = mustBeNonEmptyString(entry.url, `${entryField}.url`, sourcePath);
80
+ const packageIdentity = entry.package == null ? derivePackageIdentityFromUrl(url, `${entryField}.url`, sourcePath) : mustBeNonEmptyString(entry.package, `${entryField}.package`, sourcePath);
81
+ const products = readStringArray(entry.products, `${entryField}.products`, sourcePath, {
82
+ required: true,
83
+ nonEmpty: true
84
+ });
85
+ if (new Set(products).size !== products.length) {
86
+ throw new Error(`Duplicate product(s) found in '${entryField}.products' in ${sourcePath}`);
87
+ }
88
+ const hasFrom = entry.from != null;
89
+ const hasExact = entry.exact != null;
90
+ if (hasFrom === hasExact) {
91
+ throw new Error(`'${entryField}' must define exactly one version requirement: 'from' or 'exact' in ${sourcePath}`);
92
+ }
93
+ return {
94
+ url,
95
+ package: packageIdentity,
96
+ products,
97
+ requirement: hasFrom ? {
98
+ type: "from",
99
+ version: mustBeNonEmptyString(entry.from, `${entryField}.from`, sourcePath)
100
+ } : {
101
+ type: "exact",
102
+ version: mustBeNonEmptyString(entry.exact, `${entryField}.exact`, sourcePath)
103
+ }
104
+ };
105
+ });
106
+ }
107
+ function derivePackageIdentityFromUrl(url, fieldName, sourcePath) {
108
+ const sanitizedUrl = url.replace(/\/+$/, "");
109
+ const packageIdentity = sanitizedUrl.split("/").pop()?.replace(/\.git$/, "");
110
+ if (!packageIdentity) {
111
+ throw new Error(`Unable to derive package identity from '${fieldName}' in ${sourcePath}`);
112
+ }
113
+ return packageIdentity;
114
+ }
115
+ function parsePluginManifest(pluginDir) {
116
+ // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - pluginDir is discovered from the internal plugin root and the filename is fixed.
117
+ const manifestPath = path.join(pluginDir, "manifest.json");
118
+ if (!fs.existsSync(manifestPath)) {
119
+ return null;
120
+ }
121
+ let manifestContent;
122
+ try {
123
+ manifestContent = fs.readFileSync(manifestPath, "utf8");
124
+ } catch (error) {
125
+ throw new Error(`Failed to read plugin manifest at ${manifestPath}: ${error.message}`);
126
+ }
127
+ let manifest;
128
+ try {
129
+ manifest = JSON.parse(manifestContent);
130
+ } catch (error) {
131
+ throw new Error(`Invalid JSON in plugin manifest ${manifestPath}: ${error.message}`);
132
+ }
133
+ const id = mustBeNonEmptyString(manifest.id, "id", manifestPath);
134
+ const configKey = mustBeNonEmptyString(manifest.configKey, "configKey", manifestPath);
135
+ const platforms = readStringArray(manifest.platforms, "platforms", manifestPath, {
136
+ required: true,
137
+ nonEmpty: true
138
+ });
139
+ const androidConfig = platforms.includes("android") ? manifest.android : null;
140
+ const iosConfig = platforms.includes("ios") ? manifest.ios : null;
141
+ if (platforms.includes("android") && (!androidConfig || typeof androidConfig !== "object")) {
142
+ throw new Error(`'android' config is required for plugin '${id}' in ${manifestPath}`);
143
+ }
144
+ if (platforms.includes("ios") && (!iosConfig || typeof iosConfig !== "object")) {
145
+ throw new Error(`'ios' config is required for plugin '${id}' in ${manifestPath}`);
146
+ }
147
+ return {
148
+ pluginDir,
149
+ manifestPath,
150
+ id,
151
+ configKey,
152
+ version: mustBeNonEmptyString(manifest.version, "version", manifestPath),
153
+ displayName: mustBeNonEmptyString(manifest.displayName, "displayName", manifestPath),
154
+ description: mustBeNonEmptyString(manifest.description, "description", manifestPath),
155
+ category: mustBeNonEmptyString(manifest.category, "category", manifestPath),
156
+ platforms,
157
+ commands: readStringArray(manifest.commands, "commands", manifestPath, {
158
+ required: true,
159
+ nonEmpty: true
160
+ }),
161
+ android: androidConfig ? {
162
+ // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - pluginDir is discovered from the internal plugin root and the child directory is fixed.
163
+ sourceDir: path.join(pluginDir, "android"),
164
+ permissions: readStringArray(androidConfig.permissions, "android.permissions", manifestPath),
165
+ dependencies: readStringArray(androidConfig.dependencies, "android.dependencies", manifestPath),
166
+ className: mustBeNonEmptyString(androidConfig.className, "android.className", manifestPath)
167
+ } : null,
168
+ ios: iosConfig ? {
169
+ // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - pluginDir is discovered from the internal plugin root and the child directory is fixed.
170
+ sourceDir: path.join(pluginDir, "ios"),
171
+ dependencies: readIosDependencies(iosConfig.dependencies, "ios.dependencies", manifestPath),
172
+ className: mustBeNonEmptyString(iosConfig.className, "ios.className", manifestPath),
173
+ infoPlist: cloneJsonValue(readPlainObject(iosConfig.infoPlist, "ios.infoPlist", manifestPath), "ios.infoPlist", manifestPath),
174
+ urlSchemes: readIosUrlSchemes(iosConfig.urlSchemes, "ios.urlSchemes", manifestPath),
175
+ querySchemes: readStringArray(iosConfig.querySchemes, "ios.querySchemes", manifestPath),
176
+ entitlements: cloneJsonValue(readPlainObject(iosConfig.entitlements, "ios.entitlements", manifestPath), "ios.entitlements", manifestPath),
177
+ resources: readStringArray(iosConfig.resources, "ios.resources", manifestPath)
178
+ } : null
179
+ };
180
+ }
181
+ function discoverInternalPlugins(corePluginsRoot, log = () => {}) {
182
+ if (!corePluginsRoot || !isDir(corePluginsRoot)) {
183
+ log(`No internal plugin directory found at ${corePluginsRoot || "<empty>"}`, "info");
184
+ return [];
185
+ }
186
+ const plugins = [];
187
+ const entries = fs.readdirSync(corePluginsRoot, {
188
+ withFileTypes: true
189
+ }).sort((left, right) => left.name.localeCompare(right.name));
190
+ for (const entry of entries) {
191
+ if (!entry.isDirectory()) {
192
+ continue;
193
+ }
194
+
195
+ // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - entry.name comes from readdirSync under the internal plugin root.
196
+ const pluginDir = path.join(corePluginsRoot, entry.name);
197
+ const parsed = parsePluginManifest(pluginDir);
198
+ if (parsed) {
199
+ plugins.push(parsed);
200
+ }
201
+ }
202
+ log(`Discovered ${plugins.length} internal plugin manifest(s)`, "info");
203
+ return plugins;
204
+ }
205
+ function resolveInternalPluginsRoot(packageRoot) {
206
+ // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - These are fixed package-internal directories.
207
+ const distPluginsPath = path.join(packageRoot, "dist", "native", "internal-plugins");
208
+ // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - These are fixed package-internal directories.
209
+ const srcPluginsPath = path.join(packageRoot, "src", "native", "internal-plugins");
210
+ return fs.existsSync(distPluginsPath) ? distPluginsPath : srcPluginsPath;
211
+ }
212
+ function resolvePluginConfig(WEBVIEW_CONFIG) {
213
+ const pluginConfig = {};
214
+ if (WEBVIEW_CONFIG.plugins != null) {
215
+ if (typeof WEBVIEW_CONFIG.plugins !== "object" || Array.isArray(WEBVIEW_CONFIG.plugins)) {
216
+ throw new Error("'WEBVIEW_CONFIG.plugins' must be an object with boolean values");
217
+ }
218
+ for (const [key, value] of Object.entries(WEBVIEW_CONFIG.plugins)) {
219
+ if (typeof value !== "boolean") {
220
+ throw new Error(`'WEBVIEW_CONFIG.plugins.${key}' must be boolean`);
221
+ }
222
+ pluginConfig[key] = value;
223
+ }
224
+ }
225
+ return pluginConfig;
226
+ }
227
+ module.exports = {
228
+ discoverInternalPlugins,
229
+ parsePluginManifest,
230
+ resolvePluginConfig,
231
+ resolveInternalPluginsRoot
232
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -1 +1,227 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;class PluginNativeBridge{constructor(){this.handlers=new Map();this.requestCount=0;this.isInitialized=false;}createRequestId=()=>{this.requestCount+=1;return`plugin_${Date.now()}_${this.requestCount}`;};normalizeRequiredString=(value,fieldName)=>{if(typeof value!=="string"||!value.trim()){throw new Error(`${fieldName} must be a non-empty string`);}return value.trim();};normalizeCommand=command=>{if(command==null){return null;}return this.normalizeRequiredString(command,"command");};getHandlerKey=({pluginId,eventName,command=null}={})=>{return JSON.stringify([this.normalizeRequiredString(pluginId,"pluginId"),this.normalizeRequiredString(eventName,"eventName"),this.normalizeCommand(command)]);};getHandlerSet=(key,create=false)=>{let handlers=this.handlers.get(key);if(!handlers&&create){handlers=new Set();this.handlers.set(key,handlers);}return handlers||null;};addHandler=({pluginId,eventName,command}={},handler)=>{if(typeof handler!=="function"){throw new Error("handler must be a function");}this.getHandlerSet(this.getHandlerKey({pluginId,eventName,command}),true).add(handler);};removeHandler=({pluginId,eventName,command}={},handler)=>{const key=this.getHandlerKey({pluginId,eventName,command});const handlers=this.getHandlerSet(key,false);if(!handlers){return false;}if(handler==null){handlers.clear();this.handlers.delete(key);return true;}const removed=handlers.delete(handler);if(handlers.size===0){this.handlers.delete(key);}return removed;};ensureInitialized=()=>{if(typeof window==="undefined"||this.isInitialized){return this;}window.PluginBridgeWeb=window.PluginBridgeWeb||{};window.PluginBridgeWeb.callback=this.dispatchCallback;window.PluginBridgeWeb.dispatch=message=>{let parsed=message;if(typeof parsed==="string"){try{parsed=JSON.parse(parsed);}catch{return false;}}if(!parsed||typeof parsed!=="object"){return false;}const payload=Object.prototype.hasOwnProperty.call(parsed,"payload")?parsed.payload:null;return this.dispatchCallback(parsed.pluginId,parsed.eventName,payload,parsed.requestId??null,parsed.command??null);};this.isInitialized=true;return this;};hasAndroidBridge=()=>typeof window!=="undefined"&&!!window.PluginBridge;hasIOSBridge=()=>typeof window!=="undefined"&&!!window.webkit?.messageHandlers?.PluginBridge;init=()=>this.ensureInitialized();assertInitialized=()=>{if(!this.isInitialized){throw new Error("PluginBridge.init() must be called before using emit() or register()");}};reportHandlerError=error=>{if(typeof queueMicrotask==="function"){queueMicrotask(()=>{throw error;});return;}setTimeout(()=>{throw error;},0);};emit=({pluginId,command,data=null}={})=>{const normalizedPluginId=this.normalizeRequiredString(pluginId,"pluginId");const normalizedCommand=this.normalizeRequiredString(command,"command");if(typeof window==="undefined"){throw new Error("PluginBridge is not available in this environment");}this.assertInitialized();const payload={pluginId:normalizedPluginId,command:normalizedCommand,data,requestId:this.createRequestId()};if(this.hasAndroidBridge()){window.PluginBridge.emit(JSON.stringify(payload));return;}if(this.hasIOSBridge()){window.webkit.messageHandlers.PluginBridge.postMessage(payload);return;}throw new Error("PluginBridge is not available in this environment");};register=({pluginId,eventName,command,handler}={})=>{this.assertInitialized();this.addHandler({pluginId,eventName,command},handler);return()=>this.removeHandler({pluginId,eventName,command},handler);};unregister=({pluginId,eventName,command,handler}={})=>{if(typeof handler!=="function"){throw new Error("handler must be a function");}return this.removeHandler({pluginId,eventName,command},handler);};dispatchCallback=(pluginId,eventName,payload,requestId=null,command=null)=>{void requestId;const normalizedPluginId=typeof pluginId==="string"&&pluginId.trim()?pluginId.trim():null;const normalizedEventName=typeof eventName==="string"&&eventName.trim()?eventName.trim():null;if(normalizedPluginId==null||normalizedEventName==null){return false;}const normalizedCommand=typeof command==="string"&&command.trim()?command.trim():null;const toCall=new Set();const collectHandlers=commandScope=>{const handlers=this.getHandlerSet(JSON.stringify([normalizedPluginId,normalizedEventName,commandScope]),false);if(!handlers){return;}handlers.forEach(handler=>{toCall.add(handler);});};if(normalizedCommand!=null){collectHandlers(normalizedCommand);}collectHandlers(null);if(toCall.size===0){return false;}const meta={pluginId:normalizedPluginId,eventName:normalizedEventName,command:normalizedCommand};toCall.forEach(handler=>{try{handler(payload,meta);}catch(error){this.reportHandlerError(error);}});return true;};}const pluginNativeBridge=new PluginNativeBridge();var _default=exports.default=pluginNativeBridge;
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ class PluginNativeBridge {
8
+ constructor() {
9
+ this.handlers = new Map();
10
+ this.requestCount = 0;
11
+ this.isInitialized = false;
12
+ }
13
+ createRequestId = () => {
14
+ this.requestCount += 1;
15
+ return `plugin_${Date.now()}_${this.requestCount}`;
16
+ };
17
+ normalizeRequiredString = (value, fieldName) => {
18
+ if (typeof value !== "string" || !value.trim()) {
19
+ throw new Error(`${fieldName} must be a non-empty string`);
20
+ }
21
+ return value.trim();
22
+ };
23
+ normalizeCommand = command => {
24
+ if (command == null) {
25
+ return null;
26
+ }
27
+ return this.normalizeRequiredString(command, "command");
28
+ };
29
+ getHandlerKey = ({
30
+ pluginId,
31
+ eventName,
32
+ command = null
33
+ } = {}) => {
34
+ return JSON.stringify([this.normalizeRequiredString(pluginId, "pluginId"), this.normalizeRequiredString(eventName, "eventName"), this.normalizeCommand(command)]);
35
+ };
36
+ getHandlerSet = (key, create = false) => {
37
+ let handlers = this.handlers.get(key);
38
+ if (!handlers && create) {
39
+ handlers = new Set();
40
+ this.handlers.set(key, handlers);
41
+ }
42
+ return handlers || null;
43
+ };
44
+ addHandler = ({
45
+ pluginId,
46
+ eventName,
47
+ command
48
+ } = {}, handler) => {
49
+ if (typeof handler !== "function") {
50
+ throw new Error("handler must be a function");
51
+ }
52
+ this.getHandlerSet(this.getHandlerKey({
53
+ pluginId,
54
+ eventName,
55
+ command
56
+ }), true).add(handler);
57
+ };
58
+ removeHandler = ({
59
+ pluginId,
60
+ eventName,
61
+ command
62
+ } = {}, handler) => {
63
+ const key = this.getHandlerKey({
64
+ pluginId,
65
+ eventName,
66
+ command
67
+ });
68
+ const handlers = this.getHandlerSet(key, false);
69
+ if (!handlers) {
70
+ return false;
71
+ }
72
+ if (handler == null) {
73
+ handlers.clear();
74
+ this.handlers.delete(key);
75
+ return true;
76
+ }
77
+ const removed = handlers.delete(handler);
78
+ if (handlers.size === 0) {
79
+ this.handlers.delete(key);
80
+ }
81
+ return removed;
82
+ };
83
+ ensureInitialized = () => {
84
+ if (typeof window === "undefined" || this.isInitialized) {
85
+ return this;
86
+ }
87
+ window.PluginBridgeWeb = window.PluginBridgeWeb || {};
88
+ window.PluginBridgeWeb.callback = this.dispatchCallback;
89
+ window.PluginBridgeWeb.dispatch = message => {
90
+ let parsed = message;
91
+ if (typeof parsed === "string") {
92
+ try {
93
+ parsed = JSON.parse(parsed);
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+ if (!parsed || typeof parsed !== "object") {
99
+ return false;
100
+ }
101
+ const payload = Object.prototype.hasOwnProperty.call(parsed, "payload") ? parsed.payload : null;
102
+ return this.dispatchCallback(parsed.pluginId, parsed.eventName, payload, parsed.requestId ?? null, parsed.command ?? null);
103
+ };
104
+ this.isInitialized = true;
105
+ return this;
106
+ };
107
+ hasAndroidBridge = () => typeof window !== "undefined" && !!window.PluginBridge;
108
+ hasIOSBridge = () => typeof window !== "undefined" && !!window.webkit?.messageHandlers?.PluginBridge;
109
+ init = () => this.ensureInitialized();
110
+ assertInitialized = () => {
111
+ if (!this.isInitialized) {
112
+ throw new Error("PluginBridge.init() must be called before using emit() or register()");
113
+ }
114
+ };
115
+ reportHandlerError = error => {
116
+ if (typeof queueMicrotask === "function") {
117
+ queueMicrotask(() => {
118
+ throw error;
119
+ });
120
+ return;
121
+ }
122
+ setTimeout(() => {
123
+ throw error;
124
+ }, 0);
125
+ };
126
+ emit = ({
127
+ pluginId,
128
+ command,
129
+ data = null
130
+ } = {}) => {
131
+ const normalizedPluginId = this.normalizeRequiredString(pluginId, "pluginId");
132
+ const normalizedCommand = this.normalizeRequiredString(command, "command");
133
+ if (typeof window === "undefined") {
134
+ throw new Error("PluginBridge is not available in this environment");
135
+ }
136
+ this.assertInitialized();
137
+ const payload = {
138
+ pluginId: normalizedPluginId,
139
+ command: normalizedCommand,
140
+ data,
141
+ requestId: this.createRequestId()
142
+ };
143
+ if (this.hasAndroidBridge()) {
144
+ window.PluginBridge.emit(JSON.stringify(payload));
145
+ return;
146
+ }
147
+ if (this.hasIOSBridge()) {
148
+ window.webkit.messageHandlers.PluginBridge.postMessage(payload);
149
+ return;
150
+ }
151
+ throw new Error("PluginBridge is not available in this environment");
152
+ };
153
+ register = ({
154
+ pluginId,
155
+ eventName,
156
+ command,
157
+ handler
158
+ } = {}) => {
159
+ this.assertInitialized();
160
+ this.addHandler({
161
+ pluginId,
162
+ eventName,
163
+ command
164
+ }, handler);
165
+ return () => this.removeHandler({
166
+ pluginId,
167
+ eventName,
168
+ command
169
+ }, handler);
170
+ };
171
+ unregister = ({
172
+ pluginId,
173
+ eventName,
174
+ command,
175
+ handler
176
+ } = {}) => {
177
+ if (typeof handler !== "function") {
178
+ throw new Error("handler must be a function");
179
+ }
180
+ return this.removeHandler({
181
+ pluginId,
182
+ eventName,
183
+ command
184
+ }, handler);
185
+ };
186
+ dispatchCallback = (pluginId, eventName, payload, requestId = null, command = null) => {
187
+ void requestId;
188
+ const normalizedPluginId = typeof pluginId === "string" && pluginId.trim() ? pluginId.trim() : null;
189
+ const normalizedEventName = typeof eventName === "string" && eventName.trim() ? eventName.trim() : null;
190
+ if (normalizedPluginId == null || normalizedEventName == null) {
191
+ return false;
192
+ }
193
+ const normalizedCommand = typeof command === "string" && command.trim() ? command.trim() : null;
194
+ const toCall = new Set();
195
+ const collectHandlers = commandScope => {
196
+ const handlers = this.getHandlerSet(JSON.stringify([normalizedPluginId, normalizedEventName, commandScope]), false);
197
+ if (!handlers) {
198
+ return;
199
+ }
200
+ handlers.forEach(handler => {
201
+ toCall.add(handler);
202
+ });
203
+ };
204
+ if (normalizedCommand != null) {
205
+ collectHandlers(normalizedCommand);
206
+ }
207
+ collectHandlers(null);
208
+ if (toCall.size === 0) {
209
+ return false;
210
+ }
211
+ const meta = {
212
+ pluginId: normalizedPluginId,
213
+ eventName: normalizedEventName,
214
+ command: normalizedCommand
215
+ };
216
+ toCall.forEach(handler => {
217
+ try {
218
+ handler(payload, meta);
219
+ } catch (error) {
220
+ this.reportHandlerError(error);
221
+ }
222
+ });
223
+ return true;
224
+ };
225
+ }
226
+ const pluginNativeBridge = new PluginNativeBridge();
227
+ var _default = exports.default = pluginNativeBridge;