@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.2 → 3.9.0-ultramodern.3

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.
@@ -73,6 +73,46 @@ const collectNestedStrings = (value, key)=>{
73
73
  ...collectNestedStrings(entryValue, key)
74
74
  ]);
75
75
  };
76
+ const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
77
+ if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || 0 !== manifest.remotes.length || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
78
+ const publicPath = manifest.metaData.publicPath;
79
+ const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
80
+ if (!safeReference(publicPath)) return [];
81
+ const absoluteBase = /^https?:\/\//u.test(publicPath);
82
+ if ('auto' !== publicPath && (!publicPath.endsWith('/') || !absoluteBase && (!publicPath.startsWith('/') || publicPath.startsWith('//')))) return [];
83
+ if (absoluteBase) {
84
+ const base = new URL(publicPath);
85
+ if (base.username || base.password || base.href !== publicPath) return [];
86
+ }
87
+ const directory = external_node_path_default().posix.dirname(manifestLogicalPath);
88
+ const routesManifest = await readJson(external_node_path_default().join(distDirectory, directory, 'routes-manifest.json'));
89
+ if (!isRecord(routesManifest) || !isRecord(routesManifest.routeAssets)) return [];
90
+ const modules = new Set();
91
+ for (const route of Object.values(routesManifest.routeAssets)){
92
+ if (!isRecord(route) || !Array.isArray(route.assets)) return [];
93
+ for (const reference of route.assets){
94
+ if (!safeReference(reference) || reference.startsWith('//')) return [];
95
+ let relative = reference;
96
+ if (/^https?:\/\//u.test(reference)) {
97
+ if (!absoluteBase || !reference.startsWith(publicPath)) return [];
98
+ relative = reference.slice(publicPath.length);
99
+ } else if (reference.startsWith('/')) {
100
+ const prefix = 'auto' === publicPath ? '/' : absoluteBase ? new URL(publicPath).pathname : publicPath;
101
+ if (!reference.startsWith(prefix)) return [];
102
+ relative = reference.slice(prefix.length);
103
+ }
104
+ if (!/^(?:static|html|public)\/[^:]+$/u.test(relative) || relative.includes('//')) return [];
105
+ const logicalPath = external_node_path_default().posix.join(directory, relative);
106
+ if (!files.includes(logicalPath)) return [];
107
+ const assetStat = await promises_default().lstat(external_node_path_default().join(distDirectory, logicalPath));
108
+ if (!assetStat.isFile()) return [];
109
+ if (COMPILED_MODULE_PATTERN.test(logicalPath)) modules.add(logicalPath);
110
+ }
111
+ }
112
+ return [
113
+ ...modules
114
+ ];
115
+ };
76
116
  const manifestReferencedClientModules = async (distDirectory, files, manifestLogicalPath = 'mf-manifest.json')=>{
77
117
  const manifest = await readJson(external_node_path_default().join(distDirectory, manifestLogicalPath));
78
118
  const references = [
@@ -82,9 +122,10 @@ const manifestReferencedClientModules = async (distDirectory, files, manifestLog
82
122
  ...collectNestedStrings(manifest, 'async')
83
123
  ];
84
124
  const normalizedReferences = new Set(references.filter((value)=>'string' == typeof value).map((value)=>value.replace(/^https?:\/\/[^/]+/u, '')).map((value)=>value.replace(/^\/+/u, '')));
85
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
125
+ const modules = files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
86
126
  ...normalizedReferences
87
127
  ].some((reference)=>reference === logicalPath || reference.endsWith(`/${logicalPath}`) || logicalPath.endsWith(`/${reference}`)));
128
+ return modules.length > 0 ? modules : emptyProducerRouteModules(distDirectory, files, manifest, manifestLogicalPath);
88
129
  };
89
130
  const routeReferencedSsrModules = async (distDirectory, files, target, routeSpecLogicalPath = 'route.json')=>{
90
131
  const routeSpec = await readJson(external_node_path_default().join(distDirectory, routeSpecLogicalPath));
@@ -21,6 +21,46 @@ const collectNestedStrings = (value, key)=>{
21
21
  ...collectNestedStrings(entryValue, key)
22
22
  ]);
23
23
  };
24
+ const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
25
+ if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || 0 !== manifest.remotes.length || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
26
+ const publicPath = manifest.metaData.publicPath;
27
+ const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
28
+ if (!safeReference(publicPath)) return [];
29
+ const absoluteBase = /^https?:\/\//u.test(publicPath);
30
+ if ('auto' !== publicPath && (!publicPath.endsWith('/') || !absoluteBase && (!publicPath.startsWith('/') || publicPath.startsWith('//')))) return [];
31
+ if (absoluteBase) {
32
+ const base = new URL(publicPath);
33
+ if (base.username || base.password || base.href !== publicPath) return [];
34
+ }
35
+ const directory = node_path.posix.dirname(manifestLogicalPath);
36
+ const routesManifest = await readJson(node_path.join(distDirectory, directory, 'routes-manifest.json'));
37
+ if (!isRecord(routesManifest) || !isRecord(routesManifest.routeAssets)) return [];
38
+ const modules = new Set();
39
+ for (const route of Object.values(routesManifest.routeAssets)){
40
+ if (!isRecord(route) || !Array.isArray(route.assets)) return [];
41
+ for (const reference of route.assets){
42
+ if (!safeReference(reference) || reference.startsWith('//')) return [];
43
+ let relative = reference;
44
+ if (/^https?:\/\//u.test(reference)) {
45
+ if (!absoluteBase || !reference.startsWith(publicPath)) return [];
46
+ relative = reference.slice(publicPath.length);
47
+ } else if (reference.startsWith('/')) {
48
+ const prefix = 'auto' === publicPath ? '/' : absoluteBase ? new URL(publicPath).pathname : publicPath;
49
+ if (!reference.startsWith(prefix)) return [];
50
+ relative = reference.slice(prefix.length);
51
+ }
52
+ if (!/^(?:static|html|public)\/[^:]+$/u.test(relative) || relative.includes('//')) return [];
53
+ const logicalPath = node_path.posix.join(directory, relative);
54
+ if (!files.includes(logicalPath)) return [];
55
+ const assetStat = await promises.lstat(node_path.join(distDirectory, logicalPath));
56
+ if (!assetStat.isFile()) return [];
57
+ if (COMPILED_MODULE_PATTERN.test(logicalPath)) modules.add(logicalPath);
58
+ }
59
+ }
60
+ return [
61
+ ...modules
62
+ ];
63
+ };
24
64
  const manifestReferencedClientModules = async (distDirectory, files, manifestLogicalPath = 'mf-manifest.json')=>{
25
65
  const manifest = await readJson(node_path.join(distDirectory, manifestLogicalPath));
26
66
  const references = [
@@ -30,9 +70,10 @@ const manifestReferencedClientModules = async (distDirectory, files, manifestLog
30
70
  ...collectNestedStrings(manifest, 'async')
31
71
  ];
32
72
  const normalizedReferences = new Set(references.filter((value)=>'string' == typeof value).map((value)=>value.replace(/^https?:\/\/[^/]+/u, '')).map((value)=>value.replace(/^\/+/u, '')));
33
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
73
+ const modules = files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
34
74
  ...normalizedReferences
35
75
  ].some((reference)=>reference === logicalPath || reference.endsWith(`/${logicalPath}`) || logicalPath.endsWith(`/${reference}`)));
76
+ return modules.length > 0 ? modules : emptyProducerRouteModules(distDirectory, files, manifest, manifestLogicalPath);
36
77
  };
37
78
  const routeReferencedSsrModules = async (distDirectory, files, target, routeSpecLogicalPath = 'route.json')=>{
38
79
  const routeSpec = await readJson(node_path.join(distDirectory, routeSpecLogicalPath));
@@ -22,6 +22,46 @@ const collectNestedStrings = (value, key)=>{
22
22
  ...collectNestedStrings(entryValue, key)
23
23
  ]);
24
24
  };
25
+ const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
26
+ if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || 0 !== manifest.remotes.length || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
27
+ const publicPath = manifest.metaData.publicPath;
28
+ const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
29
+ if (!safeReference(publicPath)) return [];
30
+ const absoluteBase = /^https?:\/\//u.test(publicPath);
31
+ if ('auto' !== publicPath && (!publicPath.endsWith('/') || !absoluteBase && (!publicPath.startsWith('/') || publicPath.startsWith('//')))) return [];
32
+ if (absoluteBase) {
33
+ const base = new URL(publicPath);
34
+ if (base.username || base.password || base.href !== publicPath) return [];
35
+ }
36
+ const directory = node_path.posix.dirname(manifestLogicalPath);
37
+ const routesManifest = await readJson(node_path.join(distDirectory, directory, 'routes-manifest.json'));
38
+ if (!isRecord(routesManifest) || !isRecord(routesManifest.routeAssets)) return [];
39
+ const modules = new Set();
40
+ for (const route of Object.values(routesManifest.routeAssets)){
41
+ if (!isRecord(route) || !Array.isArray(route.assets)) return [];
42
+ for (const reference of route.assets){
43
+ if (!safeReference(reference) || reference.startsWith('//')) return [];
44
+ let relative = reference;
45
+ if (/^https?:\/\//u.test(reference)) {
46
+ if (!absoluteBase || !reference.startsWith(publicPath)) return [];
47
+ relative = reference.slice(publicPath.length);
48
+ } else if (reference.startsWith('/')) {
49
+ const prefix = 'auto' === publicPath ? '/' : absoluteBase ? new URL(publicPath).pathname : publicPath;
50
+ if (!reference.startsWith(prefix)) return [];
51
+ relative = reference.slice(prefix.length);
52
+ }
53
+ if (!/^(?:static|html|public)\/[^:]+$/u.test(relative) || relative.includes('//')) return [];
54
+ const logicalPath = node_path.posix.join(directory, relative);
55
+ if (!files.includes(logicalPath)) return [];
56
+ const assetStat = await promises.lstat(node_path.join(distDirectory, logicalPath));
57
+ if (!assetStat.isFile()) return [];
58
+ if (COMPILED_MODULE_PATTERN.test(logicalPath)) modules.add(logicalPath);
59
+ }
60
+ }
61
+ return [
62
+ ...modules
63
+ ];
64
+ };
25
65
  const manifestReferencedClientModules = async (distDirectory, files, manifestLogicalPath = 'mf-manifest.json')=>{
26
66
  const manifest = await readJson(node_path.join(distDirectory, manifestLogicalPath));
27
67
  const references = [
@@ -31,9 +71,10 @@ const manifestReferencedClientModules = async (distDirectory, files, manifestLog
31
71
  ...collectNestedStrings(manifest, 'async')
32
72
  ];
33
73
  const normalizedReferences = new Set(references.filter((value)=>'string' == typeof value).map((value)=>value.replace(/^https?:\/\/[^/]+/u, '')).map((value)=>value.replace(/^\/+/u, '')));
34
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
74
+ const modules = files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
35
75
  ...normalizedReferences
36
76
  ].some((reference)=>reference === logicalPath || reference.endsWith(`/${logicalPath}`) || logicalPath.endsWith(`/${reference}`)));
77
+ return modules.length > 0 ? modules : emptyProducerRouteModules(distDirectory, files, manifest, manifestLogicalPath);
37
78
  };
38
79
  const routeReferencedSsrModules = async (distDirectory, files, target, routeSpecLogicalPath = 'route.json')=>{
39
80
  const routeSpec = await readJson(node_path.join(distDirectory, routeSpecLogicalPath));
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "directory": "packages/solutions/app-tools-extensions"
12
12
  },
13
13
  "license": "MIT",
14
- "version": "3.9.0-ultramodern.2",
14
+ "version": "3.9.0-ultramodern.3",
15
15
  "files": [
16
16
  "dist",
17
17
  "src"
@@ -98,10 +98,10 @@
98
98
  "@babel/parser": "^8.0.4",
99
99
  "@babel/traverse": "^8.0.4",
100
100
  "@loadable/component": "5.16.7",
101
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.2",
102
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.2",
103
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.2",
104
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.2",
101
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.3",
102
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.3",
103
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.3",
104
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.3",
105
105
  "@swc/helpers": "^0.5.23",
106
106
  "std-env": "4.2.0"
107
107
  },
@@ -57,6 +57,111 @@ const collectNestedStrings = (value: unknown, key: string): string[] => {
57
57
  ]);
58
58
  };
59
59
 
60
+ // Empty native MF producers emit no remote entry or exposed execution assets.
61
+ // Only their routeAssets declarations may supply the missing browser evidence.
62
+ const emptyProducerRouteModules = async (
63
+ distDirectory: string,
64
+ files: string[],
65
+ manifest: unknown,
66
+ manifestLogicalPath: string,
67
+ ): Promise<string[]> => {
68
+ if (
69
+ !isRecord(manifest) ||
70
+ !Array.isArray(manifest.exposes) ||
71
+ manifest.exposes.length !== 0 ||
72
+ !Array.isArray(manifest.remotes) ||
73
+ manifest.remotes.length !== 0 ||
74
+ !isRecord(manifest.metaData) ||
75
+ !isRecord(manifest.metaData.remoteEntry) ||
76
+ manifest.metaData.remoteEntry.name !== '' ||
77
+ manifest.metaData.remoteEntry.path !== '' ||
78
+ manifest.metaData.remoteEntry.type !== 'global'
79
+ ) {
80
+ return [];
81
+ }
82
+ const publicPath = manifest.metaData.publicPath;
83
+ // Reject encoded/ambiguous paths before URL parsing can normalize traversal.
84
+ const safeReference = (value: unknown): value is string =>
85
+ typeof value === 'string' &&
86
+ value.length > 0 &&
87
+ !/[\\\\%?#\s]/u.test(value) &&
88
+ !value.split('/').some(segment => segment === '.' || segment === '..');
89
+ if (!safeReference(publicPath)) {
90
+ return [];
91
+ }
92
+ const absoluteBase = /^https?:\/\//u.test(publicPath);
93
+ if (
94
+ publicPath !== 'auto' &&
95
+ (!publicPath.endsWith('/') ||
96
+ (!absoluteBase &&
97
+ (!publicPath.startsWith('/') || publicPath.startsWith('//'))))
98
+ ) {
99
+ return [];
100
+ }
101
+ if (absoluteBase) {
102
+ const base = new URL(publicPath);
103
+ if (base.username || base.password || base.href !== publicPath) {
104
+ return [];
105
+ }
106
+ }
107
+ const directory = path.posix.dirname(manifestLogicalPath);
108
+ const routesManifest = await readJson(
109
+ path.join(distDirectory, directory, 'routes-manifest.json'),
110
+ );
111
+ if (!isRecord(routesManifest) || !isRecord(routesManifest.routeAssets)) {
112
+ return [];
113
+ }
114
+ const modules = new Set<string>();
115
+ for (const route of Object.values(routesManifest.routeAssets)) {
116
+ if (!isRecord(route) || !Array.isArray(route.assets)) {
117
+ return [];
118
+ }
119
+ for (const reference of route.assets) {
120
+ if (!safeReference(reference) || reference.startsWith('//')) {
121
+ return [];
122
+ }
123
+ let relative = reference;
124
+ if (/^https?:\/\//u.test(reference)) {
125
+ if (!absoluteBase || !reference.startsWith(publicPath)) {
126
+ return [];
127
+ }
128
+ relative = reference.slice(publicPath.length);
129
+ } else if (reference.startsWith('/')) {
130
+ const prefix =
131
+ publicPath === 'auto'
132
+ ? '/'
133
+ : absoluteBase
134
+ ? new URL(publicPath).pathname
135
+ : publicPath;
136
+ if (!reference.startsWith(prefix)) {
137
+ return [];
138
+ }
139
+ relative = reference.slice(prefix.length);
140
+ }
141
+ // Never allow API, SSR, backend containers, or unrelated on-disk modules.
142
+ if (
143
+ !/^(?:static|html|public)\/[^:]+$/u.test(relative) ||
144
+ relative.includes('//')
145
+ ) {
146
+ return [];
147
+ }
148
+ const logicalPath = path.posix.join(directory, relative);
149
+ if (!files.includes(logicalPath)) {
150
+ return [];
151
+ }
152
+ // A browser-named symlink to server/private bytes is not browser evidence.
153
+ const assetStat = await fs.lstat(path.join(distDirectory, logicalPath));
154
+ if (!assetStat.isFile()) {
155
+ return [];
156
+ }
157
+ if (COMPILED_MODULE_PATTERN.test(logicalPath)) {
158
+ modules.add(logicalPath);
159
+ }
160
+ }
161
+ }
162
+ return [...modules];
163
+ };
164
+
60
165
  const manifestReferencedClientModules = async (
61
166
  distDirectory: string,
62
167
  files: string[],
@@ -77,7 +182,7 @@ const manifestReferencedClientModules = async (
77
182
  .map(value => value.replace(/^https?:\/\/[^/]+/u, ''))
78
183
  .map(value => value.replace(/^\/+/u, '')),
79
184
  );
80
- return files.filter(
185
+ const modules = files.filter(
81
186
  logicalPath =>
82
187
  COMPILED_MODULE_PATTERN.test(logicalPath) &&
83
188
  [...normalizedReferences].some(
@@ -87,6 +192,14 @@ const manifestReferencedClientModules = async (
87
192
  logicalPath.endsWith(`/${reference}`),
88
193
  ),
89
194
  );
195
+ return modules.length > 0
196
+ ? modules
197
+ : emptyProducerRouteModules(
198
+ distDirectory,
199
+ files,
200
+ manifest,
201
+ manifestLogicalPath,
202
+ );
90
203
  };
91
204
 
92
205
  const routeReferencedSsrModules = async (