@mandujs/core 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,200 +1,200 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/konamgil/mandu/main/mandu_only_simbol.png" alt="Mandu" width="200" />
3
- </p>
4
-
5
- <h1 align="center">@mandujs/core</h1>
6
-
7
- <p align="center">
8
- <strong>Mandu Framework Core</strong><br/>
9
- Spec, Generator, Guard, Runtime, Filling
10
- </p>
11
-
12
- <p align="center">
13
- English | <a href="./README.ko.md"><strong>한국어</strong></a>
14
- </p>
15
-
16
- ## Installation
17
-
18
- ```bash
19
- bun add @mandujs/core
20
- ```
21
-
22
- > Typically used through `@mandujs/cli`. Direct usage is for advanced use cases.
23
-
24
- ## Module Structure
25
-
26
- ```
27
- @mandujs/core
28
- ├── spec/ # Spec schema and loading
29
- ├── generator/ # Code generation
30
- ├── guard/ # Architecture checking and auto-correction
31
- ├── runtime/ # Server and router
32
- └── report/ # Guard report generation
33
- ```
34
-
35
- ## Spec Module
36
-
37
- Route manifest schema definition and loading.
38
-
39
- ```typescript
40
- import { loadManifest, RoutesManifest, RouteSpec } from "@mandujs/core";
41
-
42
- // Load and validate manifest
43
- const result = await loadManifest("spec/routes.manifest.json");
44
-
45
- if (result.success && result.data) {
46
- const manifest: RoutesManifest = result.data;
47
- manifest.routes.forEach((route: RouteSpec) => {
48
- console.log(route.id, route.pattern, route.kind);
49
- });
50
- }
51
- ```
52
-
53
- ### Lock File
54
-
55
- ```typescript
56
- import { writeLock, readLock } from "@mandujs/core";
57
-
58
- // Write lock file
59
- const lock = await writeLock("spec/spec.lock.json", manifest);
60
- console.log(lock.routesHash);
61
-
62
- // Read lock file
63
- const existing = await readLock("spec/spec.lock.json");
64
- ```
65
-
66
- ## Generator Module
67
-
68
- Spec-based code generation.
69
-
70
- ```typescript
71
- import { generateRoutes, GenerateResult } from "@mandujs/core";
72
-
73
- const result: GenerateResult = await generateRoutes(manifest, "./");
74
-
75
- console.log("Created:", result.created);
76
- console.log("Skipped:", result.skipped); // Existing slot files
77
- ```
78
-
79
- ### Template Functions
80
-
81
- ```typescript
82
- import {
83
- generateApiHandler,
84
- generateApiHandlerWithSlot,
85
- generateSlotLogic,
86
- generatePageComponent
87
- } from "@mandujs/core";
88
-
89
- // Generate API handler
90
- const code = generateApiHandler(route);
91
-
92
- // API handler with slot
93
- const codeWithSlot = generateApiHandlerWithSlot(route);
94
-
95
- // Slot logic file
96
- const slotCode = generateSlotLogic(route);
97
- ```
98
-
99
- ## Guard Module
100
-
101
- Architecture rule checking and auto-correction.
102
-
103
- ```typescript
104
- import {
105
- runGuardCheck,
106
- runAutoCorrect,
107
- GuardResult,
108
- GuardViolation
109
- } from "@mandujs/core";
110
-
111
- // Run check
112
- const result: GuardResult = await runGuardCheck(manifest, "./");
113
-
114
- if (!result.passed) {
115
- result.violations.forEach((v: GuardViolation) => {
116
- console.log(`${v.rule}: ${v.message}`);
117
- });
118
-
119
- // Run auto-correction
120
- const corrected = await runAutoCorrect(result.violations, manifest, "./");
121
- console.log("Fixed:", corrected.steps);
122
- console.log("Remaining violations:", corrected.remainingViolations);
123
- }
124
- ```
125
-
126
- ### Guard Rules
127
-
128
- | Rule ID | Description | Auto-correctable |
129
- |---------|-------------|------------------|
130
- | `SPEC_HASH_MISMATCH` | Spec and lock hash mismatch | ✅ |
131
- | `GENERATED_MANUAL_EDIT` | Manual edit to generated file | ✅ |
132
- | `HANDLER_NOT_FOUND` | Handler file not found | ❌ |
133
- | `COMPONENT_NOT_FOUND` | Component file not found | ❌ |
134
- | `SLOT_NOT_FOUND` | Slot file not found | ✅ |
135
-
136
- ## Runtime Module
137
-
138
- Server startup and routing.
139
-
140
- ```typescript
141
- import {
142
- startServer,
143
- registerApiHandler,
144
- registerPageLoader
145
- } from "@mandujs/core";
146
-
147
- // Register API handler
148
- registerApiHandler("getUsers", async (req) => {
149
- return { users: [] };
150
- });
151
-
152
- // Register page loader
153
- registerPageLoader("homePage", () => import("./pages/Home"));
154
-
155
- // Start server
156
- const server = startServer(manifest, { port: 3000 });
157
-
158
- // Stop
159
- server.stop();
160
- ```
161
-
162
- ## Report Module
163
-
164
- Guard result report generation.
165
-
166
- ```typescript
167
- import { buildGuardReport } from "@mandujs/core";
168
-
169
- const report = buildGuardReport(guardResult, lockPath);
170
- console.log(report); // Formatted text report
171
- ```
172
-
173
- ## Types
174
-
175
- ```typescript
176
- import type {
177
- RoutesManifest,
178
- RouteSpec,
179
- RouteKind,
180
- SpecLock,
181
- GuardResult,
182
- GuardViolation,
183
- GenerateResult,
184
- AutoCorrectResult,
185
- } from "@mandujs/core";
186
- ```
187
-
188
- ## Requirements
189
-
190
- - Bun >= 1.0.0
191
- - React >= 18.0.0
192
- - Zod >= 3.0.0
193
-
194
- ## Related Packages
195
-
196
- - [@mandujs/cli](https://www.npmjs.com/package/@mandujs/cli) - CLI tool
197
-
198
- ## License
199
-
200
- MIT
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/konamgil/mandu/main/mandu_only_simbol.png" alt="Mandu" width="200" />
3
+ </p>
4
+
5
+ <h1 align="center">@mandujs/core</h1>
6
+
7
+ <p align="center">
8
+ <strong>Mandu Framework Core</strong><br/>
9
+ Spec, Generator, Guard, Runtime, Filling
10
+ </p>
11
+
12
+ <p align="center">
13
+ English | <a href="./README.ko.md"><strong>한국어</strong></a>
14
+ </p>
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ bun add @mandujs/core
20
+ ```
21
+
22
+ > Typically used through `@mandujs/cli`. Direct usage is for advanced use cases.
23
+
24
+ ## Module Structure
25
+
26
+ ```
27
+ @mandujs/core
28
+ ├── spec/ # Spec schema and loading
29
+ ├── generator/ # Code generation
30
+ ├── guard/ # Architecture checking and auto-correction
31
+ ├── runtime/ # Server and router
32
+ └── report/ # Guard report generation
33
+ ```
34
+
35
+ ## Spec Module
36
+
37
+ Route manifest schema definition and loading.
38
+
39
+ ```typescript
40
+ import { loadManifest, RoutesManifest, RouteSpec } from "@mandujs/core";
41
+
42
+ // Load and validate manifest
43
+ const result = await loadManifest("spec/routes.manifest.json");
44
+
45
+ if (result.success && result.data) {
46
+ const manifest: RoutesManifest = result.data;
47
+ manifest.routes.forEach((route: RouteSpec) => {
48
+ console.log(route.id, route.pattern, route.kind);
49
+ });
50
+ }
51
+ ```
52
+
53
+ ### Lock File
54
+
55
+ ```typescript
56
+ import { writeLock, readLock } from "@mandujs/core";
57
+
58
+ // Write lock file
59
+ const lock = await writeLock("spec/spec.lock.json", manifest);
60
+ console.log(lock.routesHash);
61
+
62
+ // Read lock file
63
+ const existing = await readLock("spec/spec.lock.json");
64
+ ```
65
+
66
+ ## Generator Module
67
+
68
+ Spec-based code generation.
69
+
70
+ ```typescript
71
+ import { generateRoutes, GenerateResult } from "@mandujs/core";
72
+
73
+ const result: GenerateResult = await generateRoutes(manifest, "./");
74
+
75
+ console.log("Created:", result.created);
76
+ console.log("Skipped:", result.skipped); // Existing slot files
77
+ ```
78
+
79
+ ### Template Functions
80
+
81
+ ```typescript
82
+ import {
83
+ generateApiHandler,
84
+ generateApiHandlerWithSlot,
85
+ generateSlotLogic,
86
+ generatePageComponent
87
+ } from "@mandujs/core";
88
+
89
+ // Generate API handler
90
+ const code = generateApiHandler(route);
91
+
92
+ // API handler with slot
93
+ const codeWithSlot = generateApiHandlerWithSlot(route);
94
+
95
+ // Slot logic file
96
+ const slotCode = generateSlotLogic(route);
97
+ ```
98
+
99
+ ## Guard Module
100
+
101
+ Architecture rule checking and auto-correction.
102
+
103
+ ```typescript
104
+ import {
105
+ runGuardCheck,
106
+ runAutoCorrect,
107
+ GuardResult,
108
+ GuardViolation
109
+ } from "@mandujs/core";
110
+
111
+ // Run check
112
+ const result: GuardResult = await runGuardCheck(manifest, "./");
113
+
114
+ if (!result.passed) {
115
+ result.violations.forEach((v: GuardViolation) => {
116
+ console.log(`${v.rule}: ${v.message}`);
117
+ });
118
+
119
+ // Run auto-correction
120
+ const corrected = await runAutoCorrect(result.violations, manifest, "./");
121
+ console.log("Fixed:", corrected.steps);
122
+ console.log("Remaining violations:", corrected.remainingViolations);
123
+ }
124
+ ```
125
+
126
+ ### Guard Rules
127
+
128
+ | Rule ID | Description | Auto-correctable |
129
+ |---------|-------------|------------------|
130
+ | `SPEC_HASH_MISMATCH` | Spec and lock hash mismatch | ✅ |
131
+ | `GENERATED_MANUAL_EDIT` | Manual edit to generated file | ✅ |
132
+ | `HANDLER_NOT_FOUND` | Handler file not found | ❌ |
133
+ | `COMPONENT_NOT_FOUND` | Component file not found | ❌ |
134
+ | `SLOT_NOT_FOUND` | Slot file not found | ✅ |
135
+
136
+ ## Runtime Module
137
+
138
+ Server startup and routing.
139
+
140
+ ```typescript
141
+ import {
142
+ startServer,
143
+ registerApiHandler,
144
+ registerPageLoader
145
+ } from "@mandujs/core";
146
+
147
+ // Register API handler
148
+ registerApiHandler("getUsers", async (req) => {
149
+ return { users: [] };
150
+ });
151
+
152
+ // Register page loader
153
+ registerPageLoader("homePage", () => import("./pages/Home"));
154
+
155
+ // Start server
156
+ const server = startServer(manifest, { port: 3000 });
157
+
158
+ // Stop
159
+ server.stop();
160
+ ```
161
+
162
+ ## Report Module
163
+
164
+ Guard result report generation.
165
+
166
+ ```typescript
167
+ import { buildGuardReport } from "@mandujs/core";
168
+
169
+ const report = buildGuardReport(guardResult, lockPath);
170
+ console.log(report); // Formatted text report
171
+ ```
172
+
173
+ ## Types
174
+
175
+ ```typescript
176
+ import type {
177
+ RoutesManifest,
178
+ RouteSpec,
179
+ RouteKind,
180
+ SpecLock,
181
+ GuardResult,
182
+ GuardViolation,
183
+ GenerateResult,
184
+ AutoCorrectResult,
185
+ } from "@mandujs/core";
186
+ ```
187
+
188
+ ## Requirements
189
+
190
+ - Bun >= 1.0.0
191
+ - React >= 18.0.0
192
+ - Zod >= 3.0.0
193
+
194
+ ## Related Packages
195
+
196
+ - [@mandujs/cli](https://www.npmjs.com/package/@mandujs/cli) - CLI tool
197
+
198
+ ## License
199
+
200
+ MIT
package/package.json CHANGED
@@ -1,41 +1,41 @@
1
- {
2
- "name": "@mandujs/core",
3
- "version": "0.8.0",
4
- "description": "Mandu Framework Core - Spec, Generator, Guard, Runtime",
5
- "type": "module",
6
- "main": "./src/index.ts",
7
- "types": "./src/index.ts",
8
- "exports": {
9
- ".": "./src/index.ts",
10
- "./client": "./src/client/index.ts",
11
- "./*": "./src/*"
12
- },
13
- "files": [
14
- "src/**/*"
15
- ],
16
- "keywords": [
17
- "mandu",
18
- "framework",
19
- "agent",
20
- "ai",
21
- "code-generation"
22
- ],
23
- "repository": {
24
- "type": "git",
25
- "url": "git+https://github.com/konamgil/mandu.git",
26
- "directory": "packages/core"
27
- },
28
- "author": "konamgil",
29
- "license": "MIT",
30
- "publishConfig": {
31
- "access": "public"
32
- },
33
- "engines": {
34
- "bun": ">=1.0.0"
35
- },
36
- "peerDependencies": {
37
- "react": ">=18.0.0",
38
- "react-dom": ">=18.0.0",
39
- "zod": ">=3.0.0"
40
- }
41
- }
1
+ {
2
+ "name": "@mandujs/core",
3
+ "version": "0.8.2",
4
+ "description": "Mandu Framework Core - Spec, Generator, Guard, Runtime",
5
+ "type": "module",
6
+ "main": "./src/index.ts",
7
+ "types": "./src/index.ts",
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./client": "./src/client/index.ts",
11
+ "./*": "./src/*"
12
+ },
13
+ "files": [
14
+ "src/**/*"
15
+ ],
16
+ "keywords": [
17
+ "mandu",
18
+ "framework",
19
+ "agent",
20
+ "ai",
21
+ "code-generation"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/konamgil/mandu.git",
26
+ "directory": "packages/core"
27
+ },
28
+ "author": "konamgil",
29
+ "license": "MIT",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "engines": {
34
+ "bun": ">=1.0.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": ">=18.0.0",
38
+ "react-dom": ">=18.0.0",
39
+ "zod": ">=3.0.0"
40
+ }
41
+ }
@@ -62,6 +62,10 @@ function generateRuntimeSource(): string {
62
62
  * Fresh-style dynamic import architecture
63
63
  */
64
64
 
65
+ // React 정적 import (Island와 같은 인스턴스 공유)
66
+ import React from 'react';
67
+ import { createRoot } from 'react-dom/client';
68
+
65
69
  // Hydrated roots 추적 (unmount용)
66
70
  const hydratedRoots = new Map();
67
71
 
@@ -134,17 +138,13 @@ async function loadAndHydrate(element, src) {
134
138
  const { definition } = island;
135
139
  const data = getServerData(id);
136
140
 
137
- // React 동적 로드
138
- const { createRoot } = await import('react-dom/client');
139
- const React = await import('react');
140
-
141
- // Island 컴포넌트
141
+ // Island 컴포넌트 (정적 import된 React 사용)
142
142
  function IslandComponent() {
143
143
  const setupResult = definition.setup(data);
144
144
  return definition.render(setupResult);
145
145
  }
146
146
 
147
- // Mount
147
+ // Mount (상단에서 import한 createRoot 사용)
148
148
  const root = createRoot(element);
149
149
  root.render(React.createElement(IslandComponent));
150
150
  hydratedRoots.set(id, root);
@@ -262,6 +262,13 @@ import React, {
262
262
  Children,
263
263
  } from 'react';
264
264
 
265
+ // JSX Runtime functions (JSX 변환에 필요)
266
+ import { jsx, jsxs } from 'react/jsx-runtime';
267
+ import { jsxDEV } from 'react/jsx-dev-runtime';
268
+
269
+ // React internals (ReactDOM이 내부적으로 접근 필요)
270
+ const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
271
+
265
272
  // Named exports
266
273
  export {
267
274
  createElement,
@@ -294,6 +301,11 @@ export {
294
301
  Component,
295
302
  PureComponent,
296
303
  Children,
304
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
305
+ // JSX Runtime exports
306
+ jsx,
307
+ jsxs,
308
+ jsxDEV,
297
309
  };
298
310
 
299
311
  // Default export
@@ -364,8 +376,9 @@ function generateJsxRuntimeShimSource(): string {
364
376
  /**
365
377
  * Mandu JSX Runtime Shim (Generated)
366
378
  * Production JSX 변환용
379
+ * 순환 참조 방지: 'react'에서 import (import map이 _react.js로 매핑)
367
380
  */
368
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
381
+ import { jsx, jsxs, Fragment } from 'react';
369
382
 
370
383
  // Named exports
371
384
  export { jsx, jsxs, Fragment };
@@ -384,8 +397,9 @@ function generateJsxDevRuntimeShimSource(): string {
384
397
  /**
385
398
  * Mandu JSX Dev Runtime Shim (Generated)
386
399
  * Development JSX 변환용
400
+ * 순환 참조 방지: 'react'에서 import (import map이 _react.js로 매핑)
387
401
  */
388
- import { jsxDEV, Fragment } from 'react/jsx-dev-runtime';
402
+ import { jsxDEV, Fragment } from 'react';
389
403
 
390
404
  // Named exports
391
405
  export { jsxDEV, Fragment };
@@ -733,6 +747,19 @@ async function buildVendorShims(
733
747
  try {
734
748
  await Bun.write(srcPath, shim.source);
735
749
 
750
+ // _react.js와 jsx-runtime들은 완전히 번들링 (external 없음)
751
+ // _react-dom*, jsx-runtime은 react를 external로 처리하여 동일한 React 인스턴스 공유
752
+ // jsx-runtime은 Fragment를 react에서 가져오므로 react만 external
753
+ let shimExternal: string[] = [];
754
+ if (shim.name === "_react-dom" || shim.name === "_react-dom-client") {
755
+ shimExternal = ["react"];
756
+ } else if (shim.name === "_jsx-runtime" || shim.name === "_jsx-dev-runtime") {
757
+ // jsx-runtime은 react를 external로 (Fragment 때문에),
758
+ // 하지만 react/jsx-runtime은 번들링되어야 함
759
+ shimExternal = ["react"];
760
+ }
761
+ // _react.js는 external 없이 React 전체를 번들링
762
+
736
763
  const result = await Bun.build({
737
764
  entrypoints: [srcPath],
738
765
  outdir: outDir,
@@ -740,6 +767,7 @@ async function buildVendorShims(
740
767
  minify: options.minify ?? process.env.NODE_ENV === "production",
741
768
  sourcemap: options.sourcemap ? "external" : "none",
742
769
  target: "browser",
770
+ external: shimExternal,
743
771
  define: {
744
772
  "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development"),
745
773
  ...options.define,