slicejs-web-framework 2.2.7 → 2.2.8

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.
@@ -7,14 +7,365 @@ export default class Controller {
7
7
  this.classes = new Map();
8
8
  this.requestedStyles = new Set(); // ✅ CRÍTICO: Para tracking de CSS cargados
9
9
  this.activeComponents = new Map();
10
-
10
+
11
11
  // 🚀 OPTIMIZACIÓN: Índice inverso para búsqueda rápida de hijos
12
12
  // parentSliceId → Set<childSliceId>
13
13
  this.childrenIndex = new Map();
14
-
14
+
15
+ // 📦 Bundle system
16
+ this.loadedBundles = new Set();
17
+ this.bundleConfig = null;
18
+ this.criticalBundleLoaded = false;
19
+
15
20
  this.idCounter = 0;
16
21
  }
17
22
 
23
+ /**
24
+ * 📦 Initializes bundle system (called automatically when config is loaded)
25
+ */
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
+ // The critical bundle should already be loaded, register its components
33
+ this.loadedBundles.add('critical');
34
+ // Note: Critical bundle registration is handled by the auto-import
35
+ }
36
+ this.criticalBundleLoaded = true;
37
+ } else {
38
+ // No bundles available, will use individual component loading
39
+ this.bundleConfig = null;
40
+ this.criticalBundleLoaded = false;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * 📦 Loads a bundle by name or category
46
+ */
47
+ async loadBundle(bundleName) {
48
+ if (this.loadedBundles.has(bundleName)) {
49
+ return; // Already loaded
50
+ }
51
+
52
+ try {
53
+ const bundleInfo = this.bundleConfig?.bundles?.routes?.[bundleName];
54
+
55
+ if (!bundleInfo) {
56
+ console.warn(`Bundle ${bundleName} not found in configuration`);
57
+ return;
58
+ }
59
+
60
+ const bundlePath = `/bundles/${bundleInfo.file}`;
61
+
62
+ // Dynamic import of the bundle
63
+ const bundleModule = await import(bundlePath);
64
+
65
+ // Manually register components from the imported bundle
66
+ if (bundleModule.SLICE_BUNDLE) {
67
+ this.registerBundle(bundleModule.SLICE_BUNDLE);
68
+ }
69
+
70
+ this.loadedBundles.add(bundleName);
71
+
72
+ } catch (error) {
73
+ console.warn(`Failed to load bundle ${bundleName}:`, error);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 📦 Registers a bundle's components (called automatically by bundle files)
79
+ */
80
+ registerBundleLegacy(bundle) {
81
+ const { components, metadata } = bundle;
82
+
83
+ console.log(`📦 Registering bundle: ${metadata.type} (${metadata.componentCount} components)`);
84
+
85
+ // Phase 1: Register templates and CSS for all components first
86
+ for (const [componentName, componentData] of Object.entries(components)) {
87
+ try {
88
+ // Register HTML template
89
+ if (componentData.html !== undefined && !this.templates.has(componentName)) {
90
+ const template = document.createElement('template');
91
+ template.innerHTML = componentData.html || '';
92
+ this.templates.set(componentName, template);
93
+ }
94
+
95
+ // Register CSS styles
96
+ if (componentData.css !== undefined && !this.requestedStyles.has(componentName)) {
97
+ // Use the existing stylesManager to register component styles
98
+ if (window.slice && window.slice.stylesManager) {
99
+ window.slice.stylesManager.registerComponentStyles(componentName, componentData.css || '');
100
+ this.requestedStyles.add(componentName);
101
+ }
102
+ }
103
+ } catch (error) {
104
+ console.warn(`❌ Failed to register assets for ${componentName}:`, error);
105
+ }
106
+ }
107
+
108
+ // Phase 2: Evaluate all external file dependencies
109
+ const processedDeps = new Set();
110
+ for (const [componentName, componentData] of Object.entries(components)) {
111
+ if (componentData.dependencies) {
112
+ for (const [depName, depContent] of Object.entries(componentData.dependencies)) {
113
+ if (!processedDeps.has(depName)) {
114
+ try {
115
+ // Convert ES6 exports to global assignments
116
+ let processedContent = depContent
117
+ .replace(/export\s+const\s+(\w+)\s*=/g, 'window.$1 =')
118
+ .replace(/export\s+let\s+(\w+)\s*=/g, 'window.$1 =')
119
+ .replace(/export\s+var\s+(\w+)\s*=/g, 'window.$1 =')
120
+ .replace(/export\s+function\s+(\w+)/g, 'window.$1 = function')
121
+ .replace(/export\s+default\s+/g, 'window.defaultExport =')
122
+ .replace(/export\s*{\s*([^}]+)\s*}/g, (match, exports) => {
123
+ return exports.split(',').map(exp => {
124
+ const cleanExp = exp.trim();
125
+ const varName = cleanExp.split(' as ')[0].trim();
126
+ return `window.${varName} = ${varName};`;
127
+ }).join('\n');
128
+ })
129
+ // Remove any remaining export keywords
130
+ .replace(/^\s*export\s+/gm, '');
131
+
132
+ // Evaluate the dependency
133
+ try {
134
+ new Function('slice', 'customElements', 'window', 'document', processedContent)
135
+ (window.slice, window.customElements, window, window.document);
136
+ } catch (evalError) {
137
+ console.warn(`❌ Failed to evaluate processed dependency ${depName}:`, evalError);
138
+ console.warn('Processed content preview:', processedContent.substring(0, 200));
139
+ // Try evaluating the original content as fallback
140
+ try {
141
+ new Function('slice', 'customElements', 'window', 'document', depContent)
142
+ (window.slice, window.customElements, window, window.document);
143
+ console.log(`✅ Fallback evaluation succeeded for ${depName}`);
144
+ } catch (fallbackError) {
145
+ console.warn(`❌ Fallback evaluation also failed for ${depName}:`, fallbackError);
146
+ }
147
+ }
148
+
149
+ processedDeps.add(depName);
150
+ console.log(`📄 Dependency loaded: ${depName}`);
151
+ } catch (depError) {
152
+ console.warn(`⚠️ Failed to load dependency ${depName} for ${componentName}:`, depError);
153
+ }
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ // Phase 3: Evaluate all component classes (now that dependencies are available)
160
+ for (const [componentName, componentData] of Object.entries(components)) {
161
+ // For JavaScript classes, we need to evaluate the code
162
+ if (componentData.js && !this.classes.has(componentName)) {
163
+ try {
164
+ // Create evaluation context with dependencies
165
+ let evalCode = componentData.js;
166
+
167
+ // Prepend dependencies to make them available
168
+ if (componentData.dependencies) {
169
+ const depCode = Object.entries(componentData.dependencies)
170
+ .map(([depName, depContent]) => {
171
+ // Convert ES6 exports to global assignments
172
+ return depContent
173
+ .replace(/export\s+const\s+(\w+)\s*=/g, 'window.$1 =')
174
+ .replace(/export\s+let\s+(\w+)\s*=/g, 'window.$1 =')
175
+ .replace(/export\s+function\s+(\w+)/g, 'window.$1 = function')
176
+ .replace(/export\s+default\s+/g, 'window.defaultExport =')
177
+ .replace(/export\s*{\s*([^}]+)\s*}/g, (match, exports) => {
178
+ return exports.split(',').map(exp => {
179
+ const cleanExp = exp.trim();
180
+ return `window.${cleanExp} = ${cleanExp};`;
181
+ }).join('\n');
182
+ });
183
+ })
184
+ .join('\n\n');
185
+
186
+ evalCode = depCode + '\n\n' + evalCode;
187
+ }
188
+
189
+ // Evaluate the complete code
190
+ const componentClass = new Function('slice', 'customElements', 'window', 'document', `
191
+ "use strict";
192
+ ${evalCode}
193
+ return ${componentName};
194
+ `)(window.slice, window.customElements, window, window.document);
195
+
196
+ if (componentClass) {
197
+ this.classes.set(componentName, componentClass);
198
+ console.log(`📝 Class registered for: ${componentName}`);
199
+ }
200
+ } catch (error) {
201
+ console.warn(`❌ Failed to evaluate class for ${componentName}:`, error);
202
+ console.warn('Code that failed:', componentData.js.substring(0, 200) + '...');
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+
209
+
210
+ /**
211
+ * 📦 New bundle registration method (simplified and robust)
212
+ */
213
+ registerBundle(bundle) {
214
+ const { components, metadata } = bundle;
215
+
216
+ console.log(`📦 Registering bundle: ${metadata.type} (${metadata.componentCount} components)`);
217
+
218
+ // Phase 1: Register all templates and CSS first
219
+ for (const [componentName, componentData] of Object.entries(components)) {
220
+ try {
221
+ if (componentData.html !== undefined && !this.templates.has(componentName)) {
222
+ const template = document.createElement('template');
223
+ template.innerHTML = componentData.html || '';
224
+ this.templates.set(componentName, template);
225
+ }
226
+
227
+ if (componentData.css !== undefined && !this.requestedStyles.has(componentName)) {
228
+ if (window.slice && window.slice.stylesManager) {
229
+ window.slice.stylesManager.registerComponentStyles(componentName, componentData.css || '');
230
+ this.requestedStyles.add(componentName);
231
+ console.log(`🎨 CSS registered for: ${componentName}`);
232
+ }
233
+ }
234
+ } catch (error) {
235
+ console.warn(`❌ Failed to register assets for ${componentName}:`, error);
236
+ }
237
+ }
238
+
239
+ // Phase 2: Evaluate all external file dependencies first
240
+ const processedDeps = new Set();
241
+ for (const [componentName, componentData] of Object.entries(components)) {
242
+ if (componentData.externalDependencies) {
243
+ for (const [depName, depContent] of Object.entries(componentData.externalDependencies)) {
244
+ if (!processedDeps.has(depName)) {
245
+ try {
246
+ // Process ES6 exports to make the code evaluable
247
+ let processedContent = depContent
248
+ // Convert named exports: export const varName = ... → window.varName = ...
249
+ .replace(/export\s+const\s+(\w+)\s*=\s*/g, 'window.$1 = ')
250
+ .replace(/export\s+let\s+(\w+)\s*=\s*/g, 'window.$1 = ')
251
+ .replace(/export\s+function\s+(\w+)/g, 'window.$1 = function')
252
+ .replace(/export\s+default\s+/g, 'window.defaultExport = ')
253
+ // Handle export { var1, var2 } statements
254
+ .replace(/export\s*{\s*([^}]+)\s*}/g, (match, exportsStr) => {
255
+ const exports = exportsStr.split(',').map(exp => exp.trim().split(' as ')[0].trim());
256
+ return exports.map(varName => `window.${varName} = ${varName};`).join('\n');
257
+ })
258
+ // Remove any remaining export keywords
259
+ .replace(/^\s*export\s+/gm, '');
260
+
261
+ // Evaluate the processed content
262
+ new Function('slice', 'customElements', 'window', 'document', processedContent)
263
+ (window.slice, window.customElements, window, window.document);
264
+
265
+ processedDeps.add(depName);
266
+ console.log(`📄 External dependency loaded: ${depName}`);
267
+ } catch (depError) {
268
+ console.warn(`⚠️ Failed to load external dependency ${depName}:`, depError);
269
+ console.warn('Original content preview:', depContent.substring(0, 200));
270
+ }
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ // Phase 3: Evaluate all component classes (external dependencies are now available)
277
+ for (const [componentName, componentData] of Object.entries(components)) {
278
+ if (componentData.js && !this.classes.has(componentName)) {
279
+ try {
280
+ // Simple evaluation
281
+ const componentClass = new Function('slice', 'customElements', 'window', 'document', `
282
+ ${componentData.js}
283
+ return ${componentName};
284
+ `)(window.slice, window.customElements, window, window.document);
285
+
286
+ if (componentClass) {
287
+ this.classes.set(componentName, componentClass);
288
+ console.log(`📝 Class registered for: ${componentName}`);
289
+ }
290
+ } catch (error) {
291
+ console.warn(`❌ Failed to evaluate class for ${componentName}:`, error);
292
+ // Continue with other components instead of failing completely
293
+ }
294
+ }
295
+ }
296
+
297
+ console.log(`✅ Bundle registration completed: ${metadata.componentCount} components processed`);
298
+ }
299
+
300
+ /**
301
+ * 📦 Determines which bundle to load for a component
302
+ */
303
+ getBundleForComponent(componentName) {
304
+ if (!this.bundleConfig?.bundles) return null;
305
+
306
+ // Check if component is in critical bundle
307
+ if (this.bundleConfig.bundles.critical?.components?.includes(componentName)) {
308
+ return 'critical';
309
+ }
310
+
311
+ // Find component in route bundles
312
+ if (this.bundleConfig.bundles.routes) {
313
+ for (const [bundleName, bundleInfo] of Object.entries(this.bundleConfig.bundles.routes)) {
314
+ if (bundleInfo.components?.includes(componentName)) {
315
+ return bundleName;
316
+ }
317
+ }
318
+ }
319
+
320
+ return null;
321
+ }
322
+
323
+ /**
324
+ * 📦 Checks if a component is available from loaded bundles
325
+ */
326
+ isComponentFromBundle(componentName) {
327
+ if (!this.bundleConfig?.bundles) return false;
328
+
329
+ // Check critical bundle
330
+ if (this.bundleConfig.bundles.critical?.components?.includes(componentName)) {
331
+ return this.criticalBundleLoaded;
332
+ }
333
+
334
+ // Check route bundles
335
+ if (this.bundleConfig.bundles.routes) {
336
+ for (const [bundleName, bundleInfo] of Object.entries(this.bundleConfig.bundles.routes)) {
337
+ if (bundleInfo.components?.includes(componentName)) {
338
+ return this.loadedBundles.has(bundleName);
339
+ }
340
+ }
341
+ }
342
+
343
+ return false;
344
+ }
345
+
346
+ /**
347
+ * 📦 Gets component data from loaded bundles
348
+ */
349
+ getComponentFromBundle(componentName) {
350
+ if (!this.bundleConfig?.bundles) return null;
351
+
352
+ // Find component in any loaded bundle
353
+ const allBundles = [
354
+ { name: 'critical', data: this.bundleConfig.bundles.critical },
355
+ ...Object.entries(this.bundleConfig.bundles.routes || {}).map(([name, data]) => ({ name, data }))
356
+ ];
357
+
358
+ for (const { name: bundleName, data: bundleData } of allBundles) {
359
+ if (bundleData?.components?.includes(componentName) && this.loadedBundles.has(bundleName)) {
360
+ // Find the bundle file and extract component data
361
+ // This is a simplified version - in practice you'd need to access the loaded bundle data
362
+ return { bundleName, componentName };
363
+ }
364
+ }
365
+
366
+ return null;
367
+ }
368
+
18
369
  logActiveComponents() {
19
370
  this.activeComponents.forEach((component) => {
20
371
  let parent = component.parentComponent;
package/Slice/Slice.js CHANGED
@@ -11,6 +11,8 @@ export default class Slice {
11
11
  this.loggerConfig = sliceConfig.logger;
12
12
  this.debuggerConfig = sliceConfig.debugger;
13
13
  this.loadingConfig = sliceConfig.loading;
14
+
15
+ // 📦 Bundle system is initialized automatically via import in index.js
14
16
  }
15
17
 
16
18
  async getClass(module) {
@@ -46,8 +48,17 @@ export default class Slice {
46
48
  return null;
47
49
  }
48
50
 
51
+ // 📦 Try to load from bundles first
52
+ const bundleName = this.controller.getBundleForComponent(componentName);
53
+ if (bundleName && !this.controller.loadedBundles.has(bundleName)) {
54
+ await this.controller.loadBundle(bundleName);
55
+ }
56
+
49
57
  let componentCategory = this.controller.componentCategories.get(componentName);
50
58
 
59
+ // 📦 Check if component is already available from loaded bundles
60
+ const isFromBundle = this.controller.isComponentFromBundle(componentName);
61
+
51
62
  if (componentCategory === 'Structural') {
52
63
  this.logger.logError(
53
64
  'Slice',
@@ -57,27 +68,31 @@ export default class Slice {
57
68
  return null;
58
69
  }
59
70
 
60
- let isVisual = slice.paths.components[componentCategory].type === "Visual";
71
+ let isVisual = slice.paths.components[componentCategory].type === "Visual";
61
72
  let modulePath = `${slice.paths.components[componentCategory].path}/${componentName}/${componentName}.js`;
62
73
 
63
74
  // Load template, class, and CSS concurrently if needed
64
75
  try {
65
- const loadTemplate =
66
- isVisual && !this.controller.templates.has(componentName)
67
- ? this.controller.fetchText(componentName, 'html', componentCategory)
68
- : Promise.resolve(null);
76
+ // 📦 Skip individual loading if component is available from bundles
77
+ const loadTemplate = (isFromBundle || !isVisual || this.controller.templates.has(componentName))
78
+ ? Promise.resolve(null)
79
+ : this.controller.fetchText(componentName, 'html', componentCategory);
69
80
 
70
- const loadClass = !this.controller.classes.has(componentName)
71
- ? this.getClass(modulePath)
72
- : Promise.resolve(null);
81
+ const loadClass = (isFromBundle || this.controller.classes.has(componentName))
82
+ ? Promise.resolve(null)
83
+ : this.getClass(modulePath);
73
84
 
74
- const loadCSS =
75
- isVisual && !this.controller.requestedStyles.has(componentName)
76
- ? this.controller.fetchText(componentName, 'css', componentCategory)
77
- : Promise.resolve(null);
85
+ const loadCSS = (isFromBundle || !isVisual || this.controller.requestedStyles.has(componentName))
86
+ ? Promise.resolve(null)
87
+ : this.controller.fetchText(componentName, 'css', componentCategory);
78
88
 
79
89
  const [html, ComponentClass, css] = await Promise.all([loadTemplate, loadClass, loadCSS]);
80
90
 
91
+ // 📦 If component is from bundle but not in cache, it should have been registered by registerBundle
92
+ if (isFromBundle) {
93
+ console.log(`📦 Using bundled component: ${componentName}`);
94
+ }
95
+
81
96
  if (html || html === '') {
82
97
  const template = document.createElement('template');
83
98
  template.innerHTML = html;
@@ -219,4 +234,16 @@ async function init() {
219
234
 
220
235
  }
221
236
 
222
- await init();
237
+ await init();
238
+
239
+ // Initialize bundles if available
240
+ try {
241
+ const { initializeBundles } = await import('/bundles/bundle.config.js');
242
+ if (initializeBundles) {
243
+ await initializeBundles(window.slice);
244
+ console.log('📦 Bundles initialized automatically');
245
+ }
246
+ } catch (error) {
247
+ // Bundles not available, continue with individual component loading
248
+ console.log('📄 Using individual component loading (no bundles found)');
249
+ }
package/api/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // api/index.js - Seguridad automática sin configuración
2
2
  import express from 'express';
3
3
  import path from 'path';
4
+ import fs from 'fs';
4
5
  import { fileURLToPath } from 'url';
5
6
  import { dirname } from 'path';
6
7
  import {
@@ -60,6 +61,15 @@ app.use(securityMiddleware({
60
61
  // MIDDLEWARES DE APLICACIÓN
61
62
  // ==============================================
62
63
 
64
+ // Middleware global para archivos JavaScript con MIME types correctos
65
+ app.use((req, res, next) => {
66
+ if (req.path.endsWith('.js')) {
67
+ // Forzar headers correctos para TODOS los archivos .js
68
+ res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
69
+ }
70
+ next();
71
+ });
72
+
63
73
  // Middleware para parsear JSON y formularios
64
74
  app.use(express.json());
65
75
  app.use(express.urlencoded({ extended: true }));
@@ -81,6 +91,76 @@ app.use((req, res, next) => {
81
91
  // ARCHIVOS ESTÁTICOS (DESPUÉS DE SEGURIDAD)
82
92
  // ==============================================
83
93
 
94
+ // Función de utilidad para verificar si existe el directorio bundles
95
+ function bundlesDirectoryExists() {
96
+ const bundleDir = path.join(__dirname, `../${folderDeployed}`, 'bundles');
97
+ return fs.existsSync(bundleDir) && fs.statSync(bundleDir).isDirectory();
98
+ }
99
+
100
+ // Capturar todas las peticiones a bundles para debugging
101
+ app.use('/bundles/', (req, res, next) => {
102
+ console.log(`🔍 Bundle request: ${req.method} ${req.originalUrl}`);
103
+ next();
104
+ });
105
+
106
+ // Middleware personalizado para archivos de bundles con MIME types correctos
107
+ // ⚠️ DEBE IR ANTES del middleware general para tener prioridad
108
+ app.use('/bundles/', (req, res, next) => {
109
+ // Verificar si existe el directorio bundles
110
+ if (!bundlesDirectoryExists()) {
111
+ console.log(`ℹ️ Bundles directory does not exist, skipping bundle processing`);
112
+ return next(); // Continuar con el siguiente middleware
113
+ }
114
+
115
+ // Solo procesar archivos .js
116
+ if (req.path.endsWith('.js')) {
117
+ const filePath = path.join(__dirname, `../${folderDeployed}`, 'bundles', req.path);
118
+ console.log(`📂 Processing bundle: ${req.path} -> ${filePath}`);
119
+
120
+ // Verificar que el archivo existe
121
+ if (fs.existsSync(filePath)) {
122
+ try {
123
+ // Leer y servir el archivo con headers correctos
124
+ const fileContent = fs.readFileSync(filePath, 'utf8');
125
+ res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
126
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); // No cachear para permitir actualizaciones en tiempo real
127
+ res.setHeader('Pragma', 'no-cache');
128
+ res.setHeader('Expires', '0');
129
+ console.log(`✅ Serving bundle: ${req.path} (${fileContent.length} bytes, ${Buffer.byteLength(fileContent, 'utf8')} bytes UTF-8)`);
130
+ return res.send(fileContent);
131
+ } catch (error) {
132
+ console.log(`❌ Error reading bundle file: ${error.message}`);
133
+ return res.status(500).send('Error reading bundle file');
134
+ }
135
+ } else {
136
+ console.log(`❌ Bundle file not found: ${filePath}`);
137
+ // Listar archivos disponibles para debugging
138
+ try {
139
+ const bundleDir = path.join(__dirname, `../${folderDeployed}`, 'bundles');
140
+ if (fs.existsSync(bundleDir)) {
141
+ const files = fs.readdirSync(bundleDir);
142
+ console.log(`📁 Available files in bundles: ${files.join(', ')}`);
143
+ }
144
+ } catch (e) {
145
+ console.log(`❌ Could not list bundle directory: ${e.message}`);
146
+ }
147
+ return res.status(404).send('Bundle file not found');
148
+ }
149
+ }
150
+
151
+ // Para archivos no .js, continuar con el middleware estático normal
152
+ next();
153
+ });
154
+
155
+ // Servir otros archivos de bundles (CSS, etc.) con el middleware estático normal
156
+ // Solo si existe el directorio bundles
157
+ if (bundlesDirectoryExists()) {
158
+ app.use('/bundles/', express.static(path.join(__dirname, `../${folderDeployed}`, 'bundles')));
159
+ console.log(`📦 Bundles directory found, serving static files`);
160
+ } else {
161
+ console.log(`ℹ️ Bundles directory not found, skipping static bundle serving`);
162
+ }
163
+
84
164
  // Servir framework Slice.js
85
165
  app.use('/Slice/', express.static(path.join(__dirname, '..', 'node_modules', 'slicejs-web-framework', 'Slice')));
86
166
 
@@ -108,40 +188,6 @@ app.get('/api/status', (req, res) => {
108
188
  });
109
189
  });
110
190
 
111
- // Ruta para verificar estado de seguridad
112
- app.get('/api/security-status', (req, res) => {
113
- const host = req.get('Host');
114
-
115
- res.json({
116
- frameworkProtection: {
117
- status: 'active',
118
- mode: 'automatic',
119
- description: 'Allows framework file loading from application, blocks direct browser access',
120
- detectedHost: host
121
- },
122
- blockedPaths: [
123
- '/node_modules/*',
124
- '/package.json',
125
- '/.env',
126
- '/.git/*'
127
- ],
128
- protectedPaths: {
129
- directAccessBlocked: [
130
- '/Slice/Components/Structural/*',
131
- '/Slice/Core/*',
132
- '/Slice/Services/*'
133
- ],
134
- allowedFrom: 'Any request with valid Referer matching current host'
135
- },
136
- howItWorks: {
137
- automatic: true,
138
- config: 'No configuration needed',
139
- localhost: 'Works automatically',
140
- customDomain: 'Works automatically',
141
- detection: 'Uses Referer and Host headers'
142
- }
143
- });
144
- });
145
191
 
146
192
  // ==============================================
147
193
  // SPA FALLBACK
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slicejs-web-framework",
3
- "version": "2.2.7",
3
+ "version": "2.2.8",
4
4
  "description": "",
5
5
  "engines": {
6
6
  "node": ">=20"