@mandujs/core 0.19.0 → 0.20.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 (100) hide show
  1. package/README.ko.md +0 -14
  2. package/package.json +4 -1
  3. package/src/brain/architecture/analyzer.ts +4 -4
  4. package/src/brain/doctor/analyzer.ts +18 -14
  5. package/src/bundler/build.test.ts +127 -0
  6. package/src/bundler/build.ts +385 -115
  7. package/src/bundler/css.ts +20 -5
  8. package/src/bundler/dev.ts +55 -2
  9. package/src/bundler/prerender.ts +195 -0
  10. package/src/bundler/types.ts +20 -0
  11. package/src/change/snapshot.ts +4 -23
  12. package/src/change/types.ts +2 -3
  13. package/src/client/Form.tsx +105 -0
  14. package/src/client/__tests__/use-sse.test.ts +153 -0
  15. package/src/client/hooks.ts +105 -6
  16. package/src/client/index.ts +35 -6
  17. package/src/client/router.ts +670 -433
  18. package/src/client/rpc.ts +140 -0
  19. package/src/client/runtime.ts +24 -21
  20. package/src/client/use-fetch.ts +239 -0
  21. package/src/client/use-head.ts +197 -0
  22. package/src/client/use-sse.ts +378 -0
  23. package/src/components/Image.tsx +162 -0
  24. package/src/config/mandu.ts +5 -0
  25. package/src/config/validate.ts +34 -0
  26. package/src/content/index.ts +5 -1
  27. package/src/devtools/client/catchers/error-catcher.ts +17 -0
  28. package/src/devtools/client/catchers/network-proxy.ts +390 -367
  29. package/src/devtools/client/components/kitchen-root.tsx +479 -467
  30. package/src/devtools/client/components/mandu-character.tsx +77 -53
  31. package/src/devtools/client/components/panel/diff-viewer.tsx +219 -0
  32. package/src/devtools/client/components/panel/errors-panel.tsx +2 -2
  33. package/src/devtools/client/components/panel/guard-panel.tsx +363 -234
  34. package/src/devtools/client/components/panel/index.ts +45 -32
  35. package/src/devtools/client/components/panel/islands-panel.tsx +30 -14
  36. package/src/devtools/client/components/panel/network-panel.tsx +2 -3
  37. package/src/devtools/client/components/panel/panel-container.tsx +273 -100
  38. package/src/devtools/client/components/panel/preview-panel.tsx +212 -0
  39. package/src/devtools/client/state-manager.ts +535 -478
  40. package/src/devtools/design-tokens.ts +265 -264
  41. package/src/devtools/init.ts +1 -1
  42. package/src/devtools/types.ts +321 -295
  43. package/src/filling/filling.ts +328 -6
  44. package/src/filling/index.ts +5 -1
  45. package/src/filling/session.ts +216 -0
  46. package/src/filling/ws.ts +78 -0
  47. package/src/generator/generate.ts +2 -2
  48. package/src/guard/auto-correct.ts +0 -29
  49. package/src/guard/check.ts +14 -31
  50. package/src/guard/presets/index.ts +296 -294
  51. package/src/guard/rules.ts +15 -19
  52. package/src/guard/validator.ts +834 -834
  53. package/src/index.ts +6 -1
  54. package/src/island/index.ts +373 -304
  55. package/src/kitchen/api/contract-api.ts +225 -0
  56. package/src/kitchen/api/diff-parser.ts +108 -0
  57. package/src/kitchen/api/file-api.ts +273 -0
  58. package/src/kitchen/api/guard-api.ts +83 -0
  59. package/src/kitchen/api/guard-decisions.ts +100 -0
  60. package/src/kitchen/api/routes-api.ts +50 -0
  61. package/src/kitchen/index.ts +21 -0
  62. package/src/kitchen/kitchen-handler.ts +335 -0
  63. package/src/kitchen/kitchen-ui.ts +1732 -0
  64. package/src/kitchen/stream/activity-sse.ts +145 -0
  65. package/src/kitchen/stream/file-tailer.ts +99 -0
  66. package/src/middleware/compress.ts +62 -0
  67. package/src/middleware/cors.ts +47 -0
  68. package/src/middleware/index.ts +10 -0
  69. package/src/middleware/jwt.ts +134 -0
  70. package/src/middleware/logger.ts +58 -0
  71. package/src/middleware/timeout.ts +55 -0
  72. package/src/observability/event-bus.ts +79 -0
  73. package/src/observability/index.ts +8 -0
  74. package/src/observability/logger-adapter.ts +36 -0
  75. package/src/paths.ts +0 -4
  76. package/src/plugins/hooks.ts +64 -0
  77. package/src/plugins/index.ts +3 -0
  78. package/src/plugins/types.ts +5 -0
  79. package/src/report/build.ts +0 -6
  80. package/src/resource/__tests__/backward-compat.test.ts +0 -1
  81. package/src/router/fs-patterns.ts +11 -1
  82. package/src/router/fs-routes.ts +78 -14
  83. package/src/router/fs-scanner.ts +2 -2
  84. package/src/router/fs-types.ts +2 -1
  85. package/src/runtime/adapter-bun.ts +62 -0
  86. package/src/runtime/adapter.ts +47 -0
  87. package/src/runtime/cache.ts +310 -0
  88. package/src/runtime/handler.ts +65 -0
  89. package/src/runtime/image-handler.ts +195 -0
  90. package/src/runtime/index.ts +13 -0
  91. package/src/runtime/middleware.ts +263 -0
  92. package/src/runtime/ppr.ts +74 -0
  93. package/src/runtime/server.ts +706 -71
  94. package/src/runtime/ssr.ts +70 -31
  95. package/src/runtime/streaming-ssr.ts +121 -78
  96. package/src/spec/index.ts +0 -1
  97. package/src/spec/schema.ts +1 -0
  98. package/src/testing/index.ts +189 -0
  99. package/src/watcher/watcher.ts +27 -1
  100. package/src/spec/lock.ts +0 -56
@@ -56,6 +56,17 @@ const DEFAULT_CONFIG: Partial<WatcherConfig> = {
56
56
  * Monitors file changes and emits warnings based on architecture rules.
57
57
  * Never blocks operations - only warns.
58
58
  */
59
+ /**
60
+ * Windows reserved device names that cannot be used as file/directory names.
61
+ * These cause EISDIR/ENOENT errors when file watchers try to access them.
62
+ * See: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
63
+ */
64
+ const WINDOWS_RESERVED_NAMES = new Set([
65
+ "CON", "PRN", "AUX", "NUL",
66
+ "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
67
+ "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
68
+ ]);
69
+
59
70
  export class FileWatcher {
60
71
  private config: WatcherConfig;
61
72
  private chokidarWatcher: FSWatcher | null = null;
@@ -118,6 +129,9 @@ export class FileWatcher {
118
129
  const basename = path.basename(filePath);
119
130
  // Ignore directories in the ignore list
120
131
  if (ignoredSet.has(basename)) return true;
132
+ // Filter out Windows reserved device names (#12)
133
+ // These cause EISDIR errors when chokidar tries to scandir them
134
+ if (WINDOWS_RESERVED_NAMES.has(basename.toUpperCase().replace(/\..*$/, ""))) return true;
121
135
  // For files, only watch matching extensions
122
136
  if (stats?.isFile() && extSet.size > 0) {
123
137
  const ext = path.extname(filePath);
@@ -158,7 +172,19 @@ export class FileWatcher {
158
172
  });
159
173
 
160
174
  this.chokidarWatcher.on("error", (error: unknown) => {
161
- console.error(`[Watch] Error:`, error instanceof Error ? error.message : String(error));
175
+ const message = error instanceof Error ? error.message : String(error);
176
+ // Suppress EISDIR errors from Windows reserved device names (#12)
177
+ // e.g. "EISDIR: illegal operation on a directory, scandir 'C:\...\nul'"
178
+ if (message.includes("EISDIR")) {
179
+ const pathMatch = message.match(/scandir\s+'([^']+)'/);
180
+ if (pathMatch) {
181
+ const baseName = pathMatch[1].split(/[/\\]/).pop() || "";
182
+ if (WINDOWS_RESERVED_NAMES.has(baseName.toUpperCase())) {
183
+ return; // Silently ignore — these are not real directories
184
+ }
185
+ }
186
+ }
187
+ console.error(`[Watch] Error:`, message);
162
188
  });
163
189
 
164
190
  this._active = true;
package/src/spec/lock.ts DELETED
@@ -1,56 +0,0 @@
1
- import { createHash } from "crypto";
2
- import type { RoutesManifest } from "./schema";
3
-
4
- export interface SpecLock {
5
- routesHash: string;
6
- updatedAt: string;
7
- }
8
-
9
- export function computeHash(manifest: RoutesManifest): string {
10
- const content = JSON.stringify(manifest, null, 2);
11
- return createHash("sha256").update(content).digest("hex");
12
- }
13
-
14
- export async function readLock(lockPath: string): Promise<SpecLock | null> {
15
- try {
16
- const file = Bun.file(lockPath);
17
- const exists = await file.exists();
18
-
19
- if (!exists) {
20
- return null;
21
- }
22
-
23
- const content = await file.text();
24
- return JSON.parse(content) as SpecLock;
25
- } catch {
26
- return null;
27
- }
28
- }
29
-
30
- export async function writeLock(lockPath: string, manifest: RoutesManifest): Promise<SpecLock> {
31
- const lock: SpecLock = {
32
- routesHash: computeHash(manifest),
33
- updatedAt: new Date().toISOString(),
34
- };
35
-
36
- await Bun.write(lockPath, JSON.stringify(lock, null, 2));
37
- return lock;
38
- }
39
-
40
- export async function verifyLock(
41
- lockPath: string,
42
- manifest: RoutesManifest
43
- ): Promise<{ valid: boolean; currentHash: string; lockHash: string | null }> {
44
- const currentHash = computeHash(manifest);
45
- const lock = await readLock(lockPath);
46
-
47
- if (!lock) {
48
- return { valid: false, currentHash, lockHash: null };
49
- }
50
-
51
- return {
52
- valid: lock.routesHash === currentHash,
53
- currentHash,
54
- lockHash: lock.routesHash,
55
- };
56
- }