bertui 1.2.9 → 2.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.
Files changed (183) hide show
  1. package/README.md +44 -242
  2. package/TYPES_PATCH.md +17 -0
  3. package/bin/bertui.js +2 -7
  4. package/package.json +32 -98
  5. package/src/config.ts +4 -0
  6. package/src/index.ts +32 -0
  7. package/src/optional.ts +49 -0
  8. package/src/router.ts +3 -0
  9. package/tsconfig.json +29 -0
  10. package/LICENSE +0 -21
  11. package/index.js +0 -103
  12. package/src/analyzer/index.js +0 -370
  13. package/src/build/compiler/file-transpiler.js +0 -216
  14. package/src/build/compiler/index.js +0 -31
  15. package/src/build/compiler/route-discoverer.js +0 -49
  16. package/src/build/compiler/router-generator.js +0 -105
  17. package/src/build/css-builder.js +0 -81
  18. package/src/build/generators/html-generator.js +0 -263
  19. package/src/build/generators/robots-generator.js +0 -58
  20. package/src/build/generators/sitemap-generator.js +0 -63
  21. package/src/build/image-optimizer.js +0 -137
  22. package/src/build/processors/asset-processor.js +0 -19
  23. package/src/build/processors/css-builder.js +0 -142
  24. package/src/build/server-island-validator.js +0 -67
  25. package/src/build/ssr-renderer.js +0 -64
  26. package/src/build.js +0 -273
  27. package/src/cli.js +0 -131
  28. package/src/client/compiler.js +0 -522
  29. package/src/client/fast-refresh.js +0 -72
  30. package/src/client/hmr-runtime.js +0 -59
  31. package/src/compiler/index.js +0 -25
  32. package/src/compiler/router-generator-pure.js +0 -104
  33. package/src/compiler/transform.js +0 -149
  34. package/src/config/defaultConfig.js +0 -37
  35. package/src/config/index.js +0 -2
  36. package/src/config/loadConfig.js +0 -64
  37. package/src/config/og-image.png +0 -0
  38. package/src/css/index.js +0 -46
  39. package/src/css/processor.js +0 -172
  40. package/src/dev.js +0 -68
  41. package/src/hydration/index.js +0 -151
  42. package/src/image-optimizer/index.js +0 -103
  43. package/src/images/index.js +0 -102
  44. package/src/images/processor.js +0 -169
  45. package/src/layouts/index.js +0 -165
  46. package/src/loading/index.js +0 -210
  47. package/src/logger/logger.js +0 -320
  48. package/src/logger/notes.md +0 -20
  49. package/src/middleware/index.js +0 -182
  50. package/src/router/Router.js +0 -150
  51. package/src/router/SSRRouter.js +0 -156
  52. package/src/router/index.js +0 -3
  53. package/src/scaffolder/index.js +0 -310
  54. package/src/serve.js +0 -193
  55. package/src/server/dev-handler.js +0 -195
  56. package/src/server/dev-server-utils.js +0 -406
  57. package/src/server/dev-server.js +0 -15
  58. package/src/server/hmr-handler.js +0 -148
  59. package/src/server/index.js +0 -3
  60. package/src/server/notes.md +0 -1
  61. package/src/server/request-handler.js +0 -36
  62. package/src/server-islands/extractor.js +0 -198
  63. package/src/server-islands/index.js +0 -59
  64. package/src/styles/bertui.css +0 -210
  65. package/src/utils/cache.js +0 -297
  66. package/src/utils/env.js +0 -87
  67. package/src/utils/importhow.js +0 -52
  68. package/src/utils/index.js +0 -11
  69. package/src/utils/meta-extractor.js +0 -127
  70. package/types/bin/bertui.d.ts +0 -3
  71. package/types/bin/bertui.d.ts.map +0 -1
  72. package/types/error-overlay.d.ts +0 -2
  73. package/types/error-overlay.d.ts.map +0 -1
  74. package/types/index.d.ts +0 -26
  75. package/types/index.d.ts.map +0 -1
  76. package/types/scripts/fix-wasm-exports.d.ts +0 -2
  77. package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
  78. package/types/src/analyzer/index.d.ts +0 -8
  79. package/types/src/analyzer/index.d.ts.map +0 -1
  80. package/types/src/build/compiler/file-transpiler.d.ts +0 -5
  81. package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
  82. package/types/src/build/compiler/index.d.ts +0 -12
  83. package/types/src/build/compiler/index.d.ts.map +0 -1
  84. package/types/src/build/compiler/route-discoverer.d.ts +0 -2
  85. package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
  86. package/types/src/build/compiler/router-generator.d.ts +0 -2
  87. package/types/src/build/compiler/router-generator.d.ts.map +0 -1
  88. package/types/src/build/css-builder.d.ts +0 -18
  89. package/types/src/build/css-builder.d.ts.map +0 -1
  90. package/types/src/build/generators/html-generator.d.ts +0 -2
  91. package/types/src/build/generators/html-generator.d.ts.map +0 -1
  92. package/types/src/build/generators/robots-generator.d.ts +0 -11
  93. package/types/src/build/generators/robots-generator.d.ts.map +0 -1
  94. package/types/src/build/generators/sitemap-generator.d.ts +0 -5
  95. package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
  96. package/types/src/build/image-optimizer.d.ts +0 -11
  97. package/types/src/build/image-optimizer.d.ts.map +0 -1
  98. package/types/src/build/processors/asset-processor.d.ts +0 -2
  99. package/types/src/build/processors/asset-processor.d.ts.map +0 -1
  100. package/types/src/build/processors/css-builder.d.ts +0 -2
  101. package/types/src/build/processors/css-builder.d.ts.map +0 -1
  102. package/types/src/build/server-island-validator.d.ts +0 -27
  103. package/types/src/build/server-island-validator.d.ts.map +0 -1
  104. package/types/src/build.d.ts +0 -5
  105. package/types/src/build.d.ts.map +0 -1
  106. package/types/src/cli.d.ts +0 -2
  107. package/types/src/cli.d.ts.map +0 -1
  108. package/types/src/client/compiler.d.ts +0 -16
  109. package/types/src/client/compiler.d.ts.map +0 -1
  110. package/types/src/client/fast-refresh.d.ts +0 -3
  111. package/types/src/client/fast-refresh.d.ts.map +0 -1
  112. package/types/src/client/hmr-runtime.d.ts +0 -4
  113. package/types/src/client/hmr-runtime.d.ts.map +0 -1
  114. package/types/src/compiler/index.d.ts +0 -8
  115. package/types/src/compiler/index.d.ts.map +0 -1
  116. package/types/src/compiler/router-generator-pure.d.ts +0 -2
  117. package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
  118. package/types/src/compiler/transform.d.ts +0 -36
  119. package/types/src/compiler/transform.d.ts.map +0 -1
  120. package/types/src/config/defaultConfig.d.ts +0 -26
  121. package/types/src/config/defaultConfig.d.ts.map +0 -1
  122. package/types/src/config/index.d.ts +0 -3
  123. package/types/src/config/index.d.ts.map +0 -1
  124. package/types/src/config/loadConfig.d.ts +0 -2
  125. package/types/src/config/loadConfig.d.ts.map +0 -1
  126. package/types/src/css/index.d.ts +0 -6
  127. package/types/src/css/index.d.ts.map +0 -1
  128. package/types/src/css/processor.d.ts +0 -23
  129. package/types/src/css/processor.d.ts.map +0 -1
  130. package/types/src/dev.d.ts +0 -2
  131. package/types/src/dev.d.ts.map +0 -1
  132. package/types/src/hydration/index.d.ts +0 -33
  133. package/types/src/hydration/index.d.ts.map +0 -1
  134. package/types/src/image-optimizer/index.d.ts +0 -24
  135. package/types/src/image-optimizer/index.d.ts.map +0 -1
  136. package/types/src/images/index.d.ts +0 -12
  137. package/types/src/images/index.d.ts.map +0 -1
  138. package/types/src/images/processor.d.ts +0 -30
  139. package/types/src/images/processor.d.ts.map +0 -1
  140. package/types/src/layouts/index.d.ts +0 -28
  141. package/types/src/layouts/index.d.ts.map +0 -1
  142. package/types/src/loading/index.d.ts +0 -28
  143. package/types/src/loading/index.d.ts.map +0 -1
  144. package/types/src/logger/logger.d.ts +0 -30
  145. package/types/src/logger/logger.d.ts.map +0 -1
  146. package/types/src/middleware/index.d.ts +0 -61
  147. package/types/src/middleware/index.d.ts.map +0 -1
  148. package/types/src/router/Router.d.ts +0 -16
  149. package/types/src/router/Router.d.ts.map +0 -1
  150. package/types/src/router/SSRRouter.d.ts +0 -20
  151. package/types/src/router/SSRRouter.d.ts.map +0 -1
  152. package/types/src/router/index.d.ts +0 -3
  153. package/types/src/router/index.d.ts.map +0 -1
  154. package/types/src/scaffolder/index.d.ts +0 -14
  155. package/types/src/scaffolder/index.d.ts.map +0 -1
  156. package/types/src/serve.d.ts +0 -3
  157. package/types/src/serve.d.ts.map +0 -1
  158. package/types/src/server/dev-handler.d.ts +0 -13
  159. package/types/src/server/dev-handler.d.ts.map +0 -1
  160. package/types/src/server/dev-server-utils.d.ts +0 -6
  161. package/types/src/server/dev-server-utils.d.ts.map +0 -1
  162. package/types/src/server/dev-server.d.ts +0 -18
  163. package/types/src/server/dev-server.d.ts.map +0 -1
  164. package/types/src/server/hmr-handler.d.ts +0 -19
  165. package/types/src/server/hmr-handler.d.ts.map +0 -1
  166. package/types/src/server/index.d.ts +0 -4
  167. package/types/src/server/index.d.ts.map +0 -1
  168. package/types/src/server/request-handler.d.ts +0 -19
  169. package/types/src/server/request-handler.d.ts.map +0 -1
  170. package/types/src/server-islands/extractor.d.ts +0 -16
  171. package/types/src/server-islands/extractor.d.ts.map +0 -1
  172. package/types/src/server-islands/index.d.ts +0 -3
  173. package/types/src/server-islands/index.d.ts.map +0 -1
  174. package/types/src/utils/cache.d.ts +0 -52
  175. package/types/src/utils/cache.d.ts.map +0 -1
  176. package/types/src/utils/env.d.ts +0 -20
  177. package/types/src/utils/env.d.ts.map +0 -1
  178. package/types/src/utils/importhow.d.ts +0 -15
  179. package/types/src/utils/importhow.d.ts.map +0 -1
  180. package/types/src/utils/index.d.ts +0 -3
  181. package/types/src/utils/index.d.ts.map +0 -1
  182. package/types/src/utils/meta-extractor.d.ts +0 -13
  183. package/types/src/utils/meta-extractor.d.ts.map +0 -1
@@ -1,406 +0,0 @@
1
- // bertui/src/server/dev-server-utils.js
2
- import { join, extname } from 'path';
3
- import { existsSync, readdirSync, watch, statSync } from 'fs';
4
- import logger from '../logger/logger.js';
5
- import { compileProject } from '../client/compiler.js';
6
- import { globalCache } from '../utils/cache.js';
7
-
8
- // Image content type mapping
9
- export function getImageContentType(ext) {
10
- const types = {
11
- '.jpg': 'image/jpeg',
12
- '.jpeg': 'image/jpeg',
13
- '.png': 'image/png',
14
- '.gif': 'image/gif',
15
- '.svg': 'image/svg+xml',
16
- '.webp': 'image/webp',
17
- '.avif': 'image/avif',
18
- '.ico': 'image/x-icon',
19
- };
20
- return types[ext] || 'application/octet-stream';
21
- }
22
-
23
- // General content type mapping
24
- export function getContentType(ext) {
25
- const types = {
26
- '.js': 'application/javascript',
27
- '.jsx': 'application/javascript',
28
- '.css': 'text/css',
29
- '.html': 'text/html',
30
- '.json': 'application/json',
31
- '.png': 'image/png',
32
- '.jpg': 'image/jpeg',
33
- '.jpeg': 'image/jpeg',
34
- '.gif': 'image/gif',
35
- '.svg': 'image/svg+xml',
36
- '.webp': 'image/webp',
37
- '.avif': 'image/avif',
38
- '.ico': 'image/x-icon',
39
- '.woff': 'font/woff',
40
- '.woff2':'font/woff2',
41
- '.ttf': 'font/ttf',
42
- '.otf': 'font/otf',
43
- '.mp4': 'video/mp4',
44
- '.webm': 'video/webm',
45
- '.mp3': 'audio/mpeg',
46
- };
47
- return types[ext] || 'text/plain';
48
- }
49
-
50
- // ─────────────────────────────────────────────────────────────────────────────
51
- // Import map builder — scans node_modules at runtime so newly installed
52
- // packages are picked up without restarting the dev server.
53
- // ─────────────────────────────────────────────────────────────────────────────
54
-
55
- // Cached importmap + the package.json mtime it was built from
56
- let _cachedImportMap = null;
57
- let _cachedPkgMtime = null;
58
-
59
- export async function buildDevImportMap(root) {
60
- const pkgJsonPath = join(root, 'package.json');
61
- const nodeModulesDir = join(root, 'node_modules');
62
-
63
- // Invalidate cache when package.json changes (new install happened)
64
- let currentMtime = null;
65
- try {
66
- currentMtime = statSync(pkgJsonPath).mtimeMs;
67
- } catch { /* package.json missing — fine */ }
68
-
69
- if (_cachedImportMap && currentMtime === _cachedPkgMtime) {
70
- return _cachedImportMap;
71
- }
72
-
73
- logger.info('🔄 Rebuilding dev import map (new packages detected)...');
74
-
75
- // Initialize importMap with default mappings
76
- const importMap = {
77
- 'react': 'https://esm.sh/react@18.2.0',
78
- 'react-dom': 'https://esm.sh/react-dom@18.2.0',
79
- 'react-dom/client': 'https://esm.sh/react-dom@18.2.0/client',
80
- 'react/jsx-runtime': 'https://esm.sh/react@18.2.0/jsx-runtime',
81
- 'react/jsx-dev-runtime': 'https://esm.sh/react@18.2.0/jsx-dev-runtime',
82
- '@bunnyx/api': '/bunnyx-api/api-client.js',
83
- '@elysiajs/eden': '/node_modules/@elysiajs/eden/dist/index.mjs',
84
- };
85
-
86
- const SKIP = new Set(['react', 'react-dom', '.bin', '.cache', '.package-lock.json', '.yarn']);
87
-
88
- if (existsSync(nodeModulesDir)) {
89
- try {
90
- const packages = readdirSync(nodeModulesDir);
91
-
92
- for (const pkg of packages) {
93
- if (SKIP.has(pkg) || pkg.startsWith('.') || pkg.startsWith('_')) continue;
94
-
95
- // Handle scoped packages (@org/pkg)
96
- let pkgNames = [pkg];
97
- if (pkg.startsWith('@')) {
98
- const scopeDir = join(nodeModulesDir, pkg);
99
- try {
100
- if (statSync(scopeDir).isDirectory()) {
101
- pkgNames = readdirSync(scopeDir).map(sub => `${pkg}/${sub}`);
102
- }
103
- } catch { continue; }
104
- }
105
-
106
- for (const pkgName of pkgNames) {
107
- const pkgDir = join(nodeModulesDir, pkgName);
108
- const pkgJsonFile = join(pkgDir, 'package.json');
109
-
110
- try {
111
- if (!statSync(pkgDir).isDirectory()) continue;
112
- } catch { continue; }
113
-
114
- if (!existsSync(pkgJsonFile)) continue;
115
-
116
- try {
117
- const pkgJson = JSON.parse(await Bun.file(pkgJsonFile).text());
118
-
119
- const possibleEntries = [
120
- pkgJson.module,
121
- pkgJson.browser,
122
- pkgJson.main,
123
- 'dist/index.js',
124
- 'lib/index.js',
125
- 'index.js',
126
- ].filter(Boolean);
127
-
128
- for (const entry of possibleEntries) {
129
- const fullPath = join(pkgDir, entry);
130
- if (existsSync(fullPath)) {
131
- importMap[pkgName] = `/node_modules/${pkgName}/${entry}`;
132
- logger.debug(`📦 Dev map: ${pkgName} → ${importMap[pkgName]}`);
133
- break;
134
- }
135
- }
136
- } catch { continue; }
137
- }
138
- }
139
- } catch (error) {
140
- logger.warn(`Failed to scan node_modules: ${error.message}`);
141
- }
142
- }
143
-
144
- _cachedImportMap = importMap;
145
- _cachedPkgMtime = currentMtime;
146
-
147
- logger.success(`✅ Import map ready (${Object.keys(importMap).length} packages)`);
148
- return importMap;
149
- }
150
-
151
- // ─────────────────────────────────────────────────────────────────────────────
152
- // HTML generator — uses the live importmap so newly installed packages
153
- // appear in the next page load without a server restart.
154
- // ─────────────────────────────────────────────────────────────────────────────
155
- export async function serveHTML(root, hasRouter, config, port) {
156
- // Don't cache HTML anymore — importmap can change between requests
157
- const meta = config.meta || {};
158
-
159
- const srcStylesDir = join(root, 'src', 'styles');
160
- let userStylesheets = '';
161
-
162
- if (existsSync(srcStylesDir)) {
163
- try {
164
- const cssFiles = readdirSync(srcStylesDir).filter(f => f.endsWith('.css'));
165
- userStylesheets = cssFiles
166
- .map(f => ` <link rel="stylesheet" href="/styles/${f}">`)
167
- .join('\n');
168
- } catch (error) {
169
- logger.warn(`Could not read styles directory: ${error.message}`);
170
- }
171
- }
172
-
173
- // Auto-detect bertui-animate CSS
174
- let bertuiAnimateStylesheet = '';
175
- const bertuiAnimatePath = join(root, 'node_modules/bertui-animate/dist/bertui-animate.min.css');
176
- if (existsSync(bertuiAnimatePath)) {
177
- bertuiAnimateStylesheet = ' <link rel="stylesheet" href="/bertui-animate.css">';
178
- }
179
-
180
- // ✅ Always get the latest importmap (cached until package.json changes)
181
- const importMap = await buildDevImportMap(root);
182
-
183
- return `<!DOCTYPE html>
184
- <html lang="${meta.lang || 'en'}">
185
- <head>
186
- <meta charset="UTF-8">
187
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
188
- <title>${meta.title || 'BertUI App'}</title>
189
-
190
- ${meta.description ? `<meta name="description" content="${meta.description}">` : ''}
191
- ${meta.keywords ? `<meta name="keywords" content="${meta.keywords}">` : ''}
192
- ${meta.author ? `<meta name="author" content="${meta.author}">` : ''}
193
- ${meta.themeColor ? `<meta name="theme-color" content="${meta.themeColor}">` : ''}
194
-
195
- ${meta.ogTitle ? `<meta property="og:title" content="${meta.ogTitle || meta.title}">` : ''}
196
- ${meta.ogDescription ? `<meta property="og:description" content="${meta.ogDescription || meta.description}">` : ''}
197
- ${meta.ogImage ? `<meta property="og:image" content="${meta.ogImage}">` : ''}
198
-
199
- <link rel="icon" type="image/svg+xml" href="/public/favicon.svg">
200
-
201
- ${userStylesheets}
202
- ${bertuiAnimateStylesheet}
203
-
204
- <script type="importmap">
205
- ${JSON.stringify({ imports: importMap }, null, 2)}
206
- </script>
207
-
208
- <style>
209
- * { margin: 0; padding: 0; box-sizing: border-box; }
210
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
211
- </style>
212
- </head>
213
- <body>
214
- <div id="root"></div>
215
-
216
- <script type="module">
217
- const ws = new WebSocket('ws://localhost:${port}/__hmr');
218
-
219
- ws.onopen = () => {
220
- console.log('%c🔥 BertUI HMR connected', 'color: #10b981; font-weight: bold');
221
- };
222
-
223
- ws.onmessage = (event) => {
224
- const data = JSON.parse(event.data);
225
-
226
- if (data.type === 'reload') {
227
- console.log('%c🔄 Reloading...', 'color: #f59e0b; font-weight: bold');
228
- if (window.__BERTUI_HIDE_ERROR__) window.__BERTUI_HIDE_ERROR__();
229
- window.location.reload();
230
- }
231
-
232
- if (data.type === 'recompiling') {
233
- console.log('%c⚙️ Recompiling...', 'color: #3b82f6');
234
- }
235
-
236
- if (data.type === 'compiled') {
237
- console.log('%c✅ Compilation complete', 'color: #10b981');
238
- if (window.__BERTUI_HIDE_ERROR__) window.__BERTUI_HIDE_ERROR__();
239
- }
240
-
241
- // ✅ New: server tells browser the importmap changed → full reload
242
- if (data.type === 'importmap-updated') {
243
- console.log('%c📦 New packages detected — reloading...', 'color: #8b5cf6; font-weight: bold');
244
- window.location.reload();
245
- }
246
-
247
- if (data.type === 'compilation-error') {
248
- if (window.__BERTUI_SHOW_ERROR__) {
249
- window.__BERTUI_SHOW_ERROR__({
250
- type: 'Compilation Error',
251
- message: data.message,
252
- stack: data.stack,
253
- file: data.file,
254
- line: data.line,
255
- column: data.column,
256
- });
257
- }
258
- }
259
- };
260
-
261
- ws.onerror = (error) => {
262
- console.error('%c❌ HMR connection error', 'color: #ef4444', error);
263
- };
264
-
265
- ws.onclose = () => {
266
- console.log('%c⚠️ HMR disconnected. Refresh to reconnect.', 'color: #f59e0b');
267
- };
268
- </script>
269
-
270
- <script src="/error-overlay.js"></script>
271
- <script type="module" src="/compiled/main.js"></script>
272
- </body>
273
- </html>`;
274
- }
275
-
276
- // ─────────────────────────────────────────────────────────────────────────────
277
- // File watcher — watches src/ for code changes AND package.json for
278
- // new installs. When package.json changes it invalidates the importmap
279
- // cache and sends an `importmap-updated` message so the browser reloads
280
- // with the new packages — no server restart needed.
281
- // ─────────────────────────────────────────────────────────────────────────────
282
- export function setupFileWatcher(root, compiledDir, clients, onRecompile) {
283
- const srcDir = join(root, 'src');
284
- const pkgJson = join(root, 'package.json');
285
- const configPath = join(root, 'bertui.config.js');
286
-
287
- if (!existsSync(srcDir)) {
288
- logger.warn('src/ directory not found');
289
- return () => {};
290
- }
291
-
292
- logger.debug(`👀 Watching: ${srcDir}`);
293
- logger.debug(`👀 Watching: ${pkgJson} (package installs)`);
294
-
295
- let isRecompiling = false;
296
- let recompileTimeout = null;
297
- const watchedExtensions = [
298
- '.js', '.jsx', '.ts', '.tsx', '.css',
299
- '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.avif',
300
- ];
301
-
302
- function notifyClients(message) {
303
- for (const client of clients) {
304
- try {
305
- client.send(JSON.stringify(message));
306
- } catch {
307
- clients.delete(client);
308
- }
309
- }
310
- }
311
-
312
- // ── Source file watcher ──────────────────────────────────────────────────
313
- const srcWatcher = watch(srcDir, { recursive: true }, async (eventType, filename) => {
314
- if (!filename) return;
315
- const ext = extname(filename);
316
- if (!watchedExtensions.includes(ext)) return;
317
-
318
- logger.debug(`📝 File changed: ${filename}`);
319
- clearTimeout(recompileTimeout);
320
-
321
- recompileTimeout = setTimeout(async () => {
322
- if (isRecompiling) return;
323
- isRecompiling = true;
324
- notifyClients({ type: 'recompiling' });
325
-
326
- try {
327
- await compileProject(root);
328
- if (onRecompile) await onRecompile();
329
- logger.success('✅ Recompiled successfully');
330
- notifyClients({ type: 'compiled' });
331
- setTimeout(() => notifyClients({ type: 'reload' }), 100);
332
- } catch (error) {
333
- logger.error(`Recompilation failed: ${error.message}`);
334
- notifyClients({
335
- type: 'compilation-error',
336
- message: error.message,
337
- stack: error.stack || null,
338
- file: error.file || null,
339
- line: error.line || null,
340
- column: error.column || null,
341
- });
342
- } finally {
343
- isRecompiling = false;
344
- }
345
- }, 150);
346
- });
347
-
348
- // ── package.json watcher — detects new npm/bun installs ─────────────────
349
- let pkgWatcher = null;
350
- let lastPkgMtime = null;
351
-
352
- if (existsSync(pkgJson)) {
353
- try {
354
- lastPkgMtime = statSync(pkgJson).mtimeMs;
355
- } catch { /* ignore */ }
356
-
357
- pkgWatcher = watch(pkgJson, async (eventType) => {
358
- if (eventType !== 'change') return;
359
-
360
- // Debounce — installs can trigger multiple change events
361
- clearTimeout(pkgWatcher._debounce);
362
- pkgWatcher._debounce = setTimeout(async () => {
363
- try {
364
- const newMtime = statSync(pkgJson).mtimeMs;
365
- if (newMtime === lastPkgMtime) return; // spurious event
366
- lastPkgMtime = newMtime;
367
-
368
- logger.info('📦 package.json changed — refreshing import map...');
369
-
370
- // Bust the importmap cache so next serveHTML call rebuilds it
371
- _cachedImportMap = null;
372
- _cachedPkgMtime = null;
373
-
374
- // Wait briefly for node_modules to finish writing
375
- await new Promise(r => setTimeout(r, 800));
376
-
377
- // Rebuild and notify browser
378
- await buildDevImportMap(root);
379
- notifyClients({ type: 'importmap-updated' });
380
-
381
- logger.success('✅ Import map updated — browser reloading');
382
- } catch (err) {
383
- logger.warn(`package.json watch error: ${err.message}`);
384
- }
385
- }, 500);
386
- });
387
- }
388
-
389
- // ── bertui.config.js watcher ─────────────────────────────────────────────
390
- let configWatcher = null;
391
- if (existsSync(configPath)) {
392
- configWatcher = watch(configPath, (eventType) => {
393
- if (eventType === 'change') {
394
- logger.debug('📝 Config changed, reloading...');
395
- notifyClients({ type: 'reload' });
396
- }
397
- });
398
- }
399
-
400
- // Return cleanup function
401
- return () => {
402
- srcWatcher.close();
403
- if (pkgWatcher) pkgWatcher.close();
404
- if (configWatcher) configWatcher.close();
405
- };
406
- }
@@ -1,15 +0,0 @@
1
- // bertui/src/server/dev-server.js - MODIFIED
2
- // Now uses the new modular dev-handler
3
-
4
- import { createDevHandler } from './dev-handler.js';
5
- import logger from '../logger/logger.js';
6
-
7
- export async function startDevServer(options = {}) {
8
- const handler = await createDevHandler(options);
9
- const server = await handler.start();
10
- return { handler, server };
11
- }
12
-
13
- // Re-export for backward compatibility
14
- export { createDevHandler } from './dev-handler.js';
15
- export { handleRequest } from './request-handler.js';
@@ -1,148 +0,0 @@
1
- // bertui/src/server/hmr-handler.js
2
- // HMR WebSocket handler for development server
3
-
4
- import logger from '../logger/logger.js';
5
- import { compileFile } from '../client/compiler.js';
6
-
7
- export class HMRHandler {
8
- constructor(root) {
9
- this.root = root;
10
- this.clients = new Set();
11
- this.compilationQueue = new Map();
12
- this.pendingUpdates = new Set();
13
- this.isProcessing = false;
14
- }
15
-
16
- // WebSocket connection handler
17
- onOpen(ws) {
18
- this.clients.add(ws);
19
- logger.debug(`HMR client connected (${this.clients.size} total)`);
20
-
21
- // Send initial state
22
- ws.send(JSON.stringify({
23
- type: 'hmr-connected',
24
- timestamp: Date.now()
25
- }));
26
- }
27
-
28
- onClose(ws) {
29
- this.clients.delete(ws);
30
- logger.debug(`HMR client disconnected (${this.clients.size} remaining)`);
31
- }
32
-
33
- onMessage(ws, message) {
34
- try {
35
- const data = JSON.parse(message);
36
-
37
- switch (data.type) {
38
- case 'hmr-accept':
39
- this.handleAccept(data.module);
40
- break;
41
- case 'hmr-decline':
42
- this.handleDecline(data.module);
43
- break;
44
- }
45
- } catch (err) {
46
- logger.error(`HMR message error: ${err.message}`);
47
- }
48
- }
49
-
50
- // Notify all clients
51
- notifyAll(message) {
52
- const payload = JSON.stringify(message);
53
-
54
- for (const client of this.clients) {
55
- try {
56
- client.send(payload);
57
- } catch (err) {
58
- this.clients.delete(client);
59
- }
60
- }
61
- }
62
-
63
- // Queue file for recompilation
64
- queueRecompile(filename) {
65
- this.pendingUpdates.add(filename);
66
-
67
- if (!this.isProcessing) {
68
- setTimeout(() => this.processQueue(), 50);
69
- }
70
- }
71
-
72
- // Process compilation queue
73
- async processQueue() {
74
- if (this.isProcessing || this.pendingUpdates.size === 0) return;
75
-
76
- this.isProcessing = true;
77
- const files = Array.from(this.pendingUpdates);
78
- this.pendingUpdates.clear();
79
-
80
- try {
81
- const start = Date.now();
82
- const results = [];
83
-
84
- for (const file of files) {
85
- try {
86
- const result = await compileFile(file, this.root);
87
- results.push(result);
88
- } catch (err) {
89
- logger.error(`HMR compile error: ${file} - ${err.message}`);
90
-
91
- // Send error overlay
92
- this.notifyAll({
93
- type: 'compilation-error',
94
- file,
95
- message: err.message,
96
- stack: err.stack
97
- });
98
- }
99
- }
100
-
101
- const duration = Date.now() - start;
102
-
103
- // Notify clients of updates
104
- for (const result of results) {
105
- if (result && result.outputPath) {
106
- this.notifyAll({
107
- type: 'hmr-update',
108
- module: `/compiled/${result.outputPath}`,
109
- time: duration / results.length,
110
- dependencies: result.dependencies || []
111
- });
112
- }
113
- }
114
-
115
- logger.success(`✅ HMR updated ${results.length} files in ${duration}ms`);
116
-
117
- } catch (err) {
118
- logger.error(`HMR queue error: ${err.message}`);
119
- this.notifyAll({ type: 'full-reload' });
120
- } finally {
121
- this.isProcessing = false;
122
- }
123
- }
124
-
125
- // Handle HMR accept
126
- handleAccept(moduleId) {
127
- // Track accepted modules if needed
128
- }
129
-
130
- // Handle HMR decline
131
- handleDecline(moduleId) {
132
- // Force full reload for declined modules
133
- this.notifyAll({ type: 'full-reload' });
134
- }
135
-
136
- // Force full reload
137
- reload() {
138
- this.notifyAll({ type: 'full-reload' });
139
- }
140
-
141
- // Dispose handler
142
- dispose() {
143
- this.notifyAll({ type: 'hmr-shutdown' });
144
- this.clients.clear();
145
- this.pendingUpdates.clear();
146
- this.compilationQueue.clear();
147
- }
148
- }
@@ -1,3 +0,0 @@
1
- export { createDevHandler } from './dev-handler.js';
2
- export { handleRequest, createElysiaMiddleware } from './request-handler.js';
3
- export { startDevServer } from './dev-server.js';
@@ -1 +0,0 @@
1
- here i want to try and impliment the creation of a dev server using elisia bun library
@@ -1,36 +0,0 @@
1
- // bertui/src/server/request-handler.js - NEW FILE
2
- // Standalone request handler for BertUI
3
-
4
- import { createDevHandler } from './dev-handler.js';
5
-
6
- /**
7
- * Handle a single HTTP request with BertUI
8
- * @param {Request} request - The HTTP request
9
- * @param {Object} options - Options
10
- * @param {string} options.root - Project root directory
11
- * @param {number} options.port - Port number
12
- * @returns {Promise<Response|null>} Response or null if not handled
13
- */
14
- export async function handleRequest(request, options = {}) {
15
- const handler = await createDevHandler(options);
16
- return handler.handleRequest(request);
17
- }
18
-
19
- /**
20
- * Create a middleware function for Elysia
21
- * @param {Object} options - Options
22
- * @returns {Function} Elysia middleware
23
- */
24
- export function createElysiaMiddleware(options = {}) {
25
- return async (ctx) => {
26
- const response = await handleRequest(ctx.request, options);
27
- if (response) {
28
- ctx.set.status = response.status;
29
- response.headers.forEach((value, key) => {
30
- ctx.set.headers[key] = value;
31
- });
32
- return response.text();
33
- }
34
- return; // Continue to next middleware
35
- };
36
- }