@mandujs/core 0.25.0 → 0.25.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.
@@ -1547,7 +1547,27 @@ async function loadPageData(
1547
1547
  const exportedObj = exported as Record<string, unknown> | null;
1548
1548
  const component = typeof exported === "function"
1549
1549
  ? (exported as RouteComponent)
1550
- : (exportedObj?.component ?? exported);
1550
+ : (exportedObj?.component ?? undefined);
1551
+ // DX-1: pageLoader 경로에서 malformed default export를 silent 404 로
1552
+ //보내지 않고 명시적 에러로 즉시 실패시킨다. 이전에는
1553
+ // `export default "hello"` / `export default undefined` / named-only
1554
+ // 같은 실수가 registerRouteComponent(undefined) → defaultCreateApp
1555
+ // 에서 404로 렌더되어 사용자가 원인을 추적하기 어려웠음. 여기서 throw
1556
+ // 하면 try/catch(아래) 의 createPageLoadErrorResponse 가 500 응답과
1557
+ // 함께 route.id + pattern 을 출력해주므로 개발자가 바로 인지한다.
1558
+ if (typeof component !== "function") {
1559
+ const defaultSummary =
1560
+ exported === undefined
1561
+ ? "undefined (missing `export default`)"
1562
+ : exported === null
1563
+ ? "null"
1564
+ : `type ${typeof exported}`;
1565
+ throw new Error(
1566
+ `[Mandu] Page module for '${route.id}' (pattern ${route.pattern}) has an invalid default export: ${defaultSummary}. ` +
1567
+ "Expected `export default function Page() {…}` or `export default { component, filling }`. " +
1568
+ "If the page file is empty or only has named exports, add a default-exported React component."
1569
+ );
1570
+ }
1551
1571
  registry.registerRouteComponent(route.id, component as RouteComponent);
1552
1572
 
1553
1573
  // #186: page 모듈에서 metadata / generateMetadata export 캐싱
@@ -2201,8 +2221,22 @@ async function handlePageRoute(
2201
2221
  const cache = settings.cacheStore;
2202
2222
  // Only call ensurePageRouteMetadata when a pageHandler exists;
2203
2223
  // routes registered via registerPageLoader are handled by loadPageData instead.
2224
+ // DX-1: if the pageHandler returns a malformed registration (component is
2225
+ // not a function), ensurePageRouteMetadata now throws with a descriptive
2226
+ // message. Catch it here so the request becomes a loud 500 instead of
2227
+ // bubbling up as an opaque "Internal Server Error".
2204
2228
  if (registry.pageHandlers.has(route.id)) {
2205
- await ensurePageRouteMetadata(route.id, registry);
2229
+ try {
2230
+ await ensurePageRouteMetadata(route.id, registry);
2231
+ } catch (error) {
2232
+ const pageError = createPageLoadErrorResponse(
2233
+ route.id,
2234
+ route.pattern,
2235
+ error instanceof Error ? error : new Error(String(error))
2236
+ );
2237
+ console.error(`[Mandu] ${pageError.errorType}:`, pageError.message);
2238
+ return err(pageError);
2239
+ }
2206
2240
  }
2207
2241
  const renderMode = getRenderModeForRoute(route.id, registry);
2208
2242
 
@@ -2467,6 +2501,19 @@ async function ensurePageRouteMetadata(
2467
2501
  }
2468
2502
 
2469
2503
  const registration = await handler();
2504
+ // DX-1: pageHandler가 malformed registration을 반환해도 silent 404 대신
2505
+ // 명시적 에러로 실패. handlers.ts 의 auto-promote 블록이 function 기본값을
2506
+ // { component } 로 감싸주지만, 직접 registerPageHandler 를 쓰는 경우나
2507
+ // 사용자 코드가 이상한 값을 반환하는 경우를 방어한다.
2508
+ if (typeof registration?.component !== "function") {
2509
+ const t = registration === null || registration === undefined
2510
+ ? String(registration)
2511
+ : typeof registration.component;
2512
+ throw new Error(
2513
+ `[Mandu] Page handler for '${routeId}' returned an invalid registration: component is ${t}. ` +
2514
+ "Expected `{ component: ReactComponent, filling? }` from the page module's default export."
2515
+ );
2516
+ }
2470
2517
  const component = registration.component as RouteComponent;
2471
2518
  registry.registerRouteComponent(routeId, component);
2472
2519