@swissjs/swite 0.3.5 → 0.4.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.
- package/CHANGELOG.md +30 -0
- package/DIRECTIVE.md +57 -2
- package/__tests__/import-rewriter-bug.test.ts +100 -113
- package/__tests__/security-r001-r002.test.ts +190 -0
- package/dist/build-engine/builder.js +9 -9
- package/dist/cli.js +0 -0
- package/dist/config/config.d.ts +0 -5
- package/dist/config/config.d.ts.map +1 -1
- package/dist/dev-engine/handlers/base-handler.d.ts +6 -0
- package/dist/dev-engine/handlers/base-handler.d.ts.map +1 -1
- package/dist/dev-engine/handlers/base-handler.js +91 -0
- package/dist/dev-engine/handlers/ui-handler.d.ts +0 -1
- package/dist/dev-engine/handlers/ui-handler.d.ts.map +1 -1
- package/dist/dev-engine/handlers/ui-handler.js +2 -64
- package/dist/dev-engine/handlers/uix-handler.d.ts +0 -1
- package/dist/dev-engine/handlers/uix-handler.d.ts.map +1 -1
- package/dist/dev-engine/handlers/uix-handler.js +2 -58
- package/dist/dev-engine/hmr/hmr-client-template.js +111 -111
- package/dist/dev-engine/hmr/hmr.d.ts +10 -1
- package/dist/dev-engine/hmr/hmr.d.ts.map +1 -1
- package/dist/dev-engine/hmr/hmr.js +40 -2
- package/dist/dev-engine/middleware/middleware-setup.js +4 -3
- package/dist/dev-engine/middleware/static-files.d.ts.map +1 -1
- package/dist/dev-engine/middleware/static-files.js +145 -62
- package/dist/dev-engine/pythonDevManager.js +1 -1
- package/dist/dev-engine/router/file-router.d.ts.map +1 -1
- package/dist/dev-engine/router/file-router.js +2 -29
- package/dist/dev-engine/server.d.ts +7 -0
- package/dist/dev-engine/server.d.ts.map +1 -1
- package/dist/dev-engine/server.js +31 -3
- package/dist/kernel/package-finder.d.ts +0 -8
- package/dist/kernel/package-finder.d.ts.map +1 -1
- package/dist/kernel/package-finder.js +2 -2
- package/dist/kernel/package-registry.d.ts +6 -0
- package/dist/kernel/package-registry.d.ts.map +1 -1
- package/dist/kernel/package-registry.js +8 -0
- package/dist/kernel/workspace.d.ts.map +1 -1
- package/dist/kernel/workspace.js +12 -9
- package/docs/architecture/build-pipeline.md +97 -97
- package/docs/architecture/dev-server.md +87 -87
- package/docs/architecture/hmr.md +78 -78
- package/docs/architecture/import-rewriting.md +101 -101
- package/docs/architecture/index.md +16 -16
- package/docs/architecture/python-integration.md +93 -93
- package/docs/architecture/resolution.md +92 -92
- package/docs/cli/build.md +78 -78
- package/docs/cli/dev.md +90 -90
- package/docs/cli/index.md +15 -15
- package/docs/cli/start.md +45 -45
- package/docs/development/contributing.md +74 -74
- package/docs/development/index.md +12 -12
- package/docs/development/internals.md +101 -101
- package/docs/guide/configuration.md +89 -89
- package/docs/guide/index.md +13 -13
- package/docs/guide/project-structure.md +75 -75
- package/docs/guide/quickstart.md +113 -113
- package/docs/index.md +16 -16
- package/package.json +29 -16
- package/src/build-engine/builder.ts +9 -9
- package/src/config/config.ts +0 -5
- package/src/config/env.ts +98 -98
- package/src/dev-engine/handlers/base-handler.ts +109 -0
- package/src/dev-engine/handlers/ui-handler.ts +30 -110
- package/src/dev-engine/handlers/uix-handler.ts +21 -95
- package/src/dev-engine/hmr/hmr-client-template.ts +122 -122
- package/src/dev-engine/hmr/hmr.ts +46 -1
- package/src/dev-engine/middleware/middleware-setup.ts +354 -354
- package/src/dev-engine/middleware/static-files.ts +203 -121
- package/src/dev-engine/pythonDevManager.ts +1 -1
- package/src/dev-engine/router/file-router.ts +2 -45
- package/src/dev-engine/server.ts +33 -3
- package/src/kernel/package-finder.ts +2 -2
- package/src/kernel/package-registry.ts +9 -0
- package/src/kernel/workspace.ts +8 -10
- package/src/resolution/cdn/cdn-fallback.ts +40 -40
- package/src/resolution/path/path-fixup.ts +27 -27
- package/src/resolution/rewriting/import-rewriter.ts +237 -237
- package/src/resolution/symlink-registry.ts +114 -114
|
@@ -26,7 +26,8 @@ export async function setupStaticFiles(
|
|
|
26
26
|
app: Express,
|
|
27
27
|
config: StaticFilesConfig,
|
|
28
28
|
): Promise<void> {
|
|
29
|
-
|
|
29
|
+
const _debug = process.env["SWITE_DEBUG"] === "1";
|
|
30
|
+
if (_debug) console.log(chalk.magenta(`[static-files] ⚡ setupStaticFiles called with root: ${config.root}`));
|
|
30
31
|
|
|
31
32
|
// Static file serving - ONLY serve public directory
|
|
32
33
|
// Do NOT serve dist/ folder - it contains old build artifacts with bare imports
|
|
@@ -145,11 +146,13 @@ export async function setupStaticFiles(
|
|
|
145
146
|
|
|
146
147
|
next();
|
|
147
148
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
if (_debug) {
|
|
150
|
+
console.log(
|
|
151
|
+
chalk.gray(
|
|
152
|
+
` 📦 Serving workspace node_modules from ${workspaceNodeModules}`,
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
153
156
|
} catch {
|
|
154
157
|
// Workspace node_modules doesn't exist, skip
|
|
155
158
|
}
|
|
@@ -161,70 +164,94 @@ export async function setupStaticFiles(
|
|
|
161
164
|
const workspaceRoot =
|
|
162
165
|
workspaceRootForNodeModules || (await findWorkspaceRoot(config.root));
|
|
163
166
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
)
|
|
167
|
+
if (_debug) {
|
|
168
|
+
console.log(
|
|
169
|
+
chalk.blue(`[static-files] Workspace root: ${workspaceRoot}`),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
if (_debug) {
|
|
173
|
+
console.log(
|
|
174
|
+
chalk.blue(`[static-files] App root: ${config.root}`),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
170
177
|
|
|
171
178
|
// Try to serve lib/ directory - check both workspace root and app root parent
|
|
172
179
|
let libPath: string | null = null;
|
|
173
180
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
if (_debug) {
|
|
182
|
+
console.log(
|
|
183
|
+
chalk.blue(`[static-files] Determining lib/ path... workspaceRoot: ${workspaceRoot}, config.root: ${config.root}`),
|
|
184
|
+
);
|
|
185
|
+
}
|
|
177
186
|
|
|
178
187
|
// First, try workspace root
|
|
179
188
|
if (workspaceRoot && workspaceRoot !== config.root) {
|
|
180
189
|
libPath = path.join(workspaceRoot, "lib");
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
190
|
+
if (_debug) {
|
|
191
|
+
console.log(
|
|
192
|
+
chalk.blue(`[static-files] Trying workspace root lib/: ${libPath}`),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
184
195
|
} else {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
if (_debug) {
|
|
197
|
+
console.log(
|
|
198
|
+
chalk.yellow(`[static-files] Workspace root equals app root, trying parent directories...`),
|
|
199
|
+
);
|
|
200
|
+
}
|
|
188
201
|
// If workspace root equals app root, try going up from app root
|
|
189
202
|
const parentDir = path.dirname(config.root);
|
|
190
203
|
const parentLibPath = path.join(parentDir, "lib");
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
204
|
+
if (_debug) {
|
|
205
|
+
console.log(
|
|
206
|
+
chalk.blue(`[static-files] Trying parent lib/: ${parentLibPath}`),
|
|
207
|
+
);
|
|
208
|
+
}
|
|
194
209
|
try {
|
|
195
210
|
await fs.access(parentLibPath);
|
|
196
211
|
libPath = parentLibPath;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
212
|
+
if (_debug) {
|
|
213
|
+
console.log(
|
|
214
|
+
chalk.blue(`[static-files] Using parent directory lib/: ${libPath}`),
|
|
215
|
+
);
|
|
216
|
+
}
|
|
200
217
|
} catch (error) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
218
|
+
if (_debug) {
|
|
219
|
+
console.log(
|
|
220
|
+
chalk.yellow(`[static-files] Parent lib/ not found: ${error instanceof Error ? error.message : String(error)}`),
|
|
221
|
+
);
|
|
222
|
+
}
|
|
204
223
|
// Parent lib/ doesn't exist, try grandparent
|
|
205
224
|
const grandparentDir = path.dirname(parentDir);
|
|
206
225
|
const grandparentLibPath = path.join(grandparentDir, "lib");
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
226
|
+
if (_debug) {
|
|
227
|
+
console.log(
|
|
228
|
+
chalk.blue(`[static-files] Trying grandparent lib/: ${grandparentLibPath}`),
|
|
229
|
+
);
|
|
230
|
+
}
|
|
210
231
|
try {
|
|
211
232
|
await fs.access(grandparentLibPath);
|
|
212
233
|
libPath = grandparentLibPath;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
234
|
+
if (_debug) {
|
|
235
|
+
console.log(
|
|
236
|
+
chalk.blue(`[static-files] Using grandparent directory lib/: ${libPath}`),
|
|
237
|
+
);
|
|
238
|
+
}
|
|
216
239
|
} catch (error2) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
240
|
+
if (_debug) {
|
|
241
|
+
console.log(
|
|
242
|
+
chalk.yellow(`[static-files] Grandparent lib/ not found: ${error2 instanceof Error ? error2.message : String(error2)}`),
|
|
243
|
+
);
|
|
244
|
+
}
|
|
220
245
|
}
|
|
221
246
|
}
|
|
222
247
|
}
|
|
223
248
|
|
|
224
249
|
// Serve lib/ directory if found
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
250
|
+
if (_debug) {
|
|
251
|
+
console.log(
|
|
252
|
+
chalk.blue(`[static-files] Checking for lib/ directory... libPath: ${libPath}`),
|
|
253
|
+
);
|
|
254
|
+
}
|
|
228
255
|
|
|
229
256
|
// ALWAYS try to register /lib/ static serving
|
|
230
257
|
// Calculate the lib path - prefer workspace root, fallback to parent of app root
|
|
@@ -239,49 +266,67 @@ export async function setupStaticFiles(
|
|
|
239
266
|
finalLibPath = path.join(parentDir, "lib");
|
|
240
267
|
}
|
|
241
268
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
269
|
+
if (_debug) {
|
|
270
|
+
console.log(
|
|
271
|
+
chalk.blue(`[static-files] Final lib path to check: ${finalLibPath}`),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (_debug) {
|
|
275
|
+
console.log(
|
|
276
|
+
chalk.blue(`[static-files] workspaceRoot: ${workspaceRoot}, config.root: ${config.root}`),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
248
279
|
|
|
249
280
|
// Try to access the directory
|
|
250
281
|
let libPathExists = false;
|
|
251
282
|
try {
|
|
252
283
|
await fs.access(finalLibPath);
|
|
253
284
|
libPathExists = true;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
285
|
+
if (_debug) {
|
|
286
|
+
console.log(
|
|
287
|
+
chalk.green(`[static-files] ✅ Found lib/ directory at: ${finalLibPath}`),
|
|
288
|
+
);
|
|
289
|
+
}
|
|
257
290
|
|
|
258
291
|
// Verify the CSS file exists
|
|
259
292
|
const testCssPath = path.join(finalLibPath, "skltn", "src", "css", "index.css");
|
|
260
293
|
try {
|
|
261
294
|
await fs.access(testCssPath);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
295
|
+
if (_debug) {
|
|
296
|
+
console.log(
|
|
297
|
+
chalk.green(`[static-files] ✅ Test CSS file exists: ${testCssPath}`),
|
|
298
|
+
);
|
|
299
|
+
}
|
|
265
300
|
} catch (error) {
|
|
301
|
+
if (_debug) {
|
|
302
|
+
console.error(
|
|
303
|
+
chalk.yellow(`[static-files] ⚠️ Test CSS file NOT found: ${testCssPath}`),
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (_debug) {
|
|
266
309
|
console.error(
|
|
267
|
-
chalk.
|
|
310
|
+
chalk.red(`[static-files] ❌ lib/ directory not found at: ${finalLibPath}`),
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
if (_debug) {
|
|
314
|
+
console.error(
|
|
315
|
+
chalk.red(`[static-files] Error: ${error instanceof Error ? error.message : String(error)}`),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
if (_debug) {
|
|
319
|
+
console.error(
|
|
320
|
+
chalk.red(`[static-files] ⚠️ /lib middleware will NOT be registered - CSS files will 404!`),
|
|
268
321
|
);
|
|
269
322
|
}
|
|
270
|
-
} catch (error) {
|
|
271
|
-
console.error(
|
|
272
|
-
chalk.red(`[static-files] ❌ lib/ directory not found at: ${finalLibPath}`),
|
|
273
|
-
);
|
|
274
|
-
console.error(
|
|
275
|
-
chalk.red(`[static-files] Error: ${error instanceof Error ? error.message : String(error)}`),
|
|
276
|
-
);
|
|
277
|
-
console.error(
|
|
278
|
-
chalk.red(`[static-files] ⚠️ /lib middleware will NOT be registered - CSS files will 404!`),
|
|
279
|
-
);
|
|
280
323
|
}
|
|
281
324
|
|
|
282
325
|
// Register static file middleware ONLY if directory exists
|
|
283
326
|
if (libPathExists) {
|
|
284
|
-
|
|
327
|
+
if (_debug) {
|
|
328
|
+
console.log(chalk.green(`[static-files] ✅ Registering /lib middleware with finalLibPath: ${finalLibPath}`));
|
|
329
|
+
}
|
|
285
330
|
|
|
286
331
|
// CRITICAL: First middleware to block source files BEFORE any express.static can serve them
|
|
287
332
|
// This MUST run before express.static to prevent wrong MIME types
|
|
@@ -298,17 +343,21 @@ export async function setupStaticFiles(
|
|
|
298
343
|
(path.endsWith(".js") && !path.includes("node_modules")) || path.endsWith(".mjs");
|
|
299
344
|
|
|
300
345
|
if (isSourceFile) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
346
|
+
if (_debug) {
|
|
347
|
+
console.log(
|
|
348
|
+
chalk.red(
|
|
349
|
+
`[static-files] ⚠️ FIRST BLOCK: Skipping source file: url=${url}, path=${path} - should be handled by module middleware`
|
|
350
|
+
)
|
|
351
|
+
);
|
|
352
|
+
}
|
|
306
353
|
return next(); // Let module transformation middleware handle it
|
|
307
354
|
}
|
|
308
355
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
356
|
+
if (_debug) {
|
|
357
|
+
console.log(
|
|
358
|
+
chalk.cyan(`[static-files] Request for /lib${path} (static file)`),
|
|
359
|
+
);
|
|
360
|
+
}
|
|
312
361
|
next();
|
|
313
362
|
});
|
|
314
363
|
|
|
@@ -324,7 +373,9 @@ export async function setupStaticFiles(
|
|
|
324
373
|
res.setHeader("Pragma", "no-cache");
|
|
325
374
|
res.setHeader("Expires", "0");
|
|
326
375
|
} catch (error) {
|
|
327
|
-
|
|
376
|
+
if (_debug) {
|
|
377
|
+
console.error(chalk.red(`[static-files] Error setting headers for ${filePath}:`), error);
|
|
378
|
+
}
|
|
328
379
|
}
|
|
329
380
|
},
|
|
330
381
|
});
|
|
@@ -344,11 +395,13 @@ export async function setupStaticFiles(
|
|
|
344
395
|
(path.endsWith(".js") && !path.includes("node_modules")) || path.endsWith(".mjs");
|
|
345
396
|
|
|
346
397
|
if (isSourceFile) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
398
|
+
if (_debug) {
|
|
399
|
+
console.log(
|
|
400
|
+
chalk.red(
|
|
401
|
+
`[static-files /lib express.static] ⚠️ BLOCKING source file: url=${url}, path=${path} - should be handled by module transformation middleware`
|
|
402
|
+
)
|
|
403
|
+
);
|
|
404
|
+
}
|
|
352
405
|
// CRITICAL: Don't call libStatic - return next() to skip it
|
|
353
406
|
return next(); // Let module transformation middleware handle it
|
|
354
407
|
}
|
|
@@ -359,9 +412,11 @@ export async function setupStaticFiles(
|
|
|
359
412
|
// Source files should be handled by module transformation middleware (registered before this)
|
|
360
413
|
// Only static files (CSS, images) should be served, and they're handled by the custom handler above
|
|
361
414
|
// If a file isn't found, let it 404 rather than serving with wrong MIME type
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
415
|
+
if (_debug) {
|
|
416
|
+
console.log(
|
|
417
|
+
chalk.gray(` 📦 Serving workspace lib/ from ${finalLibPath}`),
|
|
418
|
+
);
|
|
419
|
+
}
|
|
365
420
|
}
|
|
366
421
|
|
|
367
422
|
// Continue with other workspace directories if workspaceRoot is different from app root
|
|
@@ -372,9 +427,11 @@ export async function setupStaticFiles(
|
|
|
372
427
|
try {
|
|
373
428
|
await fs.access(librariesPath);
|
|
374
429
|
app.use("/libraries", express.static(librariesPath));
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
430
|
+
if (_debug) {
|
|
431
|
+
console.log(
|
|
432
|
+
chalk.gray(` 📦 Serving workspace libraries/ from ${librariesPath}`),
|
|
433
|
+
);
|
|
434
|
+
}
|
|
378
435
|
} catch {
|
|
379
436
|
// libraries/ doesn't exist, skip
|
|
380
437
|
}
|
|
@@ -404,9 +461,11 @@ export async function setupStaticFiles(
|
|
|
404
461
|
}
|
|
405
462
|
express.static(modulesPath)(req, res, next);
|
|
406
463
|
});
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
464
|
+
if (_debug) {
|
|
465
|
+
console.log(
|
|
466
|
+
chalk.gray(` 📦 Serving workspace modules/ from ${modulesPath}`),
|
|
467
|
+
);
|
|
468
|
+
}
|
|
410
469
|
} catch {
|
|
411
470
|
// modules/ doesn't exist, skip
|
|
412
471
|
}
|
|
@@ -425,7 +484,10 @@ export async function setupSPAFallback(
|
|
|
425
484
|
app: Express,
|
|
426
485
|
config: StaticFilesConfig,
|
|
427
486
|
): Promise<void> {
|
|
428
|
-
|
|
487
|
+
const _debug = process.env["SWITE_DEBUG"] === "1";
|
|
488
|
+
if (_debug) {
|
|
489
|
+
console.log(chalk.magenta(`[SWITE] setupSPAFallback loaded - VERSION 0.3.5 (NO HARDCODED CSS)`));
|
|
490
|
+
}
|
|
429
491
|
// Use app.all() to catch ALL HTTP methods, but only for non-source files
|
|
430
492
|
app.all("*", async (req, res, next) => {
|
|
431
493
|
const url = req.url.split("?")[0];
|
|
@@ -433,16 +495,11 @@ export async function setupSPAFallback(
|
|
|
433
495
|
const accept = String(req.headers?.accept || "");
|
|
434
496
|
|
|
435
497
|
// DEBUG: Verify handler is being called
|
|
436
|
-
process.stderr.write(`[SPA FALLBACK] Handler called for: ${req.method} ${fullUrl}\n`);
|
|
437
|
-
console.error(`[SWITE CSS DEBUG] ========== SPA FALLBACK HANDLER START ==========`);
|
|
438
|
-
console.error(`[SWITE CSS DEBUG] URL: ${url}, Full URL: ${fullUrl}`);
|
|
439
498
|
|
|
440
499
|
// --- CRITICAL SAFETY CHECK ---
|
|
441
500
|
// NEVER serve HTML for /src/* requests - these are source files that must be handled by middleware
|
|
442
501
|
// Even if middleware fails, we should return 404, not HTML
|
|
443
502
|
if (req.path?.startsWith("/src/") || url.startsWith("/src/")) {
|
|
444
|
-
console.error(chalk.red(`[SPA FALLBACK] ⚠️ BLOCKED: Attempt to serve HTML for source path: ${req.method} ${fullUrl}`));
|
|
445
|
-
console.error(chalk.red(`[SPA FALLBACK] This should have been handled by /src middleware! Returning 404.`));
|
|
446
503
|
res.status(404).setHeader("Content-Type", "text/plain");
|
|
447
504
|
res.send(`File not found: ${url}`);
|
|
448
505
|
return;
|
|
@@ -452,8 +509,6 @@ export async function setupSPAFallback(
|
|
|
452
509
|
// NEVER serve HTML for /swiss-packages/* requests - these are SWISS framework packages
|
|
453
510
|
// They should be handled by TS/JS handlers to rewrite imports
|
|
454
511
|
if (req.path?.startsWith("/swiss-packages/") || url.startsWith("/swiss-packages/")) {
|
|
455
|
-
console.error(chalk.red(`[SPA FALLBACK] ⚠️ BLOCKED: Attempt to serve HTML for SWISS package: ${req.method} ${fullUrl}`));
|
|
456
|
-
console.error(chalk.red(`[SPA FALLBACK] This should have been handled by module transformation middleware! Returning 404.`));
|
|
457
512
|
res.status(404).setHeader("Content-Type", "text/plain");
|
|
458
513
|
res.send(`File not found: ${url}`);
|
|
459
514
|
return;
|
|
@@ -463,21 +518,15 @@ export async function setupSPAFallback(
|
|
|
463
518
|
// NEVER serve HTML for /lib/* requests - these are workspace library files
|
|
464
519
|
// They should be handled by static file middleware
|
|
465
520
|
if (req.path?.startsWith("/lib/") || url.startsWith("/lib/")) {
|
|
466
|
-
console.error(chalk.red(`[SPA FALLBACK] ⚠️ BLOCKED: Attempt to serve HTML for /lib/ path: ${req.method} ${fullUrl}`));
|
|
467
|
-
console.error(chalk.red(`[SPA FALLBACK] This should have been handled by static file middleware! Returning 404.`));
|
|
468
521
|
res.status(404).setHeader("Content-Type", "text/plain");
|
|
469
522
|
res.send(`File not found: ${url}`);
|
|
470
523
|
return;
|
|
471
524
|
}
|
|
472
525
|
|
|
473
526
|
// Log every request that hits the fallback (for diagnostics)
|
|
474
|
-
console.log(chalk.gray(`[SPA FALLBACK] Serving HTML for: ${req.method} ${fullUrl}`));
|
|
475
|
-
process.stderr.write(`[SPA FALLBACK] About to read HTML file...\n`);
|
|
476
527
|
|
|
477
528
|
// Log if SPA fallback is being hit for .ui files (this should NOT happen after /src check)
|
|
478
529
|
if (url.endsWith(".ui")) {
|
|
479
|
-
console.error(chalk.red(`[SPA FALLBACK] ⚠️ WARNING: SPA fallback intercepted .ui file: ${fullUrl}`));
|
|
480
|
-
console.error(chalk.red(`[SPA FALLBACK] This should have been handled by module transformation middleware!`));
|
|
481
530
|
}
|
|
482
531
|
|
|
483
532
|
// DO NOT serve HTML for source files - they should be handled by handlers
|
|
@@ -494,7 +543,6 @@ export async function setupSPAFallback(
|
|
|
494
543
|
) {
|
|
495
544
|
// These should have been handled by middleware handlers
|
|
496
545
|
// If we reach here, the file wasn't found, return 404 with proper content type
|
|
497
|
-
console.error(chalk.red(`[SPA FALLBACK] Returning 404 for ${url} - should have been handled earlier`));
|
|
498
546
|
res.status(404).setHeader("Content-Type", "text/plain");
|
|
499
547
|
res.send(`File not found: ${url}`);
|
|
500
548
|
return;
|
|
@@ -548,12 +596,18 @@ export async function setupSPAFallback(
|
|
|
548
596
|
// This dynamically discovers CSS files from the app's entry point
|
|
549
597
|
// CRITICAL: This MUST run before import map injection
|
|
550
598
|
// IMPORTANT: Only inject CSS files that actually exist in the app's directory
|
|
551
|
-
|
|
552
|
-
|
|
599
|
+
if (_debug) {
|
|
600
|
+
console.log(chalk.magenta(`[SWITE CSS] ========== CSS EXTRACTION START (VERSION 0.3.5) ==========`));
|
|
601
|
+
}
|
|
602
|
+
if (_debug) {
|
|
603
|
+
console.log(chalk.magenta(`[SWITE CSS] App root: ${config.root}`));
|
|
604
|
+
}
|
|
553
605
|
try {
|
|
554
606
|
const entryFile = config.entry ?? "src/index.ui";
|
|
555
607
|
const entryPointPath = path.join(config.root, entryFile);
|
|
556
|
-
|
|
608
|
+
if (_debug) {
|
|
609
|
+
console.log(chalk.blue(`[SWITE CSS] Checking entry point: ${entryPointPath}`));
|
|
610
|
+
}
|
|
557
611
|
const entryPointContent = await fs.readFile(entryPointPath, "utf-8");
|
|
558
612
|
|
|
559
613
|
// Extract CSS imports using regex
|
|
@@ -620,10 +674,14 @@ export async function setupSPAFallback(
|
|
|
620
674
|
}
|
|
621
675
|
}
|
|
622
676
|
|
|
623
|
-
|
|
677
|
+
if (_debug) {
|
|
678
|
+
console.log(chalk.blue(`[SWITE CSS] Found ${cssImports.size} CSS import(s) in code`));
|
|
679
|
+
}
|
|
624
680
|
if (cssImports.size > 0) {
|
|
625
681
|
const cssArray = Array.from(cssImports);
|
|
626
|
-
|
|
682
|
+
if (_debug) {
|
|
683
|
+
console.log(chalk.blue(`[SWITE CSS] CSS imports found: ${cssArray.join(", ")}`));
|
|
684
|
+
}
|
|
627
685
|
|
|
628
686
|
// Verify CSS files exist before injecting them
|
|
629
687
|
const existingCssFiles: string[] = [];
|
|
@@ -634,22 +692,32 @@ export async function setupSPAFallback(
|
|
|
634
692
|
? path.join(config.root, url.substring(1)) // Remove leading /
|
|
635
693
|
: path.join(config.root, "src", cssPath);
|
|
636
694
|
|
|
637
|
-
|
|
695
|
+
if (_debug) {
|
|
696
|
+
console.log(chalk.blue(`[SWITE CSS] Checking if CSS file exists: ${filePath} (url: ${url})`));
|
|
697
|
+
}
|
|
638
698
|
try {
|
|
639
699
|
await fs.access(filePath);
|
|
640
|
-
|
|
700
|
+
if (_debug) {
|
|
701
|
+
console.log(chalk.green(`[SWITE CSS] ✅ CSS file exists: ${filePath}`));
|
|
702
|
+
}
|
|
641
703
|
existingCssFiles.push(url);
|
|
642
704
|
} catch {
|
|
643
705
|
// CSS file doesn't exist, skip it
|
|
644
706
|
// This allows different apps/websites to have different CSS files
|
|
645
|
-
|
|
707
|
+
if (_debug) {
|
|
708
|
+
console.log(chalk.yellow(`[SWITE CSS] ⚠️ CSS file NOT found: ${filePath}, skipping`));
|
|
709
|
+
}
|
|
646
710
|
}
|
|
647
711
|
}
|
|
648
712
|
|
|
649
713
|
// Only inject CSS files that actually exist
|
|
650
|
-
|
|
714
|
+
if (_debug) {
|
|
715
|
+
console.log(chalk.blue(`[SWITE CSS] ${existingCssFiles.length} CSS file(s) exist out of ${cssArray.length} found`));
|
|
716
|
+
}
|
|
651
717
|
if (existingCssFiles.length === 0) {
|
|
652
|
-
|
|
718
|
+
if (_debug) {
|
|
719
|
+
console.log(chalk.yellow(`[SWITE CSS] ⚠️ No CSS files exist, skipping injection`));
|
|
720
|
+
}
|
|
653
721
|
} else if (existingCssFiles.length > 0) {
|
|
654
722
|
const cssLinks = existingCssFiles
|
|
655
723
|
.map(url => ` <link rel="stylesheet" href="${url}">`)
|
|
@@ -665,19 +733,27 @@ export async function setupSPAFallback(
|
|
|
665
733
|
const beforeReplace = html;
|
|
666
734
|
html = html.replace(/\s*<\/head>/i, `${cssLinks}\n </head>`);
|
|
667
735
|
if (html === beforeReplace) {
|
|
668
|
-
|
|
736
|
+
if (_debug) {
|
|
737
|
+
console.warn(chalk.yellow("[SWITE] Failed to inject CSS links - </head> not found"));
|
|
738
|
+
}
|
|
669
739
|
} else {
|
|
670
|
-
|
|
740
|
+
if (_debug) {
|
|
741
|
+
console.log(chalk.green(`[SWITE] ✅ Injected ${existingCssFiles.length} CSS link(s): ${existingCssFiles.join(", ")}`));
|
|
742
|
+
}
|
|
671
743
|
}
|
|
672
744
|
} else {
|
|
673
|
-
|
|
745
|
+
if (_debug) {
|
|
746
|
+
console.log(chalk.blue(`[SWITE CSS] CSS links already in HTML, skipping injection`));
|
|
747
|
+
}
|
|
674
748
|
}
|
|
675
749
|
}
|
|
676
750
|
}
|
|
677
751
|
} catch (error) {
|
|
678
752
|
// If entry point doesn't exist or can't be read, continue without CSS injection
|
|
679
753
|
// Silently continue - CSS injection is optional
|
|
680
|
-
|
|
754
|
+
if (_debug) {
|
|
755
|
+
console.log(chalk.yellow(`[SWITE CSS] Could not extract CSS imports: ${error instanceof Error ? error.message : String(error)}`));
|
|
756
|
+
}
|
|
681
757
|
}
|
|
682
758
|
|
|
683
759
|
// Add/merge import map to help browser resolve bare module specifiers.
|
|
@@ -701,13 +777,19 @@ export async function setupSPAFallback(
|
|
|
701
777
|
const beforeReplace = html;
|
|
702
778
|
html = html.replace(/\s*<\/head>/i, `${importMap}\n </head>`);
|
|
703
779
|
if (html === beforeReplace) {
|
|
704
|
-
|
|
780
|
+
if (_debug) {
|
|
781
|
+
console.warn("[SWITE] Failed to add import map - </head> not found or already replaced");
|
|
782
|
+
}
|
|
705
783
|
} else {
|
|
706
|
-
|
|
784
|
+
if (_debug) {
|
|
785
|
+
console.log(`[SWITE] Added import map with ${Object.keys(switeImports).length} entries`);
|
|
786
|
+
}
|
|
707
787
|
}
|
|
708
788
|
} else {
|
|
709
789
|
// Importmap already in HTML — merge swite entries without overwriting existing ones
|
|
710
|
-
|
|
790
|
+
if (_debug) {
|
|
791
|
+
console.log("[SWITE] Import map already exists in HTML — merging swite entries");
|
|
792
|
+
}
|
|
711
793
|
if (Object.keys(switeImports).length > 0) {
|
|
712
794
|
html = html.replace(
|
|
713
795
|
/(<script\s+type=["']importmap["'][^>]*>)\s*([\s\S]*?)(\s*<\/script>)/i,
|
|
@@ -5,7 +5,7 @@ import { initPythonProxy } from "../adapters/proxy/proxyToPython.js";
|
|
|
5
5
|
import type { PythonServiceConfig } from "../config/config.js";
|
|
6
6
|
|
|
7
7
|
const POLL_INTERVAL_MS = 500;
|
|
8
|
-
const HEALTH_TIMEOUT_MS =
|
|
8
|
+
const HEALTH_TIMEOUT_MS = 30_000;
|
|
9
9
|
const BACKOFF_THRESHOLD = 5;
|
|
10
10
|
|
|
11
11
|
let _child: ChildProcess | null = null;
|
|
@@ -11,7 +11,6 @@ import type { RouteDefinition } from "@swissjs/core";
|
|
|
11
11
|
import { RouteScanner } from "@swissjs/plugin-file-router/core";
|
|
12
12
|
import { createFileWatcher } from "@swissjs/plugin-file-router/dev";
|
|
13
13
|
import { HMREngine } from "../hmr/hmr.js";
|
|
14
|
-
import { findWorkspaceRoot } from "../../kernel/workspace.js";
|
|
15
14
|
|
|
16
15
|
export interface FileRouterConfig {
|
|
17
16
|
root: string;
|
|
@@ -38,7 +37,6 @@ export async function setupFileRouter(
|
|
|
38
37
|
};
|
|
39
38
|
|
|
40
39
|
try {
|
|
41
|
-
const workspaceRoot = await findWorkspaceRoot(config.root);
|
|
42
40
|
const appRoot = config.root;
|
|
43
41
|
|
|
44
42
|
// Initialize route scanner
|
|
@@ -49,59 +47,18 @@ export async function setupFileRouter(
|
|
|
49
47
|
lazyLoading: true,
|
|
50
48
|
});
|
|
51
49
|
|
|
52
|
-
// Scan routes from multiple locations:
|
|
53
|
-
// 1. App's pages directory (apps/alpine/src/pages)
|
|
54
|
-
// 2. SKLTN's pages directory (framework/skltn/src/pages) - for reusable auth pages
|
|
55
50
|
const routesToScan: string[] = [];
|
|
56
51
|
|
|
57
|
-
// App pages
|
|
52
|
+
// App pages directory
|
|
58
53
|
const appPagesDir = path.join(appRoot, "src", "pages");
|
|
59
54
|
try {
|
|
60
55
|
await fs.access(appPagesDir);
|
|
61
56
|
routesToScan.push(appPagesDir);
|
|
62
|
-
console.log(chalk.gray(`
|
|
57
|
+
console.log(chalk.gray(` Scanning app routes from ${appPagesDir}`));
|
|
63
58
|
} catch {
|
|
64
59
|
// pages directory doesn't exist, skip
|
|
65
60
|
}
|
|
66
61
|
|
|
67
|
-
// SKLTN pages (if workspace root exists)
|
|
68
|
-
if (workspaceRoot && workspaceRoot !== appRoot) {
|
|
69
|
-
// Try framework/skltn first (new location), then fallback to lib/skltn (legacy)
|
|
70
|
-
const skltnPagesDir = path.join(
|
|
71
|
-
workspaceRoot,
|
|
72
|
-
"framework",
|
|
73
|
-
"skltn",
|
|
74
|
-
"src",
|
|
75
|
-
"pages",
|
|
76
|
-
);
|
|
77
|
-
const legacySkltnPagesDir = path.join(
|
|
78
|
-
workspaceRoot,
|
|
79
|
-
"lib",
|
|
80
|
-
"skltn",
|
|
81
|
-
"src",
|
|
82
|
-
"pages",
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
await fs.access(skltnPagesDir);
|
|
87
|
-
routesToScan.push(skltnPagesDir);
|
|
88
|
-
console.log(
|
|
89
|
-
chalk.gray(` 📄 Scanning SKLTN routes from ${skltnPagesDir}`),
|
|
90
|
-
);
|
|
91
|
-
} catch {
|
|
92
|
-
// Try legacy location
|
|
93
|
-
try {
|
|
94
|
-
await fs.access(legacySkltnPagesDir);
|
|
95
|
-
routesToScan.push(legacySkltnPagesDir);
|
|
96
|
-
console.log(
|
|
97
|
-
chalk.gray(` 📄 Scanning SKLTN routes from ${legacySkltnPagesDir} (legacy)`),
|
|
98
|
-
);
|
|
99
|
-
} catch {
|
|
100
|
-
// pages directory doesn't exist, skip
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
62
|
// Scan all route directories
|
|
106
63
|
for (const pagesDir of routesToScan) {
|
|
107
64
|
try {
|