nuclie 1.0.0
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 -0
- package/README.md +516 -0
- package/dist/ai/analyzer.d.ts +29 -0
- package/dist/ai/analyzer.js +202 -0
- package/dist/ai/chat/cli.d.ts +3 -0
- package/dist/ai/chat/cli.js +38 -0
- package/dist/ai/client.d.ts +17 -0
- package/dist/ai/client.js +68 -0
- package/dist/ai/cloud/api.d.ts +28 -0
- package/dist/ai/cloud/api.js +118 -0
- package/dist/ai/cloud/modelSync.d.ts +18 -0
- package/dist/ai/cloud/modelSync.js +104 -0
- package/dist/ai/cloud/telemetry.d.ts +14 -0
- package/dist/ai/cloud/telemetry.js +23 -0
- package/dist/ai/config.d.ts +14 -0
- package/dist/ai/config.js +9 -0
- package/dist/ai/core/errorMemory.d.ts +14 -0
- package/dist/ai/core/errorMemory.js +36 -0
- package/dist/ai/dashboard/cli.d.ts +3 -0
- package/dist/ai/dashboard/cli.js +32 -0
- package/dist/ai/healer/applier.d.ts +9 -0
- package/dist/ai/healer/applier.js +74 -0
- package/dist/ai/healer/cli.d.ts +3 -0
- package/dist/ai/healer/cli.js +57 -0
- package/dist/ai/healer/collector.d.ts +16 -0
- package/dist/ai/healer/collector.js +41 -0
- package/dist/ai/healer/fixer.d.ts +12 -0
- package/dist/ai/healer/fixer.js +40 -0
- package/dist/ai/healer/llm.d.ts +9 -0
- package/dist/ai/healer/llm.js +20 -0
- package/dist/ai/healer/parser.d.ts +16 -0
- package/dist/ai/healer/parser.js +67 -0
- package/dist/ai/learning/evolver.d.ts +8 -0
- package/dist/ai/learning/evolver.js +24 -0
- package/dist/ai/llm/fixGenerator.d.ts +9 -0
- package/dist/ai/llm/fixGenerator.js +21 -0
- package/dist/ai/llm/ollama.d.ts +10 -0
- package/dist/ai/llm/ollama.js +56 -0
- package/dist/ai/local/fixStore.d.ts +19 -0
- package/dist/ai/local/fixStore.js +105 -0
- package/dist/ai/optimizer/analyzer.d.ts +9 -0
- package/dist/ai/optimizer/analyzer.js +65 -0
- package/dist/ai/optimizer/engine.d.ts +16 -0
- package/dist/ai/optimizer/engine.js +51 -0
- package/dist/ai/optimizer/llm.d.ts +8 -0
- package/dist/ai/optimizer/llm.js +14 -0
- package/dist/ai/optimizer/profiler.d.ts +11 -0
- package/dist/ai/optimizer/profiler.js +111 -0
- package/dist/ai/optimizer/rules.d.ts +12 -0
- package/dist/ai/optimizer/rules.js +37 -0
- package/dist/ai/patterns/common.d.ts +8 -0
- package/dist/ai/patterns/common.js +181 -0
- package/dist/ai/reporter/assembler.d.ts +11 -0
- package/dist/ai/reporter/assembler.js +10 -0
- package/dist/ai/reporter/generator.d.ts +4 -0
- package/dist/ai/reporter/generator.js +42 -0
- package/dist/ai/reporter/narrator.d.ts +8 -0
- package/dist/ai/reporter/narrator.js +29 -0
- package/dist/ai/schema.d.ts +104 -0
- package/dist/ai/schema.js +45 -0
- package/dist/ai/telemetry.d.ts +14 -0
- package/dist/ai/telemetry.js +96 -0
- package/dist/audit/a11y.d.ts +5 -0
- package/dist/audit/a11y.js +123 -0
- package/dist/audit/best-practices.d.ts +5 -0
- package/dist/audit/best-practices.js +68 -0
- package/dist/audit/build-integration.d.ts +59 -0
- package/dist/audit/build-integration.js +138 -0
- package/dist/audit/core.d.ts +62 -0
- package/dist/audit/core.js +327 -0
- package/dist/audit/index.d.ts +4 -0
- package/dist/audit/index.js +60 -0
- package/dist/audit/perf.d.ts +5 -0
- package/dist/audit/perf.js +69 -0
- package/dist/audit/seo.d.ts +5 -0
- package/dist/audit/seo.js +63 -0
- package/dist/audit/types.d.ts +35 -0
- package/dist/audit/types.js +1 -0
- package/dist/audit-stub/types.d.ts +25 -0
- package/dist/audit-stub/types.js +1 -0
- package/dist/build/bundle-stats.d.ts +2 -0
- package/dist/build/bundle-stats.js +42 -0
- package/dist/build/bundler.d.ts +46 -0
- package/dist/build/bundler.js +31 -0
- package/dist/build/index.d.ts +36 -0
- package/dist/build/index.js +69 -0
- package/dist/build/pipeline.d.ts +31 -0
- package/dist/build/pipeline.js +68 -0
- package/dist/builder/server.d.ts +11 -0
- package/dist/builder/server.js +253 -0
- package/dist/cache/incremental.d.ts +75 -0
- package/dist/cache/incremental.js +200 -0
- package/dist/cache/index.d.ts +17 -0
- package/dist/cache/index.js +186 -0
- package/dist/cache/rocksdb.d.ts +18 -0
- package/dist/cache/rocksdb.js +63 -0
- package/dist/cli/css-cli.d.ts +5 -0
- package/dist/cli/css-cli.js +112 -0
- package/dist/cli/inspect.d.ts +1 -0
- package/dist/cli/inspect.js +94 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +586 -0
- package/dist/commands/analyze.d.ts +1 -0
- package/dist/commands/analyze.js +295 -0
- package/dist/commands/doctor.d.ts +21 -0
- package/dist/commands/doctor.js +364 -0
- package/dist/commands/ssr.d.ts +12 -0
- package/dist/commands/ssr.js +30 -0
- package/dist/commands/verify.d.ts +38 -0
- package/dist/commands/verify.js +459 -0
- package/dist/config/index.d.ts +145 -0
- package/dist/config/index.js +227 -0
- package/dist/config/live-config.d.ts +22 -0
- package/dist/config/live-config.js +88 -0
- package/dist/core/__tests__/permissions.test.d.ts +1 -0
- package/dist/core/__tests__/permissions.test.js +16 -0
- package/dist/core/__tests__/universal-transformer.test.d.ts +1 -0
- package/dist/core/__tests__/universal-transformer.test.js +27 -0
- package/dist/core/build/globalOptimizer.d.ts +8 -0
- package/dist/core/build/globalOptimizer.js +21 -0
- package/dist/core/build/incremental.d.ts +13 -0
- package/dist/core/build/incremental.js +29 -0
- package/dist/core/bundler-rolldown.d.ts +42 -0
- package/dist/core/bundler-rolldown.js +100 -0
- package/dist/core/cache/lazy-init.d.ts +50 -0
- package/dist/core/cache/lazy-init.js +153 -0
- package/dist/core/cache-manager.d.ts +51 -0
- package/dist/core/cache-manager.js +149 -0
- package/dist/core/css/engine.d.ts +37 -0
- package/dist/core/css/engine.js +113 -0
- package/dist/core/css-framework-detector.d.ts +10 -0
- package/dist/core/css-framework-detector.js +169 -0
- package/dist/core/detection/files.d.ts +2 -0
- package/dist/core/detection/files.js +77 -0
- package/dist/core/detection/index.d.ts +8 -0
- package/dist/core/detection/index.js +39 -0
- package/dist/core/detection/resolver.d.ts +2 -0
- package/dist/core/detection/resolver.js +116 -0
- package/dist/core/detection/scanner.d.ts +4 -0
- package/dist/core/detection/scanner.js +145 -0
- package/dist/core/detection/types.d.ts +33 -0
- package/dist/core/detection/types.js +12 -0
- package/dist/core/engine/cache.d.ts +18 -0
- package/dist/core/engine/cache.js +72 -0
- package/dist/core/engine/config.d.ts +11 -0
- package/dist/core/engine/config.js +158 -0
- package/dist/core/engine/emit.d.ts +8 -0
- package/dist/core/engine/emit.js +60 -0
- package/dist/core/engine/events.d.ts +13 -0
- package/dist/core/engine/events.js +35 -0
- package/dist/core/engine/execute.d.ts +5 -0
- package/dist/core/engine/execute.js +226 -0
- package/dist/core/engine/hash.d.ts +8 -0
- package/dist/core/engine/hash.js +39 -0
- package/dist/core/engine/index.d.ts +49 -0
- package/dist/core/engine/index.js +156 -0
- package/dist/core/engine/optimize.d.ts +2 -0
- package/dist/core/engine/optimize.js +99 -0
- package/dist/core/engine/plan.d.ts +9 -0
- package/dist/core/engine/plan.js +196 -0
- package/dist/core/engine/types.d.ts +120 -0
- package/dist/core/engine/types.js +1 -0
- package/dist/core/errors/hero-errors.d.ts +57 -0
- package/dist/core/errors/hero-errors.js +269 -0
- package/dist/core/framework-detector.d.ts +20 -0
- package/dist/core/framework-detector.js +148 -0
- package/dist/core/graph/js-graph-analyzer.d.ts +51 -0
- package/dist/core/graph/js-graph-analyzer.js +178 -0
- package/dist/core/graph/serializer.d.ts +7 -0
- package/dist/core/graph/serializer.js +24 -0
- package/dist/core/interop/analyze.d.ts +8 -0
- package/dist/core/interop/analyze.js +82 -0
- package/dist/core/interop/analyze_ast.d.ts +9 -0
- package/dist/core/interop/analyze_ast.js +174 -0
- package/dist/core/interop/index.d.ts +19 -0
- package/dist/core/interop/index.js +36 -0
- package/dist/core/interop/resolve.d.ts +9 -0
- package/dist/core/interop/resolve.js +55 -0
- package/dist/core/interop/types.d.ts +28 -0
- package/dist/core/interop/types.js +2 -0
- package/dist/core/interop/wrapper.d.ts +11 -0
- package/dist/core/interop/wrapper.js +50 -0
- package/dist/core/parser-bun.d.ts +54 -0
- package/dist/core/parser-bun.js +86 -0
- package/dist/core/permissions.d.ts +16 -0
- package/dist/core/permissions.js +47 -0
- package/dist/core/pipeline/framework-pipeline.d.ts +71 -0
- package/dist/core/pipeline/framework-pipeline.js +113 -0
- package/dist/core/plugins/index.d.ts +5 -0
- package/dist/core/plugins/index.js +5 -0
- package/dist/core/plugins/manager.d.ts +30 -0
- package/dist/core/plugins/manager.js +123 -0
- package/dist/core/plugins/sandbox_js.d.ts +9 -0
- package/dist/core/plugins/sandbox_js.js +37 -0
- package/dist/core/plugins/sandbox_wasm.d.ts +10 -0
- package/dist/core/plugins/sandbox_wasm.js +68 -0
- package/dist/core/plugins/types.d.ts +37 -0
- package/dist/core/plugins/types.js +2 -0
- package/dist/core/plugins/validation.d.ts +8 -0
- package/dist/core/plugins/validation.js +30 -0
- package/dist/core/sandbox.d.ts +9 -0
- package/dist/core/sandbox.js +79 -0
- package/dist/core/steps/css-optimization.d.ts +65 -0
- package/dist/core/steps/css-optimization.js +318 -0
- package/dist/core/steps.d.ts +7 -0
- package/dist/core/steps.js +17 -0
- package/dist/core/transform/batchTransformer.d.ts +12 -0
- package/dist/core/transform/batchTransformer.js +24 -0
- package/dist/core/transform/transformer.d.ts +9 -0
- package/dist/core/transform/transformer.js +189 -0
- package/dist/core/universal-transformer.d.ts +81 -0
- package/dist/core/universal-transformer.js +780 -0
- package/dist/create/index.d.ts +25 -0
- package/dist/create/index.js +584 -0
- package/dist/create/ui.d.ts +13 -0
- package/dist/create/ui.js +218 -0
- package/dist/create-nuclie/cli.d.ts +7 -0
- package/dist/create-nuclie/cli.js +73 -0
- package/dist/create-nuclie/templates.d.ts +18 -0
- package/dist/create-nuclie/templates.js +73 -0
- package/dist/create-nuclie.d.ts +2 -0
- package/dist/create-nuclie.js +7 -0
- package/dist/dashboard/metrics.d.ts +31 -0
- package/dist/dashboard/metrics.js +59 -0
- package/dist/dashboard/server/router.d.ts +52 -0
- package/dist/dashboard/server/router.js +36 -0
- package/dist/dev/__tests__/preBundler.test.d.ts +1 -0
- package/dist/dev/__tests__/preBundler.test.js +51 -0
- package/dist/dev/configWatcher.d.ts +10 -0
- package/dist/dev/configWatcher.js +42 -0
- package/dist/dev/devServer.d.ts +2 -0
- package/dist/dev/devServer.js +1398 -0
- package/dist/dev/devServer.minimal.d.ts +8 -0
- package/dist/dev/devServer.minimal.js +122 -0
- package/dist/dev/federation-dev.d.ts +14 -0
- package/dist/dev/federation-dev.js +69 -0
- package/dist/dev/hmr-engine.d.ts +12 -0
- package/dist/dev/hmr-engine.js +66 -0
- package/dist/dev/hmr-v2.d.ts +40 -0
- package/dist/dev/hmr-v2.js +87 -0
- package/dist/dev/hmrThrottle.d.ts +13 -0
- package/dist/dev/hmrThrottle.js +56 -0
- package/dist/dev/overlay/overlay-client.d.ts +7 -0
- package/dist/dev/overlay/overlay-client.js +53 -0
- package/dist/dev/overlay/overlay-ui.d.ts +17 -0
- package/dist/dev/overlay/overlay-ui.js +133 -0
- package/dist/dev/preBundler.d.ts +17 -0
- package/dist/dev/preBundler.js +343 -0
- package/dist/dev/statusHandler.d.ts +11 -0
- package/dist/dev/statusHandler.js +44 -0
- package/dist/dev/types.d.ts +30 -0
- package/dist/dev/types.js +1 -0
- package/dist/dev/watcher.d.ts +11 -0
- package/dist/dev/watcher.js +40 -0
- package/dist/dev-server-manual.d.ts +5 -0
- package/dist/dev-server-manual.js +24 -0
- package/dist/dev-server.d.ts +25 -0
- package/dist/dev-server.js +255 -0
- package/dist/env/api.d.ts +27 -0
- package/dist/env/api.js +36 -0
- package/dist/fix/ast-transforms.d.ts +81 -0
- package/dist/fix/ast-transforms.js +449 -0
- package/dist/hmr/classifier.d.ts +51 -0
- package/dist/hmr/classifier.js +232 -0
- package/dist/hmr/index.d.ts +5 -0
- package/dist/hmr/index.js +5 -0
- package/dist/hmr/overlay.d.ts +39 -0
- package/dist/hmr/overlay.js +285 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +57 -0
- package/dist/init/bootstrap.d.ts +1 -0
- package/dist/init/bootstrap.js +106 -0
- package/dist/init/index.d.ts +1 -0
- package/dist/init/index.js +74 -0
- package/dist/init/templates.d.ts +2 -0
- package/dist/init/templates.js +227 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +3 -0
- package/dist/marketplace/client.d.ts +25 -0
- package/dist/marketplace/client.js +73 -0
- package/dist/marketplace/db.d.ts +24 -0
- package/dist/marketplace/db.js +57 -0
- package/dist/marketplace/plugin-adapter.d.ts +14 -0
- package/dist/marketplace/plugin-adapter.js +85 -0
- package/dist/marketplace/server.d.ts +66 -0
- package/dist/marketplace/server.js +97 -0
- package/dist/meta-frameworks/base-router.d.ts +63 -0
- package/dist/meta-frameworks/base-router.js +259 -0
- package/dist/meta-frameworks/index.d.ts +8 -0
- package/dist/meta-frameworks/index.js +8 -0
- package/dist/meta-frameworks/nextjs/router.d.ts +35 -0
- package/dist/meta-frameworks/nextjs/router.js +176 -0
- package/dist/meta-frameworks/nuxt/router.d.ts +22 -0
- package/dist/meta-frameworks/nuxt/router.js +84 -0
- package/dist/meta-frameworks/remix/router.d.ts +28 -0
- package/dist/meta-frameworks/remix/router.js +136 -0
- package/dist/meta-frameworks/ssr/react-renderer.d.ts +24 -0
- package/dist/meta-frameworks/ssr/react-renderer.js +53 -0
- package/dist/meta-frameworks/ssr/server.d.ts +92 -0
- package/dist/meta-frameworks/ssr/server.js +312 -0
- package/dist/meta-frameworks/ssr/vue-renderer.d.ts +11 -0
- package/dist/meta-frameworks/ssr/vue-renderer.js +35 -0
- package/dist/meta-frameworks/types.d.ts +76 -0
- package/dist/meta-frameworks/types.js +5 -0
- package/dist/migrate/analyzer.d.ts +46 -0
- package/dist/migrate/analyzer.js +254 -0
- package/dist/migrate/cli.d.ts +10 -0
- package/dist/migrate/cli.js +63 -0
- package/dist/migrate/generator.d.ts +32 -0
- package/dist/migrate/generator.js +214 -0
- package/dist/native/cache.d.ts +86 -0
- package/dist/native/cache.js +154 -0
- package/dist/native/index.d.ts +4 -0
- package/dist/native/index.js +56 -0
- package/dist/native/orchestrator.d.ts +78 -0
- package/dist/native/orchestrator.js +107 -0
- package/dist/native/wasm.d.ts +22 -0
- package/dist/native/wasm.js +33 -0
- package/dist/nuclie_native.node +0 -0
- package/dist/plugins/assets.d.ts +2 -0
- package/dist/plugins/assets.js +50 -0
- package/dist/plugins/compat/adapter.d.ts +33 -0
- package/dist/plugins/compat/adapter.js +102 -0
- package/dist/plugins/compat/deferred.d.ts +17 -0
- package/dist/plugins/compat/deferred.js +28 -0
- package/dist/plugins/compat/index.d.ts +11 -0
- package/dist/plugins/compat/index.js +11 -0
- package/dist/plugins/compat/rollup.d.ts +19 -0
- package/dist/plugins/compat/rollup.js +76 -0
- package/dist/plugins/compat/tier-a.d.ts +60 -0
- package/dist/plugins/compat/tier-a.js +132 -0
- package/dist/plugins/compat/tier-b.d.ts +34 -0
- package/dist/plugins/compat/tier-b.js +90 -0
- package/dist/plugins/compat/tier-c.d.ts +48 -0
- package/dist/plugins/compat/tier-c.js +49 -0
- package/dist/plugins/compat/webpack.d.ts +26 -0
- package/dist/plugins/compat/webpack.js +77 -0
- package/dist/plugins/core/linker.d.ts +8 -0
- package/dist/plugins/core/linker.js +51 -0
- package/dist/plugins/css/bootstrap.d.ts +25 -0
- package/dist/plugins/css/bootstrap.js +110 -0
- package/dist/plugins/css/bulma.d.ts +23 -0
- package/dist/plugins/css/bulma.js +75 -0
- package/dist/plugins/css/css-modules.d.ts +19 -0
- package/dist/plugins/css/css-modules.js +96 -0
- package/dist/plugins/css/css-optimizer.d.ts +43 -0
- package/dist/plugins/css/css-optimizer.js +155 -0
- package/dist/plugins/css/emotion.d.ts +35 -0
- package/dist/plugins/css/emotion.js +109 -0
- package/dist/plugins/css/less.d.ts +6 -0
- package/dist/plugins/css/less.js +33 -0
- package/dist/plugins/css/material.d.ts +24 -0
- package/dist/plugins/css/material.js +97 -0
- package/dist/plugins/css/postcss.d.ts +2 -0
- package/dist/plugins/css/postcss.js +96 -0
- package/dist/plugins/css/sass.d.ts +6 -0
- package/dist/plugins/css/sass.js +36 -0
- package/dist/plugins/css/styled-components.d.ts +33 -0
- package/dist/plugins/css/styled-components.js +94 -0
- package/dist/plugins/css/stylus.d.ts +6 -0
- package/dist/plugins/css/stylus.js +41 -0
- package/dist/plugins/css/tailwind.d.ts +9 -0
- package/dist/plugins/css/tailwind.js +132 -0
- package/dist/plugins/css-in-js.d.ts +10 -0
- package/dist/plugins/css-in-js.js +24 -0
- package/dist/plugins/edge.d.ts +7 -0
- package/dist/plugins/edge.js +38 -0
- package/dist/plugins/esbuildAdapter.d.ts +3 -0
- package/dist/plugins/esbuildAdapter.js +77 -0
- package/dist/plugins/federation_next.d.ts +16 -0
- package/dist/plugins/federation_next.js +78 -0
- package/dist/plugins/framework-plugins.d.ts +3 -0
- package/dist/plugins/framework-plugins.js +40 -0
- package/dist/plugins/frameworks/index.d.ts +8 -0
- package/dist/plugins/frameworks/index.js +10 -0
- package/dist/plugins/frameworks/lit.d.ts +36 -0
- package/dist/plugins/frameworks/lit.js +114 -0
- package/dist/plugins/frameworks/react.d.ts +38 -0
- package/dist/plugins/frameworks/react.js +144 -0
- package/dist/plugins/frameworks/solid.d.ts +36 -0
- package/dist/plugins/frameworks/solid.js +108 -0
- package/dist/plugins/frameworks/svelte.d.ts +43 -0
- package/dist/plugins/frameworks/svelte.js +144 -0
- package/dist/plugins/frameworks/vue.d.ts +43 -0
- package/dist/plugins/frameworks/vue.js +240 -0
- package/dist/plugins/governance.d.ts +36 -0
- package/dist/plugins/governance.js +50 -0
- package/dist/plugins/html.d.ts +2 -0
- package/dist/plugins/html.js +49 -0
- package/dist/plugins/implementations/analytics.d.ts +7 -0
- package/dist/plugins/implementations/analytics.js +15 -0
- package/dist/plugins/implementations/apollo.d.ts +7 -0
- package/dist/plugins/implementations/apollo.js +15 -0
- package/dist/plugins/implementations/audit.d.ts +7 -0
- package/dist/plugins/implementations/audit.js +30 -0
- package/dist/plugins/implementations/auto-fix.d.ts +7 -0
- package/dist/plugins/implementations/auto-fix.js +15 -0
- package/dist/plugins/implementations/avif.d.ts +7 -0
- package/dist/plugins/implementations/avif.js +27 -0
- package/dist/plugins/implementations/babel.d.ts +7 -0
- package/dist/plugins/implementations/babel.js +15 -0
- package/dist/plugins/implementations/bundle-analyzer.d.ts +7 -0
- package/dist/plugins/implementations/bundle-analyzer.js +21 -0
- package/dist/plugins/implementations/bundle-size.d.ts +7 -0
- package/dist/plugins/implementations/bundle-size.js +21 -0
- package/dist/plugins/implementations/checker.d.ts +7 -0
- package/dist/plugins/implementations/checker.js +15 -0
- package/dist/plugins/implementations/chromatic.d.ts +7 -0
- package/dist/plugins/implementations/chromatic.js +15 -0
- package/dist/plugins/implementations/cloudflare.d.ts +7 -0
- package/dist/plugins/implementations/cloudflare.js +15 -0
- package/dist/plugins/implementations/code-split.d.ts +7 -0
- package/dist/plugins/implementations/code-split.js +21 -0
- package/dist/plugins/implementations/compression.d.ts +7 -0
- package/dist/plugins/implementations/compression.js +21 -0
- package/dist/plugins/implementations/copy.d.ts +7 -0
- package/dist/plugins/implementations/copy.js +15 -0
- package/dist/plugins/implementations/critical-css.d.ts +7 -0
- package/dist/plugins/implementations/critical-css.js +25 -0
- package/dist/plugins/implementations/crypto-sign.d.ts +7 -0
- package/dist/plugins/implementations/crypto-sign.js +30 -0
- package/dist/plugins/implementations/css-framework.d.ts +7 -0
- package/dist/plugins/implementations/css-framework.js +25 -0
- package/dist/plugins/implementations/css.d.ts +7 -0
- package/dist/plugins/implementations/css.js +25 -0
- package/dist/plugins/implementations/cypress.d.ts +7 -0
- package/dist/plugins/implementations/cypress.js +15 -0
- package/dist/plugins/implementations/determinism.d.ts +7 -0
- package/dist/plugins/implementations/determinism.js +21 -0
- package/dist/plugins/implementations/edge.d.ts +8 -0
- package/dist/plugins/implementations/edge.js +35 -0
- package/dist/plugins/implementations/env-validation.d.ts +7 -0
- package/dist/plugins/implementations/env-validation.js +30 -0
- package/dist/plugins/implementations/eslint.d.ts +7 -0
- package/dist/plugins/implementations/eslint.js +15 -0
- package/dist/plugins/implementations/federation.d.ts +7 -0
- package/dist/plugins/implementations/federation.js +15 -0
- package/dist/plugins/implementations/file.d.ts +7 -0
- package/dist/plugins/implementations/file.js +27 -0
- package/dist/plugins/implementations/font-subset.d.ts +7 -0
- package/dist/plugins/implementations/font-subset.js +27 -0
- package/dist/plugins/implementations/fonts.d.ts +7 -0
- package/dist/plugins/implementations/fonts.js +27 -0
- package/dist/plugins/implementations/formatjs.d.ts +7 -0
- package/dist/plugins/implementations/formatjs.js +18 -0
- package/dist/plugins/implementations/graphql.d.ts +7 -0
- package/dist/plugins/implementations/graphql.js +15 -0
- package/dist/plugins/implementations/hmr-classify.d.ts +7 -0
- package/dist/plugins/implementations/hmr-classify.js +21 -0
- package/dist/plugins/implementations/html.d.ts +7 -0
- package/dist/plugins/implementations/html.js +15 -0
- package/dist/plugins/implementations/i18n.d.ts +7 -0
- package/dist/plugins/implementations/i18n.js +15 -0
- package/dist/plugins/implementations/icon.d.ts +7 -0
- package/dist/plugins/implementations/icon.js +27 -0
- package/dist/plugins/implementations/imagemin.d.ts +7 -0
- package/dist/plugins/implementations/imagemin.js +27 -0
- package/dist/plugins/implementations/inspect.d.ts +7 -0
- package/dist/plugins/implementations/inspect.js +15 -0
- package/dist/plugins/implementations/jest.d.ts +7 -0
- package/dist/plugins/implementations/jest.js +19 -0
- package/dist/plugins/implementations/jotai.d.ts +8 -0
- package/dist/plugins/implementations/jotai.js +35 -0
- package/dist/plugins/implementations/lazy-load.d.ts +7 -0
- package/dist/plugins/implementations/lazy-load.js +21 -0
- package/dist/plugins/implementations/legacy.d.ts +7 -0
- package/dist/plugins/implementations/legacy.js +15 -0
- package/dist/plugins/implementations/lighthouse.d.ts +7 -0
- package/dist/plugins/implementations/lighthouse.js +21 -0
- package/dist/plugins/implementations/manifest.d.ts +7 -0
- package/dist/plugins/implementations/manifest.js +15 -0
- package/dist/plugins/implementations/markdown.d.ts +7 -0
- package/dist/plugins/implementations/markdown.js +15 -0
- package/dist/plugins/implementations/md.d.ts +7 -0
- package/dist/plugins/implementations/md.js +15 -0
- package/dist/plugins/implementations/mdx.d.ts +7 -0
- package/dist/plugins/implementations/mdx.js +15 -0
- package/dist/plugins/implementations/meta-tags.d.ts +7 -0
- package/dist/plugins/implementations/meta-tags.js +15 -0
- package/dist/plugins/implementations/mini-css-extract-plugin.d.ts +7 -0
- package/dist/plugins/implementations/mini-css-extract-plugin.js +25 -0
- package/dist/plugins/implementations/mobx.d.ts +8 -0
- package/dist/plugins/implementations/mobx.js +35 -0
- package/dist/plugins/implementations/mock.d.ts +7 -0
- package/dist/plugins/implementations/mock.js +15 -0
- package/dist/plugins/implementations/msw.d.ts +7 -0
- package/dist/plugins/implementations/msw.js +19 -0
- package/dist/plugins/implementations/nanostores.d.ts +7 -0
- package/dist/plugins/implementations/nanostores.js +18 -0
- package/dist/plugins/implementations/netlify.d.ts +7 -0
- package/dist/plugins/implementations/netlify.js +15 -0
- package/dist/plugins/implementations/observability.d.ts +7 -0
- package/dist/plugins/implementations/observability.js +15 -0
- package/dist/plugins/implementations/og-image.d.ts +7 -0
- package/dist/plugins/implementations/og-image.js +15 -0
- package/dist/plugins/implementations/pages.d.ts +7 -0
- package/dist/plugins/implementations/pages.js +15 -0
- package/dist/plugins/implementations/pinia.d.ts +8 -0
- package/dist/plugins/implementations/pinia.js +35 -0
- package/dist/plugins/implementations/plausible.d.ts +7 -0
- package/dist/plugins/implementations/plausible.js +18 -0
- package/dist/plugins/implementations/playwright.d.ts +7 -0
- package/dist/plugins/implementations/playwright.js +15 -0
- package/dist/plugins/implementations/postcss.d.ts +7 -0
- package/dist/plugins/implementations/postcss.js +25 -0
- package/dist/plugins/implementations/posthog.d.ts +7 -0
- package/dist/plugins/implementations/posthog.js +18 -0
- package/dist/plugins/implementations/prebundle.d.ts +7 -0
- package/dist/plugins/implementations/prebundle.js +21 -0
- package/dist/plugins/implementations/prefetch.d.ts +7 -0
- package/dist/plugins/implementations/prefetch.js +21 -0
- package/dist/plugins/implementations/preload.d.ts +7 -0
- package/dist/plugins/implementations/preload.js +21 -0
- package/dist/plugins/implementations/prisma.d.ts +7 -0
- package/dist/plugins/implementations/prisma.js +15 -0
- package/dist/plugins/implementations/pwa.d.ts +7 -0
- package/dist/plugins/implementations/pwa.js +15 -0
- package/dist/plugins/implementations/qr-code.d.ts +7 -0
- package/dist/plugins/implementations/qr-code.js +19 -0
- package/dist/plugins/implementations/razorpay.d.ts +7 -0
- package/dist/plugins/implementations/razorpay.js +19 -0
- package/dist/plugins/implementations/react-i18next.d.ts +7 -0
- package/dist/plugins/implementations/react-i18next.js +18 -0
- package/dist/plugins/implementations/react-query.d.ts +8 -0
- package/dist/plugins/implementations/react-query.js +35 -0
- package/dist/plugins/implementations/react.d.ts +8 -0
- package/dist/plugins/implementations/react.js +35 -0
- package/dist/plugins/implementations/recoil.d.ts +8 -0
- package/dist/plugins/implementations/recoil.js +35 -0
- package/dist/plugins/implementations/redux.d.ts +8 -0
- package/dist/plugins/implementations/redux.js +35 -0
- package/dist/plugins/implementations/relay.d.ts +7 -0
- package/dist/plugins/implementations/relay.js +15 -0
- package/dist/plugins/implementations/repro.d.ts +7 -0
- package/dist/plugins/implementations/repro.js +15 -0
- package/dist/plugins/implementations/robots.d.ts +7 -0
- package/dist/plugins/implementations/robots.js +15 -0
- package/dist/plugins/implementations/root-cause.d.ts +7 -0
- package/dist/plugins/implementations/root-cause.js +15 -0
- package/dist/plugins/implementations/rss.d.ts +7 -0
- package/dist/plugins/implementations/rss.js +15 -0
- package/dist/plugins/implementations/sass.d.ts +7 -0
- package/dist/plugins/implementations/sass.js +25 -0
- package/dist/plugins/implementations/sentry.d.ts +7 -0
- package/dist/plugins/implementations/sentry.js +15 -0
- package/dist/plugins/implementations/sitemap.d.ts +7 -0
- package/dist/plugins/implementations/sitemap.js +15 -0
- package/dist/plugins/implementations/solid.d.ts +8 -0
- package/dist/plugins/implementations/solid.js +35 -0
- package/dist/plugins/implementations/sprite.d.ts +7 -0
- package/dist/plugins/implementations/sprite.js +27 -0
- package/dist/plugins/implementations/ssr.d.ts +8 -0
- package/dist/plugins/implementations/ssr.js +35 -0
- package/dist/plugins/implementations/storybook.d.ts +7 -0
- package/dist/plugins/implementations/storybook.js +15 -0
- package/dist/plugins/implementations/stripe.d.ts +7 -0
- package/dist/plugins/implementations/stripe.js +19 -0
- package/dist/plugins/implementations/style.d.ts +7 -0
- package/dist/plugins/implementations/style.js +25 -0
- package/dist/plugins/implementations/svelte.d.ts +8 -0
- package/dist/plugins/implementations/svelte.js +35 -0
- package/dist/plugins/implementations/tailwind.d.ts +7 -0
- package/dist/plugins/implementations/tailwind.js +25 -0
- package/dist/plugins/implementations/tanstack-query.d.ts +7 -0
- package/dist/plugins/implementations/tanstack-query.js +18 -0
- package/dist/plugins/implementations/terser.d.ts +7 -0
- package/dist/plugins/implementations/terser.js +21 -0
- package/dist/plugins/implementations/testing-library-react.d.ts +7 -0
- package/dist/plugins/implementations/testing-library-react.js +19 -0
- package/dist/plugins/implementations/testing-library.d.ts +7 -0
- package/dist/plugins/implementations/testing-library.js +15 -0
- package/dist/plugins/implementations/tree-shake.d.ts +7 -0
- package/dist/plugins/implementations/tree-shake.js +21 -0
- package/dist/plugins/implementations/trpc.d.ts +7 -0
- package/dist/plugins/implementations/trpc.js +15 -0
- package/dist/plugins/implementations/ts.d.ts +7 -0
- package/dist/plugins/implementations/ts.js +15 -0
- package/dist/plugins/implementations/typescript.d.ts +7 -0
- package/dist/plugins/implementations/typescript.js +15 -0
- package/dist/plugins/implementations/unocss.d.ts +7 -0
- package/dist/plugins/implementations/unocss.js +25 -0
- package/dist/plugins/implementations/upi-payment.d.ts +7 -0
- package/dist/plugins/implementations/upi-payment.js +19 -0
- package/dist/plugins/implementations/url.d.ts +7 -0
- package/dist/plugins/implementations/url.js +27 -0
- package/dist/plugins/implementations/vercel.d.ts +7 -0
- package/dist/plugins/implementations/vercel.js +15 -0
- package/dist/plugins/implementations/visualizer.d.ts +7 -0
- package/dist/plugins/implementations/visualizer.js +15 -0
- package/dist/plugins/implementations/vite-svg-loader.d.ts +7 -0
- package/dist/plugins/implementations/vite-svg-loader.js +27 -0
- package/dist/plugins/implementations/vitest.d.ts +7 -0
- package/dist/plugins/implementations/vitest.js +15 -0
- package/dist/plugins/implementations/vue-i18n-next.d.ts +7 -0
- package/dist/plugins/implementations/vue-i18n-next.js +18 -0
- package/dist/plugins/implementations/vue-i18n.d.ts +7 -0
- package/dist/plugins/implementations/vue-i18n.js +15 -0
- package/dist/plugins/implementations/vue-layouts.d.ts +8 -0
- package/dist/plugins/implementations/vue-layouts.js +35 -0
- package/dist/plugins/implementations/vue.d.ts +8 -0
- package/dist/plugins/implementations/vue.js +35 -0
- package/dist/plugins/implementations/vuex.d.ts +8 -0
- package/dist/plugins/implementations/vuex.js +35 -0
- package/dist/plugins/implementations/wasm-sandbox.d.ts +7 -0
- package/dist/plugins/implementations/wasm-sandbox.js +30 -0
- package/dist/plugins/implementations/webp.d.ts +7 -0
- package/dist/plugins/implementations/webp.js +27 -0
- package/dist/plugins/implementations/windicss.d.ts +7 -0
- package/dist/plugins/implementations/windicss.js +25 -0
- package/dist/plugins/implementations/workbox.d.ts +7 -0
- package/dist/plugins/implementations/workbox.js +15 -0
- package/dist/plugins/implementations/xstate.d.ts +7 -0
- package/dist/plugins/implementations/xstate.js +18 -0
- package/dist/plugins/implementations/zod.d.ts +7 -0
- package/dist/plugins/implementations/zod.js +15 -0
- package/dist/plugins/implementations/zustand-devtools.d.ts +7 -0
- package/dist/plugins/implementations/zustand-devtools.js +18 -0
- package/dist/plugins/implementations/zustand.d.ts +8 -0
- package/dist/plugins/implementations/zustand.js +35 -0
- package/dist/plugins/index.d.ts +49 -0
- package/dist/plugins/index.js +117 -0
- package/dist/plugins/js-transform.d.ts +2 -0
- package/dist/plugins/js-transform.js +49 -0
- package/dist/plugins/json.d.ts +2 -0
- package/dist/plugins/json.js +34 -0
- package/dist/plugins/pluginWorker.mjs +95 -0
- package/dist/plugins/ported/adapter.d.ts +92 -0
- package/dist/plugins/ported/adapter.js +226 -0
- package/dist/plugins/registry.d.ts +51 -0
- package/dist/plugins/registry.js +151 -0
- package/dist/plugins/reporter.d.ts +5 -0
- package/dist/plugins/reporter.js +47 -0
- package/dist/plugins/samplePlugin.mjs +4 -0
- package/dist/plugins/sandbox.d.ts +12 -0
- package/dist/plugins/sandbox.js +126 -0
- package/dist/plugins/signer.d.ts +53 -0
- package/dist/plugins/signer.js +109 -0
- package/dist/plugins/static.d.ts +2 -0
- package/dist/plugins/static.js +47 -0
- package/dist/plugins/svelte.d.ts +7 -0
- package/dist/plugins/svelte.js +27 -0
- package/dist/plugins/testSandbox.d.ts +1 -0
- package/dist/plugins/testSandbox.js +14 -0
- package/dist/plugins/verify.d.ts +3 -0
- package/dist/plugins/verify.js +113 -0
- package/dist/plugins/vue.d.ts +7 -0
- package/dist/plugins/vue.js +86 -0
- package/dist/plugins/wasm-runtime.d.ts +15 -0
- package/dist/plugins/wasm-runtime.js +33 -0
- package/dist/plugins/wasm.d.ts +5 -0
- package/dist/plugins/wasm.js +44 -0
- package/dist/polyfills/corejs.d.ts +9 -0
- package/dist/polyfills/corejs.js +18 -0
- package/dist/presets/core.d.ts +111 -0
- package/dist/presets/core.js +239 -0
- package/dist/presets/frameworks.d.ts +34 -0
- package/dist/presets/frameworks.js +270 -0
- package/dist/presets/index.d.ts +8 -0
- package/dist/presets/index.js +3 -0
- package/dist/presets/infrastructure.d.ts +2 -0
- package/dist/presets/infrastructure.js +33 -0
- package/dist/presets/spa.d.ts +2 -0
- package/dist/presets/spa.js +15 -0
- package/dist/presets/ssg.d.ts +2 -0
- package/dist/presets/ssg.js +9 -0
- package/dist/presets/ssr.d.ts +2 -0
- package/dist/presets/ssr.js +13 -0
- package/dist/repro/dashboard.d.ts +83 -0
- package/dist/repro/dashboard.js +251 -0
- package/dist/repro/github.d.ts +26 -0
- package/dist/repro/github.js +73 -0
- package/dist/resolve/css-precedence.d.ts +16 -0
- package/dist/resolve/css-precedence.js +56 -0
- package/dist/resolve/graph.d.ts +48 -0
- package/dist/resolve/graph.js +232 -0
- package/dist/resolve/utils.d.ts +13 -0
- package/dist/resolve/utils.js +53 -0
- package/dist/runtime/client.d.ts +9 -0
- package/dist/runtime/client.js +218 -0
- package/dist/runtime/error-overlay.d.ts +15 -0
- package/dist/runtime/error-overlay.js +327 -0
- package/dist/runtime/federation-fallback.d.ts +67 -0
- package/dist/runtime/federation-fallback.js +225 -0
- package/dist/runtime/federation.d.ts +27 -0
- package/dist/runtime/federation.js +210 -0
- package/dist/runtime/federation_runtime.js +90 -0
- package/dist/runtime/hmr-client.d.ts +5 -0
- package/dist/runtime/hmr-client.js +70 -0
- package/dist/security/anomaly.d.ts +41 -0
- package/dist/security/anomaly.js +77 -0
- package/dist/server/security-headers.d.ts +37 -0
- package/dist/server/security-headers.js +110 -0
- package/dist/ssr/adapters/edge.d.ts +12 -0
- package/dist/ssr/adapters/edge.js +26 -0
- package/dist/ssr/adapters/index.d.ts +23 -0
- package/dist/ssr/adapters/index.js +58 -0
- package/dist/ssr/app-router.d.ts +24 -0
- package/dist/ssr/app-router.js +70 -0
- package/dist/ssr/edge/handlers.d.ts +24 -0
- package/dist/ssr/edge/handlers.js +48 -0
- package/dist/ssr/image.d.ts +24 -0
- package/dist/ssr/image.js +38 -0
- package/dist/ssr/isr.d.ts +14 -0
- package/dist/ssr/isr.js +29 -0
- package/dist/ssr/rsc.d.ts +19 -0
- package/dist/ssr/rsc.js +33 -0
- package/dist/ssr/streaming.d.ts +31 -0
- package/dist/ssr/streaming.js +78 -0
- package/dist/ssr/universal-engine.d.ts +36 -0
- package/dist/ssr/universal-engine.js +139 -0
- package/dist/templates/manager.d.ts +28 -0
- package/dist/templates/manager.js +162 -0
- package/dist/templates/starters/angular-spa.d.ts +6 -0
- package/dist/templates/starters/angular-spa.js +149 -0
- package/dist/templates/starters/edge.d.ts +6 -0
- package/dist/templates/starters/edge.js +93 -0
- package/dist/templates/starters/fintech.d.ts +6 -0
- package/dist/templates/starters/fintech.js +211 -0
- package/dist/templates/starters/monorepo.d.ts +6 -0
- package/dist/templates/starters/monorepo.js +133 -0
- package/dist/templates/starters/nextjs-app.d.ts +13 -0
- package/dist/templates/starters/nextjs-app.js +116 -0
- package/dist/templates/starters/preact-spa.d.ts +6 -0
- package/dist/templates/starters/preact-spa.js +97 -0
- package/dist/templates/starters/premium-dashboard.d.ts +6 -0
- package/dist/templates/starters/premium-dashboard.js +762 -0
- package/dist/templates/starters/react-spa.d.ts +6 -0
- package/dist/templates/starters/react-spa.js +152 -0
- package/dist/templates/starters/react-ssr.d.ts +6 -0
- package/dist/templates/starters/react-ssr.js +190 -0
- package/dist/templates/starters/remix-app.d.ts +12 -0
- package/dist/templates/starters/remix-app.js +108 -0
- package/dist/templates/starters/solid-spa.d.ts +6 -0
- package/dist/templates/starters/solid-spa.js +158 -0
- package/dist/templates/starters/svelte-spa.d.ts +6 -0
- package/dist/templates/starters/svelte-spa.js +147 -0
- package/dist/templates/starters/vue-spa.d.ts +6 -0
- package/dist/templates/starters/vue-spa.js +136 -0
- package/dist/test/api.d.ts +58 -0
- package/dist/test/api.js +154 -0
- package/dist/test/coverage.d.ts +1 -0
- package/dist/test/coverage.js +134 -0
- package/dist/test/determinism.d.ts +1 -0
- package/dist/test/determinism.js +122 -0
- package/dist/test/regression.d.ts +1 -0
- package/dist/test/regression.js +30 -0
- package/dist/test/runner.d.ts +1 -0
- package/dist/test/runner.js +159 -0
- package/dist/test-server.d.ts +1 -0
- package/dist/test-server.js +22 -0
- package/dist/ui/terminal-warnings.d.ts +10 -0
- package/dist/ui/terminal-warnings.js +26 -0
- package/dist/ui/types.d.ts +13 -0
- package/dist/ui/types.js +5 -0
- package/dist/ui/warning-detector.d.ts +46 -0
- package/dist/ui/warning-detector.js +178 -0
- package/dist/ui/warning-library.d.ts +51 -0
- package/dist/ui/warning-library.js +283 -0
- package/dist/utils/interactive.d.ts +2 -0
- package/dist/utils/interactive.js +37 -0
- package/dist/utils/logger.d.ts +26 -0
- package/dist/utils/logger.js +130 -0
- package/dist/utils/path-normalize.d.ts +24 -0
- package/dist/utils/path-normalize.js +37 -0
- package/dist/visual/chart-generator.d.ts +11 -0
- package/dist/visual/chart-generator.js +30 -0
- package/dist/visual/client/renderer.d.ts +31 -0
- package/dist/visual/client/renderer.js +98 -0
- package/dist/visual/federation-editor.d.ts +1 -0
- package/dist/visual/federation-editor.js +231 -0
- package/dist/visual/graph-engine.d.ts +38 -0
- package/dist/visual/graph-engine.js +64 -0
- package/dist/visual/graph-ui.d.ts +2 -0
- package/dist/visual/graph-ui.js +119 -0
- package/dist/visual/graph-visualizer.d.ts +69 -0
- package/dist/visual/graph-visualizer.js +282 -0
- package/dist/visual/root-cause.d.ts +83 -0
- package/dist/visual/root-cause.js +265 -0
- package/package.json +169 -0
|
@@ -0,0 +1,1398 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import { anomalyDetector } from '../security/anomaly.js';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { log } from '../utils/logger.js';
|
|
7
|
+
import { PluginManager } from '../plugins/index.js';
|
|
8
|
+
import { PluginSandbox } from '../core/sandbox.js';
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
// Load Native Worker
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
let NativeWorker;
|
|
14
|
+
try {
|
|
15
|
+
const candidates = [
|
|
16
|
+
path.resolve(__dirname, '../../nuclie_native.node'), // From src/dev/devServer.ts
|
|
17
|
+
path.resolve(__dirname, '../nuclie_native.node'), // From dist/dev/devServer.js
|
|
18
|
+
path.resolve(__dirname, './nuclie_native.node'), // From dist/
|
|
19
|
+
path.resolve(process.cwd(), 'nuclie_native.node'), // Root fallback
|
|
20
|
+
path.resolve(process.cwd(), 'dist/nuclie_native.node')
|
|
21
|
+
];
|
|
22
|
+
let pathFound = '';
|
|
23
|
+
for (const c of candidates) {
|
|
24
|
+
try {
|
|
25
|
+
if (require('fs').existsSync(c)) {
|
|
26
|
+
pathFound = c;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
}
|
|
32
|
+
if (!pathFound)
|
|
33
|
+
throw new Error('Native binary not found');
|
|
34
|
+
const nativeModule = require(pathFound);
|
|
35
|
+
NativeWorker = nativeModule.NativeWorker;
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
// Native worker not found or failed to load, will fallback to JS implementation
|
|
39
|
+
if (process.env.DEBUG)
|
|
40
|
+
log.debug('Native worker not found, using JS fallback');
|
|
41
|
+
// Mock Native Worker
|
|
42
|
+
NativeWorker = class {
|
|
43
|
+
constructor(workers) { }
|
|
44
|
+
processFile(filePath) { return null; }
|
|
45
|
+
invalidate(filePath) { }
|
|
46
|
+
rebuild(filePath) { return []; }
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
import { HMRThrottle } from './hmrThrottle.js';
|
|
50
|
+
import { ConfigWatcher } from './configWatcher.js';
|
|
51
|
+
import { StatusHandler } from './statusHandler.js';
|
|
52
|
+
import { LiveConfigManager } from '../config/live-config.js';
|
|
53
|
+
/**
|
|
54
|
+
* Rewrite bare module imports to node_modules paths
|
|
55
|
+
* Converts: import React from 'react'
|
|
56
|
+
* To: import React from '/node_modules/react/index.js'
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* Rewrite bare module imports to node_modules paths
|
|
60
|
+
* Production-grade AST-based rewriting (Phase C1 Honest)
|
|
61
|
+
*/
|
|
62
|
+
async function rewriteImports(code, rootDir, preBundledDeps) {
|
|
63
|
+
try {
|
|
64
|
+
const acorn = await import('acorn');
|
|
65
|
+
const ast = acorn.parse(code, {
|
|
66
|
+
sourceType: 'module',
|
|
67
|
+
ecmaVersion: 'latest'
|
|
68
|
+
});
|
|
69
|
+
const replacements = [];
|
|
70
|
+
const addReplacement = (node) => {
|
|
71
|
+
if (node && node.type === 'Literal' && typeof node.value === 'string') {
|
|
72
|
+
const specifier = node.value;
|
|
73
|
+
if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('http')) {
|
|
74
|
+
// Handle relative CSS/JSON
|
|
75
|
+
if (specifier.endsWith('.css') || specifier.endsWith('.json')) {
|
|
76
|
+
replacements.push({
|
|
77
|
+
start: node.start,
|
|
78
|
+
end: node.end,
|
|
79
|
+
replacement: `'${specifier}?import'`
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
let replacement = `/node_modules/${specifier}`;
|
|
85
|
+
if (preBundledDeps && preBundledDeps.has(specifier)) {
|
|
86
|
+
replacement = `${preBundledDeps.get(specifier)}?v=${Date.now()}`;
|
|
87
|
+
}
|
|
88
|
+
else if (preBundledDeps) {
|
|
89
|
+
// Subpath check
|
|
90
|
+
const parts = specifier.split('/');
|
|
91
|
+
const pkgName = specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
92
|
+
if (preBundledDeps.has(pkgName)) {
|
|
93
|
+
const safeName = specifier.replace(/\//g, '_');
|
|
94
|
+
replacement = `/@nuclie-deps/${safeName}.js?v=${Date.now()}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
replacements.push({
|
|
98
|
+
start: node.start,
|
|
99
|
+
end: node.end,
|
|
100
|
+
replacement: `'${replacement}'`
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
// Walk AST
|
|
105
|
+
for (const node of ast.body) {
|
|
106
|
+
if (node.type === 'ImportDeclaration') {
|
|
107
|
+
addReplacement(node.source);
|
|
108
|
+
}
|
|
109
|
+
else if (node.type === 'ExportNamedDeclaration' && node.source) {
|
|
110
|
+
addReplacement(node.source);
|
|
111
|
+
}
|
|
112
|
+
else if (node.type === 'ExportAllDeclaration' && node.source) {
|
|
113
|
+
addReplacement(node.source);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Sort replacements backwards to avoid offset issues
|
|
117
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
118
|
+
let output = code;
|
|
119
|
+
for (const { start, end, replacement } of replacements) {
|
|
120
|
+
output = output.slice(0, start) + replacement + output.slice(end);
|
|
121
|
+
}
|
|
122
|
+
return output;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
// If AST fails (e.g. non-JS content), return as is
|
|
126
|
+
return code;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if a port is available
|
|
131
|
+
*/
|
|
132
|
+
async function isPortAvailable(port, host) {
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
const server = http.createServer();
|
|
135
|
+
server.on('error', () => resolve(false));
|
|
136
|
+
server.listen(port, host, () => {
|
|
137
|
+
server.close(() => resolve(true));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Find the next available port
|
|
143
|
+
*/
|
|
144
|
+
async function findAvailablePort(startPort, host) {
|
|
145
|
+
let port = startPort;
|
|
146
|
+
while (!(await isPortAvailable(port, host))) {
|
|
147
|
+
log.warn(`Port ${port} is already in use, trying ${port + 1}...`, { category: 'server' });
|
|
148
|
+
port++;
|
|
149
|
+
if (port > startPort + 100) {
|
|
150
|
+
throw new Error(`Could not find an available port after ${port - startPort} attempts`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return port;
|
|
154
|
+
}
|
|
155
|
+
export async function startDevServer(cliCfg, existingServer) {
|
|
156
|
+
// 1. Load User Config (Phase S3 Correctness)
|
|
157
|
+
// Ensure we have the full config from disk, even if CLI passed a skeletal one
|
|
158
|
+
const { loadConfig } = await import('../config/index.js');
|
|
159
|
+
let cfg = cliCfg;
|
|
160
|
+
try {
|
|
161
|
+
const loaded = await loadConfig(cliCfg.root);
|
|
162
|
+
// Merge CLI overrides (cliCfg) over Disk Config (loaded)
|
|
163
|
+
// CLI args take precedence for port, mode, etc.
|
|
164
|
+
cfg = {
|
|
165
|
+
...loaded,
|
|
166
|
+
...cliCfg,
|
|
167
|
+
server: { ...loaded.server, ...cliCfg.server },
|
|
168
|
+
build: { ...loaded.build, ...cliCfg.build },
|
|
169
|
+
// Preserve plugins from both? Or just use loaded?
|
|
170
|
+
// Usually CLI doesn't pass plugins in skeletal mode.
|
|
171
|
+
plugins: loaded.plugins,
|
|
172
|
+
prebundle: loaded.prebundle
|
|
173
|
+
};
|
|
174
|
+
log.debug('Merged User Config with CLI arguments');
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
log.warn('Failed to load user config, using defaults: ' + e.message);
|
|
178
|
+
}
|
|
179
|
+
// 2. Load Environment Variables (silently)
|
|
180
|
+
try {
|
|
181
|
+
// Suppress dotenv's verbose output
|
|
182
|
+
const originalLog = console.log;
|
|
183
|
+
console.log = () => { }; // Silence console temporarily
|
|
184
|
+
const dotenvModule = await import('dotenv');
|
|
185
|
+
const loadEnv = dotenvModule.config || dotenvModule.default?.config;
|
|
186
|
+
if (loadEnv) {
|
|
187
|
+
loadEnv({ path: path.join(cfg.root, '.env') });
|
|
188
|
+
loadEnv({ path: path.join(cfg.root, '.env.local') });
|
|
189
|
+
}
|
|
190
|
+
console.log = originalLog; // Restore console
|
|
191
|
+
}
|
|
192
|
+
catch (e) { }
|
|
193
|
+
// Filter public env vars
|
|
194
|
+
const publicEnv = Object.keys(process.env)
|
|
195
|
+
.filter(key => key.startsWith('NUCLIE_') || key.startsWith('PUBLIC_') || key === 'NODE_ENV')
|
|
196
|
+
.reduce((acc, key) => ({ ...acc, [key]: process.env[key] }), {
|
|
197
|
+
NODE_ENV: process.env.NODE_ENV || 'development'
|
|
198
|
+
});
|
|
199
|
+
log.debug('Loaded Environment Variables', { category: 'server', count: Object.keys(publicEnv).length });
|
|
200
|
+
// 3. Detect Framework (Universal Support)
|
|
201
|
+
const { FrameworkDetector } = await import('../core/framework-detector.js');
|
|
202
|
+
// 1. Initialize Framework Pipeline (Phase B3)
|
|
203
|
+
const { FrameworkPipeline } = await import('../core/pipeline/framework-pipeline.js');
|
|
204
|
+
const pipeline = await FrameworkPipeline.auto(cfg);
|
|
205
|
+
let primaryFramework = pipeline.getFramework();
|
|
206
|
+
if (cfg.adapter && cfg.adapter.includes('react')) {
|
|
207
|
+
primaryFramework = 'react';
|
|
208
|
+
}
|
|
209
|
+
// @ts-ignore - Pipeline owns opinionated defaults
|
|
210
|
+
pipeline.applyDefaults();
|
|
211
|
+
log.info(`--> Dev Server: Active ${primaryFramework} workflow`, { category: 'server' });
|
|
212
|
+
if (primaryFramework === 'vanilla') {
|
|
213
|
+
log.warn('--> Dev Server: No framework detected, HMR might be limited', { category: 'server' });
|
|
214
|
+
}
|
|
215
|
+
// 3. Initialize Universal Transformer
|
|
216
|
+
const { UniversalTransformer } = await import('../core/universal-transformer.js');
|
|
217
|
+
const universalTransformer = new UniversalTransformer(cfg.root);
|
|
218
|
+
const nativeWorker = new NativeWorker(4); // 4 threads
|
|
219
|
+
const pluginManager = new PluginManager();
|
|
220
|
+
if (cfg.plugins) {
|
|
221
|
+
cfg.plugins.forEach(p => pluginManager.register(p));
|
|
222
|
+
}
|
|
223
|
+
// Initialize Sandbox
|
|
224
|
+
const { PermissionManager } = await import('../core/permissions.js');
|
|
225
|
+
const sandbox = new PluginSandbox(new PermissionManager());
|
|
226
|
+
// Auto-register Tailwind Plugin (Zero-Config or File-Based)
|
|
227
|
+
const tailwindConfigPath = path.join(cfg.root, 'tailwind.config.js');
|
|
228
|
+
const hasTailwindFile = await fs.access(tailwindConfigPath).then(() => true).catch(() => false);
|
|
229
|
+
const isTailwindRequested = cfg.css?.framework === 'tailwind' || hasTailwindFile;
|
|
230
|
+
if (isTailwindRequested) {
|
|
231
|
+
const { TailwindPlugin } = await import('../plugins/css/tailwind.js');
|
|
232
|
+
pluginManager.register(new TailwindPlugin(cfg.root, cfg));
|
|
233
|
+
log.info(`--> Dev Server: Tailwind CSS Plugin registered ${hasTailwindFile ? '(using file)' : '(zero-config)'}`, { category: 'server' });
|
|
234
|
+
}
|
|
235
|
+
// Auto-register CSS Preprocessor Plugins
|
|
236
|
+
const { SassPlugin } = await import('../plugins/css/sass.js');
|
|
237
|
+
pluginManager.register(new SassPlugin(cfg.root));
|
|
238
|
+
const { LessPlugin } = await import('../plugins/css/less.js');
|
|
239
|
+
pluginManager.register(new LessPlugin(cfg.root));
|
|
240
|
+
const { StylusPlugin } = await import('../plugins/css/stylus.js');
|
|
241
|
+
pluginManager.register(new StylusPlugin(cfg.root));
|
|
242
|
+
// Svelte Support removed - Handled by UniversalTransformer
|
|
243
|
+
// Vue Support removed - Handled by UniversalTransformer
|
|
244
|
+
const { DependencyPreBundler } = await import('./preBundler.js');
|
|
245
|
+
const preBundler = new DependencyPreBundler(cfg.root);
|
|
246
|
+
// Initialize Live Config Manager
|
|
247
|
+
const liveConfig = new LiveConfigManager(cfg, cfg.root);
|
|
248
|
+
// Scan and pre-bundle dependencies on server start
|
|
249
|
+
log.debug('Scanning dependencies for pre-bundling...');
|
|
250
|
+
const entryPoint = path.join(cfg.root, 'public', 'index.html');
|
|
251
|
+
let preBundledDeps = new Map();
|
|
252
|
+
try {
|
|
253
|
+
// 1. Load package.json dependencies
|
|
254
|
+
let pkgDeps = [];
|
|
255
|
+
try {
|
|
256
|
+
const pkgPath = path.join(cfg.root, 'package.json');
|
|
257
|
+
const pkgContent = await fs.readFile(pkgPath, 'utf-8');
|
|
258
|
+
const pkg = JSON.parse(pkgContent);
|
|
259
|
+
pkgDeps = [
|
|
260
|
+
...Object.keys(pkg.dependencies || {}),
|
|
261
|
+
...Object.keys(pkg.devDependencies || {})
|
|
262
|
+
];
|
|
263
|
+
}
|
|
264
|
+
catch (e) {
|
|
265
|
+
log.warn('Could not read package.json dependencies', { category: 'server' });
|
|
266
|
+
}
|
|
267
|
+
// 2. Framework Defaults
|
|
268
|
+
const frameworkDeps = {
|
|
269
|
+
react: ['react', 'react-dom', 'react-dom/client', 'react/jsx-dev-runtime', 'react/jsx-runtime', 'react-router-dom', '@remix-run/router', 'react-router'],
|
|
270
|
+
next: ['react', 'react-dom', 'react-dom/client', 'react/jsx-dev-runtime', 'react/jsx-runtime', 'react-router-dom'],
|
|
271
|
+
remix: ['react', 'react-dom', 'react-dom/client', 'react/jsx-dev-runtime', 'react/jsx-runtime', 'react-router-dom'],
|
|
272
|
+
preact: ['preact', 'preact/hooks', 'preact/jsx-runtime', 'preact/jsx-dev-runtime'],
|
|
273
|
+
vue: ['vue'],
|
|
274
|
+
nuxt: ['vue'],
|
|
275
|
+
svelte: [
|
|
276
|
+
'svelte',
|
|
277
|
+
'svelte/animate',
|
|
278
|
+
'svelte/easing',
|
|
279
|
+
'svelte/internal',
|
|
280
|
+
'svelte/internal/disclose-version',
|
|
281
|
+
'svelte/motion',
|
|
282
|
+
'svelte/store',
|
|
283
|
+
'svelte/transition'
|
|
284
|
+
],
|
|
285
|
+
solid: ['solid-js', 'solid-js/web', 'solid-js/store'],
|
|
286
|
+
angular: [
|
|
287
|
+
'@angular/core',
|
|
288
|
+
'@angular/common',
|
|
289
|
+
'@angular/compiler',
|
|
290
|
+
'@angular/platform-browser',
|
|
291
|
+
'@angular/platform-browser-dynamic',
|
|
292
|
+
'@angular/router',
|
|
293
|
+
'@angular/forms',
|
|
294
|
+
'rxjs',
|
|
295
|
+
'rxjs/operators',
|
|
296
|
+
'zone.js'
|
|
297
|
+
]
|
|
298
|
+
};
|
|
299
|
+
const defaultDeps = frameworkDeps[primaryFramework] || [];
|
|
300
|
+
// 3. User Config (prebundle)
|
|
301
|
+
const prebundleConfig = cfg.prebundle || { enabled: true, include: [], exclude: [] };
|
|
302
|
+
if (prebundleConfig.enabled !== false) {
|
|
303
|
+
// Merge sources
|
|
304
|
+
let depsToBundle = new Set([
|
|
305
|
+
...defaultDeps,
|
|
306
|
+
...(prebundleConfig.include || [])
|
|
307
|
+
]);
|
|
308
|
+
// Filter 1: Must verify existence in node_modules (Avoid resolve errors)
|
|
309
|
+
const validDeps = new Set();
|
|
310
|
+
// Use require.resolve to check existence, but be careful with exports
|
|
311
|
+
for (const dep of depsToBundle) {
|
|
312
|
+
// Exclude specific overrides
|
|
313
|
+
if (prebundleConfig.exclude?.includes(dep))
|
|
314
|
+
continue;
|
|
315
|
+
// Verify existence
|
|
316
|
+
try {
|
|
317
|
+
// Check if package.json or dependency exists in node_modules
|
|
318
|
+
// We can't always use require.resolve for sub-paths (like react/jsx-runtime) comfortably without conditions
|
|
319
|
+
// So we check if the ROOT package is installed
|
|
320
|
+
const rootPkg = dep.startsWith('@') ? dep.split('/').slice(0, 2).join('/') : dep.split('/')[0];
|
|
321
|
+
// Only strict check if it's NOT in package.json?
|
|
322
|
+
// Ideally we pre-bundle only what IS available.
|
|
323
|
+
// Check if root package is in pkgDeps (direct dependency) OR we can resolve it
|
|
324
|
+
const isDirectDep = pkgDeps.includes(rootPkg);
|
|
325
|
+
if (isDirectDep) {
|
|
326
|
+
validDeps.add(dep);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// Try to resolve it to ensure it exists (transitive deps like @remix-run/router)
|
|
330
|
+
try {
|
|
331
|
+
require.resolve(dep, { paths: [cfg.root] });
|
|
332
|
+
validDeps.add(dep);
|
|
333
|
+
}
|
|
334
|
+
catch (e) {
|
|
335
|
+
// Try resolving package.json of the dep
|
|
336
|
+
try {
|
|
337
|
+
const pkgJsonPath = path.join(cfg.root, 'node_modules', rootPkg, 'package.json');
|
|
338
|
+
await fs.access(pkgJsonPath);
|
|
339
|
+
validDeps.add(dep);
|
|
340
|
+
}
|
|
341
|
+
catch { }
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
catch (e) {
|
|
346
|
+
// Skip missing dep
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (validDeps.size > 0) {
|
|
350
|
+
// 4. Pass to PreBundler
|
|
351
|
+
preBundledDeps = await preBundler.preBundleDependencies(Array.from(validDeps));
|
|
352
|
+
log.debug('Dependencies pre-bundled successfully', { count: preBundledDeps.size });
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Warmup Build (Phase C1/C2) - Check for errors immediately
|
|
356
|
+
log.info('→ Dev Server: Warming up graph...');
|
|
357
|
+
const buildResult = await pipeline.build();
|
|
358
|
+
if (!buildResult.success) {
|
|
359
|
+
const error = buildResult.error;
|
|
360
|
+
const errorMsg = error?.message || 'Unknown error during warmup';
|
|
361
|
+
log.projectError({
|
|
362
|
+
file: error?.file || 'unknown',
|
|
363
|
+
message: errorMsg,
|
|
364
|
+
line: error?.loc?.line,
|
|
365
|
+
column: error?.loc?.column,
|
|
366
|
+
type: 'Build Error',
|
|
367
|
+
plugin: 'nuclie:pipeline'
|
|
368
|
+
});
|
|
369
|
+
log.error('→ Dev Server: Warmup build failed - Fix the errors above');
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
console.log(`\x1b[32mCompiled successfully!\x1b[0m\n`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
console.log('\n' + '='.repeat(60));
|
|
377
|
+
console.log('\x1b[31m❌ INITIALIZATION ERROR\x1b[0m');
|
|
378
|
+
console.log('='.repeat(60));
|
|
379
|
+
console.log(`\x1b[33mError:\x1b[0m ${error.message}`);
|
|
380
|
+
if (error.stack) {
|
|
381
|
+
console.log(`\n\x1b[90m${error.stack}\x1b[0m`);
|
|
382
|
+
}
|
|
383
|
+
console.log('='.repeat(60) + '\n');
|
|
384
|
+
log.warn('Failed to pre-bundle or warmup:', error.message);
|
|
385
|
+
}
|
|
386
|
+
let port = cfg.server?.port || cfg.port || 5173;
|
|
387
|
+
const host = cfg.server?.host || 'localhost';
|
|
388
|
+
// Dynamic port detection - skip if existingServer provided (minimal server already bound the port)
|
|
389
|
+
if (!cfg.server?.strictPort && !existingServer) {
|
|
390
|
+
port = await findAvailablePort(port, host);
|
|
391
|
+
}
|
|
392
|
+
// 2. Setup Proxy
|
|
393
|
+
const { default: httpProxy } = await import('http-proxy');
|
|
394
|
+
const proxy = httpProxy.createProxyServer({});
|
|
395
|
+
proxy.on('error', (err, req, res) => {
|
|
396
|
+
log.error('Proxy error: ' + err.message, { category: 'server' });
|
|
397
|
+
if (res.writeHead) {
|
|
398
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
399
|
+
res.end('Proxy error: ' + err.message);
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
// 3. Setup HTTPS
|
|
403
|
+
let httpsOptions = null;
|
|
404
|
+
if (cfg.server?.https) {
|
|
405
|
+
if (typeof cfg.server.https === 'object') {
|
|
406
|
+
httpsOptions = cfg.server.https;
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// Generate self-signed cert
|
|
410
|
+
const certDir = path.join(cfg.root, '.nuclie', 'certs');
|
|
411
|
+
await fs.mkdir(certDir, { recursive: true });
|
|
412
|
+
const keyPath = path.join(certDir, 'dev.key');
|
|
413
|
+
const certPath = path.join(certDir, 'dev.crt');
|
|
414
|
+
if (await fs.access(keyPath).then(() => true).catch(() => false)) {
|
|
415
|
+
httpsOptions = {
|
|
416
|
+
key: await fs.readFile(keyPath),
|
|
417
|
+
cert: await fs.readFile(certPath)
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
log.info('Generating self-signed certificate...', { category: 'server' });
|
|
422
|
+
const selfsigned = await import('selfsigned');
|
|
423
|
+
// @ts-ignore
|
|
424
|
+
const pems = await selfsigned.generate([{ name: 'commonName', value: 'localhost' }], { days: 30 });
|
|
425
|
+
await fs.writeFile(keyPath, pems.private);
|
|
426
|
+
await fs.writeFile(certPath, pems.cert);
|
|
427
|
+
httpsOptions = {
|
|
428
|
+
key: pems.private,
|
|
429
|
+
cert: pems.cert
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// 4. Initialize Premium Features
|
|
435
|
+
const statusHandler = new StatusHandler();
|
|
436
|
+
// WebSocket Server setup (early init for HMRThrottle)
|
|
437
|
+
// We need the server instance first, but we can setup the WSS later or pass a callback
|
|
438
|
+
// Let's create the broadcast function first
|
|
439
|
+
let wss;
|
|
440
|
+
const broadcast = (msg) => {
|
|
441
|
+
if (wss) {
|
|
442
|
+
wss.clients.forEach((c) => {
|
|
443
|
+
// WebSocket.OPEN is 1
|
|
444
|
+
if (c.readyState === 1)
|
|
445
|
+
c.send(msg);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
const hmrThrottle = new HMRThrottle(broadcast);
|
|
450
|
+
// Initialize Federation Dev
|
|
451
|
+
const { FederationDev } = await import('./federation-dev.js');
|
|
452
|
+
const federationDev = new FederationDev(cfg, broadcast);
|
|
453
|
+
federationDev.start();
|
|
454
|
+
// Initialize security headers once
|
|
455
|
+
const { createSecurityHeaders } = await import('../server/security-headers.js');
|
|
456
|
+
const securityHeaders = createSecurityHeaders({
|
|
457
|
+
csp: false,
|
|
458
|
+
hsts: cfg.server?.https ? true : false,
|
|
459
|
+
frameOptions: 'SAMEORIGIN',
|
|
460
|
+
xssProtection: true,
|
|
461
|
+
contentTypeNosniff: true
|
|
462
|
+
});
|
|
463
|
+
// Detect network IP for WebSocket origin validation
|
|
464
|
+
const os = await import('os');
|
|
465
|
+
const networkInterfaces = os.networkInterfaces();
|
|
466
|
+
let networkIP = '';
|
|
467
|
+
for (const name of Object.keys(networkInterfaces)) {
|
|
468
|
+
const ifaces = networkInterfaces[name];
|
|
469
|
+
if (!ifaces)
|
|
470
|
+
continue;
|
|
471
|
+
for (const iface of ifaces) {
|
|
472
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
473
|
+
networkIP = iface.address;
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (networkIP)
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
// Setup WebSocket Handlers for Config Sync (Advanced & Secure)
|
|
481
|
+
const setupWssHandlers = (server) => {
|
|
482
|
+
server.on('connection', (ws, req) => {
|
|
483
|
+
// Security Gate: Origin Validation
|
|
484
|
+
const origin = req.headers.origin;
|
|
485
|
+
const allowedOrigins = [
|
|
486
|
+
`http://${host}:${port}`,
|
|
487
|
+
`https://${host}:${port}`,
|
|
488
|
+
`http://localhost:${port}`,
|
|
489
|
+
`http://127.0.0.1:${port}`
|
|
490
|
+
];
|
|
491
|
+
// Add network IP if available
|
|
492
|
+
if (networkIP) {
|
|
493
|
+
allowedOrigins.push(`http://${networkIP}:${port}`);
|
|
494
|
+
allowedOrigins.push(`https://${networkIP}:${port}`);
|
|
495
|
+
}
|
|
496
|
+
if (origin && !allowedOrigins.some(o => origin.startsWith(o))) {
|
|
497
|
+
log.warn(`Blocked unauthorized WebSocket connection from origin: ${origin}`);
|
|
498
|
+
ws.terminate();
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
log.info('HMR client connected', { category: 'hmr' });
|
|
502
|
+
hmrThrottle.registerClient(ws);
|
|
503
|
+
ws.on('close', () => hmrThrottle.unregisterClient(ws));
|
|
504
|
+
// 1. Initial Handshake: Send current config AND session token
|
|
505
|
+
ws.send(JSON.stringify({
|
|
506
|
+
type: 'config:init',
|
|
507
|
+
config: liveConfig.getConfig(),
|
|
508
|
+
token: liveConfig.getSessionToken() // Only shared over this secure local WS
|
|
509
|
+
}));
|
|
510
|
+
// 2. Heartbeat to keep connection alive
|
|
511
|
+
const heartbeat = setInterval(() => {
|
|
512
|
+
if (ws.readyState === ws.OPEN)
|
|
513
|
+
ws.ping();
|
|
514
|
+
}, 30000);
|
|
515
|
+
ws.on('close', () => clearInterval(heartbeat));
|
|
516
|
+
ws.on('message', async (data) => {
|
|
517
|
+
try {
|
|
518
|
+
const message = JSON.parse(data.toString());
|
|
519
|
+
if (message.type === 'config:update') {
|
|
520
|
+
// Security: Token must match
|
|
521
|
+
const success = liveConfig.updateConfig(message.update, message.token);
|
|
522
|
+
if (success) {
|
|
523
|
+
// Broadcast update to ALL clients (without token)
|
|
524
|
+
broadcast(JSON.stringify({
|
|
525
|
+
type: 'config:changed',
|
|
526
|
+
config: liveConfig.getConfig(),
|
|
527
|
+
update: message.update
|
|
528
|
+
}));
|
|
529
|
+
if (message.persist) {
|
|
530
|
+
await liveConfig.persist();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
ws.send(JSON.stringify({
|
|
535
|
+
type: 'config:error',
|
|
536
|
+
message: 'Update rejected (invalid token or protected path)'
|
|
537
|
+
}));
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (message.type === 'config:get') {
|
|
541
|
+
ws.send(JSON.stringify({
|
|
542
|
+
type: 'config:current',
|
|
543
|
+
config: liveConfig.getConfig()
|
|
544
|
+
}));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
catch (e) {
|
|
548
|
+
log.error('Failed to handle WS message', e);
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
};
|
|
553
|
+
const requestHandler = async (req, res) => {
|
|
554
|
+
if (process.env.DEBUG) {
|
|
555
|
+
// Diagnostic log removed for cleaner production output
|
|
556
|
+
// log.debug(`[DevServer] Request: ${req.url} Preset: ${cfg.preset}`);
|
|
557
|
+
}
|
|
558
|
+
statusHandler.trackRequest();
|
|
559
|
+
if (await statusHandler.handleRequest(req, res))
|
|
560
|
+
return;
|
|
561
|
+
if (federationDev.handleRequest(req, res))
|
|
562
|
+
return;
|
|
563
|
+
// Security Scan (Day 41)
|
|
564
|
+
if (!anomalyDetector.scanRequest({ url: req.url || '', headers: req.headers, method: req.method || 'GET' })) {
|
|
565
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
566
|
+
res.end('Request Blocked by Nuclie Security Shield');
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (req.url === '/__nuclie/security') {
|
|
570
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
571
|
+
res.end(JSON.stringify(anomalyDetector.getDashboard(), null, 2));
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
// Apply security headers
|
|
575
|
+
securityHeaders.apply(req, res);
|
|
576
|
+
// Ignore Chrome DevTools extension probes
|
|
577
|
+
if (req.url?.includes('.well-known/appspecific/com.chrome.devtools.json')) {
|
|
578
|
+
res.writeHead(404);
|
|
579
|
+
res.end();
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
// Federation Editor
|
|
583
|
+
if (req.url === '/__federation') {
|
|
584
|
+
const { getEditorHtml } = await import('../visual/federation-editor.js');
|
|
585
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
586
|
+
res.end(getEditorHtml(cfg));
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
// Graph Visualizer
|
|
590
|
+
if (req.url === '/__graph') {
|
|
591
|
+
const { getGraphUIHtml } = await import('../visual/graph-ui.js');
|
|
592
|
+
const liveGraph = pipeline.getEngine().getGraph();
|
|
593
|
+
if (!liveGraph) {
|
|
594
|
+
res.writeHead(503);
|
|
595
|
+
res.end('Graph not yet warmed up');
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
599
|
+
res.end(getGraphUIHtml(liveGraph));
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const url = req.url || '/';
|
|
603
|
+
// Headers
|
|
604
|
+
if (cfg.server?.headers) {
|
|
605
|
+
Object.entries(cfg.server.headers).forEach(([k, v]) => res.setHeader(k, v));
|
|
606
|
+
}
|
|
607
|
+
if (cfg.server?.cors) {
|
|
608
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
609
|
+
}
|
|
610
|
+
// Proxy Handler
|
|
611
|
+
if (cfg.server?.proxy) {
|
|
612
|
+
for (const [context, target] of Object.entries(cfg.server.proxy)) {
|
|
613
|
+
if (url.startsWith(context)) {
|
|
614
|
+
log.debug(`Proxying ${url} -> ${target}`, { category: 'server' });
|
|
615
|
+
const options = typeof target === 'string' ? { target } : target;
|
|
616
|
+
proxy.web(req, res, options);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
// SPA Fallback: If route has no extension and it's not a known internal route, serve index.html
|
|
622
|
+
const isInternal = url.startsWith('/@') || url.startsWith('/__') || url.startsWith('/node_modules/');
|
|
623
|
+
const hasExtension = path.extname(url.split('?')[0]) !== '';
|
|
624
|
+
const acceptsHtml = req.headers.accept?.includes('text/html');
|
|
625
|
+
if ((url === '/' || (!hasExtension && !isInternal && acceptsHtml)) && cfg.preset === 'spa') {
|
|
626
|
+
let p = path.join(cfg.root, 'index.html');
|
|
627
|
+
let data = '';
|
|
628
|
+
// 1. Try Root (Vite standard)
|
|
629
|
+
try {
|
|
630
|
+
log.debug(`Reading index from ${p}`);
|
|
631
|
+
data = await fs.readFile(p, 'utf-8');
|
|
632
|
+
}
|
|
633
|
+
catch (e) {
|
|
634
|
+
// 2. Fallback to public/index.html
|
|
635
|
+
try {
|
|
636
|
+
p = path.join(cfg.root, 'public', 'index.html');
|
|
637
|
+
log.debug(`Reading index from ${p}`);
|
|
638
|
+
data = await fs.readFile(p, 'utf-8');
|
|
639
|
+
}
|
|
640
|
+
catch (e2) {
|
|
641
|
+
// 3. Fallback to src/index.html
|
|
642
|
+
try {
|
|
643
|
+
p = path.join(cfg.root, 'src', 'index.html');
|
|
644
|
+
log.debug(`Reading index from ${p}`);
|
|
645
|
+
data = await fs.readFile(p, 'utf-8');
|
|
646
|
+
}
|
|
647
|
+
catch (e3) {
|
|
648
|
+
// Final failure
|
|
649
|
+
log.debug(`Failed to find index.html in root, public, or src`);
|
|
650
|
+
if (e3.code === 'EISDIR') { /* ignore */ }
|
|
651
|
+
res.writeHead(404);
|
|
652
|
+
res.end('index.html not found');
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
try {
|
|
658
|
+
// Inject entry point if not present (simple heuristic)
|
|
659
|
+
// Angular CLI projects often don't have the script tag in source index.html
|
|
660
|
+
if (!data.includes('src="main.ts"') && !data.includes('src="/src/main.ts"')) {
|
|
661
|
+
// Try to inject main entry point script at the end of body
|
|
662
|
+
// We need to guess the entry point or use config.
|
|
663
|
+
// Config has cfg.entry which is an array.
|
|
664
|
+
if (cfg.entry && cfg.entry.length > 0) {
|
|
665
|
+
const entryScript = `<script type="module" src="/${cfg.entry[0]}"></script>`;
|
|
666
|
+
data = data.replace('</body>', `${entryScript}</body>`);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// Inject only client runtime
|
|
670
|
+
let clientScript = `
|
|
671
|
+
<script type="module" src="/@nuclie/client"></script>
|
|
672
|
+
`;
|
|
673
|
+
// Always inject basic shims in dev mode to prevent ReferenceErrors from any React-ish modules
|
|
674
|
+
let preamble = `
|
|
675
|
+
<script>
|
|
676
|
+
window.$RefreshReg$ = () => {};
|
|
677
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
678
|
+
</script>
|
|
679
|
+
`;
|
|
680
|
+
// Inject full React Refresh Preamble if React is detected or configured
|
|
681
|
+
const isReact = ['react', 'next', 'remix', 'react-typescript', 'react-adapter'].includes(primaryFramework) ||
|
|
682
|
+
(cfg.adapter && cfg.adapter.includes('react'));
|
|
683
|
+
if (isReact) {
|
|
684
|
+
if (process.env.DEBUG) {
|
|
685
|
+
log.info('[Nuclie] Injecting React Refresh Preamble', { category: 'server' });
|
|
686
|
+
}
|
|
687
|
+
preamble += `
|
|
688
|
+
<script type="module">
|
|
689
|
+
import RefreshRuntime from "/@react-refresh";
|
|
690
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
691
|
+
window.$RefreshReg$ = (type, id) => {
|
|
692
|
+
RefreshRuntime.register(type, id);
|
|
693
|
+
};
|
|
694
|
+
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
|
|
695
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
696
|
+
</script>
|
|
697
|
+
`;
|
|
698
|
+
}
|
|
699
|
+
clientScript = preamble + clientScript;
|
|
700
|
+
// Use a more robust injection that handles case-sensitivity and space variations
|
|
701
|
+
if (data.includes('<head>')) {
|
|
702
|
+
data = data.replace('<head>', '<head>' + clientScript);
|
|
703
|
+
}
|
|
704
|
+
else if (data.includes('<HEAD>')) {
|
|
705
|
+
data = data.replace('<HEAD>', '<HEAD>' + clientScript);
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
// Fallback if no head tag found
|
|
709
|
+
data = clientScript + data;
|
|
710
|
+
}
|
|
711
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
712
|
+
res.end(data);
|
|
713
|
+
}
|
|
714
|
+
catch (e) {
|
|
715
|
+
log.error('Error serving index.html', e);
|
|
716
|
+
res.writeHead(500);
|
|
717
|
+
res.end('Internal Server Error');
|
|
718
|
+
}
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
if (url === '/favicon.ico') {
|
|
722
|
+
const p = path.join(cfg.root, 'public', 'favicon.ico');
|
|
723
|
+
try {
|
|
724
|
+
const data = await fs.readFile(p);
|
|
725
|
+
res.writeHead(200, { 'Content-Type': 'image/x-icon' });
|
|
726
|
+
res.end(data);
|
|
727
|
+
}
|
|
728
|
+
catch (e) {
|
|
729
|
+
// Serve empty response or default icon to avoid 404/500 noise
|
|
730
|
+
res.writeHead(204);
|
|
731
|
+
res.end();
|
|
732
|
+
}
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
// Serve pre-bundled dependencies
|
|
736
|
+
if (url.startsWith('/@nuclie-deps/')) {
|
|
737
|
+
// Strip query parameters
|
|
738
|
+
const cleanUrl = url.split('?')[0];
|
|
739
|
+
const depFile = cleanUrl.replace('/@nuclie-deps/', '');
|
|
740
|
+
const depPath = path.join(cfg.root, 'node_modules', '.nuclie', depFile);
|
|
741
|
+
try {
|
|
742
|
+
const content = await fs.readFile(depPath, 'utf-8');
|
|
743
|
+
res.writeHead(200, {
|
|
744
|
+
'Content-Type': 'application/javascript',
|
|
745
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate'
|
|
746
|
+
});
|
|
747
|
+
res.end(content);
|
|
748
|
+
}
|
|
749
|
+
catch (error) {
|
|
750
|
+
log.error(`Failed to serve pre-bundled dep: ${depFile}`, { error });
|
|
751
|
+
res.writeHead(404);
|
|
752
|
+
res.end(`Pre-bundled dependency not found: ${depFile}`);
|
|
753
|
+
}
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
if (url === '/@react-refresh') {
|
|
757
|
+
try {
|
|
758
|
+
let runtimePath;
|
|
759
|
+
// Try to find react-refresh in node_modules
|
|
760
|
+
const searchPaths = [
|
|
761
|
+
path.join(cfg.root, 'node_modules/react-refresh/cjs/react-refresh-runtime.development.js'),
|
|
762
|
+
path.join(cfg.root, '../node_modules/react-refresh/cjs/react-refresh-runtime.development.js'),
|
|
763
|
+
path.join(process.cwd(), 'node_modules/react-refresh/cjs/react-refresh-runtime.development.js'),
|
|
764
|
+
];
|
|
765
|
+
let runtime = null;
|
|
766
|
+
for (const checkPath of searchPaths) {
|
|
767
|
+
try {
|
|
768
|
+
runtime = await fs.readFile(checkPath, 'utf-8');
|
|
769
|
+
runtimePath = checkPath;
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
catch {
|
|
773
|
+
// Continue to next path
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
if (!runtime) {
|
|
777
|
+
throw new Error('Could not find react-refresh runtime in any node_modules');
|
|
778
|
+
}
|
|
779
|
+
// Wrap the CJS module with process polyfill for browser environment
|
|
780
|
+
const wrappedRuntime = `
|
|
781
|
+
const process = { env: { NODE_ENV: 'development' } };
|
|
782
|
+
const exports = {};
|
|
783
|
+
const module = { exports };
|
|
784
|
+
|
|
785
|
+
${runtime}
|
|
786
|
+
|
|
787
|
+
export default module.exports;
|
|
788
|
+
`;
|
|
789
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
790
|
+
res.end(wrappedRuntime);
|
|
791
|
+
}
|
|
792
|
+
catch (e) {
|
|
793
|
+
log.error('Failed to resolve React Refresh', { category: 'server', error: e });
|
|
794
|
+
res.writeHead(404);
|
|
795
|
+
res.end('React Refresh runtime not found');
|
|
796
|
+
}
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
if (url === '/@nuclie/client') {
|
|
800
|
+
const clientPath = path.resolve(__dirname, '../runtime/client.ts');
|
|
801
|
+
try {
|
|
802
|
+
const raw = await fs.readFile(clientPath, 'utf-8');
|
|
803
|
+
const { transform } = await import('esbuild');
|
|
804
|
+
const result = await transform(raw, { loader: 'ts' });
|
|
805
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
806
|
+
res.end(result.code);
|
|
807
|
+
}
|
|
808
|
+
catch (e) {
|
|
809
|
+
// Fallback to JS if TS missing
|
|
810
|
+
const jsPath = path.resolve(__dirname, '../runtime/client.js');
|
|
811
|
+
try {
|
|
812
|
+
const client = await fs.readFile(jsPath, 'utf-8');
|
|
813
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
814
|
+
res.end(client);
|
|
815
|
+
}
|
|
816
|
+
catch (e2) {
|
|
817
|
+
res.writeHead(404);
|
|
818
|
+
res.end('Nuclie client runtime not found');
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
if (url === '/@nuclie/error-overlay.js') {
|
|
824
|
+
// Also transform error-overlay if ts
|
|
825
|
+
const overlayPath = path.resolve(__dirname, '../runtime/error-overlay.ts');
|
|
826
|
+
try {
|
|
827
|
+
const raw = await fs.readFile(overlayPath, 'utf-8');
|
|
828
|
+
const { transform } = await import('esbuild');
|
|
829
|
+
const result = await transform(raw, { loader: 'ts' });
|
|
830
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
831
|
+
res.end(result.code);
|
|
832
|
+
}
|
|
833
|
+
catch (e) {
|
|
834
|
+
// Fallback
|
|
835
|
+
const jsPath = path.resolve(__dirname, '../runtime/error-overlay.js');
|
|
836
|
+
try {
|
|
837
|
+
const overlay = await fs.readFile(jsPath, 'utf-8');
|
|
838
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
839
|
+
res.end(overlay);
|
|
840
|
+
}
|
|
841
|
+
catch (e2) {
|
|
842
|
+
res.writeHead(404);
|
|
843
|
+
res.end('Nuclie error overlay not found');
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
// Open in Editor
|
|
849
|
+
if (url.startsWith('/__open-in-editor')) {
|
|
850
|
+
const urlObj = new URL(req.url || '', `http://${req.headers.host}`);
|
|
851
|
+
const file = urlObj.searchParams.get('file');
|
|
852
|
+
const line = parseInt(urlObj.searchParams.get('line') || '1');
|
|
853
|
+
const column = parseInt(urlObj.searchParams.get('column') || '1');
|
|
854
|
+
if (file) {
|
|
855
|
+
const launch = await import('launch-editor');
|
|
856
|
+
launch.default(file, `${line}:${column}`);
|
|
857
|
+
res.writeHead(200);
|
|
858
|
+
res.end('Opened in editor');
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
res.writeHead(400);
|
|
862
|
+
res.end('Missing file parameter');
|
|
863
|
+
}
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
// Serve from node_modules
|
|
867
|
+
if (url.startsWith('/node_modules/')) {
|
|
868
|
+
const cleanUrl = url.split('?')[0];
|
|
869
|
+
let modulePath = path.join(cfg.root, cleanUrl);
|
|
870
|
+
try {
|
|
871
|
+
// Handle potential directory or missing extension
|
|
872
|
+
let stats;
|
|
873
|
+
try {
|
|
874
|
+
stats = await fs.stat(modulePath);
|
|
875
|
+
}
|
|
876
|
+
catch (e) {
|
|
877
|
+
// Try appending .js
|
|
878
|
+
if (!modulePath.endsWith('.js')) {
|
|
879
|
+
modulePath += '.js';
|
|
880
|
+
stats = await fs.stat(modulePath);
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
throw e;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// If directory, resolve entry point
|
|
887
|
+
if (stats.isDirectory()) {
|
|
888
|
+
const pkgPath = path.join(modulePath, 'package.json');
|
|
889
|
+
try {
|
|
890
|
+
const pkgContent = await fs.readFile(pkgPath, 'utf-8');
|
|
891
|
+
const pkg = JSON.parse(pkgContent);
|
|
892
|
+
// Prefer module (ESM) > main > index.js
|
|
893
|
+
let entry = pkg.module || pkg.main || 'index.js';
|
|
894
|
+
modulePath = path.join(modulePath, entry);
|
|
895
|
+
}
|
|
896
|
+
catch (e) {
|
|
897
|
+
// No package.json, try index.js
|
|
898
|
+
modulePath = path.join(modulePath, 'index.js');
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
const ext = path.extname(modulePath);
|
|
902
|
+
// Transform JS files from node_modules using esbuild
|
|
903
|
+
if (ext === '.js' || ext === '.mjs' || ext === '.cjs') {
|
|
904
|
+
const { build } = await import('esbuild');
|
|
905
|
+
try {
|
|
906
|
+
// Use esbuild to bundle/transform to ESM
|
|
907
|
+
const result = await build({
|
|
908
|
+
entryPoints: [modulePath],
|
|
909
|
+
bundle: true, // Bundle dependencies of this module
|
|
910
|
+
format: 'esm',
|
|
911
|
+
platform: 'browser',
|
|
912
|
+
write: false,
|
|
913
|
+
define: {
|
|
914
|
+
'process.env.NODE_ENV': '"development"',
|
|
915
|
+
'global': 'window'
|
|
916
|
+
},
|
|
917
|
+
plugins: [{
|
|
918
|
+
name: 'node-modules-resolver',
|
|
919
|
+
setup(build) {
|
|
920
|
+
// Mark other node_modules as external to avoid bundling EVERYTHING
|
|
921
|
+
// We want to bundle internal deps of the package, but keep peer deps external
|
|
922
|
+
// This is a simplified approach
|
|
923
|
+
build.onResolve({ filter: /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/ }, args => {
|
|
924
|
+
if (args.path !== modulePath && !args.path.startsWith('.')) {
|
|
925
|
+
// Bundle scheduler to avoid dynamic require issues in react-dom
|
|
926
|
+
if (args.path === 'scheduler')
|
|
927
|
+
return null;
|
|
928
|
+
// Bundle react if imported by react-dom or jsx-dev-runtime (to avoid dynamic require issues)
|
|
929
|
+
if (args.path === 'react' && (modulePath.includes('react-dom') || modulePath.includes('jsx-dev-runtime')))
|
|
930
|
+
return null;
|
|
931
|
+
// Bundle react-dom if imported by react-dom/client
|
|
932
|
+
if (args.path === 'react-dom' && modulePath.includes('react-dom/client'))
|
|
933
|
+
return null;
|
|
934
|
+
return { path: `/node_modules/${args.path}`, external: true };
|
|
935
|
+
}
|
|
936
|
+
return null;
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}]
|
|
940
|
+
});
|
|
941
|
+
const code = result.outputFiles[0].text;
|
|
942
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
943
|
+
res.end(code);
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
catch (e) {
|
|
947
|
+
log.error(`Failed to transform module: ${url}`, { category: 'server', error: e });
|
|
948
|
+
// Fallback to raw file if build fails
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
let data = await fs.readFile(modulePath, 'utf-8');
|
|
952
|
+
const mime = ext === '.js' || ext === '.mjs' ? 'application/javascript' :
|
|
953
|
+
ext === '.css' ? 'text/css' : 'application/octet-stream';
|
|
954
|
+
res.writeHead(200, { 'Content-Type': mime });
|
|
955
|
+
res.end(data);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
catch (e) {
|
|
959
|
+
log.error(`[SERVER] Failed to serve module: ${url}`, e);
|
|
960
|
+
if (!res.headersSent) {
|
|
961
|
+
res.writeHead(404);
|
|
962
|
+
res.end('Module not found');
|
|
963
|
+
}
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
// Try to serve from public first
|
|
968
|
+
const publicPath = path.join(cfg.root, 'public', url);
|
|
969
|
+
try {
|
|
970
|
+
await fs.access(publicPath);
|
|
971
|
+
const data = await fs.readFile(publicPath);
|
|
972
|
+
// simple mime type guess
|
|
973
|
+
const ext = path.extname(publicPath);
|
|
974
|
+
const mime = ext === '.js' ? 'application/javascript' : ext === '.css' ? 'text/css' : 'application/octet-stream';
|
|
975
|
+
res.writeHead(200, { 'Content-Type': mime });
|
|
976
|
+
res.end(data);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
catch (e) { }
|
|
980
|
+
// Try to serve from root (src, node_modules, etc)
|
|
981
|
+
// Remove query params
|
|
982
|
+
const cleanUrl = url.split('?')[0];
|
|
983
|
+
let filePath = path.join(cfg.root, cleanUrl);
|
|
984
|
+
// console.log('Serving:', { url, cleanUrl, filePath });
|
|
985
|
+
// SECURITY: Path Traversal Protection
|
|
986
|
+
if (!filePath.startsWith(cfg.root)) {
|
|
987
|
+
res.writeHead(403);
|
|
988
|
+
res.end('Access denied');
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
// Try to resolve extension if file doesn't exist
|
|
992
|
+
try {
|
|
993
|
+
await fs.access(filePath);
|
|
994
|
+
}
|
|
995
|
+
catch (e) {
|
|
996
|
+
// Try extensions
|
|
997
|
+
const extensions = ['.jsx', '.tsx', '.js', '.ts', '.mjs'];
|
|
998
|
+
let found = false;
|
|
999
|
+
for (const ext of extensions) {
|
|
1000
|
+
if (await fs.access(filePath + ext).then(() => true).catch(() => false)) {
|
|
1001
|
+
filePath += ext;
|
|
1002
|
+
found = true;
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (!found) {
|
|
1007
|
+
// If still not found, let it fall through to 404 handler (or next logic)
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
try {
|
|
1011
|
+
const stats = await fs.stat(filePath);
|
|
1012
|
+
if (stats.isDirectory()) {
|
|
1013
|
+
// If trying to read a directory (like root '/'), default to index.html
|
|
1014
|
+
filePath = path.join(filePath, 'index.html');
|
|
1015
|
+
}
|
|
1016
|
+
const ext = path.extname(filePath);
|
|
1017
|
+
if (ext === '.ts' || ext === '.tsx' || ext === '.jsx' || ext === '.js' || ext === '.mjs' || ext === '.vue' || ext === '.svelte' || ext === '.astro') {
|
|
1018
|
+
let raw = await fs.readFile(filePath, 'utf-8');
|
|
1019
|
+
// Native Transform (Caching + Graph) - only for JS/TS files
|
|
1020
|
+
if (ext === '.ts' || ext === '.tsx' || ext === '.jsx' || ext === '.js' || ext === '.mjs') {
|
|
1021
|
+
try {
|
|
1022
|
+
raw = nativeWorker.transformSync(raw, filePath);
|
|
1023
|
+
}
|
|
1024
|
+
catch (e) {
|
|
1025
|
+
// Silently continue - native worker is optional optimization
|
|
1026
|
+
// Only log in debug mode to avoid terminal spam
|
|
1027
|
+
if (process.env.DEBUG) {
|
|
1028
|
+
log.debug(`NativeWorker skipped for ${filePath}: ${e.message}`, { category: 'build' });
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
// Plugin transform (JS plugins like Tailwind)
|
|
1033
|
+
raw = await pluginManager.transform(raw, filePath);
|
|
1034
|
+
// Inject Env Vars and React Refresh Shims (only for JS/TS files)
|
|
1035
|
+
// Aggressive In-Module Shim: Guarantee $RefreshSig$ existence
|
|
1036
|
+
if (ext === '.ts' || ext === '.tsx' || ext === '.jsx' || ext === '.js' || ext === '.mjs') {
|
|
1037
|
+
raw = `
|
|
1038
|
+
/** Nuclie Dev Preamble **/
|
|
1039
|
+
if (typeof window !== 'undefined') {
|
|
1040
|
+
window.$RefreshReg$ = window.$RefreshReg$ || (() => {});
|
|
1041
|
+
window.$RefreshSig$ = window.$RefreshSig$ || (() => (type) => type);
|
|
1042
|
+
}
|
|
1043
|
+
if (!window.process) window.process = { env: {} };
|
|
1044
|
+
Object.assign(window.process.env, ${JSON.stringify(publicEnv)});
|
|
1045
|
+
|
|
1046
|
+
${raw}
|
|
1047
|
+
`;
|
|
1048
|
+
}
|
|
1049
|
+
// Use Universal Transformer (supports all frameworks)
|
|
1050
|
+
try {
|
|
1051
|
+
const transformResult = await universalTransformer.transform({
|
|
1052
|
+
filePath,
|
|
1053
|
+
code: raw,
|
|
1054
|
+
framework: primaryFramework,
|
|
1055
|
+
root: cfg.root,
|
|
1056
|
+
isDev: true
|
|
1057
|
+
});
|
|
1058
|
+
// Rewrite imports after transformation
|
|
1059
|
+
let code = await rewriteImports(transformResult.code, cfg.root, preBundledDeps);
|
|
1060
|
+
res.writeHead(200, {
|
|
1061
|
+
'Content-Type': 'application/javascript',
|
|
1062
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate'
|
|
1063
|
+
});
|
|
1064
|
+
res.end(code);
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
catch (error) {
|
|
1068
|
+
// Compute preamble line offset (we prepend a dev preamble before the original file)
|
|
1069
|
+
let reportedLine = undefined;
|
|
1070
|
+
try {
|
|
1071
|
+
const sep = '\n\n';
|
|
1072
|
+
const sepIdx = typeof raw === 'string' ? raw.indexOf(sep) : -1;
|
|
1073
|
+
let preambleLines = 0;
|
|
1074
|
+
if (sepIdx !== -1) {
|
|
1075
|
+
preambleLines = raw.slice(0, sepIdx).split(/\r?\n/).length;
|
|
1076
|
+
}
|
|
1077
|
+
if (error && error.loc && typeof error.loc.line === 'number') {
|
|
1078
|
+
reportedLine = Math.max(1, error.loc.line - preambleLines);
|
|
1079
|
+
}
|
|
1080
|
+
else if (error && error.loc && typeof error.loc === 'object' && error.loc.line) {
|
|
1081
|
+
reportedLine = Math.max(1, Number(error.loc.line) - preambleLines);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
catch (e) {
|
|
1085
|
+
reportedLine = error.loc?.line;
|
|
1086
|
+
}
|
|
1087
|
+
const relativePath = path.relative(cfg.root, filePath).replace(/^[\\\/]/, '');
|
|
1088
|
+
log.projectError({
|
|
1089
|
+
file: relativePath,
|
|
1090
|
+
message: error.message || String(error),
|
|
1091
|
+
line: reportedLine,
|
|
1092
|
+
column: error.loc?.column
|
|
1093
|
+
});
|
|
1094
|
+
// Send error to browser console as well (minimal)
|
|
1095
|
+
const errorPayload = {
|
|
1096
|
+
file: relativePath,
|
|
1097
|
+
message: error.message || String(error),
|
|
1098
|
+
line: reportedLine,
|
|
1099
|
+
column: error.loc?.column
|
|
1100
|
+
};
|
|
1101
|
+
const errorScript = `console.error('Project Error:', ${JSON.stringify(errorPayload)});`;
|
|
1102
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
1103
|
+
res.end(errorScript);
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
if (ext === '.css' || ext === '.scss' || ext === '.sass' || ext === '.less' || ext === '.styl') {
|
|
1108
|
+
let raw = await fs.readFile(filePath, 'utf-8');
|
|
1109
|
+
raw = await pluginManager.transform(raw, filePath);
|
|
1110
|
+
// Check if imported as module
|
|
1111
|
+
if (url.includes('?import')) {
|
|
1112
|
+
const jsModule = `
|
|
1113
|
+
const style = document.createElement('style');
|
|
1114
|
+
style.textContent = ${JSON.stringify(raw)};
|
|
1115
|
+
document.head.appendChild(style);
|
|
1116
|
+
export default ${JSON.stringify(raw)};
|
|
1117
|
+
`;
|
|
1118
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
1119
|
+
res.end(jsModule);
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
res.writeHead(200, { 'Content-Type': 'text/css' });
|
|
1123
|
+
res.end(raw);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
if (ext === '.json') {
|
|
1127
|
+
const raw = await fs.readFile(filePath, 'utf-8');
|
|
1128
|
+
if (url.includes('?import')) {
|
|
1129
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
1130
|
+
res.end(`export default ${raw}; `);
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1134
|
+
res.end(raw);
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
// Serve other files raw
|
|
1138
|
+
const data = await fs.readFile(filePath);
|
|
1139
|
+
let mime = 'application/octet-stream';
|
|
1140
|
+
if (ext === '.map')
|
|
1141
|
+
mime = 'application/json';
|
|
1142
|
+
if (ext === '.html')
|
|
1143
|
+
mime = 'text/html';
|
|
1144
|
+
if (ext === '.svg')
|
|
1145
|
+
mime = 'image/svg+xml';
|
|
1146
|
+
res.writeHead(200, { 'Content-Type': mime });
|
|
1147
|
+
res.end(data);
|
|
1148
|
+
}
|
|
1149
|
+
catch (e) {
|
|
1150
|
+
log.error(`Request error: ${e.message}`, { category: 'server' });
|
|
1151
|
+
if (process.env.DEBUG || process.env.NODE_ENV === 'test') {
|
|
1152
|
+
console.error(e.stack);
|
|
1153
|
+
}
|
|
1154
|
+
else {
|
|
1155
|
+
// Always show stack for request errors in dev mode for visibility
|
|
1156
|
+
console.error(e);
|
|
1157
|
+
}
|
|
1158
|
+
const isJS = url.match(/\.(js|ts|tsx|jsx|mjs|vue|svelte|astro)/);
|
|
1159
|
+
// If it's a build error (has loc/frame/stack), broadcast it
|
|
1160
|
+
if (e.message && (e.frame || e.loc || e.stack)) {
|
|
1161
|
+
const errorData = {
|
|
1162
|
+
message: e.message,
|
|
1163
|
+
stack: e.stack,
|
|
1164
|
+
filename: filePath,
|
|
1165
|
+
frame: e.frame
|
|
1166
|
+
};
|
|
1167
|
+
broadcast(JSON.stringify({
|
|
1168
|
+
type: 'error',
|
|
1169
|
+
error: errorData
|
|
1170
|
+
}));
|
|
1171
|
+
if (isJS && !res.headersSent) {
|
|
1172
|
+
// Serve a JS fallback that throws in console and triggers overlay
|
|
1173
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
1174
|
+
res.end(`
|
|
1175
|
+
console.error("[Nuclie Build Error] ${e.message.replace(/"/g, '\\"')}");
|
|
1176
|
+
const error = ${JSON.stringify(errorData)};
|
|
1177
|
+
if (window.__NUCLIE_ERROR_OVERLAY__) {
|
|
1178
|
+
window.__NUCLIE_ERROR_OVERLAY__.show(error);
|
|
1179
|
+
}
|
|
1180
|
+
throw new Error("[Nuclie Build Error] See overlay for details");
|
|
1181
|
+
`);
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
if (!res.headersSent) {
|
|
1186
|
+
res.writeHead(500);
|
|
1187
|
+
res.end(e.message || 'Internal Server Error');
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
let server;
|
|
1192
|
+
if (existingServer) {
|
|
1193
|
+
server = existingServer;
|
|
1194
|
+
server.__nuclie_handler = requestHandler;
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
if (httpsOptions) {
|
|
1198
|
+
const https = await import('https');
|
|
1199
|
+
server = https.createServer(httpsOptions, requestHandler);
|
|
1200
|
+
}
|
|
1201
|
+
else {
|
|
1202
|
+
server = http.createServer(requestHandler);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
// WebSocket Server setup
|
|
1206
|
+
const { WebSocketServer } = await import('ws');
|
|
1207
|
+
wss = new WebSocketServer({ server });
|
|
1208
|
+
// Initialize Config Sync Handlers
|
|
1209
|
+
setupWssHandlers(wss);
|
|
1210
|
+
// Upgrade handling for Proxy WebSockets
|
|
1211
|
+
server.on('upgrade', (req, socket, head) => {
|
|
1212
|
+
if (cfg.server?.proxy) {
|
|
1213
|
+
for (const [context, target] of Object.entries(cfg.server.proxy)) {
|
|
1214
|
+
if (req.url?.startsWith(context)) {
|
|
1215
|
+
const options = typeof target === 'string' ? { target, ws: true } : { ...target, ws: true };
|
|
1216
|
+
proxy.ws(req, socket, head, options);
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
// Config Watcher
|
|
1223
|
+
const configWatcher = new ConfigWatcher(cfg.root, async (type, file) => {
|
|
1224
|
+
if (type === 'hot' || (file.endsWith('.json') && !file.includes('package.json'))) {
|
|
1225
|
+
log.info(`Hot reloading config from ${path.basename(file)}...`, { category: 'server' });
|
|
1226
|
+
try {
|
|
1227
|
+
const { loadConfig } = await import('../config/index.js');
|
|
1228
|
+
const updatedCfg = await loadConfig(cfg.root);
|
|
1229
|
+
// Update live config manager (which will broadcast to clients)
|
|
1230
|
+
// We do a full replacement here because the whole file changed
|
|
1231
|
+
Object.entries(updatedCfg).forEach(([key, value]) => {
|
|
1232
|
+
liveConfig.updateConfig({ path: key, value });
|
|
1233
|
+
});
|
|
1234
|
+
broadcast(JSON.stringify({
|
|
1235
|
+
type: 'config:changed',
|
|
1236
|
+
config: liveConfig.getConfig()
|
|
1237
|
+
}));
|
|
1238
|
+
}
|
|
1239
|
+
catch (e) {
|
|
1240
|
+
log.error('Failed to hot reload config', e);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
else if (type === 'restart') {
|
|
1244
|
+
log.warn('Restarting server due to config change...', { category: 'server' });
|
|
1245
|
+
broadcast(JSON.stringify({ type: 'restarting' }));
|
|
1246
|
+
await new Promise(r => setTimeout(r, 500)); // Give clients time to receive message
|
|
1247
|
+
server.close();
|
|
1248
|
+
wss?.close();
|
|
1249
|
+
await configWatcher.close();
|
|
1250
|
+
federationDev.stop();
|
|
1251
|
+
// Re-run startDevServer (recursive)
|
|
1252
|
+
// Note: This might stack overflow if done repeatedly without process exit,
|
|
1253
|
+
// but for dev server it's usually fine or we should use a wrapper.
|
|
1254
|
+
// For now, let's just exit and let nodemon/supervisor handle it if present,
|
|
1255
|
+
// OR we can just re-call startDevServer.
|
|
1256
|
+
// Re-calling is better for "graceful" feel.
|
|
1257
|
+
startDevServer(cfg).catch(e => log.error('Failed to restart', { error: e }));
|
|
1258
|
+
}
|
|
1259
|
+
});
|
|
1260
|
+
configWatcher.start();
|
|
1261
|
+
// Track files with errors
|
|
1262
|
+
const filesWithErrors = new Set();
|
|
1263
|
+
const { default: chokidar } = await import('chokidar');
|
|
1264
|
+
const watcher = chokidar.watch(cfg.root, {
|
|
1265
|
+
ignored: ['**/node_modules/**', '**/.git/**', '**/.nuclie/**', '**/.nuclie_cache/**'],
|
|
1266
|
+
ignoreInitial: true
|
|
1267
|
+
});
|
|
1268
|
+
watcher.on('change', async (file) => {
|
|
1269
|
+
try {
|
|
1270
|
+
// Clear transform cache for changed file
|
|
1271
|
+
universalTransformer.clearCache(file);
|
|
1272
|
+
// Proactively check for errors in JS/TS files
|
|
1273
|
+
const ext = path.extname(file);
|
|
1274
|
+
if (['.ts', '.tsx', '.jsx', '.js', '.mjs', '.vue', '.svelte'].includes(ext)) {
|
|
1275
|
+
const hadError = filesWithErrors.has(file);
|
|
1276
|
+
try {
|
|
1277
|
+
const code = await fs.readFile(file, 'utf-8');
|
|
1278
|
+
// Attempt transformation to catch errors immediately
|
|
1279
|
+
await universalTransformer.transform({
|
|
1280
|
+
filePath: file,
|
|
1281
|
+
code,
|
|
1282
|
+
framework: primaryFramework,
|
|
1283
|
+
root: cfg.root,
|
|
1284
|
+
isDev: true
|
|
1285
|
+
});
|
|
1286
|
+
// If transformation succeeds and there was a previous error, show success
|
|
1287
|
+
if (hadError) {
|
|
1288
|
+
filesWithErrors.delete(file);
|
|
1289
|
+
const relativePath = path.relative(cfg.root, file);
|
|
1290
|
+
console.log(`\n\x1b[32mCompiled successfully!\x1b[0m`);
|
|
1291
|
+
console.log(`\x1b[90m${new Date().toLocaleTimeString()} - ${relativePath}\x1b[0m\n`);
|
|
1292
|
+
// Broadcast success to browser
|
|
1293
|
+
broadcast(JSON.stringify({
|
|
1294
|
+
type: 'error-fixed',
|
|
1295
|
+
file: relativePath
|
|
1296
|
+
}));
|
|
1297
|
+
}
|
|
1298
|
+
else if (process.env.DEBUG) {
|
|
1299
|
+
log.debug(`✓ ${path.relative(cfg.root, file)} validated`, { category: 'hmr' });
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
catch (transformError) {
|
|
1303
|
+
// Track this file has an error
|
|
1304
|
+
filesWithErrors.add(file);
|
|
1305
|
+
// Error is already logged by universal-transformer
|
|
1306
|
+
// Also broadcast to browser
|
|
1307
|
+
const relativePath = path.relative(cfg.root, file);
|
|
1308
|
+
broadcast(JSON.stringify({
|
|
1309
|
+
type: 'error',
|
|
1310
|
+
error: {
|
|
1311
|
+
message: transformError.message || String(transformError),
|
|
1312
|
+
file: relativePath,
|
|
1313
|
+
line: transformError.loc?.line,
|
|
1314
|
+
column: transformError.loc?.column,
|
|
1315
|
+
stack: transformError.stack
|
|
1316
|
+
}
|
|
1317
|
+
}));
|
|
1318
|
+
// Don't continue with HMR if there's an error
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
// Native Invalidation & Rebuild
|
|
1323
|
+
try {
|
|
1324
|
+
if (nativeWorker && typeof nativeWorker.invalidate === 'function') {
|
|
1325
|
+
nativeWorker.invalidate(file);
|
|
1326
|
+
}
|
|
1327
|
+
let affected = [];
|
|
1328
|
+
if (nativeWorker && typeof nativeWorker.rebuild === 'function') {
|
|
1329
|
+
affected = nativeWorker.rebuild(file);
|
|
1330
|
+
}
|
|
1331
|
+
if (affected.length > 0) {
|
|
1332
|
+
log.info(`Rebuild affected ${affected.length} files`, { category: 'build', duration: 10 }); // Mock duration
|
|
1333
|
+
}
|
|
1334
|
+
affected.forEach((affectedFile) => {
|
|
1335
|
+
// Clear cache for affected files too
|
|
1336
|
+
universalTransformer.clearCache(affectedFile);
|
|
1337
|
+
// Determine message type
|
|
1338
|
+
let type = 'reload';
|
|
1339
|
+
if (affectedFile.endsWith('.css')) {
|
|
1340
|
+
type = 'update-css';
|
|
1341
|
+
}
|
|
1342
|
+
// Normalize path for client (relative to root)
|
|
1343
|
+
const rel = '/' + path.relative(cfg.root, affectedFile);
|
|
1344
|
+
// Queue update via throttle
|
|
1345
|
+
hmrThrottle.queueUpdate(rel, type);
|
|
1346
|
+
statusHandler.trackHMR();
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
catch (nativeError) {
|
|
1350
|
+
log.warn(`Native HMR unavailable for ${path.relative(cfg.root, file)}: ${nativeError.message || 'Unknown error'}. Falling back to full reload`, { category: 'hmr' });
|
|
1351
|
+
// Don't broadcast 'error' here, just restart
|
|
1352
|
+
broadcast(JSON.stringify({ type: 'restarting' }));
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
catch (e) {
|
|
1356
|
+
log.error(`Watcher crash recovery for ${file}:`, e);
|
|
1357
|
+
// Ensure we don't leave the client hanging
|
|
1358
|
+
broadcast(JSON.stringify({
|
|
1359
|
+
type: 'error',
|
|
1360
|
+
error: { message: `Watcher error: ${e.message}`, stack: e.stack }
|
|
1361
|
+
}));
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
if (!existingServer) {
|
|
1365
|
+
server.listen(port, () => {
|
|
1366
|
+
const protocol = httpsOptions ? 'https' : 'http';
|
|
1367
|
+
const url = `${protocol}://${host}:${port}`;
|
|
1368
|
+
if (cfg.server?.open)
|
|
1369
|
+
openBrowser(url);
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
else {
|
|
1373
|
+
// If we're using the minimal server, it already handles port binding and logs.
|
|
1374
|
+
// We just handle the 'open' browser request here if needed.
|
|
1375
|
+
if (cfg.server?.open) {
|
|
1376
|
+
const protocol = httpsOptions ? 'https' : 'http';
|
|
1377
|
+
const url = `${protocol}://${host}:${port}`;
|
|
1378
|
+
openBrowser(url);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
return server;
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Open browser helper
|
|
1385
|
+
*/
|
|
1386
|
+
async function openBrowser(url) {
|
|
1387
|
+
try {
|
|
1388
|
+
const { spawn } = await import('child_process');
|
|
1389
|
+
const isWin = process.platform === 'win32';
|
|
1390
|
+
const cmd = isWin ? 'cmd' : (process.platform === 'darwin' ? 'open' : 'xdg-open');
|
|
1391
|
+
const args = isWin ? ['/c', 'start', '', url] : [url];
|
|
1392
|
+
const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
|
|
1393
|
+
child.unref();
|
|
1394
|
+
}
|
|
1395
|
+
catch (e) {
|
|
1396
|
+
// Ignore browser open errors
|
|
1397
|
+
}
|
|
1398
|
+
}
|