@mandujs/core 0.13.0 → 0.13.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 (155) hide show
  1. package/README.ko.md +4 -4
  2. package/README.md +653 -653
  3. package/package.json +1 -1
  4. package/src/bundler/build.ts +91 -91
  5. package/src/bundler/css.ts +302 -302
  6. package/src/client/Link.tsx +227 -227
  7. package/src/client/globals.ts +44 -44
  8. package/src/client/hooks.ts +267 -267
  9. package/src/client/index.ts +5 -5
  10. package/src/client/island.ts +8 -8
  11. package/src/client/router.ts +435 -435
  12. package/src/client/runtime.ts +23 -23
  13. package/src/client/serialize.ts +404 -404
  14. package/src/client/window-state.ts +101 -101
  15. package/src/config/mandu.ts +9 -0
  16. package/src/config/validate.ts +12 -0
  17. package/src/config/watcher.ts +311 -311
  18. package/src/constants.ts +40 -40
  19. package/src/content/content-layer.ts +314 -314
  20. package/src/content/content.test.ts +433 -433
  21. package/src/content/data-store.ts +245 -245
  22. package/src/content/digest.ts +133 -133
  23. package/src/content/index.ts +164 -164
  24. package/src/content/loader-context.ts +172 -172
  25. package/src/content/loaders/api.ts +216 -216
  26. package/src/content/loaders/file.ts +169 -169
  27. package/src/content/loaders/glob.ts +252 -252
  28. package/src/content/loaders/index.ts +34 -34
  29. package/src/content/loaders/types.ts +137 -137
  30. package/src/content/meta-store.ts +209 -209
  31. package/src/content/types.ts +282 -282
  32. package/src/content/watcher.ts +135 -135
  33. package/src/contract/client-safe.test.ts +42 -42
  34. package/src/contract/client-safe.ts +114 -114
  35. package/src/contract/client.ts +16 -16
  36. package/src/contract/define.ts +459 -459
  37. package/src/contract/handler.ts +10 -10
  38. package/src/contract/normalize.test.ts +276 -276
  39. package/src/contract/normalize.ts +404 -404
  40. package/src/contract/registry.test.ts +206 -206
  41. package/src/contract/registry.ts +568 -568
  42. package/src/contract/schema.ts +48 -48
  43. package/src/contract/types.ts +58 -58
  44. package/src/contract/validator.ts +32 -32
  45. package/src/devtools/ai/context-builder.ts +375 -375
  46. package/src/devtools/ai/index.ts +25 -25
  47. package/src/devtools/ai/mcp-connector.ts +465 -465
  48. package/src/devtools/client/catchers/error-catcher.ts +327 -327
  49. package/src/devtools/client/catchers/index.ts +18 -18
  50. package/src/devtools/client/catchers/network-proxy.ts +363 -363
  51. package/src/devtools/client/components/index.ts +39 -39
  52. package/src/devtools/client/components/kitchen-root.tsx +362 -362
  53. package/src/devtools/client/components/mandu-character.tsx +241 -241
  54. package/src/devtools/client/components/overlay.tsx +368 -368
  55. package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
  56. package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
  57. package/src/devtools/client/components/panel/index.ts +32 -32
  58. package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
  59. package/src/devtools/client/components/panel/network-panel.tsx +292 -292
  60. package/src/devtools/client/components/panel/panel-container.tsx +259 -259
  61. package/src/devtools/client/filters/context-filters.ts +282 -282
  62. package/src/devtools/client/filters/index.ts +16 -16
  63. package/src/devtools/client/index.ts +63 -63
  64. package/src/devtools/client/persistence.ts +335 -335
  65. package/src/devtools/client/state-manager.ts +478 -478
  66. package/src/devtools/design-tokens.ts +263 -263
  67. package/src/devtools/hook/create-hook.ts +207 -207
  68. package/src/devtools/hook/index.ts +13 -13
  69. package/src/devtools/index.ts +439 -439
  70. package/src/devtools/init.ts +266 -266
  71. package/src/devtools/protocol.ts +237 -237
  72. package/src/devtools/server/index.ts +17 -17
  73. package/src/devtools/server/source-context.ts +444 -444
  74. package/src/devtools/types.ts +319 -319
  75. package/src/devtools/worker/index.ts +25 -25
  76. package/src/devtools/worker/redaction-worker.ts +222 -222
  77. package/src/devtools/worker/worker-manager.ts +409 -409
  78. package/src/error/domains.ts +265 -265
  79. package/src/error/result.ts +46 -46
  80. package/src/error/types.ts +6 -6
  81. package/src/errors/extractor.ts +409 -409
  82. package/src/errors/index.ts +19 -19
  83. package/src/filling/auth.ts +308 -308
  84. package/src/filling/context.ts +24 -1
  85. package/src/filling/deps.ts +238 -238
  86. package/src/filling/index.ts +2 -0
  87. package/src/filling/sse.test.ts +168 -0
  88. package/src/filling/sse.ts +162 -0
  89. package/src/generator/index.ts +3 -3
  90. package/src/guard/analyzer.ts +360 -360
  91. package/src/guard/ast-analyzer.ts +806 -806
  92. package/src/guard/contract-guard.ts +9 -9
  93. package/src/guard/file-type.test.ts +24 -24
  94. package/src/guard/presets/atomic.ts +70 -70
  95. package/src/guard/presets/clean.ts +77 -77
  96. package/src/guard/presets/fsd.ts +79 -79
  97. package/src/guard/presets/hexagonal.ts +68 -68
  98. package/src/guard/presets/index.ts +291 -291
  99. package/src/guard/reporter.ts +445 -445
  100. package/src/guard/rules.ts +12 -12
  101. package/src/guard/statistics.ts +578 -578
  102. package/src/guard/suggestions.ts +358 -358
  103. package/src/guard/types.ts +348 -348
  104. package/src/guard/validator.ts +834 -834
  105. package/src/guard/watcher.ts +404 -404
  106. package/src/index.ts +6 -1
  107. package/src/intent/index.ts +310 -310
  108. package/src/island/index.ts +304 -304
  109. package/src/logging/index.ts +22 -22
  110. package/src/logging/transports.ts +365 -365
  111. package/src/plugins/index.ts +38 -38
  112. package/src/plugins/registry.ts +377 -377
  113. package/src/plugins/types.ts +363 -363
  114. package/src/report/index.ts +1 -1
  115. package/src/router/fs-patterns.ts +387 -387
  116. package/src/router/fs-scanner.ts +497 -497
  117. package/src/runtime/boundary.tsx +232 -232
  118. package/src/runtime/compose.ts +222 -222
  119. package/src/runtime/escape.ts +44 -0
  120. package/src/runtime/lifecycle.ts +381 -381
  121. package/src/runtime/logger.test.ts +345 -345
  122. package/src/runtime/logger.ts +677 -677
  123. package/src/runtime/router.test.ts +476 -476
  124. package/src/runtime/router.ts +105 -105
  125. package/src/runtime/security.ts +155 -155
  126. package/src/runtime/server.ts +257 -0
  127. package/src/runtime/session-key.ts +328 -328
  128. package/src/runtime/ssr.ts +16 -21
  129. package/src/runtime/streaming-ssr.ts +24 -33
  130. package/src/runtime/trace.ts +144 -144
  131. package/src/seo/index.ts +214 -214
  132. package/src/seo/integration/ssr.ts +307 -307
  133. package/src/seo/render/basic.ts +427 -427
  134. package/src/seo/render/index.ts +143 -143
  135. package/src/seo/render/jsonld.ts +539 -539
  136. package/src/seo/render/opengraph.ts +191 -191
  137. package/src/seo/render/robots.ts +116 -116
  138. package/src/seo/render/sitemap.ts +137 -137
  139. package/src/seo/render/twitter.ts +126 -126
  140. package/src/seo/resolve/index.ts +353 -353
  141. package/src/seo/resolve/opengraph.ts +143 -143
  142. package/src/seo/resolve/robots.ts +73 -73
  143. package/src/seo/resolve/title.ts +94 -94
  144. package/src/seo/resolve/twitter.ts +73 -73
  145. package/src/seo/resolve/url.ts +97 -97
  146. package/src/seo/routes/index.ts +290 -290
  147. package/src/seo/types.ts +575 -575
  148. package/src/slot/validator.ts +39 -39
  149. package/src/spec/index.ts +3 -3
  150. package/src/spec/load.ts +76 -76
  151. package/src/spec/lock.ts +56 -56
  152. package/src/utils/bun.ts +8 -8
  153. package/src/utils/lru-cache.ts +75 -75
  154. package/src/utils/safe-io.ts +188 -188
  155. package/src/utils/string-safe.ts +298 -298
@@ -1,265 +1,265 @@
1
- /**
2
- * 도메인별 에러 클래스
3
- *
4
- * ManduError 인터페이스 기반의 실제 Error 클래스들.
5
- * try-catch에서 instanceof 체크 가능.
6
- */
7
-
8
- import { ErrorCode, ERROR_MESSAGES, ERROR_SUMMARIES } from "./types";
9
- import type { ManduError, RouteContext, ErrorType } from "./types";
10
-
11
- /**
12
- * Mandu 에러 베이스 클래스
13
- */
14
- export abstract class ManduBaseError extends Error implements ManduError {
15
- abstract readonly errorType: ErrorType;
16
- readonly code: ErrorCode | string;
17
- readonly httpStatus?: number;
18
- readonly summary: string;
19
- readonly fix: { file: string; suggestion: string; line?: number };
20
- readonly route?: RouteContext;
21
- readonly timestamp: string;
22
-
23
- constructor(
24
- code: ErrorCode | string,
25
- message: string,
26
- fix: { file: string; suggestion: string; line?: number },
27
- options?: {
28
- httpStatus?: number;
29
- route?: RouteContext;
30
- cause?: unknown;
31
- }
32
- ) {
33
- super(message, { cause: options?.cause });
34
- this.name = this.constructor.name;
35
- this.code = code;
36
- this.httpStatus = options?.httpStatus;
37
- this.summary =
38
- typeof code === "string" && code in ERROR_SUMMARIES
39
- ? ERROR_SUMMARIES[code as ErrorCode]
40
- : message;
41
- this.fix = fix;
42
- this.route = options?.route;
43
- this.timestamp = new Date().toISOString();
44
- }
45
-
46
- /**
47
- * ManduError 인터페이스로 변환
48
- */
49
- toManduError(): ManduError {
50
- return {
51
- errorType: this.errorType,
52
- code: this.code,
53
- httpStatus: this.httpStatus,
54
- message: this.message,
55
- summary: this.summary,
56
- fix: this.fix,
57
- route: this.route,
58
- timestamp: this.timestamp,
59
- };
60
- }
61
- }
62
-
63
- // ============================================================
64
- // 파일 시스템 에러
65
- // ============================================================
66
-
67
- /**
68
- * 파일 읽기/쓰기 에러
69
- */
70
- export class FileError extends ManduBaseError {
71
- readonly errorType = "LOGIC_ERROR" as const;
72
- readonly filePath: string;
73
- readonly operation: "read" | "write" | "access" | "stat";
74
-
75
- constructor(
76
- filePath: string,
77
- operation: "read" | "write" | "access" | "stat",
78
- cause?: unknown
79
- ) {
80
- const message = `파일 ${operation} 실패: ${filePath}`;
81
- super(
82
- ErrorCode.SLOT_IMPORT_ERROR,
83
- message,
84
- {
85
- file: filePath,
86
- suggestion: `파일이 존재하고 읽기 권한이 있는지 확인하세요`,
87
- },
88
- { cause }
89
- );
90
- this.filePath = filePath;
91
- this.operation = operation;
92
- }
93
- }
94
-
95
- /**
96
- * 디렉토리 읽기 에러
97
- */
98
- export class DirectoryError extends ManduBaseError {
99
- readonly errorType = "LOGIC_ERROR" as const;
100
- readonly dirPath: string;
101
-
102
- constructor(dirPath: string, cause?: unknown) {
103
- super(
104
- ErrorCode.SLOT_NOT_FOUND,
105
- `디렉토리 읽기 실패: ${dirPath}`,
106
- {
107
- file: dirPath,
108
- suggestion: `디렉토리가 존재하고 접근 가능한지 확인하세요`,
109
- },
110
- { cause }
111
- );
112
- this.dirPath = dirPath;
113
- }
114
- }
115
-
116
- // ============================================================
117
- // Guard 에러
118
- // ============================================================
119
-
120
- /**
121
- * Guard 아키텍처 검사 에러
122
- */
123
- export class GuardError extends ManduBaseError {
124
- readonly errorType = "LOGIC_ERROR" as const;
125
- readonly ruleId: string;
126
-
127
- constructor(
128
- ruleId: string,
129
- message: string,
130
- file: string,
131
- options?: {
132
- line?: number;
133
- suggestion?: string;
134
- cause?: unknown;
135
- }
136
- ) {
137
- super(
138
- ErrorCode.SLOT_VALIDATION_ERROR,
139
- message,
140
- {
141
- file,
142
- suggestion: options?.suggestion || "아키텍처 규칙을 확인하세요",
143
- line: options?.line,
144
- },
145
- { cause: options?.cause }
146
- );
147
- this.ruleId = ruleId;
148
- }
149
- }
150
-
151
- // ============================================================
152
- // Router 에러
153
- // ============================================================
154
-
155
- /**
156
- * 라우터 에러
157
- */
158
- export class RouterError extends ManduBaseError {
159
- readonly errorType = "FRAMEWORK_BUG" as const;
160
-
161
- constructor(
162
- message: string,
163
- file: string,
164
- options?: {
165
- route?: RouteContext;
166
- cause?: unknown;
167
- }
168
- ) {
169
- super(
170
- ErrorCode.FRAMEWORK_ROUTER_ERROR,
171
- message,
172
- {
173
- file,
174
- suggestion: "라우트 설정을 확인하세요",
175
- },
176
- { httpStatus: 500, ...options }
177
- );
178
- }
179
- }
180
-
181
- // ============================================================
182
- // SSR 에러
183
- // ============================================================
184
-
185
- /**
186
- * SSR 렌더링 에러
187
- */
188
- export class SSRError extends ManduBaseError {
189
- readonly errorType = "FRAMEWORK_BUG" as const;
190
-
191
- constructor(
192
- message: string,
193
- route: RouteContext,
194
- cause?: unknown
195
- ) {
196
- super(
197
- ErrorCode.FRAMEWORK_SSR_ERROR,
198
- message,
199
- {
200
- file: `app/${route.id}/page.tsx`,
201
- suggestion: "페이지 컴포넌트에서 렌더링 오류가 발생했습니다",
202
- },
203
- { httpStatus: 500, route, cause }
204
- );
205
- }
206
- }
207
-
208
- // ============================================================
209
- // Contract 에러
210
- // ============================================================
211
-
212
- /**
213
- * API 계약 위반 에러
214
- */
215
- export class ContractError extends ManduBaseError {
216
- readonly errorType = "LOGIC_ERROR" as const;
217
-
218
- constructor(
219
- message: string,
220
- contractFile: string,
221
- options?: {
222
- route?: RouteContext;
223
- cause?: unknown;
224
- }
225
- ) {
226
- super(
227
- ErrorCode.SLOT_VALIDATION_ERROR,
228
- message,
229
- {
230
- file: contractFile,
231
- suggestion: "API 계약과 실제 구현이 일치하는지 확인하세요",
232
- },
233
- { httpStatus: 400, ...options }
234
- );
235
- }
236
- }
237
-
238
- // ============================================================
239
- // Security 에러
240
- // ============================================================
241
-
242
- /**
243
- * 보안 관련 에러
244
- */
245
- export class SecurityError extends ManduBaseError {
246
- readonly errorType = "LOGIC_ERROR" as const;
247
- readonly securityType: "path_traversal" | "injection" | "unauthorized" | "import_violation";
248
-
249
- constructor(
250
- securityType: "path_traversal" | "injection" | "unauthorized" | "import_violation",
251
- message: string,
252
- file?: string
253
- ) {
254
- super(
255
- ErrorCode.SLOT_HANDLER_ERROR,
256
- message,
257
- {
258
- file: file || "unknown",
259
- suggestion: "보안 정책을 위반하는 요청입니다",
260
- },
261
- { httpStatus: 403 }
262
- );
263
- this.securityType = securityType;
264
- }
265
- }
1
+ /**
2
+ * 도메인별 에러 클래스
3
+ *
4
+ * ManduError 인터페이스 기반의 실제 Error 클래스들.
5
+ * try-catch에서 instanceof 체크 가능.
6
+ */
7
+
8
+ import { ErrorCode, ERROR_MESSAGES, ERROR_SUMMARIES } from "./types";
9
+ import type { ManduError, RouteContext, ErrorType } from "./types";
10
+
11
+ /**
12
+ * Mandu 에러 베이스 클래스
13
+ */
14
+ export abstract class ManduBaseError extends Error implements ManduError {
15
+ abstract readonly errorType: ErrorType;
16
+ readonly code: ErrorCode | string;
17
+ readonly httpStatus?: number;
18
+ readonly summary: string;
19
+ readonly fix: { file: string; suggestion: string; line?: number };
20
+ readonly route?: RouteContext;
21
+ readonly timestamp: string;
22
+
23
+ constructor(
24
+ code: ErrorCode | string,
25
+ message: string,
26
+ fix: { file: string; suggestion: string; line?: number },
27
+ options?: {
28
+ httpStatus?: number;
29
+ route?: RouteContext;
30
+ cause?: unknown;
31
+ }
32
+ ) {
33
+ super(message, { cause: options?.cause });
34
+ this.name = this.constructor.name;
35
+ this.code = code;
36
+ this.httpStatus = options?.httpStatus;
37
+ this.summary =
38
+ typeof code === "string" && code in ERROR_SUMMARIES
39
+ ? ERROR_SUMMARIES[code as ErrorCode]
40
+ : message;
41
+ this.fix = fix;
42
+ this.route = options?.route;
43
+ this.timestamp = new Date().toISOString();
44
+ }
45
+
46
+ /**
47
+ * ManduError 인터페이스로 변환
48
+ */
49
+ toManduError(): ManduError {
50
+ return {
51
+ errorType: this.errorType,
52
+ code: this.code,
53
+ httpStatus: this.httpStatus,
54
+ message: this.message,
55
+ summary: this.summary,
56
+ fix: this.fix,
57
+ route: this.route,
58
+ timestamp: this.timestamp,
59
+ };
60
+ }
61
+ }
62
+
63
+ // ============================================================
64
+ // 파일 시스템 에러
65
+ // ============================================================
66
+
67
+ /**
68
+ * 파일 읽기/쓰기 에러
69
+ */
70
+ export class FileError extends ManduBaseError {
71
+ readonly errorType = "LOGIC_ERROR" as const;
72
+ readonly filePath: string;
73
+ readonly operation: "read" | "write" | "access" | "stat";
74
+
75
+ constructor(
76
+ filePath: string,
77
+ operation: "read" | "write" | "access" | "stat",
78
+ cause?: unknown
79
+ ) {
80
+ const message = `파일 ${operation} 실패: ${filePath}`;
81
+ super(
82
+ ErrorCode.SLOT_IMPORT_ERROR,
83
+ message,
84
+ {
85
+ file: filePath,
86
+ suggestion: `파일이 존재하고 읽기 권한이 있는지 확인하세요`,
87
+ },
88
+ { cause }
89
+ );
90
+ this.filePath = filePath;
91
+ this.operation = operation;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * 디렉토리 읽기 에러
97
+ */
98
+ export class DirectoryError extends ManduBaseError {
99
+ readonly errorType = "LOGIC_ERROR" as const;
100
+ readonly dirPath: string;
101
+
102
+ constructor(dirPath: string, cause?: unknown) {
103
+ super(
104
+ ErrorCode.SLOT_NOT_FOUND,
105
+ `디렉토리 읽기 실패: ${dirPath}`,
106
+ {
107
+ file: dirPath,
108
+ suggestion: `디렉토리가 존재하고 접근 가능한지 확인하세요`,
109
+ },
110
+ { cause }
111
+ );
112
+ this.dirPath = dirPath;
113
+ }
114
+ }
115
+
116
+ // ============================================================
117
+ // Guard 에러
118
+ // ============================================================
119
+
120
+ /**
121
+ * Guard 아키텍처 검사 에러
122
+ */
123
+ export class GuardError extends ManduBaseError {
124
+ readonly errorType = "LOGIC_ERROR" as const;
125
+ readonly ruleId: string;
126
+
127
+ constructor(
128
+ ruleId: string,
129
+ message: string,
130
+ file: string,
131
+ options?: {
132
+ line?: number;
133
+ suggestion?: string;
134
+ cause?: unknown;
135
+ }
136
+ ) {
137
+ super(
138
+ ErrorCode.SLOT_VALIDATION_ERROR,
139
+ message,
140
+ {
141
+ file,
142
+ suggestion: options?.suggestion || "아키텍처 규칙을 확인하세요",
143
+ line: options?.line,
144
+ },
145
+ { cause: options?.cause }
146
+ );
147
+ this.ruleId = ruleId;
148
+ }
149
+ }
150
+
151
+ // ============================================================
152
+ // Router 에러
153
+ // ============================================================
154
+
155
+ /**
156
+ * 라우터 에러
157
+ */
158
+ export class RouterError extends ManduBaseError {
159
+ readonly errorType = "FRAMEWORK_BUG" as const;
160
+
161
+ constructor(
162
+ message: string,
163
+ file: string,
164
+ options?: {
165
+ route?: RouteContext;
166
+ cause?: unknown;
167
+ }
168
+ ) {
169
+ super(
170
+ ErrorCode.FRAMEWORK_ROUTER_ERROR,
171
+ message,
172
+ {
173
+ file,
174
+ suggestion: "라우트 설정을 확인하세요",
175
+ },
176
+ { httpStatus: 500, ...options }
177
+ );
178
+ }
179
+ }
180
+
181
+ // ============================================================
182
+ // SSR 에러
183
+ // ============================================================
184
+
185
+ /**
186
+ * SSR 렌더링 에러
187
+ */
188
+ export class SSRError extends ManduBaseError {
189
+ readonly errorType = "FRAMEWORK_BUG" as const;
190
+
191
+ constructor(
192
+ message: string,
193
+ route: RouteContext,
194
+ cause?: unknown
195
+ ) {
196
+ super(
197
+ ErrorCode.FRAMEWORK_SSR_ERROR,
198
+ message,
199
+ {
200
+ file: `app/${route.id}/page.tsx`,
201
+ suggestion: "페이지 컴포넌트에서 렌더링 오류가 발생했습니다",
202
+ },
203
+ { httpStatus: 500, route, cause }
204
+ );
205
+ }
206
+ }
207
+
208
+ // ============================================================
209
+ // Contract 에러
210
+ // ============================================================
211
+
212
+ /**
213
+ * API 계약 위반 에러
214
+ */
215
+ export class ContractError extends ManduBaseError {
216
+ readonly errorType = "LOGIC_ERROR" as const;
217
+
218
+ constructor(
219
+ message: string,
220
+ contractFile: string,
221
+ options?: {
222
+ route?: RouteContext;
223
+ cause?: unknown;
224
+ }
225
+ ) {
226
+ super(
227
+ ErrorCode.SLOT_VALIDATION_ERROR,
228
+ message,
229
+ {
230
+ file: contractFile,
231
+ suggestion: "API 계약과 실제 구현이 일치하는지 확인하세요",
232
+ },
233
+ { httpStatus: 400, ...options }
234
+ );
235
+ }
236
+ }
237
+
238
+ // ============================================================
239
+ // Security 에러
240
+ // ============================================================
241
+
242
+ /**
243
+ * 보안 관련 에러
244
+ */
245
+ export class SecurityError extends ManduBaseError {
246
+ readonly errorType = "LOGIC_ERROR" as const;
247
+ readonly securityType: "path_traversal" | "injection" | "unauthorized" | "import_violation";
248
+
249
+ constructor(
250
+ securityType: "path_traversal" | "injection" | "unauthorized" | "import_violation",
251
+ message: string,
252
+ file?: string
253
+ ) {
254
+ super(
255
+ ErrorCode.SLOT_HANDLER_ERROR,
256
+ message,
257
+ {
258
+ file: file || "unknown",
259
+ suggestion: "보안 정책을 위반하는 요청입니다",
260
+ },
261
+ { httpStatus: 403 }
262
+ );
263
+ this.securityType = securityType;
264
+ }
265
+ }
@@ -1,46 +1,46 @@
1
- import type { ManduError } from "./types";
2
- import { ErrorCode } from "./types";
3
- import { formatErrorResponse } from "./formatter";
4
-
5
- /**
6
- * Result 타입 - 성공/실패를 명시적으로 표현
7
- */
8
- export type Result<T> =
9
- | { ok: true; value: T }
10
- | { ok: false; error: ManduError };
11
-
12
- export const ok = <T>(value: T): Result<T> => ({ ok: true, value });
13
- export const err = (error: ManduError): Result<never> => ({ ok: false, error });
14
-
15
- /**
16
- * ManduError -> HTTP status 매핑
17
- */
18
- export function statusFromError(error: ManduError): number {
19
- if (typeof error.httpStatus === "number") {
20
- return error.httpStatus;
21
- }
22
-
23
- switch (error.code) {
24
- case ErrorCode.SPEC_NOT_FOUND:
25
- return 404;
26
- case ErrorCode.SPEC_PARSE_ERROR:
27
- case ErrorCode.SPEC_VALIDATION_ERROR:
28
- case ErrorCode.SPEC_ROUTE_DUPLICATE:
29
- return 400;
30
- case ErrorCode.SPEC_ROUTE_NOT_FOUND:
31
- return 404;
32
- case ErrorCode.SLOT_VALIDATION_ERROR:
33
- return 400;
34
- default:
35
- return 500;
36
- }
37
- }
38
-
39
- /**
40
- * 에러를 Response로 변환
41
- */
42
- export function errorToResponse(error: ManduError, isDev: boolean): Response {
43
- return Response.json(formatErrorResponse(error, { isDev }), {
44
- status: statusFromError(error),
45
- });
46
- }
1
+ import type { ManduError } from "./types";
2
+ import { ErrorCode } from "./types";
3
+ import { formatErrorResponse } from "./formatter";
4
+
5
+ /**
6
+ * Result 타입 - 성공/실패를 명시적으로 표현
7
+ */
8
+ export type Result<T> =
9
+ | { ok: true; value: T }
10
+ | { ok: false; error: ManduError };
11
+
12
+ export const ok = <T>(value: T): Result<T> => ({ ok: true, value });
13
+ export const err = (error: ManduError): Result<never> => ({ ok: false, error });
14
+
15
+ /**
16
+ * ManduError -> HTTP status 매핑
17
+ */
18
+ export function statusFromError(error: ManduError): number {
19
+ if (typeof error.httpStatus === "number") {
20
+ return error.httpStatus;
21
+ }
22
+
23
+ switch (error.code) {
24
+ case ErrorCode.SPEC_NOT_FOUND:
25
+ return 404;
26
+ case ErrorCode.SPEC_PARSE_ERROR:
27
+ case ErrorCode.SPEC_VALIDATION_ERROR:
28
+ case ErrorCode.SPEC_ROUTE_DUPLICATE:
29
+ return 400;
30
+ case ErrorCode.SPEC_ROUTE_NOT_FOUND:
31
+ return 404;
32
+ case ErrorCode.SLOT_VALIDATION_ERROR:
33
+ return 400;
34
+ default:
35
+ return 500;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * 에러를 Response로 변환
41
+ */
42
+ export function errorToResponse(error: ManduError, isDev: boolean): Response {
43
+ return Response.json(formatErrorResponse(error, { isDev }), {
44
+ status: statusFromError(error),
45
+ });
46
+ }
@@ -73,12 +73,12 @@ export interface DebugInfo {
73
73
  export interface ManduError {
74
74
  /** 에러 타입 */
75
75
  errorType: ErrorType;
76
- /** 에러 코드 */
77
- code: ErrorCode | string;
78
- /** HTTP 상태 코드 (선택) */
79
- httpStatus?: number;
80
- /** 에러 메시지 */
81
- message: string;
76
+ /** 에러 코드 */
77
+ code: ErrorCode | string;
78
+ /** HTTP 상태 코드 (선택) */
79
+ httpStatus?: number;
80
+ /** 에러 메시지 */
81
+ message: string;
82
82
  /** 한줄 요약 (에이전트용) */
83
83
  summary: string;
84
84
  /** 수정 대상 정보 */