@swissjs/swite 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/adapters/proxy/SwiteProxyError.d.ts.map +1 -0
  2. package/dist/{proxy → adapters/proxy}/proxyToPython.d.ts +1 -1
  3. package/dist/adapters/proxy/proxyToPython.d.ts.map +1 -0
  4. package/dist/build-engine/builder.d.ts.map +1 -0
  5. package/dist/{builder.js → build-engine/builder.js} +8 -14
  6. package/dist/cli.js +5 -5
  7. package/dist/config/config-loader.d.ts.map +1 -0
  8. package/dist/config/config.d.ts.map +1 -0
  9. package/dist/config/env.d.ts +25 -0
  10. package/dist/config/env.d.ts.map +1 -0
  11. package/dist/config/env.js +84 -0
  12. package/dist/{handlers → dev-engine/handlers}/base-handler.d.ts +3 -1
  13. package/dist/dev-engine/handlers/base-handler.d.ts.map +1 -0
  14. package/dist/{handlers → dev-engine/handlers}/base-handler.js +22 -2
  15. package/dist/dev-engine/handlers/js-handler.d.ts.map +1 -0
  16. package/dist/{handlers → dev-engine/handlers}/js-handler.js +1 -1
  17. package/dist/dev-engine/handlers/mjs-handler.d.ts.map +1 -0
  18. package/dist/{handlers → dev-engine/handlers}/mjs-handler.js +1 -1
  19. package/dist/dev-engine/handlers/node-module-handler.d.ts.map +1 -0
  20. package/dist/{handlers → dev-engine/handlers}/node-module-handler.js +4 -4
  21. package/dist/{handlers → dev-engine/handlers}/ts-handler.d.ts +0 -4
  22. package/dist/dev-engine/handlers/ts-handler.d.ts.map +1 -0
  23. package/dist/{handlers → dev-engine/handlers}/ts-handler.js +5 -28
  24. package/dist/{handlers → dev-engine/handlers}/ui-handler.d.ts +0 -4
  25. package/dist/dev-engine/handlers/ui-handler.d.ts.map +1 -0
  26. package/dist/dev-engine/handlers/ui-handler.js +84 -0
  27. package/dist/{handlers → dev-engine/handlers}/uix-handler.d.ts +0 -4
  28. package/dist/dev-engine/handlers/uix-handler.d.ts.map +1 -0
  29. package/dist/dev-engine/handlers/uix-handler.js +70 -0
  30. package/dist/dev-engine/hmr/hmr-client-template.d.ts +10 -0
  31. package/dist/dev-engine/hmr/hmr-client-template.d.ts.map +1 -0
  32. package/dist/dev-engine/hmr/hmr-client-template.js +122 -0
  33. package/dist/dev-engine/hmr/hmr.d.ts.map +1 -0
  34. package/dist/{hmr.js → dev-engine/hmr/hmr.js} +2 -134
  35. package/dist/{middleware → dev-engine/middleware}/hmr-routes.d.ts +2 -2
  36. package/dist/dev-engine/middleware/hmr-routes.d.ts.map +1 -0
  37. package/dist/{middleware → dev-engine/middleware}/hmr-routes.js +1 -1
  38. package/dist/dev-engine/middleware/middleware-setup.d.ts +34 -0
  39. package/dist/dev-engine/middleware/middleware-setup.d.ts.map +1 -0
  40. package/dist/dev-engine/middleware/middleware-setup.js +327 -0
  41. package/dist/dev-engine/middleware/static-files.d.ts.map +1 -0
  42. package/dist/{middleware → dev-engine/middleware}/static-files.js +2 -2
  43. package/dist/{dev → dev-engine}/pythonDevManager.d.ts +1 -1
  44. package/dist/dev-engine/pythonDevManager.d.ts.map +1 -0
  45. package/dist/{dev → dev-engine}/pythonDevManager.js +1 -1
  46. package/dist/{router → dev-engine/router}/file-router.d.ts +4 -4
  47. package/dist/dev-engine/router/file-router.d.ts.map +1 -0
  48. package/dist/{router → dev-engine/router}/file-router.js +4 -4
  49. package/dist/dev-engine/server.d.ts.map +1 -0
  50. package/dist/{server.js → dev-engine/server.js} +6 -6
  51. package/dist/index.d.ts +13 -13
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +9 -9
  54. package/dist/internal/cache/compilation-cache.d.ts.map +1 -0
  55. package/dist/{cache → internal/cache}/compilation-cache.js +3 -2
  56. package/dist/internal/generate-import-map-cli.d.ts.map +1 -0
  57. package/dist/{utils → internal}/generate-import-map-cli.js +1 -1
  58. package/dist/internal/generate-import-map.d.ts.map +1 -0
  59. package/dist/{utils → internal}/generate-import-map.js +3 -3
  60. package/dist/{utils → kernel}/package-finder.d.ts +3 -1
  61. package/dist/kernel/package-finder.d.ts.map +1 -0
  62. package/dist/{utils → kernel}/package-finder.js +29 -52
  63. package/dist/kernel/package-registry.d.ts.map +1 -0
  64. package/dist/kernel/workspace.d.ts.map +1 -0
  65. package/dist/{resolver → resolution}/bare-import-resolver.d.ts +1 -1
  66. package/dist/resolution/bare-import-resolver.d.ts.map +1 -0
  67. package/dist/{resolver → resolution}/bare-import-resolver.js +12 -49
  68. package/dist/resolution/cdn/cdn-fallback.d.ts.map +1 -0
  69. package/dist/resolution/path/file-path-resolver.d.ts.map +1 -0
  70. package/dist/{utils → resolution/path}/file-path-resolver.js +11 -20
  71. package/dist/resolution/path/path-fixup.d.ts +13 -0
  72. package/dist/resolution/path/path-fixup.d.ts.map +1 -0
  73. package/dist/resolution/path/path-fixup.js +20 -0
  74. package/dist/{resolver.d.ts → resolution/resolver.d.ts} +1 -1
  75. package/dist/resolution/resolver.d.ts.map +1 -0
  76. package/dist/{resolver.js → resolution/resolver.js} +8 -37
  77. package/dist/{import-rewriter.d.ts → resolution/rewriting/import-rewriter.d.ts} +1 -1
  78. package/dist/resolution/rewriting/import-rewriter.d.ts.map +1 -0
  79. package/dist/resolution/rewriting/import-rewriter.js +199 -0
  80. package/dist/{resolver → resolution}/symlink-registry.d.ts +1 -1
  81. package/dist/resolution/symlink-registry.d.ts.map +1 -0
  82. package/dist/{resolver → resolution}/symlink-registry.js +1 -1
  83. package/dist/resolution/url-resolver.d.ts.map +1 -0
  84. package/dist/{resolver → resolution}/url-resolver.js +38 -109
  85. package/dist/resolution/workspace-package-resolver.d.ts.map +1 -0
  86. package/dist/resolution/workspace-package-resolver.js +77 -0
  87. package/package.json +24 -15
  88. package/src/cli.ts +1 -1
  89. package/src/resolution/url-resolver.ts +1 -1
  90. package/dist/builder.d.ts.map +0 -1
  91. package/dist/cache/compilation-cache.d.ts.map +0 -1
  92. package/dist/config-loader.d.ts.map +0 -1
  93. package/dist/config.d.ts.map +0 -1
  94. package/dist/dev/pythonDevManager.d.ts.map +0 -1
  95. package/dist/env.d.ts +0 -19
  96. package/dist/env.d.ts.map +0 -1
  97. package/dist/env.js +0 -112
  98. package/dist/handlers/base-handler.d.ts.map +0 -1
  99. package/dist/handlers/js-handler.d.ts.map +0 -1
  100. package/dist/handlers/mjs-handler.d.ts.map +0 -1
  101. package/dist/handlers/node-module-handler.d.ts.map +0 -1
  102. package/dist/handlers/ts-handler.d.ts.map +0 -1
  103. package/dist/handlers/ui-handler.d.ts.map +0 -1
  104. package/dist/handlers/ui-handler.js +0 -182
  105. package/dist/handlers/uix-handler.d.ts.map +0 -1
  106. package/dist/handlers/uix-handler.js +0 -135
  107. package/dist/hmr.d.ts.map +0 -1
  108. package/dist/import-rewriter.d.ts.map +0 -1
  109. package/dist/import-rewriter.js +0 -351
  110. package/dist/middleware/hmr-routes.d.ts.map +0 -1
  111. package/dist/middleware/middleware-setup.d.ts +0 -23
  112. package/dist/middleware/middleware-setup.d.ts.map +0 -1
  113. package/dist/middleware/middleware-setup.js +0 -596
  114. package/dist/middleware/static-files.d.ts.map +0 -1
  115. package/dist/proxy/SwiteProxyError.d.ts.map +0 -1
  116. package/dist/proxy/proxyToPython.d.ts.map +0 -1
  117. package/dist/resolver/bare-import-resolver.d.ts.map +0 -1
  118. package/dist/resolver/symlink-registry.d.ts.map +0 -1
  119. package/dist/resolver/url-resolver.d.ts.map +0 -1
  120. package/dist/resolver/workspace-package-resolver.d.ts.map +0 -1
  121. package/dist/resolver/workspace-package-resolver.js +0 -185
  122. package/dist/resolver.d.ts.map +0 -1
  123. package/dist/router/file-router.d.ts.map +0 -1
  124. package/dist/server.d.ts.map +0 -1
  125. package/dist/utils/cdn-fallback.d.ts.map +0 -1
  126. package/dist/utils/file-path-resolver.d.ts.map +0 -1
  127. package/dist/utils/generate-import-map-cli.d.ts.map +0 -1
  128. package/dist/utils/generate-import-map.d.ts.map +0 -1
  129. package/dist/utils/package-finder.d.ts.map +0 -1
  130. package/dist/utils/package-registry.d.ts.map +0 -1
  131. package/dist/utils/workspace.d.ts.map +0 -1
  132. /package/dist/{proxy → adapters/proxy}/SwiteProxyError.d.ts +0 -0
  133. /package/dist/{proxy → adapters/proxy}/SwiteProxyError.js +0 -0
  134. /package/dist/{proxy → adapters/proxy}/proxyToPython.js +0 -0
  135. /package/dist/{builder.d.ts → build-engine/builder.d.ts} +0 -0
  136. /package/dist/{config-loader.d.ts → config/config-loader.d.ts} +0 -0
  137. /package/dist/{config-loader.js → config/config-loader.js} +0 -0
  138. /package/dist/{config.d.ts → config/config.d.ts} +0 -0
  139. /package/dist/{config.js → config/config.js} +0 -0
  140. /package/dist/{handlers → dev-engine/handlers}/js-handler.d.ts +0 -0
  141. /package/dist/{handlers → dev-engine/handlers}/mjs-handler.d.ts +0 -0
  142. /package/dist/{handlers → dev-engine/handlers}/node-module-handler.d.ts +0 -0
  143. /package/dist/{hmr.d.ts → dev-engine/hmr/hmr.d.ts} +0 -0
  144. /package/dist/{middleware → dev-engine/middleware}/static-files.d.ts +0 -0
  145. /package/dist/{server.d.ts → dev-engine/server.d.ts} +0 -0
  146. /package/dist/{cache → internal/cache}/compilation-cache.d.ts +0 -0
  147. /package/dist/{utils → internal}/generate-import-map-cli.d.ts +0 -0
  148. /package/dist/{utils → internal}/generate-import-map.d.ts +0 -0
  149. /package/dist/{utils → kernel}/package-registry.d.ts +0 -0
  150. /package/dist/{utils → kernel}/package-registry.js +0 -0
  151. /package/dist/{utils → kernel}/workspace.d.ts +0 -0
  152. /package/dist/{utils → kernel}/workspace.js +0 -0
  153. /package/dist/{utils → resolution/cdn}/cdn-fallback.d.ts +0 -0
  154. /package/dist/{utils → resolution/cdn}/cdn-fallback.js +0 -0
  155. /package/dist/{utils → resolution/path}/file-path-resolver.d.ts +0 -0
  156. /package/dist/{resolver → resolution}/url-resolver.d.ts +0 -0
  157. /package/dist/{resolver → resolution}/workspace-package-resolver.d.ts +0 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Build the HMR client script served to the browser at /__swite_hmr_client.
3
+ *
4
+ * The client is plain JavaScript (no TS syntax) because it is injected into
5
+ * browser pages as-is. Keeping it in a separate module rather than embedded
6
+ * inside hmr.ts makes it editable with syntax highlighting and avoids
7
+ * template-literal escaping issues.
8
+ */
9
+ export function buildHmrClientScript(port) {
10
+ return `// SWITE HMR Client
11
+ console.log('[SWITE] HMR enabled');
12
+
13
+ const socket = new WebSocket('ws://' + window.location.hostname + ':${port}');
14
+ const moduleGraph = new Map();
15
+ const hotModules = new Map();
16
+
17
+ socket.addEventListener('open', () => {
18
+ console.log('[SWITE] HMR connected');
19
+ });
20
+
21
+ socket.addEventListener('message', async (event) => {
22
+ const data = JSON.parse(event.data);
23
+
24
+ if (data.type === 'update') {
25
+ console.log('[SWITE] Processing update:', data.path, 'Type:', data.updateType);
26
+
27
+ if (data.updateType === 'style') {
28
+ updateStyles();
29
+ console.log('[SWITE] Styles hot updated');
30
+ } else if (data.updateType === 'hot') {
31
+ const moduleName = extractModuleName(data.path);
32
+
33
+ if (moduleName && hotModules.has(moduleName)) {
34
+ try {
35
+ invalidateModule(moduleName);
36
+ invalidateDependents(moduleName);
37
+
38
+ const updatedModule = await import(data.path + '?t=' + Date.now());
39
+ hotModules.set(moduleName, updatedModule);
40
+
41
+ updateComponent(moduleName, updatedModule);
42
+ console.log('[SWITE] Component hot updated:', moduleName);
43
+ } catch (error) {
44
+ console.error('[SWITE] Hot update failed:', error);
45
+ window.location.reload();
46
+ }
47
+ } else {
48
+ console.log('[SWITE] New component detected, reloading page');
49
+ window.location.reload();
50
+ }
51
+ } else {
52
+ console.log('[SWITE] Full page reload required');
53
+ window.location.reload();
54
+ }
55
+ }
56
+ });
57
+
58
+ function updateStyles() {
59
+ const links = document.querySelectorAll('link[rel="stylesheet"]');
60
+ links.forEach(link => {
61
+ const href = link.getAttribute('href');
62
+ if (href) {
63
+ const base = href.replace(/[?&]t=\\d+/, '');
64
+ link.setAttribute('href', base + (base.includes('?') ? '&' : '?') + 't=' + Date.now());
65
+ }
66
+ });
67
+ }
68
+
69
+ function extractModuleName(filePath) {
70
+ const parts = filePath.split('/');
71
+ const fileName = parts[parts.length - 1];
72
+ return fileName ? fileName.replace(/\\.[^.]+$/, '') : null;
73
+ }
74
+
75
+ function invalidateModule(moduleName) {
76
+ if (window.__swiss_modules__) {
77
+ delete window.__swiss_modules__[moduleName];
78
+ }
79
+ }
80
+
81
+ function invalidateDependents(moduleName) {
82
+ const dependents = moduleGraph.get(moduleName);
83
+ if (dependents) {
84
+ for (const dependent of dependents) {
85
+ invalidateModule(dependent);
86
+ }
87
+ }
88
+ }
89
+
90
+ function updateComponent(moduleName, newModule) {
91
+ if (window.__swiss_instances__) {
92
+ const instances = window.__swiss_instances__[moduleName];
93
+ if (instances && Array.isArray(instances)) {
94
+ instances.forEach(instance => {
95
+ if (instance && typeof instance.update === 'function') {
96
+ instance.update(newModule.default || newModule);
97
+ }
98
+ });
99
+ }
100
+ }
101
+ }
102
+
103
+ socket.addEventListener('close', () => {
104
+ console.log('[SWITE] HMR disconnected');
105
+ });
106
+
107
+ socket.addEventListener('error', (error) => {
108
+ console.error('[SWITE] HMR error:', error);
109
+ });
110
+
111
+ window.__swiss_modules__ = window.__swiss_modules__ || {};
112
+ window.__swiss_instances__ = window.__swiss_instances__ || {};
113
+
114
+ const currentScript = document.currentScript;
115
+ if (currentScript && currentScript.src) {
116
+ const moduleName = extractModuleName(currentScript.src);
117
+ if (moduleName) {
118
+ window.__swiss_modules__[moduleName] = true;
119
+ }
120
+ }
121
+ `;
122
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/hmr/hmr.ts"],"names":[],"mappings":"AAUA,qBAAa,SAAS;IAOlB,OAAO,CAAC,IAAI;IANd,OAAO,CAAC,GAAG,CAAmB;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAAS;gBAGX,IAAI,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM;IAOZ,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBnB,kBAAkB;IAUhC,OAAO,CAAC,cAAc;YAYR,YAAY;IAmB1B,OAAO,IAAI,MAAM;IAIX,KAAK;IA4BX,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYpC,eAAe,IAAI,MAAM;IAIzB,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,SAAS;IAcX,IAAI;CAIX"}
@@ -5,6 +5,7 @@ import * as chokidar from "chokidar";
5
5
  import { WebSocketServer, WebSocket } from "ws";
6
6
  import * as net from "net";
7
7
  import chalk from "chalk";
8
+ import { buildHmrClientScript } from "./hmr-client-template.js";
8
9
  export class HMREngine {
9
10
  constructor(root, hmrPort) {
10
11
  this.root = root;
@@ -98,140 +99,7 @@ export class HMREngine {
98
99
  });
99
100
  }
100
101
  getClientScript() {
101
- return `
102
- // SWITE HMR Client
103
- console.log('[SWITE] HMR enabled');
104
-
105
- const socket = new WebSocket('ws://localhost:${this.port}');
106
- const moduleGraph = new Map<string, Set<string>>();
107
- const hotModules = new Map<string, any>();
108
-
109
- socket.addEventListener('open', () => {
110
- console.log('[SWITE] HMR connected');
111
- });
112
-
113
- socket.addEventListener('message', (event) => {
114
- const data = JSON.parse(event.data);
115
-
116
- if (data.type === 'update') {
117
- console.log('[SWITE] Processing update:', data.path, 'Type:', data.updateType);
118
-
119
- if (data.updateType === 'style') {
120
- // Hot swap CSS
121
- updateStyles();
122
- console.log('[SWITE] Styles hot updated');
123
- } else if (data.updateType === 'hot') {
124
- // Hot reload component
125
- const moduleName = extractModuleName(data.path);
126
-
127
- if (moduleName && hotModules.has(moduleName)) {
128
- const oldModule = hotModules.get(moduleName);
129
- try {
130
- invalidateModule(moduleName);
131
- invalidateDependents(moduleName);
132
-
133
- const updatedModule = await import(data.path + '?t=' + Date.now());
134
- hotModules.set(moduleName, updatedModule);
135
-
136
- updateComponent(moduleName, updatedModule);
137
- console.log('[SWITE] Component hot updated:', moduleName);
138
- } catch (error) {
139
- console.error('[SWITE] Hot update failed:', error);
140
- window.location.reload();
141
- }
142
- } else {
143
- console.log('[SWITE] New component detected, reloading page');
144
- window.location.reload();
145
- }
146
- } else {
147
- // Full reload for everything else
148
- console.log('[SWITE] Full page reload required');
149
- window.location.reload();
150
- }
151
- }
152
- });
153
-
154
- function updateStyles() {
155
- // Find all style and link tags
156
- const styles = document.querySelectorAll('link[rel="stylesheet"], style');
157
- styles.forEach(style => {
158
- if (style.tagName === 'LINK' && style.getAttribute('href')) {
159
- const href = style.getAttribute('href');
160
- if (href && !href.includes('?t=')) {
161
- // Add timestamp to force reload
162
- style.setAttribute('href', href + '?t=' + Date.now());
163
- }
164
- }
165
- });
166
- }
167
-
168
- function extractModuleName(path: string): string | null {
169
- // Extract module name from file path
170
- const parts = path.split('/');
171
- const fileName = parts[parts.length - 1];
172
-
173
- if (fileName) {
174
- const nameWithoutExt = fileName.replace(/.[^.]+$/, "");
175
- return nameWithoutExt;
176
- }
177
-
178
- return null;
179
- }
180
-
181
- function invalidateModule(moduleName: string) {
182
- // Clear module from cache
183
- if (typeof window !== 'undefined' && (window as any).__swiss_modules__) {
184
- delete (window as any).__swiss_modules__[moduleName];
185
- }
186
- }
187
-
188
- function invalidateDependents(moduleName: string) {
189
- const dependents = moduleGraph.get(moduleName);
190
- if (dependents) {
191
- for (const dependent of dependents) {
192
- invalidateModule(dependent);
193
- }
194
- }
195
- }
196
-
197
- function updateComponent(moduleName: string, newModule: any) {
198
- // Find and update component instances
199
- if (typeof window !== 'undefined' && (window as any).__swiss_instances__) {
200
- const instances = (window as any).__swiss_instances__[moduleName];
201
- if (instances && Array.isArray(instances)) {
202
- instances.forEach(instance => {
203
- // Update component state if it has update method
204
- if (instance && typeof instance.update === 'function') {
205
- instance.update(newModule.default || newModule);
206
- }
207
- });
208
- }
209
- }
210
- }
211
-
212
- socket.addEventListener('close', () => {
213
- console.log('[SWITE] HMR disconnected');
214
- });
215
-
216
- socket.addEventListener('error', (error) => {
217
- console.error('[SWITE] HMR error:', error);
218
- });
219
-
220
- // Register module for hot reloading
221
- if (typeof window !== 'undefined') {
222
- (window as any).__swiss_modules__ = (window as any).__swiss_modules__ || {};
223
- (window as any).__swiss_instances__ = (window as any).__swiss_instances__ || {};
224
-
225
- // Auto-register current module
226
- const currentScript = document.currentScript;
227
- if (currentScript && currentScript.src) {
228
- const moduleName = extractModuleName(currentScript.src);
229
- if (moduleName) {
230
- (window as any).__swiss_modules__[moduleName] = true;
231
- }
232
- }
233
- }
234
- `;
102
+ return buildHmrClientScript(this.port);
235
103
  }
236
104
  getUpdateType(fileExt, filePath) {
237
105
  if (!fileExt || !filePath)
@@ -1,6 +1,6 @@
1
1
  import type { Express } from "express";
2
- import type { RouteDefinition } from "@kibologic/core";
3
- import { HMREngine } from "../hmr.js";
2
+ import type { RouteDefinition } from "@swissjs/core";
3
+ import { HMREngine } from "../hmr/hmr.js";
4
4
  export interface HMRRoutesConfig {
5
5
  hmr: HMREngine;
6
6
  routes: RouteDefinition[];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmr-routes.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/middleware/hmr-routes.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqG1E"}
@@ -3,7 +3,7 @@
3
3
  * SWITE - SWISS Development Server
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { HMREngine } from "../hmr.js";
6
+ import { HMREngine } from "../hmr/hmr.js";
7
7
  /**
8
8
  * Setup HMR client endpoint and routes endpoint
9
9
  */
@@ -0,0 +1,34 @@
1
+ import type { Express } from "express";
2
+ import type { RouteDefinition } from "@swissjs/core";
3
+ import { RouteScanner } from "@swissjs/plugin-file-router/core";
4
+ import { createFileWatcher } from "@swissjs/plugin-file-router/dev";
5
+ import { ModuleResolver } from "../../resolution/resolver.js";
6
+ import { HMREngine } from "../hmr/hmr.js";
7
+ export interface MiddlewareConfig {
8
+ root: string;
9
+ workspaceRoot?: string | null;
10
+ publicDir: string;
11
+ resolver: ModuleResolver;
12
+ hmr: HMREngine;
13
+ }
14
+ export interface MiddlewareResult {
15
+ routes: RouteDefinition[];
16
+ routeScanner: RouteScanner | null;
17
+ routeWatcher: Awaited<ReturnType<typeof createFileWatcher>> | null;
18
+ }
19
+ /**
20
+ * Setup all middleware for the SWITE server.
21
+ *
22
+ * Middleware registration order (matters for Express):
23
+ * 1. File router + HMR routes
24
+ * 2. /packages source files
25
+ * 3. /src source files (highest priority for that prefix)
26
+ * 4. /lib source files (pre-static guard)
27
+ * 5. .ui/.uix MIME-type guard (belt-and-suspenders for slipped-through requests)
28
+ * 6. /.skltn/modules.css → 204
29
+ * 7. Static file serving (public/, node_modules/, lib/)
30
+ * 8. General source-file transformation (all other paths)
31
+ * 9. SPA fallback
32
+ */
33
+ export declare function setupMiddleware(app: Express, config: MiddlewareConfig): Promise<MiddlewareResult>;
34
+ //# sourceMappingURL=middleware-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware-setup.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/middleware/middleware-setup.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAmC,MAAM,SAAS,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAIpE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAa9D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAK1C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,GAAG,IAAI,CAAC;CACpE;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CA2Q3B"}
@@ -0,0 +1,327 @@
1
+ /*
2
+ * Copyright (c) 2024 Themba Mzumara
3
+ * SWITE - SWISS Development Server
4
+ * Licensed under the MIT License.
5
+ */
6
+ import { RouteScanner } from "@swissjs/plugin-file-router/core";
7
+ import { createFileWatcher } from "@swissjs/plugin-file-router/dev";
8
+ import chalk from "chalk";
9
+ import path from "path";
10
+ import fs from "fs/promises";
11
+ import { ModuleResolver } from "../../resolution/resolver.js";
12
+ import { UIHandler } from "../handlers/ui-handler.js";
13
+ import { UIXHandler } from "../handlers/uix-handler.js";
14
+ import { TSHandler } from "../handlers/ts-handler.js";
15
+ import { JSHandler } from "../handlers/js-handler.js";
16
+ import { MJSHandler } from "../handlers/mjs-handler.js";
17
+ import { NodeModuleHandler } from "../handlers/node-module-handler.js";
18
+ import { setupStaticFiles, setupSPAFallback } from "./static-files.js";
19
+ import { setupHMRRoutes } from "./hmr-routes.js";
20
+ import { setupFileRouter, } from "../router/file-router.js";
21
+ import { HMREngine } from "../hmr/hmr.js";
22
+ import { findWorkspaceRoot } from "../../kernel/workspace.js";
23
+ import { loadImportMap } from "../../internal/generate-import-map.js";
24
+ import { loadEnv } from "../../config/env.js";
25
+ const SOURCE_EXTS = new Set([".ui", ".uix", ".ts", ".mjs"]);
26
+ function isFileNotFoundError(error) {
27
+ return (error instanceof Error &&
28
+ (("code" in error && error.code === "ENOENT") ||
29
+ ("errno" in error && error.errno === -4058)));
30
+ }
31
+ function sendSourceError(res, error, fullPath) {
32
+ if (res.headersSent)
33
+ return;
34
+ const status = isFileNotFoundError(error) ? 404 : 500;
35
+ res.status(status).setHeader("Content-Type", "text/plain");
36
+ res.send(isFileNotFoundError(error)
37
+ ? `File not found: ${fullPath}`
38
+ : `Error loading module: ${error instanceof Error ? error.message : String(error)}`);
39
+ }
40
+ /**
41
+ * Setup all middleware for the SWITE server.
42
+ *
43
+ * Middleware registration order (matters for Express):
44
+ * 1. File router + HMR routes
45
+ * 2. /packages source files
46
+ * 3. /src source files (highest priority for that prefix)
47
+ * 4. /lib source files (pre-static guard)
48
+ * 5. .ui/.uix MIME-type guard (belt-and-suspenders for slipped-through requests)
49
+ * 6. /.skltn/modules.css → 204
50
+ * 7. Static file serving (public/, node_modules/, lib/)
51
+ * 8. General source-file transformation (all other paths)
52
+ * 9. SPA fallback
53
+ */
54
+ export async function setupMiddleware(app, config) {
55
+ // ── 1. File router + HMR ───────────────────────────────────────────────────
56
+ const fileRouterResult = await setupFileRouter({
57
+ root: config.root,
58
+ hmr: config.hmr,
59
+ });
60
+ setupHMRRoutes(app, {
61
+ hmr: config.hmr,
62
+ routes: fileRouterResult.routes,
63
+ });
64
+ // ── Workspace + import-map setup ───────────────────────────────────────────
65
+ const workspaceRoot = await findWorkspaceRoot(config.root);
66
+ console.log(chalk.blue(`[SWITE] App root: ${config.root}`));
67
+ console.log(chalk.blue(`[SWITE] Workspace root: ${workspaceRoot}`));
68
+ const { join } = await import("node:path");
69
+ const importMapPath = join(config.root, ".swite", "import-map.json");
70
+ const importMap = await loadImportMap(importMapPath);
71
+ if (importMap) {
72
+ config.resolver.setImportMap(importMap);
73
+ }
74
+ else {
75
+ console.log(chalk.yellow(`[SWITE] No import map at ${importMapPath}, using runtime resolution`));
76
+ }
77
+ // ── Load .env files for import.meta.env inlining ──────────────────────────
78
+ const mode = process.env.NODE_ENV === "production" ? "production" : "development";
79
+ const env = loadEnv(config.root, mode);
80
+ // ── Create handlers ────────────────────────────────────────────────────────
81
+ const handlerContext = {
82
+ resolver: config.resolver,
83
+ root: config.root,
84
+ workspaceRoot,
85
+ env,
86
+ };
87
+ const uiHandler = new UIHandler(handlerContext);
88
+ const uixHandler = new UIXHandler(handlerContext);
89
+ const tsHandler = new TSHandler(handlerContext);
90
+ const jsHandler = new JSHandler(handlerContext);
91
+ const mjsHandler = new MJSHandler(handlerContext);
92
+ const nodeModuleHandler = new NodeModuleHandler(handlerContext);
93
+ // ── 2. /packages workspace source files ────────────────────────────────────
94
+ app.use("/packages", async (req, res, next) => {
95
+ const rawUrl = req.url?.split("?")[0] || "";
96
+ const fullUrl = "/packages" + (rawUrl.startsWith("/") ? rawUrl : "/" + rawUrl);
97
+ try {
98
+ if (fullUrl.endsWith(".ts") && !fullUrl.endsWith(".d.ts")) {
99
+ await tsHandler.handle(fullUrl, res);
100
+ if (res.headersSent)
101
+ return;
102
+ }
103
+ else if (fullUrl.endsWith(".js") || fullUrl.endsWith(".mjs")) {
104
+ await (fullUrl.endsWith(".js") ? jsHandler : mjsHandler).handle(fullUrl, res);
105
+ if (res.headersSent)
106
+ return;
107
+ }
108
+ }
109
+ catch (error) {
110
+ console.error(chalk.red(`[/packages] Error ${fullUrl}:`), error);
111
+ if (!res.headersSent)
112
+ res.status(500).setHeader("Content-Type", "text/plain").send(String(error));
113
+ return;
114
+ }
115
+ next();
116
+ });
117
+ // ── 3. /src source files ───────────────────────────────────────────────────
118
+ // When Express mounts at "/src", req.url is relative (e.g. "/index.ui")
119
+ app.use("/src", async (req, res, next) => {
120
+ const relativeUrl = req.url.split("?")[0];
121
+ const fullPath = "/src" + relativeUrl;
122
+ if (relativeUrl.endsWith(".ui")) {
123
+ if (res.headersSent)
124
+ return;
125
+ if (req.method === "HEAD") {
126
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
127
+ res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
128
+ res.setHeader("Pragma", "no-cache");
129
+ res.setHeader("Expires", "0");
130
+ return res.status(200).end();
131
+ }
132
+ try {
133
+ await uiHandler.handle(fullPath, res);
134
+ if (!res.headersSent)
135
+ res.status(500).send("Internal server error: handler did not send response");
136
+ }
137
+ catch (error) {
138
+ console.error(chalk.red(`[/src] .ui error ${fullPath}:`), error);
139
+ sendSourceError(res, error, fullPath);
140
+ }
141
+ return;
142
+ }
143
+ if (relativeUrl.endsWith(".uix")) {
144
+ try {
145
+ await uixHandler.handle(fullPath, res);
146
+ if (!res.headersSent)
147
+ res.status(500).setHeader("Content-Type", "text/plain").send("Error loading module");
148
+ }
149
+ catch (error) {
150
+ console.error(chalk.red(`[/src] .uix error ${fullPath}:`), error);
151
+ sendSourceError(res, error, fullPath);
152
+ }
153
+ return;
154
+ }
155
+ if (relativeUrl.endsWith(".ts") && !relativeUrl.endsWith(".d.ts")) {
156
+ try {
157
+ await tsHandler.handle(fullPath, res);
158
+ if (!res.headersSent)
159
+ res.status(500).setHeader("Content-Type", "text/plain").send("Error loading module");
160
+ }
161
+ catch (error) {
162
+ console.error(chalk.red(`[/src] .ts error ${fullPath}:`), error);
163
+ sendSourceError(res, error, fullPath);
164
+ }
165
+ return;
166
+ }
167
+ if (relativeUrl.endsWith(".js") || relativeUrl.endsWith(".mjs")) {
168
+ try {
169
+ await (relativeUrl.endsWith(".js") ? jsHandler : mjsHandler).handle(fullPath, res);
170
+ if (res.headersSent)
171
+ return;
172
+ }
173
+ catch {
174
+ // fall through to static file serving below
175
+ }
176
+ if (!res.headersSent)
177
+ return next();
178
+ return;
179
+ }
180
+ // Other files under /src (CSS, images, etc.) — serve as static
181
+ const filePath = path.join(config.root, "src", relativeUrl);
182
+ try {
183
+ const stats = await fs.stat(filePath);
184
+ if (!stats.isFile())
185
+ return next();
186
+ const ext = path.extname(relativeUrl).toLowerCase();
187
+ // Guard: source files should never reach here
188
+ if (SOURCE_EXTS.has(ext) || ext === ".js") {
189
+ res.status(404).setHeader("Content-Type", "text/plain");
190
+ return res.send(`Source file not found: ${fullPath}`);
191
+ }
192
+ const contentTypeMap = {
193
+ ".css": "text/css",
194
+ ".json": "application/json",
195
+ ".png": "image/png",
196
+ ".jpg": "image/jpeg",
197
+ ".jpeg": "image/jpeg",
198
+ ".gif": "image/gif",
199
+ ".svg": "image/svg+xml",
200
+ ".webp": "image/webp",
201
+ };
202
+ const content = await fs.readFile(filePath);
203
+ res.setHeader("Content-Type", contentTypeMap[ext] || "application/octet-stream");
204
+ res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
205
+ res.setHeader("Pragma", "no-cache");
206
+ res.setHeader("Expires", "0");
207
+ res.send(content);
208
+ }
209
+ catch {
210
+ res.status(404).setHeader("Content-Type", "text/plain");
211
+ res.send(`File not found: ${fullPath}`);
212
+ }
213
+ });
214
+ // ── 4. /lib source files (pre-static guard) ────────────────────────────────
215
+ app.use(async (req, res, next) => {
216
+ const url = req.url.split("?")[0];
217
+ if (!url.startsWith("/lib/"))
218
+ return next();
219
+ const isSource = url.endsWith(".ui") ||
220
+ url.endsWith(".uix") ||
221
+ url.endsWith(".ts") ||
222
+ (url.endsWith(".js") && !url.includes("node_modules"));
223
+ if (!isSource)
224
+ return next();
225
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
226
+ try {
227
+ if (url.endsWith(".ui")) {
228
+ await uiHandler.handle(url, res);
229
+ return;
230
+ }
231
+ if (url.endsWith(".uix")) {
232
+ await uixHandler.handle(url, res);
233
+ return;
234
+ }
235
+ // .ts/.js — fall through to general middleware
236
+ return next();
237
+ }
238
+ catch (error) {
239
+ console.error(chalk.red(`[/lib] Error ${url}:`), error);
240
+ if (!res.headersSent)
241
+ res.status(500).send("Internal server error");
242
+ }
243
+ });
244
+ // ── 5. .ui/.uix MIME guard (belt-and-suspenders) ──────────────────────────
245
+ app.use((req, res, next) => {
246
+ const url = req.url.split("?")[0];
247
+ if (url.endsWith(".ui") || url.endsWith(".uix")) {
248
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
249
+ }
250
+ next();
251
+ });
252
+ // ── 6. /.skltn/modules.css → 204 (dev mode — CSS not bundled) ─────────────
253
+ app.use("/.skltn/modules.css", (_req, res) => {
254
+ res.status(204).end();
255
+ });
256
+ // ── 7. Static file serving ─────────────────────────────────────────────────
257
+ await setupStaticFiles(app, {
258
+ root: config.root,
259
+ publicDir: config.publicDir,
260
+ workspaceRoot: config.workspaceRoot ?? null,
261
+ });
262
+ // ── 8. General source-file transformation ──────────────────────────────────
263
+ app.use(async (req, res, next) => {
264
+ const url = req.url.split("?")[0];
265
+ // /src is already handled above
266
+ if (url.startsWith("/src"))
267
+ return next();
268
+ // /lib static files are handled by static middleware; source files handled above
269
+ if (url.startsWith("/lib/")) {
270
+ const isSource = url.endsWith(".ui") ||
271
+ url.endsWith(".uix") ||
272
+ url.endsWith(".ts") ||
273
+ (url.endsWith(".js") && !url.includes("node_modules"));
274
+ if (!isSource)
275
+ return next();
276
+ }
277
+ try {
278
+ if (url.endsWith(".ui")) {
279
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
280
+ if (res.headersSent)
281
+ return;
282
+ await uiHandler.handle(url, res);
283
+ if (!res.headersSent)
284
+ res.status(500).send("Internal server error: handler did not send response");
285
+ return;
286
+ }
287
+ if (url.endsWith(".uix")) {
288
+ await uixHandler.handle(url, res);
289
+ return;
290
+ }
291
+ if (url.endsWith(".ts") && !url.endsWith(".d.ts")) {
292
+ await tsHandler.handle(url, res);
293
+ return;
294
+ }
295
+ if ((url.endsWith(".js") || url.endsWith(".mjs")) && url.includes("node_modules")) {
296
+ await nodeModuleHandler.handle(url, res);
297
+ return;
298
+ }
299
+ if (url.endsWith(".js")) {
300
+ await jsHandler.handle(url, res);
301
+ return;
302
+ }
303
+ if (url.endsWith(".mjs")) {
304
+ await mjsHandler.handle(url, res);
305
+ return;
306
+ }
307
+ // Static assets — pass to static middleware
308
+ next();
309
+ }
310
+ catch (error) {
311
+ console.error(chalk.red(`[middleware] Error ${url}:`), error);
312
+ if (!res.headersSent) {
313
+ res.status(500).send(`Error: ${error instanceof Error ? error.message : String(error)}`);
314
+ }
315
+ }
316
+ });
317
+ // ── 9. SPA fallback ────────────────────────────────────────────────────────
318
+ await setupSPAFallback(app, {
319
+ root: config.root,
320
+ publicDir: config.publicDir,
321
+ });
322
+ return {
323
+ routes: fileRouterResult.routes,
324
+ routeScanner: fileRouterResult.routeScanner,
325
+ routeWatcher: fileRouterResult.routeWatcher,
326
+ };
327
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-files.d.ts","sourceRoot":"","sources":["../../../src/dev-engine/middleware/static-files.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAMvC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CAuYf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CA+Sf"}