@mandujs/core 0.53.2 → 0.54.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 (338) hide show
  1. package/README.md +654 -654
  2. package/package.json +2 -2
  3. package/src/a11y/__tests__/run-audit.test.ts +333 -333
  4. package/src/a11y/fix-hints.ts +76 -76
  5. package/src/a11y/index.ts +18 -18
  6. package/src/a11y/run-audit.ts +394 -394
  7. package/src/a11y/types.ts +125 -125
  8. package/src/auth/__tests__/login.test.ts +1 -1
  9. package/src/auth/__tests__/password.test.ts +122 -122
  10. package/src/auth/__tests__/tokens.test.ts +274 -274
  11. package/src/auth/__tests__/verification.test.ts +274 -274
  12. package/src/auth/index.ts +76 -76
  13. package/src/auth/login.ts +225 -225
  14. package/src/auth/password.ts +120 -120
  15. package/src/auth/reset.ts +243 -243
  16. package/src/auth/tokens.ts +612 -612
  17. package/src/auth/verification.ts +253 -253
  18. package/src/brain/__tests__/redactor.test.ts +94 -94
  19. package/src/brain/adapters/__tests__/_helpers.ts +83 -83
  20. package/src/brain/adapters/__tests__/anthropic-oauth.test.ts +196 -196
  21. package/src/brain/adapters/__tests__/chatgpt-auth.test.ts +193 -193
  22. package/src/brain/adapters/__tests__/openai-oauth.test.ts +209 -209
  23. package/src/brain/adapters/__tests__/resolver.test.ts +143 -143
  24. package/src/brain/adapters/anthropic-oauth.ts +1 -1
  25. package/src/brain/adapters/chatgpt-auth.ts +300 -300
  26. package/src/brain/adapters/index.ts +319 -319
  27. package/src/brain/adapters/oauth-flow.ts +439 -439
  28. package/src/brain/consent.ts +240 -240
  29. package/src/brain/credentials.ts +396 -396
  30. package/src/bundler/__tests__/build-runner.ts +113 -113
  31. package/src/bundler/__tests__/dev-reliability.test.ts +619 -619
  32. package/src/bundler/__tests__/extended-watch.test.ts +711 -711
  33. package/src/bundler/__tests__/fast-refresh.test.ts +10 -10
  34. package/src/bundler/__tests__/hdr.test.ts +353 -353
  35. package/src/bundler/__tests__/hmr-client.test.ts +532 -532
  36. package/src/bundler/__tests__/manifest-schema.test.ts +266 -266
  37. package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
  38. package/src/bundler/__tests__/reverse-import-graph.test.ts +519 -519
  39. package/src/bundler/__tests__/slot-dispatch.test.ts +573 -573
  40. package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -286
  41. package/src/bundler/__tests__/vendor-cache.test.ts +455 -455
  42. package/src/bundler/budget.ts +404 -404
  43. package/src/bundler/build.test.ts +179 -179
  44. package/src/bundler/build.ts +55 -55
  45. package/src/bundler/dev.ts +42 -42
  46. package/src/bundler/manifest-schema.ts +301 -301
  47. package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +263 -263
  48. package/src/bundler/plugins/__tests__/react-compiler-config.test.ts +83 -83
  49. package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -110
  50. package/src/bundler/plugins/block-generated-imports.ts +155 -155
  51. package/src/bundler/plugins/index.ts +83 -83
  52. package/src/bundler/plugins/react-compiler-config.ts +108 -108
  53. package/src/bundler/plugins/react-compiler-lint.ts +253 -253
  54. package/src/bundler/plugins/react-compiler.ts +162 -162
  55. package/src/bundler/reverse-import-graph.ts +339 -339
  56. package/src/bundler/safe-build.test.ts +201 -201
  57. package/src/bundler/safe-build.ts +103 -103
  58. package/src/bundler/scenario-matrix.ts +229 -229
  59. package/src/bundler/types.ts +10 -10
  60. package/src/bundler/vendor-cache-types.ts +130 -130
  61. package/src/bundler/vendor-cache.ts +526 -526
  62. package/src/change/snapshot.ts +18 -18
  63. package/src/client/Form.tsx +105 -105
  64. package/src/client/Link.tsx +9 -9
  65. package/src/client/__tests__/use-sse.test.ts +153 -153
  66. package/src/client/globals.ts +1 -1
  67. package/src/client/hooks.ts +362 -362
  68. package/src/client/hydrate.ts +340 -340
  69. package/src/client/prefetch-helper.ts +55 -55
  70. package/src/client/router.ts +11 -11
  71. package/src/client/runtime.ts +47 -47
  72. package/src/client/serialize.ts +404 -404
  73. package/src/client/use-fetch.ts +6 -6
  74. package/src/client/use-head.ts +197 -197
  75. package/src/client/use-sse.ts +378 -378
  76. package/src/client/window-state.ts +101 -101
  77. package/src/components/Image.tsx +162 -162
  78. package/src/config/validate.ts +3 -3
  79. package/src/config/watcher.ts +311 -311
  80. package/src/constants.ts +40 -40
  81. package/src/content/collection.ts +8 -8
  82. package/src/content/content-layer.ts +7 -7
  83. package/src/content/data-store.ts +245 -245
  84. package/src/content/frontmatter.ts +189 -189
  85. package/src/content/loader-context.ts +171 -171
  86. package/src/content/loaders/api.ts +216 -216
  87. package/src/content/loaders/file.ts +172 -172
  88. package/src/content/loaders/glob.ts +253 -253
  89. package/src/content/loaders/index.ts +34 -34
  90. package/src/content/loaders/types.ts +137 -137
  91. package/src/content/meta-store.ts +209 -209
  92. package/src/content/prebuild.test.ts +571 -571
  93. package/src/content/prebuild.ts +636 -636
  94. package/src/content/schema.ts +20 -20
  95. package/src/content/sidebar.ts +630 -630
  96. package/src/content/slug.ts +110 -110
  97. package/src/content/types.ts +282 -282
  98. package/src/content/watcher.ts +135 -135
  99. package/src/contract/client-safe.test.ts +42 -42
  100. package/src/contract/client-safe.ts +114 -114
  101. package/src/contract/define.ts +11 -11
  102. package/src/contract/index.ts +1 -1
  103. package/src/contract/normalize.test.ts +276 -276
  104. package/src/contract/normalize.ts +410 -410
  105. package/src/contract/registry.test.ts +206 -206
  106. package/src/contract/route-helpers.ts +1 -1
  107. package/src/contract/rpc.ts +443 -443
  108. package/src/contract/schema.ts +48 -48
  109. package/src/contract/types.ts +58 -58
  110. package/src/db/__tests__/db.test.ts +482 -482
  111. package/src/db/index.ts +138 -138
  112. package/src/db/migrations/history-table.ts +345 -345
  113. package/src/db/migrations/index.ts +3 -3
  114. package/src/db/migrations/lock.ts +324 -324
  115. package/src/db/migrations/runner.ts +650 -650
  116. package/src/deploy/cache.ts +140 -140
  117. package/src/deploy/compile/vercel.ts +344 -344
  118. package/src/deploy/index.ts +87 -87
  119. package/src/deploy/inference/brain.ts +268 -268
  120. package/src/deploy/inference/context.ts +182 -182
  121. package/src/deploy/inference/filling-extract.ts +245 -245
  122. package/src/deploy/inference/heuristic.ts +182 -182
  123. package/src/deploy/intent.ts +173 -173
  124. package/src/deploy/plan.ts +178 -178
  125. package/src/design/__tests__/agents-link.test.ts +109 -109
  126. package/src/design/__tests__/extract-patch-diff.test.ts +265 -265
  127. package/src/design/__tests__/lint.test.ts +110 -110
  128. package/src/design/__tests__/parser.test.ts +195 -195
  129. package/src/design/__tests__/tailwind-theme.test.ts +229 -229
  130. package/src/design/agents-link.ts +165 -165
  131. package/src/design/diff.ts +138 -138
  132. package/src/design/extract.ts +285 -285
  133. package/src/design/index.ts +102 -102
  134. package/src/design/lint.ts +209 -209
  135. package/src/design/parser.ts +555 -555
  136. package/src/design/patch.ts +241 -241
  137. package/src/design/scaffold.ts +147 -147
  138. package/src/design/tailwind-theme.ts +441 -441
  139. package/src/design/types.ts +210 -210
  140. package/src/desktop/__tests__/webview-fallback.test.ts +254 -254
  141. package/src/desktop/__tests__/window.test.ts +248 -248
  142. package/src/desktop/__tests__/worker.test.ts +266 -266
  143. package/src/desktop/index.ts +43 -43
  144. package/src/desktop/types.ts +158 -158
  145. package/src/desktop/worker.ts +180 -180
  146. package/src/dev-error-overlay/__tests__/overlay-injector.test.ts +241 -241
  147. package/src/dev-error-overlay/index.ts +30 -30
  148. package/src/dev-error-overlay/overlay-injector.ts +243 -243
  149. package/src/dev-error-overlay/overlay-styles.ts +52 -52
  150. package/src/dev-error-overlay/types.ts +66 -66
  151. package/src/devtools/ai/context-builder.ts +375 -375
  152. package/src/devtools/ai/index.ts +25 -25
  153. package/src/devtools/ai/mcp-connector.ts +25 -25
  154. package/src/devtools/client/catchers/error-catcher.ts +344 -344
  155. package/src/devtools/client/catchers/index.ts +18 -18
  156. package/src/devtools/client/components/index.ts +39 -39
  157. package/src/devtools/client/components/mandu-character.tsx +331 -331
  158. package/src/devtools/client/components/overlay.tsx +368 -368
  159. package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
  160. package/src/devtools/client/components/panel/guard-panel.tsx +30 -30
  161. package/src/devtools/client/components/panel/islands-panel.tsx +320 -320
  162. package/src/devtools/client/components/panel/network-panel.tsx +291 -291
  163. package/src/devtools/client/components/panel/panel-container.tsx +500 -500
  164. package/src/devtools/client/components/panel/preview-panel.tsx +46 -46
  165. package/src/devtools/client/filters/context-filters.ts +282 -282
  166. package/src/devtools/client/filters/index.ts +16 -16
  167. package/src/devtools/client/index.ts +63 -63
  168. package/src/devtools/client/persistence.ts +335 -335
  169. package/src/devtools/hook/create-hook.ts +207 -207
  170. package/src/devtools/hook/index.ts +13 -13
  171. package/src/devtools/index.ts +439 -439
  172. package/src/devtools/init.ts +265 -265
  173. package/src/devtools/protocol.ts +237 -237
  174. package/src/devtools/server/index.ts +17 -17
  175. package/src/devtools/server/source-context.ts +450 -450
  176. package/src/devtools/types.ts +35 -35
  177. package/src/devtools/worker/index.ts +25 -25
  178. package/src/devtools/worker/redaction-worker.ts +233 -233
  179. package/src/devtools/worker/worker-manager.ts +410 -410
  180. package/src/diagnose/__tests__/checks.test.ts +451 -380
  181. package/src/diagnose/checks.ts +832 -720
  182. package/src/diagnose/index.ts +17 -16
  183. package/src/diagnose/run.ts +93 -91
  184. package/src/diagnose/types.ts +53 -53
  185. package/src/email/__tests__/email.test.ts +355 -355
  186. package/src/email/index.ts +282 -282
  187. package/src/email/smtp.ts +64 -64
  188. package/src/error/domains.ts +265 -265
  189. package/src/error/result.ts +60 -60
  190. package/src/error/types.ts +6 -6
  191. package/src/errors/extractor.ts +409 -409
  192. package/src/errors/index.ts +19 -19
  193. package/src/filling/__tests__/session-sqlite.test.ts +454 -454
  194. package/src/filling/auth.ts +308 -308
  195. package/src/filling/cookie-codec.ts +299 -299
  196. package/src/filling/deps.ts +265 -265
  197. package/src/filling/session-sqlite.ts +617 -617
  198. package/src/filling/sse.ts +5 -5
  199. package/src/filling/ws.ts +78 -78
  200. package/src/generator/index.ts +3 -3
  201. package/src/guard/__tests__/design-inline-class.test.ts +219 -219
  202. package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -347
  203. package/src/guard/analyzer.ts +360 -360
  204. package/src/guard/auto-correct.ts +1 -1
  205. package/src/guard/contract-guard.ts +9 -9
  206. package/src/guard/define-rule.ts +243 -243
  207. package/src/guard/design-inline-class.ts +393 -393
  208. package/src/guard/file-type.test.ts +24 -24
  209. package/src/guard/graph.ts +1 -1
  210. package/src/guard/healing.ts +36 -36
  211. package/src/guard/presets/atomic.ts +70 -70
  212. package/src/guard/presets/clean.ts +77 -77
  213. package/src/guard/presets/fsd.ts +79 -79
  214. package/src/guard/presets/hexagonal.ts +68 -68
  215. package/src/guard/reporter.ts +442 -442
  216. package/src/guard/rule-presets.ts +379 -379
  217. package/src/guard/semantic-slots.ts +1 -1
  218. package/src/guard/suggestions.ts +358 -358
  219. package/src/guard/tsgolint-bridge.ts +512 -512
  220. package/src/guard/types.ts +348 -348
  221. package/src/guard/watcher.ts +405 -405
  222. package/src/i18n/define.ts +126 -126
  223. package/src/i18n/index.ts +52 -52
  224. package/src/i18n/message-registry.ts +173 -173
  225. package/src/i18n/types.ts +112 -112
  226. package/src/id/index.ts +105 -105
  227. package/src/index.ts +2 -2
  228. package/src/kitchen/api/agent-devtools-api.ts +779 -544
  229. package/src/kitchen/api/errors-grouping.ts +126 -0
  230. package/src/kitchen/kitchen-handler.ts +192 -63
  231. package/src/kitchen/kitchen-ui.ts +842 -464
  232. package/src/logging/index.ts +22 -22
  233. package/src/logging/transports.ts +365 -365
  234. package/src/middleware/bridge.ts +147 -147
  235. package/src/middleware/compose.ts +134 -134
  236. package/src/middleware/compress.ts +62 -62
  237. package/src/middleware/cors.ts +47 -47
  238. package/src/middleware/csrf.ts +328 -328
  239. package/src/middleware/define.ts +132 -132
  240. package/src/middleware/jwt.ts +134 -134
  241. package/src/middleware/logger.ts +58 -58
  242. package/src/middleware/oauth/__tests__/oauth.test.ts +1 -1
  243. package/src/middleware/oauth/index.ts +505 -505
  244. package/src/middleware/oauth/providers.ts +115 -115
  245. package/src/middleware/rate-limit/index.ts +522 -522
  246. package/src/middleware/rate-limit/sqlite-store.ts +382 -382
  247. package/src/middleware/scheduler-cron.ts +96 -96
  248. package/src/middleware/secure/__tests__/secure.test.ts +360 -360
  249. package/src/middleware/secure/csp.ts +193 -193
  250. package/src/middleware/session.ts +174 -174
  251. package/src/middleware/timeout.ts +55 -55
  252. package/src/observability/logger-adapter.ts +36 -36
  253. package/src/observability/sqlite-store.ts +254 -254
  254. package/src/openapi/generator.ts +1 -1
  255. package/src/openapi/openapi.test.ts +43 -43
  256. package/src/perf/__tests__/user-marks.test.ts +354 -354
  257. package/src/perf/index.ts +133 -133
  258. package/src/plugins/__tests__/lifecycle-integration.test.ts +272 -272
  259. package/src/plugins/__tests__/runner.test.ts +409 -409
  260. package/src/plugins/define.ts +124 -124
  261. package/src/plugins/examples/dep-check-plugin.ts +80 -80
  262. package/src/plugins/examples/prerender-cache-plugin.ts +111 -111
  263. package/src/plugins/examples/sitemap-plugin.ts +65 -65
  264. package/src/plugins/runner.ts +361 -361
  265. package/src/plugins/types.ts +368 -368
  266. package/src/report/index.ts +1 -1
  267. package/src/resource/__tests__/generator.test.ts +32 -32
  268. package/src/resource/ddl/__tests__/diff.test.ts +639 -639
  269. package/src/resource/ddl/__tests__/emit.test.ts +823 -823
  270. package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
  271. package/src/resource/ddl/emit.ts +559 -559
  272. package/src/resource/ddl/persistence-types.ts +218 -218
  273. package/src/resource/ddl/type-map.ts +223 -223
  274. package/src/resource/ddl/types.ts +232 -232
  275. package/src/resource/generator-repo.ts +630 -630
  276. package/src/resource/schema.ts +1 -1
  277. package/src/router/fs-patterns.test.ts +96 -96
  278. package/src/router/fs-routes.ts +6 -6
  279. package/src/routes/index.ts +74 -74
  280. package/src/routes/metadata-routes.ts +427 -427
  281. package/src/routes/types.ts +341 -341
  282. package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -141
  283. package/src/runtime/__tests__/hdr-client.test.ts +223 -223
  284. package/src/runtime/__tests__/http-errors.test.ts +117 -117
  285. package/src/runtime/__tests__/not-found.test.ts +152 -152
  286. package/src/runtime/adapter.ts +47 -47
  287. package/src/runtime/boundary.tsx +252 -252
  288. package/src/runtime/cache.ts +494 -494
  289. package/src/runtime/compose.ts +222 -222
  290. package/src/runtime/fast-refresh-runtime.ts +322 -322
  291. package/src/runtime/handler.ts +65 -65
  292. package/src/runtime/handlers.ts +300 -300
  293. package/src/runtime/http-errors.ts +113 -113
  294. package/src/runtime/image-handler.ts +1 -1
  295. package/src/runtime/lifecycle.ts +381 -381
  296. package/src/runtime/logger.test.ts +345 -345
  297. package/src/runtime/middleware.ts +264 -264
  298. package/src/runtime/not-found.ts +93 -93
  299. package/src/runtime/openapi-endpoint.ts +236 -236
  300. package/src/runtime/ppr.ts +74 -74
  301. package/src/runtime/registry.ts +171 -171
  302. package/src/runtime/router.ts +105 -105
  303. package/src/runtime/server.ts +67 -67
  304. package/src/runtime/shims.ts +48 -48
  305. package/src/runtime/ssr.ts +24 -31
  306. package/src/runtime/streaming-ssr.ts +32 -37
  307. package/src/runtime/trace.ts +144 -144
  308. package/src/scheduler/validate.ts +169 -169
  309. package/src/seo/index.ts +219 -219
  310. package/src/seo/integration/ssr.ts +306 -306
  311. package/src/seo/render/basic.ts +435 -435
  312. package/src/seo/render/index.ts +143 -143
  313. package/src/seo/render/jsonld.ts +539 -539
  314. package/src/seo/render/opengraph.ts +197 -197
  315. package/src/seo/render/robots.ts +116 -116
  316. package/src/seo/render/sitemap.ts +137 -137
  317. package/src/seo/render/twitter.ts +127 -127
  318. package/src/seo/resolve/opengraph.ts +143 -143
  319. package/src/seo/resolve/robots.ts +73 -73
  320. package/src/seo/resolve/title.ts +94 -94
  321. package/src/seo/resolve/twitter.ts +73 -73
  322. package/src/seo/resolve/url.ts +104 -104
  323. package/src/seo/routes/index.ts +290 -290
  324. package/src/seo/types.ts +588 -588
  325. package/src/slot/validator.ts +39 -39
  326. package/src/storage/s3/__tests__/s3.test.ts +479 -479
  327. package/src/storage/s3/index.ts +412 -412
  328. package/src/testing/__tests__/assertions.test.ts +632 -632
  329. package/src/testing/__tests__/reporter.test.ts +454 -454
  330. package/src/testing/assertions.ts +986 -986
  331. package/src/testing/db.ts +157 -157
  332. package/src/testing/mocks.ts +203 -203
  333. package/src/testing/session.ts +190 -190
  334. package/src/types/branded.ts +56 -56
  335. package/src/types/index.ts +1 -1
  336. package/src/utils/safe-io.ts +188 -188
  337. package/src/utils/string-safe.ts +298 -298
  338. package/src/watcher/watcher.ts +18 -18
@@ -81,14 +81,14 @@ export class RouterError extends Error {
81
81
  /**
82
82
  * Wildcard 설정
83
83
  */
84
- interface WildcardConfig {
85
- /** 파라미터 이름 (예: "path" for :path*) */
86
- name: string;
87
- /** optional 여부 (예: :path*? 는 optional) */
88
- optional: boolean;
89
- /** 라우트 정보 */
90
- route: RouteSpec;
91
- }
84
+ interface WildcardConfig {
85
+ /** 파라미터 이름 (예: "path" for :path*) */
86
+ name: string;
87
+ /** optional 여부 (예: :path*? 는 optional) */
88
+ optional: boolean;
89
+ /** 라우트 정보 */
90
+ route: RouteSpec;
91
+ }
92
92
 
93
93
  /**
94
94
  * Trie node for dynamic route matching
@@ -133,7 +133,7 @@ class TrieNode {
133
133
  *
134
134
  * @returns Decoded string or null if security violation
135
135
  */
136
- function safeDecodeURIComponent(str: string): string | null {
136
+ function safeDecodeURIComponent(str: string): string | null {
137
137
  // 1. Pre-decode %2F check
138
138
  if (ENCODED_SLASH_PATTERN.test(str)) {
139
139
  return null;
@@ -158,26 +158,26 @@ function safeDecodeURIComponent(str: string): string | null {
158
158
  return null;
159
159
  }
160
160
 
161
- return decoded;
162
- }
163
-
164
- /**
165
- * Decode wildcard segments safely (per-segment)
166
- */
167
- function decodeWildcardSegments(segments: string[]): string | null {
168
- if (segments.length === 0) return "";
169
-
170
- const decodedSegments: string[] = [];
171
- for (const segment of segments) {
172
- const decoded = safeDecodeURIComponent(segment);
173
- if (decoded === null) {
174
- return null;
175
- }
176
- decodedSegments.push(decoded);
177
- }
178
-
179
- return decodedSegments.join("/");
180
- }
161
+ return decoded;
162
+ }
163
+
164
+ /**
165
+ * Decode wildcard segments safely (per-segment)
166
+ */
167
+ function decodeWildcardSegments(segments: string[]): string | null {
168
+ if (segments.length === 0) return "";
169
+
170
+ const decodedSegments: string[] = [];
171
+ for (const segment of segments) {
172
+ const decoded = safeDecodeURIComponent(segment);
173
+ if (decoded === null) {
174
+ return null;
175
+ }
176
+ decodedSegments.push(decoded);
177
+ }
178
+
179
+ return decodedSegments.join("/");
180
+ }
181
181
 
182
182
  // ═══════════════════════════════════════════════════════════════════════════
183
183
  // Router Class
@@ -371,47 +371,47 @@ export class Router {
371
371
  private insertTrie(pattern: string, segments: string[], route: RouteSpec): void {
372
372
  let node = this.trie;
373
373
 
374
- for (let i = 0; i < segments.length; i++) {
375
- const seg = segments[i];
376
-
377
- // Legacy wildcard: *
378
- if (seg === "*") {
379
- if (node.wildcardConfig) {
380
- throw new RouterError(
381
- `Wildcard conflict in pattern "${pattern}"`,
382
- "ROUTE_CONFLICT",
383
- route.id,
384
- node.wildcardConfig.route.id
385
- );
386
- }
387
- node.wildcardConfig = {
388
- name: WILDCARD_PARAM_KEY,
389
- optional: false,
390
- route,
391
- };
392
- return;
393
- }
374
+ for (let i = 0; i < segments.length; i++) {
375
+ const seg = segments[i];
376
+
377
+ // Legacy wildcard: *
378
+ if (seg === "*") {
379
+ if (node.wildcardConfig) {
380
+ throw new RouterError(
381
+ `Wildcard conflict in pattern "${pattern}"`,
382
+ "ROUTE_CONFLICT",
383
+ route.id,
384
+ node.wildcardConfig.route.id
385
+ );
386
+ }
387
+ node.wildcardConfig = {
388
+ name: WILDCARD_PARAM_KEY,
389
+ optional: false,
390
+ route,
391
+ };
392
+ return;
393
+ }
394
394
 
395
395
  // Parameter handling (including wildcards)
396
396
  if (seg.startsWith(":")) {
397
397
  // Check for wildcard pattern: :param* or :param*?
398
398
  const wildcardMatch = seg.match(/^:([^*?]+)\*(\?)?$/);
399
- if (wildcardMatch) {
400
- const paramName = wildcardMatch[1];
401
- const isOptional = wildcardMatch[2] === "?";
402
-
403
- if (node.wildcardConfig) {
404
- throw new RouterError(
405
- `Wildcard conflict in pattern "${pattern}"`,
406
- "ROUTE_CONFLICT",
407
- route.id,
408
- node.wildcardConfig.route.id
409
- );
410
- }
411
-
412
- node.wildcardConfig = {
413
- name: paramName,
414
- optional: isOptional,
399
+ if (wildcardMatch) {
400
+ const paramName = wildcardMatch[1];
401
+ const isOptional = wildcardMatch[2] === "?";
402
+
403
+ if (node.wildcardConfig) {
404
+ throw new RouterError(
405
+ `Wildcard conflict in pattern "${pattern}"`,
406
+ "ROUTE_CONFLICT",
407
+ route.id,
408
+ node.wildcardConfig.route.id
409
+ );
410
+ }
411
+
412
+ node.wildcardConfig = {
413
+ name: paramName,
414
+ optional: isOptional,
415
415
  route,
416
416
  };
417
417
 
@@ -494,18 +494,18 @@ export class Router {
494
494
  continue;
495
495
  }
496
496
 
497
- // 3. No match - try wildcard fallback
498
- if (wildcardMatch) {
499
- const remainingSegments = segments.slice(wildcardMatch.consumed);
500
- const remaining = decodeWildcardSegments(remainingSegments);
501
- if (remaining === null) {
502
- return null;
503
- }
504
- if (this.debug) {
505
- console.log(`[Router] Wildcard match: ${wildcardMatch.config.route.id} with ${remaining}`);
506
- }
507
- return {
508
- route: wildcardMatch.config.route,
497
+ // 3. No match - try wildcard fallback
498
+ if (wildcardMatch) {
499
+ const remainingSegments = segments.slice(wildcardMatch.consumed);
500
+ const remaining = decodeWildcardSegments(remainingSegments);
501
+ if (remaining === null) {
502
+ return null;
503
+ }
504
+ if (this.debug) {
505
+ console.log(`[Router] Wildcard match: ${wildcardMatch.config.route.id} with ${remaining}`);
506
+ }
507
+ return {
508
+ route: wildcardMatch.config.route,
509
509
  params: { ...params, [wildcardMatch.config.name]: remaining },
510
510
  };
511
511
  }
@@ -522,36 +522,36 @@ export class Router {
522
522
  return { route: node.route, params };
523
523
  }
524
524
 
525
- // Check for wildcard at current node (but with no remaining segments)
526
- if (node.wildcardConfig) {
527
- // Optional wildcard: /files/:path*? matches /files (with empty path param)
528
- if (node.wildcardConfig.optional) {
529
- if (this.debug) {
530
- console.log(`[Router] Optional wildcard match: ${node.wildcardConfig.route.id} with empty path`);
531
- }
532
- return {
533
- route: node.wildcardConfig.route,
534
- params,
535
- };
536
- }
537
- // Non-optional wildcard: /files/:path* does NOT match /files
538
- if (this.debug) {
539
- console.log(`[Router] Wildcard policy: ${pathname} does not match non-optional wildcard`);
540
- }
525
+ // Check for wildcard at current node (but with no remaining segments)
526
+ if (node.wildcardConfig) {
527
+ // Optional wildcard: /files/:path*? matches /files (with empty path param)
528
+ if (node.wildcardConfig.optional) {
529
+ if (this.debug) {
530
+ console.log(`[Router] Optional wildcard match: ${node.wildcardConfig.route.id} with empty path`);
531
+ }
532
+ return {
533
+ route: node.wildcardConfig.route,
534
+ params,
535
+ };
536
+ }
537
+ // Non-optional wildcard: /files/:path* does NOT match /files
538
+ if (this.debug) {
539
+ console.log(`[Router] Wildcard policy: ${pathname} does not match non-optional wildcard`);
540
+ }
541
541
  }
542
542
 
543
- // Try wildcard fallback from earlier in the path
544
- if (wildcardMatch) {
545
- const remainingSegments = segments.slice(wildcardMatch.consumed);
546
- const remaining = decodeWildcardSegments(remainingSegments);
547
- if (remaining === null) {
548
- return null;
549
- }
550
- return {
551
- route: wildcardMatch.config.route,
552
- params: { ...params, [wildcardMatch.config.name]: remaining },
553
- };
554
- }
543
+ // Try wildcard fallback from earlier in the path
544
+ if (wildcardMatch) {
545
+ const remainingSegments = segments.slice(wildcardMatch.consumed);
546
+ const remaining = decodeWildcardSegments(remainingSegments);
547
+ if (remaining === null) {
548
+ return null;
549
+ }
550
+ return {
551
+ route: wildcardMatch.config.route,
552
+ params: { ...params, [wildcardMatch.config.name]: remaining },
553
+ };
554
+ }
555
555
 
556
556
  return null;
557
557
  }
@@ -1,28 +1,28 @@
1
- import type { BunFile, Server, ServerWebSocket } from "bun";
1
+ import type { BunFile, Server, ServerWebSocket } from "bun";
2
2
  import type { RoutesManifest, RouteSpec, HydrationConfig, StaticParamSetSchema } from "../spec/schema";
3
3
  import type { BundleManifest } from "../bundler/types";
4
4
  import type { ManduFilling, RenderMode } from "../filling/filling";
5
5
  import { ManduContext, CookieManager } from "../filling/context";
6
6
  import { Router } from "./router";
7
7
  import { renderSSR, renderStreamingResponse, resolveAsyncElement } from "./ssr";
8
- import {
9
- resolveMetadata,
10
- renderMetadata,
11
- renderTitle,
12
- type Metadata,
8
+ import {
9
+ resolveMetadata,
10
+ renderMetadata,
11
+ renderTitle,
12
+ type Metadata,
13
13
  type MetadataItem,
14
- type GenerateMetadata,
15
- } from "../seo";
16
- import { type ErrorFallbackProps } from "./boundary";
17
- import React from "react";
14
+ type GenerateMetadata,
15
+ } from "../seo";
16
+ import { type ErrorFallbackProps } from "./boundary";
17
+ import React from "react";
18
18
  import path from "path";
19
19
  import fs from "fs/promises";
20
20
  import { PORTS } from "../constants";
21
21
  import {
22
- type CacheStore,
23
- type CacheStoreStats,
24
- type CacheConfig,
25
- lookupCache,
22
+ type CacheStore,
23
+ type CacheStoreStats,
24
+ type CacheConfig,
25
+ lookupCache,
26
26
  createCacheEntry,
27
27
  createCachedResponse,
28
28
  computeCacheControl,
@@ -51,12 +51,12 @@ import {
51
51
  } from "./cors";
52
52
  import { validateImportPath } from "./security";
53
53
  import { KITCHEN_PREFIX, KitchenHandler, recordRequest } from "../kitchen/kitchen-handler";
54
- import {
55
- eventBus,
56
- type EventType,
57
- type ObservabilityEvent,
58
- type ObservabilitySeverity,
59
- } from "../observability/event-bus";
54
+ import {
55
+ eventBus,
56
+ type EventType,
57
+ type ObservabilityEvent,
58
+ type ObservabilitySeverity,
59
+ } from "../observability/event-bus";
60
60
  import {
61
61
  HEAP_ENDPOINT,
62
62
  METRICS_ENDPOINT,
@@ -65,12 +65,12 @@ import {
65
65
  isObservabilityExposed,
66
66
  recordHttpRequest,
67
67
  } from "../observability/metrics";
68
- import {
69
- handleOpenAPIRequest,
70
- isOpenAPIEndpointEnabled,
71
- resolveOpenAPIEndpointSettings,
72
- type OpenAPIEndpointSettings,
73
- } from "./openapi-endpoint";
68
+ import {
69
+ handleOpenAPIRequest,
70
+ isOpenAPIEndpointEnabled,
71
+ resolveOpenAPIEndpointSettings,
72
+ type OpenAPIEndpointSettings,
73
+ } from "./openapi-endpoint";
74
74
  // Phase 18.ψ — user-facing perf marks dashboard append. We include a
75
75
  // `perf` block on the `/_mandu/heap` payload when the feature is active
76
76
  // so operators see a unified view (heap + caches + perf histogram).
@@ -81,7 +81,7 @@ import { collectPerfSnapshot } from "../perf/user-marks";
81
81
  // `startServer()`; `runWithSpan` is used at the absolute TOP of the
82
82
  // request handler so every downstream await (middleware, filling
83
83
  // loader, SSR render) inherits the active span via AsyncLocalStorage.
84
- import type { Tracer } from "../observability/tracing";
84
+ import type { Tracer } from "../observability/tracing";
85
85
  import {
86
86
  createTracerFromConfig,
87
87
  runWithSpan,
@@ -102,10 +102,10 @@ import type { Middleware } from "../middleware/define";
102
102
  // Phase 18.λ — scheduler wiring (statically imported so `startServer` stays
103
103
  // synchronous; the cost of unused code is trivial — `defineCron` is a thin
104
104
  // wrapper around `Bun.cron`).
105
- import { defineCron as schedulerDefineCron, type CronDef, type CronRegistration } from "../scheduler";
105
+ import { defineCron as schedulerDefineCron, type CronDef, type CronRegistration } from "../scheduler";
106
106
  import { setActiveSchedulerRegistration } from "../middleware/scheduler-cron";
107
107
  import { createFetchHandler } from "./handler";
108
- import { wrapBunWebSocket, type WSHandlers, type WSUpgradeData } from "../filling/ws";
108
+ import { wrapBunWebSocket, type WSHandlers, type WSUpgradeData } from "../filling/ws";
109
109
  import { handleImageRequest } from "./image-handler";
110
110
  import { extractShellHtml, createPPRResponse } from "./ppr";
111
111
  import { isRedirectResponse } from "./redirect";
@@ -113,16 +113,16 @@ import { isNotFoundResponse } from "./not-found";
113
113
  import { newId } from "../id";
114
114
  // Phase 18.κ — typed RPC dispatch (tRPC-like). See
115
115
  // `packages/core/src/contract/rpc.ts` + `docs/architect/typed-rpc.md`.
116
- import {
117
- matchRpcPath,
118
- dispatchRpc,
119
- registerRpc,
120
- clearRpcRegistry,
121
- type RpcDefinition,
122
- type RpcProcedureRecord,
123
- } from "../contract/rpc";
124
- import type { GuardConfig } from "../guard/types";
125
- import type { ManduHooks, ManduPlugin } from "../plugins/hooks";
116
+ import {
117
+ matchRpcPath,
118
+ dispatchRpc,
119
+ registerRpc,
120
+ clearRpcRegistry,
121
+ type RpcDefinition,
122
+ type RpcProcedureRecord,
123
+ } from "../contract/rpc";
124
+ import type { GuardConfig } from "../guard/types";
125
+ import type { ManduHooks, ManduPlugin } from "../plugins/hooks";
126
126
  import { handleMetadataRoute as dispatchMetadataRoute } from "../routes/metadata-routes";
127
127
  import {
128
128
  DEFAULT_PRERENDER_DIR,
@@ -426,7 +426,7 @@ export interface ServerOptions {
426
426
  /**
427
427
  * Guard config for Kitchen dev dashboard (dev mode only)
428
428
  */
429
- guardConfig?: GuardConfig | null;
429
+ guardConfig?: GuardConfig | null;
430
430
  /**
431
431
  * SSR 캐시 설정 (ISR/SWR 용).
432
432
  *
@@ -582,8 +582,8 @@ export interface ServerOptions {
582
582
  * `options.middleware` so they run BEFORE user-declared layers. Both
583
583
  * fields are optional; omission is a zero-overhead passthrough.
584
584
  */
585
- plugins?: readonly ManduPlugin[];
586
- configHooks?: Partial<ManduHooks>;
585
+ plugins?: readonly ManduPlugin[];
586
+ configHooks?: Partial<ManduHooks>;
587
587
  /**
588
588
  * Phase 18.κ — tRPC-like typed RPC endpoints.
589
589
  *
@@ -596,7 +596,7 @@ export interface ServerOptions {
596
596
  * Typically threaded from `ManduConfig.rpc.endpoints`.
597
597
  */
598
598
  rpc?: {
599
- endpoints?: Record<string, RpcDefinition<RpcProcedureRecord>>;
599
+ endpoints?: Record<string, RpcDefinition<RpcProcedureRecord>>;
600
600
  };
601
601
  /**
602
602
  * Phase 18.λ — declarative cron scheduler.
@@ -612,7 +612,7 @@ export interface ServerOptions {
612
612
  * Typically threaded from `ManduConfig.scheduler`.
613
613
  */
614
614
  scheduler?: {
615
- jobs?: CronDef[];
615
+ jobs?: CronDef[];
616
616
  disabled?: boolean;
617
617
  };
618
618
  /**
@@ -823,7 +823,7 @@ export interface ServerRegistrySettings {
823
823
  * tracing is disabled (the hot path is branch-free). When set, every
824
824
  * request opens a root span via `tracer.startSpanFromRequest()`.
825
825
  */
826
- tracer?: Tracer;
826
+ tracer?: Tracer;
827
827
  /**
828
828
  * Production OpenAPI endpoint — resolved from `ServerOptions.openapi`.
829
829
  * `undefined` means the endpoint is disabled (hot path branch-free).
@@ -831,7 +831,7 @@ export interface ServerRegistrySettings {
831
831
  * `<basePath>.json` / `<basePath>.yaml` short-circuits before route
832
832
  * dispatch to serve the cached spec body.
833
833
  */
834
- openapi?: OpenAPIEndpointSettings;
834
+ openapi?: OpenAPIEndpointSettings;
835
835
  /**
836
836
  * Phase 18 — resolved prerender pass-through state. `undefined`
837
837
  * means the feature is disabled for this server instance.
@@ -917,7 +917,7 @@ export class ServerRegistry {
917
917
  /** Layout slot 파일 경로 캐시 (모듈 경로 → slot 경로 | null) */
918
918
  readonly layoutSlotPaths: Map<string, string | null> = new Map();
919
919
  /** WebSocket 핸들러 (라우트 ID → WSHandlers) */
920
- readonly wsHandlers: Map<string, WSHandlers> = new Map();
920
+ readonly wsHandlers: Map<string, WSHandlers> = new Map();
921
921
  /**
922
922
  * Metadata API 캐시 (#186)
923
923
  * - pageMetadata: routeId → page 모듈의 static `metadata` export
@@ -925,10 +925,10 @@ export class ServerRegistry {
925
925
  * - layoutMetadata: layout 모듈 경로 → static `metadata` export (null = 시도했지만 없음)
926
926
  * - layoutGenerateMetadata: layout 모듈 경로 → `generateMetadata` 함수
927
927
  */
928
- readonly pageMetadata: Map<string, Metadata> = new Map();
929
- readonly pageGenerateMetadata: Map<string, GenerateMetadata> = new Map();
930
- readonly layoutMetadata: Map<string, Metadata | null> = new Map();
931
- readonly layoutGenerateMetadata: Map<string, GenerateMetadata> = new Map();
928
+ readonly pageMetadata: Map<string, Metadata> = new Map();
929
+ readonly pageGenerateMetadata: Map<string, GenerateMetadata> = new Map();
930
+ readonly layoutMetadata: Map<string, Metadata | null> = new Map();
931
+ readonly layoutGenerateMetadata: Map<string, GenerateMetadata> = new Map();
932
932
  settings: ServerRegistrySettings = {
933
933
  isDev: false,
934
934
  rootDir: process.cwd(),
@@ -1277,7 +1277,7 @@ export function registerNotFoundHandler(handler: PageHandler): void {
1277
1277
  defaultRegistry.registerNotFoundHandler(handler);
1278
1278
  }
1279
1279
 
1280
- export function registerWSHandler(routeId: string, handlers: WSHandlers): void {
1280
+ export function registerWSHandler(routeId: string, handlers: WSHandlers): void {
1281
1281
  defaultRegistry.wsHandlers.set(routeId, handlers);
1282
1282
  }
1283
1283
 
@@ -1363,7 +1363,7 @@ function handleEventsStreamRequest(req: Request): Response {
1363
1363
  const filterSource = url.searchParams.get("source") || undefined;
1364
1364
  const filterTrace = url.searchParams.get("trace") || undefined;
1365
1365
 
1366
- const matches = (e: ObservabilityEvent): boolean => {
1366
+ const matches = (e: ObservabilityEvent): boolean => {
1367
1367
  if (filterType && e.type !== filterType) return false;
1368
1368
  if (filterSeverity && e.severity !== filterSeverity) return false;
1369
1369
  if (filterSource && e.source !== filterSource) return false;
@@ -1444,8 +1444,8 @@ function handleEventsRecentRequest(req: Request): Response {
1444
1444
  const events = eventBus.getRecent(
1445
1445
  count ? Number(count) : undefined,
1446
1446
  {
1447
- type: type as EventType | undefined,
1448
- severity: severity as ObservabilitySeverity | undefined,
1447
+ type: type as EventType | undefined,
1448
+ severity: severity as ObservabilitySeverity | undefined,
1449
1449
  },
1450
1450
  );
1451
1451
  const stats = eventBus.getStats(windowMs);
@@ -1551,7 +1551,7 @@ function evictEtagCacheIfNeeded(): void {
1551
1551
  */
1552
1552
  async function computeStrongEtag(
1553
1553
  filePath: string,
1554
- file: BunFile,
1554
+ file: BunFile,
1555
1555
  ): Promise<string> {
1556
1556
  const size = file.size;
1557
1557
  const mtime = file.lastModified;
@@ -4682,12 +4682,12 @@ export function startServer(manifest: RoutesManifest, options: ServerOptions = {
4682
4682
  }
4683
4683
  // ─── End Phase 18.ζ ────────────────────────────────────────────────────
4684
4684
 
4685
- // Kitchen dev dashboard (dev mode only)
4686
- if (isDev) {
4687
- const kitchen = new KitchenHandler({ rootDir, manifest, guardConfig });
4688
- void kitchen.start();
4689
- registry.kitchen = kitchen;
4690
- }
4685
+ // Kitchen dev dashboard (dev mode only)
4686
+ if (isDev) {
4687
+ const kitchen = new KitchenHandler({ rootDir, manifest, guardConfig });
4688
+ void kitchen.start();
4689
+ registry.kitchen = kitchen;
4690
+ }
4691
4691
 
4692
4692
  const router = new Router(manifest.routes);
4693
4693
 
@@ -4869,7 +4869,7 @@ export function startServer(manifest: RoutesManifest, options: ServerOptions = {
4869
4869
  // other boot errors rather than aborting the server. `startServer` is
4870
4870
  // synchronous by contract, so we use the already-imported scheduler
4871
4871
  // module rather than `await import`.
4872
- let schedulerRegistration: CronRegistration | null = null;
4872
+ let schedulerRegistration: CronRegistration | null = null;
4873
4873
  const jobDefs = schedulerOption?.jobs ?? [];
4874
4874
  const schedulerDisabled = schedulerOption?.disabled === true;
4875
4875
  if (jobDefs.length > 0 && !schedulerDisabled) {
@@ -4921,10 +4921,10 @@ export function startServer(manifest: RoutesManifest, options: ServerOptions = {
4921
4921
  console.error("[scheduler] shutdown error:", err);
4922
4922
  });
4923
4923
  }
4924
- void server.stop();
4925
- },
4926
- };
4927
- }
4924
+ void server.stop();
4925
+ },
4926
+ };
4927
+ }
4928
4928
 
4929
4929
  // Clear registries (useful for testing) - deprecated, use clearDefaultRegistry()
4930
4930
  export function clearRegistry(): void {
@@ -1,48 +1,48 @@
1
- /**
2
- * Runtime Shims for React Compatibility
3
- *
4
- * React 19+ 호환성을 위한 런타임 shim 스크립트들을 제공합니다.
5
- *
6
- * @module runtime/shims
7
- */
8
-
9
- /**
10
- * React 19 Client Internals Shim Script
11
- *
12
- * React 19에서 react-dom/client가 실행되기 전에 ReactSharedInternals.S가
13
- * 존재하는지 확인하고 필요시 초기화하는 inline 스크립트입니다.
14
- *
15
- * **사용 목적**:
16
- * - Playwright headless 환경에서 hydration 실패 방지
17
- * - React 19의 __CLIENT_INTERNALS.S가 null일 수 있는 문제 해결
18
- * - SSR HTML에 삽입하여 번들 로드 전에 실행
19
- *
20
- * **안전성**:
21
- * - try-catch로 감싸져 있어 오류 발생 시에도 안전
22
- * - 기존 값이 있으면 덮어쓰지 않음
23
- * - React가 없거나 internals가 없어도 실패하지 않음
24
- *
25
- * @example
26
- * ```typescript
27
- * // SSR HTML에 삽입
28
- * const html = `
29
- * ${hydrationScripts}
30
- * ${REACT_INTERNALS_SHIM_SCRIPT}
31
- * ${routerScript}
32
- * `;
33
- * ```
34
- */
35
- export const REACT_INTERNALS_SHIM_SCRIPT = `<script>
36
- // React 19 internals shim: ensure ReactSharedInternals.S exists before react-dom/client runs.
37
- // Some builds expect React.__CLIENT_INTERNALS... .S to be a function, but it may be null.
38
- // This shim is safe: it only fills the slot if missing.
39
- (function(){
40
- try {
41
- var React = window.React;
42
- var i = React && React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
43
- if (i && i.S == null) {
44
- i.S = function(){};
45
- }
46
- } catch(e) {}
47
- })();
48
- </script>`;
1
+ /**
2
+ * Runtime Shims for React Compatibility
3
+ *
4
+ * React 19+ 호환성을 위한 런타임 shim 스크립트들을 제공합니다.
5
+ *
6
+ * @module runtime/shims
7
+ */
8
+
9
+ /**
10
+ * React 19 Client Internals Shim Script
11
+ *
12
+ * React 19에서 react-dom/client가 실행되기 전에 ReactSharedInternals.S가
13
+ * 존재하는지 확인하고 필요시 초기화하는 inline 스크립트입니다.
14
+ *
15
+ * **사용 목적**:
16
+ * - Playwright headless 환경에서 hydration 실패 방지
17
+ * - React 19의 __CLIENT_INTERNALS.S가 null일 수 있는 문제 해결
18
+ * - SSR HTML에 삽입하여 번들 로드 전에 실행
19
+ *
20
+ * **안전성**:
21
+ * - try-catch로 감싸져 있어 오류 발생 시에도 안전
22
+ * - 기존 값이 있으면 덮어쓰지 않음
23
+ * - React가 없거나 internals가 없어도 실패하지 않음
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // SSR HTML에 삽입
28
+ * const html = `
29
+ * ${hydrationScripts}
30
+ * ${REACT_INTERNALS_SHIM_SCRIPT}
31
+ * ${routerScript}
32
+ * `;
33
+ * ```
34
+ */
35
+ export const REACT_INTERNALS_SHIM_SCRIPT = `<script>
36
+ // React 19 internals shim: ensure ReactSharedInternals.S exists before react-dom/client runs.
37
+ // Some builds expect React.__CLIENT_INTERNALS... .S to be a function, but it may be null.
38
+ // This shim is safe: it only fills the slot if missing.
39
+ (function(){
40
+ try {
41
+ var React = window.React;
42
+ var i = React && React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
43
+ if (i && i.S == null) {
44
+ i.S = function(){};
45
+ }
46
+ } catch(e) {}
47
+ })();
48
+ </script>`;