slicejs-web-framework 2.3.5 → 2.4.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/LICENSE +21 -21
- package/README.md +24 -5
- package/Slice/Components/Structural/Controller/Controller.js +156 -154
- package/Slice/Components/Structural/Debugger/Debugger.css +619 -619
- package/Slice/Components/Structural/Debugger/Debugger.html +72 -72
- package/Slice/Components/Structural/Logger/Log.js +10 -10
- package/Slice/Components/Structural/StylesManager/StylesManager.js +6 -3
- package/Slice/Slice.js +118 -51
- package/api/index.js +261 -233
- package/api/middleware/securityMiddleware.js +252 -252
- package/package.json +37 -37
- package/sliceConfig.schema.json +4 -0
- package/src/App/index.html +22 -22
- package/src/App/index.js +23 -23
- package/src/App/style.css +40 -40
- package/src/Components/AppComponents/HomePage/HomePage.css +204 -204
- package/src/Components/AppComponents/HomePage/HomePage.html +48 -48
- package/src/Components/AppComponents/HomePage/HomePage.js +195 -195
- package/src/Components/AppComponents/Playground/Playground.css +11 -11
- package/src/Components/AppComponents/Playground/Playground.js +111 -111
- package/src/Components/Service/FetchManager/FetchManager.js +133 -133
- package/src/Components/Service/IndexedDbManager/IndexedDbManager.js +141 -141
- package/src/Components/Service/LocalStorageManager/LocalStorageManager.js +45 -45
- package/src/Components/Visual/Button/Button.css +47 -47
- package/src/Components/Visual/Button/Button.html +5 -5
- package/src/Components/Visual/Button/Button.js +92 -92
- package/src/Components/Visual/Card/Card.css +68 -68
- package/src/Components/Visual/Card/Card.html +7 -7
- package/src/Components/Visual/Card/Card.js +107 -107
- package/src/Components/Visual/Checkbox/Checkbox.css +87 -87
- package/src/Components/Visual/Checkbox/Checkbox.html +8 -8
- package/src/Components/Visual/Checkbox/Checkbox.js +86 -86
- package/src/Components/Visual/CodeVisualizer/CodeVisualizer.css +129 -129
- package/src/Components/Visual/CodeVisualizer/CodeVisualizer.html +3 -3
- package/src/Components/Visual/CodeVisualizer/CodeVisualizer.js +259 -259
- package/src/Components/Visual/Details/Details.css +70 -70
- package/src/Components/Visual/Details/Details.html +9 -9
- package/src/Components/Visual/Details/Details.js +76 -76
- package/src/Components/Visual/DropDown/DropDown.css +60 -60
- package/src/Components/Visual/DropDown/DropDown.html +5 -5
- package/src/Components/Visual/DropDown/DropDown.js +63 -63
- package/src/Components/Visual/Grid/Grid.css +7 -7
- package/src/Components/Visual/Grid/Grid.html +1 -1
- package/src/Components/Visual/Grid/Grid.js +57 -57
- package/src/Components/Visual/Icon/Icon.css +510 -510
- package/src/Components/Visual/Icon/Icon.js +89 -89
- package/src/Components/Visual/Icon/slc.json +554 -554
- package/src/Components/Visual/Icon/slc.styl +507 -507
- package/src/Components/Visual/Icon/slc.svg +1485 -1485
- package/src/Components/Visual/Icon/slc.symbol.svg +1058 -1058
- package/src/Components/Visual/Input/Input.css +91 -91
- package/src/Components/Visual/Input/Input.html +4 -4
- package/src/Components/Visual/Input/Input.js +215 -215
- package/src/Components/Visual/Layout/Layout.js +49 -49
- package/src/Components/Visual/Loading/Loading.css +56 -56
- package/src/Components/Visual/Loading/Loading.html +83 -83
- package/src/Components/Visual/Loading/Loading.js +38 -38
- package/src/Components/Visual/MultiRoute/MultiRoute.js +93 -93
- package/src/Components/Visual/Navbar/Navbar.css +115 -115
- package/src/Components/Visual/Navbar/Navbar.html +44 -44
- package/src/Components/Visual/Navbar/Navbar.js +141 -141
- package/src/Components/Visual/NotFound/NotFound.css +116 -116
- package/src/Components/Visual/NotFound/NotFound.html +23 -23
- package/src/Components/Visual/NotFound/NotFound.js +16 -16
- package/src/Components/Visual/Route/Route.js +93 -93
- package/src/Components/Visual/Select/Select.css +84 -84
- package/src/Components/Visual/Select/Select.html +8 -8
- package/src/Components/Visual/Select/Select.js +195 -195
- package/src/Components/Visual/Switch/Switch.css +76 -76
- package/src/Components/Visual/Switch/Switch.html +8 -8
- package/src/Components/Visual/Switch/Switch.js +102 -102
- package/src/Components/Visual/TreeItem/TreeItem.css +36 -36
- package/src/Components/Visual/TreeItem/TreeItem.html +1 -1
- package/src/Components/Visual/TreeItem/TreeItem.js +126 -126
- package/src/Components/Visual/TreeView/TreeView.css +8 -8
- package/src/Components/Visual/TreeView/TreeView.html +1 -1
- package/src/Components/Visual/TreeView/TreeView.js +48 -48
- package/src/Styles/sliceStyles.css +34 -34
- package/src/Themes/Dark.css +42 -42
- package/src/Themes/Light.css +31 -31
- package/src/Themes/Slice.css +47 -47
- package/src/routes.js +15 -15
- package/src/sliceConfig.json +8 -3
- package/src/testing.js +887 -887
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 Victor Jose Kneider Alnahi and Julio Antonio Graterol Bracho
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Victor Jose Kneider Alnahi and Julio Antonio Graterol Bracho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -99,10 +99,30 @@ _Below is an example of how you can instruct your audience on installing and set
|
|
|
99
99
|
```sh
|
|
100
100
|
npm run slice:init
|
|
101
101
|
```
|
|
102
|
-
3.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
3. Build production output
|
|
103
|
+
```sh
|
|
104
|
+
npm run slice:build
|
|
105
|
+
```
|
|
106
|
+
4. Start production server
|
|
107
|
+
```sh
|
|
108
|
+
npm run slice:start
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Production uses `publicFolders` from `sliceConfig.json` to expose public asset folders like
|
|
112
|
+
`/Themes`, `/Styles`, and `/assets`.
|
|
113
|
+
|
|
114
|
+
Structural framework components are bundled into a dedicated framework bundle during `slice build`
|
|
115
|
+
and served from `/dist/bundles/slice-bundle.framework.js`.
|
|
116
|
+
|
|
117
|
+
### Documentation Access
|
|
118
|
+
|
|
119
|
+
Slice.js provides an MCP (Model Context Protocol) server for programmatic access to documentation:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx slicejs-mcp
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This allows AI assistants and tools to query, search, and retrieve Slice.js documentation seamlessly.
|
|
106
126
|
|
|
107
127
|
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
108
128
|
|
|
@@ -152,4 +172,3 @@ Distributed under the MIT License. See `LICENSE` for more information.
|
|
|
152
172
|
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
|
|
153
173
|
[linkedin-url]: https://linkedin.com/in/VKneider
|
|
154
174
|
[product-screenshot]: readme_images/screenshot.JPG
|
|
155
|
-
|
|
@@ -23,23 +23,21 @@ export default class Controller {
|
|
|
23
23
|
/**
|
|
24
24
|
* 📦 Initializes bundle system (called automatically when config is loaded)
|
|
25
25
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
}
|
|
26
|
+
initializeBundles(config = null) {
|
|
27
|
+
if (config) {
|
|
28
|
+
this.bundleConfig = config;
|
|
29
|
+
|
|
30
|
+
// Register critical bundle components if available
|
|
31
|
+
if (config.bundles?.critical) {
|
|
32
|
+
// Critical bundle will be loaded explicitly
|
|
33
|
+
}
|
|
34
|
+
this.criticalBundleLoaded = false;
|
|
35
|
+
} else {
|
|
36
|
+
// No bundles available, will use individual component loading
|
|
37
|
+
this.bundleConfig = null;
|
|
38
|
+
this.criticalBundleLoaded = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
43
41
|
|
|
44
42
|
/**
|
|
45
43
|
* 📦 Loads a bundle by name or category
|
|
@@ -49,17 +47,23 @@ export default class Controller {
|
|
|
49
47
|
return; // Already loaded
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
let bundleInfo =
|
|
50
|
+
try {
|
|
51
|
+
let bundleInfo = null;
|
|
54
52
|
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
if (bundleName === 'critical') {
|
|
54
|
+
bundleInfo = this.bundleConfig?.bundles?.critical;
|
|
55
|
+
} else {
|
|
56
|
+
bundleInfo = this.bundleConfig?.bundles?.routes?.[bundleName];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!bundleInfo && this.bundleConfig?.bundles?.routes && bundleName !== 'critical') {
|
|
60
|
+
const normalizedName = bundleName?.toLowerCase();
|
|
61
|
+
const matchedKey = Object.keys(this.bundleConfig.bundles.routes).find(
|
|
62
|
+
(key) => key.toLowerCase() === normalizedName
|
|
63
|
+
);
|
|
64
|
+
if (matchedKey) {
|
|
65
|
+
bundleInfo = this.bundleConfig.bundles.routes[matchedKey];
|
|
66
|
+
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
if (!bundleInfo) {
|
|
@@ -69,6 +73,12 @@ export default class Controller {
|
|
|
69
73
|
|
|
70
74
|
const bundlePath = `/bundles/${bundleInfo.file}`;
|
|
71
75
|
|
|
76
|
+
const integrityOk = await this.verifyBundleIntegrity(bundlePath, bundleInfo.integrity);
|
|
77
|
+
if (!integrityOk) {
|
|
78
|
+
console.warn(`❌ Integrity check failed for bundle ${bundleName}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
// Dynamic import of the bundle
|
|
73
83
|
const bundleModule = await import(bundlePath);
|
|
74
84
|
|
|
@@ -81,7 +91,48 @@ export default class Controller {
|
|
|
81
91
|
} catch (error) {
|
|
82
92
|
console.warn(`Failed to load bundle ${bundleName}:`, error);
|
|
83
93
|
}
|
|
84
|
-
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Verifies bundle integrity by comparing sha256 hash.
|
|
98
|
+
* @param {string} bundlePath
|
|
99
|
+
* @param {string|null} expectedIntegrity
|
|
100
|
+
* @returns {Promise<boolean>}
|
|
101
|
+
*/
|
|
102
|
+
async verifyBundleIntegrity(bundlePath, expectedIntegrity) {
|
|
103
|
+
if (!expectedIntegrity) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(bundlePath, { cache: 'no-store' });
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
console.warn(`Failed to fetch bundle for integrity check: ${response.status}`);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const content = await response.text();
|
|
115
|
+
const actualIntegrity = await this.hashSha256(content);
|
|
116
|
+
return actualIntegrity === expectedIntegrity;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.warn(`Integrity check error for ${bundlePath}:`, error);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Calculates sha256 digest for a string.
|
|
125
|
+
* @param {string} content
|
|
126
|
+
* @returns {Promise<string>}
|
|
127
|
+
*/
|
|
128
|
+
async hashSha256(content) {
|
|
129
|
+
const encoder = new TextEncoder();
|
|
130
|
+
const data = encoder.encode(content);
|
|
131
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
132
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
133
|
+
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
134
|
+
return `sha256:${hashHex}`;
|
|
135
|
+
}
|
|
85
136
|
|
|
86
137
|
/**
|
|
87
138
|
* 📦 Registers a bundle's components (called automatically by bundle files)
|
|
@@ -237,147 +288,98 @@ export default class Controller {
|
|
|
237
288
|
/**
|
|
238
289
|
* 📦 New bundle registration method (simplified and robust)
|
|
239
290
|
*/
|
|
240
|
-
|
|
241
|
-
|
|
291
|
+
registerBundle(bundle) {
|
|
292
|
+
const validation = this.validateBundle(bundle);
|
|
293
|
+
if (!validation.isValid) {
|
|
294
|
+
console.warn(`❌ Bundle validation failed: ${validation.error}`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const { components, metadata } = bundle;
|
|
242
299
|
|
|
243
300
|
console.log(`📦 Registering bundle: ${metadata.type} (${metadata.componentCount} components)`);
|
|
244
301
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (componentData.html !== undefined && !this.templates.has(componentName)) {
|
|
249
|
-
const template = document.createElement('template');
|
|
250
|
-
template.innerHTML = componentData.html || '';
|
|
251
|
-
this.templates.set(componentName, template);
|
|
252
|
-
}
|
|
302
|
+
const entries = Object.entries(components);
|
|
303
|
+
const chunkSize = 50;
|
|
304
|
+
let index = 0;
|
|
253
305
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
306
|
+
const processChunk = () => {
|
|
307
|
+
const sliceEntries = entries.slice(index, index + chunkSize);
|
|
308
|
+
|
|
309
|
+
for (const [componentName, componentData] of sliceEntries) {
|
|
310
|
+
try {
|
|
311
|
+
if (componentData.html !== undefined && !this.templates.has(componentName)) {
|
|
312
|
+
const template = document.createElement('template');
|
|
313
|
+
template.innerHTML = componentData.html || '';
|
|
314
|
+
this.templates.set(componentName, template);
|
|
259
315
|
}
|
|
316
|
+
|
|
317
|
+
if (componentData.css !== undefined && !this.requestedStyles.has(componentName)) {
|
|
318
|
+
if (window.slice && window.slice.stylesManager) {
|
|
319
|
+
window.slice.stylesManager.registerComponentStyles(componentName, componentData.css || '');
|
|
320
|
+
this.requestedStyles.add(componentName);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (componentData.class && !this.classes.has(componentName)) {
|
|
325
|
+
const registeredName = componentData.isFramework
|
|
326
|
+
? `Framework/Structural/${componentName}`
|
|
327
|
+
: componentName;
|
|
328
|
+
this.classes.set(registeredName, componentData.class);
|
|
329
|
+
}
|
|
330
|
+
} catch (error) {
|
|
331
|
+
console.warn(`❌ Failed to register component ${componentName}:`, error);
|
|
260
332
|
}
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.warn(`❌ Failed to register assets for ${componentName}:`, error);
|
|
263
333
|
}
|
|
264
|
-
}
|
|
265
334
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const bindings = typeof depEntry === 'string' ? [] : depEntry.bindings || [];
|
|
276
|
-
|
|
277
|
-
const fileBaseName = depKey
|
|
278
|
-
? depKey
|
|
279
|
-
.split('/')
|
|
280
|
-
.pop()
|
|
281
|
-
.replace(/\.[^.]+$/, '')
|
|
282
|
-
: '';
|
|
283
|
-
const dataName = fileBaseName ? `${fileBaseName}Data` : '';
|
|
284
|
-
const exportPrefix = dataName ? `window.${dataName} = ` : '';
|
|
285
|
-
|
|
286
|
-
// Process ES6 exports to make the code evaluable
|
|
287
|
-
let processedContent = depContent
|
|
288
|
-
// Convert named exports: export const varName = ... → window.varName = ...
|
|
289
|
-
.replace(/export\s+const\s+(\w+)\s*=\s*/g, 'window.$1 = ')
|
|
290
|
-
.replace(/export\s+let\s+(\w+)\s*=\s*/g, 'window.$1 = ')
|
|
291
|
-
.replace(/export\s+function\s+(\w+)/g, 'window.$1 = function')
|
|
292
|
-
.replace(/export\s+default\s+/g, 'window.defaultExport = ')
|
|
293
|
-
// Promote default export to <file>Data for data modules
|
|
294
|
-
.replace(/window\.defaultExport\s*=\s*/g, exportPrefix || 'window.defaultExport = ')
|
|
295
|
-
// Handle export { var1, var2 } statements
|
|
296
|
-
.replace(/export\s*{\s*([^}]+)\s*}/g, (match, exportsStr) => {
|
|
297
|
-
const exports = exportsStr.split(',').map((exp) => exp.trim().split(' as ')[0].trim());
|
|
298
|
-
return exports.map((varName) => `window.${varName} = ${varName};`).join('\n');
|
|
299
|
-
})
|
|
300
|
-
// Remove any remaining export keywords
|
|
301
|
-
.replace(/^\s*export\s+/gm, '');
|
|
335
|
+
index += chunkSize;
|
|
336
|
+
if (index < entries.length) {
|
|
337
|
+
if (typeof requestIdleCallback === 'function') {
|
|
338
|
+
requestIdleCallback(processChunk);
|
|
339
|
+
} else {
|
|
340
|
+
setTimeout(processChunk, 0);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
302
344
|
|
|
303
|
-
|
|
304
|
-
new Function('slice', 'customElements', 'window', 'document', processedContent)(
|
|
305
|
-
window.slice,
|
|
306
|
-
window.customElements,
|
|
307
|
-
window,
|
|
308
|
-
window.document
|
|
309
|
-
);
|
|
310
|
-
|
|
311
|
-
// Apply import bindings to map local identifiers to globals
|
|
312
|
-
for (const binding of bindings) {
|
|
313
|
-
if (!binding?.localName) continue;
|
|
314
|
-
|
|
315
|
-
if (binding.type === 'default') {
|
|
316
|
-
if (!window[binding.localName]) {
|
|
317
|
-
const fallbackValue =
|
|
318
|
-
dataName && window[dataName] !== undefined ? window[dataName] : window.defaultExport;
|
|
319
|
-
if (fallbackValue !== undefined) {
|
|
320
|
-
window[binding.localName] = fallbackValue;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
345
|
+
processChunk();
|
|
324
346
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
window[binding.localName] = window[binding.importedName];
|
|
328
|
-
}
|
|
329
|
-
}
|
|
347
|
+
console.log(`✅ Bundle registration completed: ${metadata.componentCount} components processed`);
|
|
348
|
+
}
|
|
330
349
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
350
|
+
/**
|
|
351
|
+
* Validates bundle structure before registering.
|
|
352
|
+
* @param {object} bundle
|
|
353
|
+
* @returns {{isValid: boolean, error?: string}}
|
|
354
|
+
*/
|
|
355
|
+
validateBundle(bundle) {
|
|
356
|
+
if (!bundle || typeof bundle !== 'object') {
|
|
357
|
+
return { isValid: false, error: 'Bundle payload is invalid' };
|
|
358
|
+
}
|
|
339
359
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
console.warn(`⚠️ Failed to load external dependency ${depName}:`, depError);
|
|
344
|
-
const preview = typeof depEntry === 'string' ? depEntry : depEntry.content;
|
|
345
|
-
console.warn('Original content preview:', preview.substring(0, 200));
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
360
|
+
if (!bundle.metadata || typeof bundle.metadata !== 'object') {
|
|
361
|
+
return { isValid: false, error: 'Bundle metadata missing' };
|
|
362
|
+
}
|
|
351
363
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
try {
|
|
356
|
-
// Simple evaluation
|
|
357
|
-
const componentClass = new Function(
|
|
358
|
-
'slice',
|
|
359
|
-
'customElements',
|
|
360
|
-
'window',
|
|
361
|
-
'document',
|
|
362
|
-
`
|
|
363
|
-
${componentData.js}
|
|
364
|
-
return ${componentName};
|
|
365
|
-
`
|
|
366
|
-
)(window.slice, window.customElements, window, window.document);
|
|
364
|
+
if (!bundle.components || typeof bundle.components !== 'object') {
|
|
365
|
+
return { isValid: false, error: 'Bundle components missing' };
|
|
366
|
+
}
|
|
367
367
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
} catch (error) {
|
|
373
|
-
console.warn(`❌ Failed to evaluate class for ${componentName}:`, error);
|
|
374
|
-
// Continue with other components instead of failing completely
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
368
|
+
if (typeof bundle.metadata.componentCount !== 'number') {
|
|
369
|
+
return { isValid: false, error: 'Bundle metadata missing componentCount' };
|
|
370
|
+
}
|
|
378
371
|
|
|
379
|
-
|
|
380
|
-
|
|
372
|
+
if (bundle.metadata.componentCount !== Object.keys(bundle.components).length) {
|
|
373
|
+
return { isValid: false, error: 'Bundle component count mismatch' };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const maxComponents = 5000;
|
|
377
|
+
if (bundle.metadata.componentCount > maxComponents) {
|
|
378
|
+
return { isValid: false, error: 'Bundle component count exceeds limit' };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return { isValid: true };
|
|
382
|
+
}
|
|
381
383
|
|
|
382
384
|
/**
|
|
383
385
|
* 📦 Determines which bundle to load for a component
|