@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,267 +1,267 @@
1
- /**
2
- * Mandu Router Hooks 🪝
3
- * React hooks for client-side routing
4
- */
5
-
6
- import { useState, useEffect, useCallback, useSyncExternalStore } from "react";
7
- import {
8
- subscribe,
9
- getRouterState,
10
- getCurrentRoute,
11
- getLoaderData,
12
- getNavigationState,
13
- navigate,
14
- type RouteInfo,
15
- type NavigationState,
16
- type NavigateOptions,
17
- } from "./router";
18
-
19
- /**
20
- * 라우터 상태 전체 접근
21
- *
22
- * @example
23
- * ```tsx
24
- * const { currentRoute, loaderData, navigation } = useRouterState();
25
- * ```
26
- */
27
- export function useRouterState() {
28
- return useSyncExternalStore(
29
- subscribe,
30
- getRouterState,
31
- getRouterState // SSR에서도 동일
32
- );
33
- }
34
-
35
- /**
36
- * 현재 라우트 정보
37
- *
38
- * @example
39
- * ```tsx
40
- * const route = useRoute();
41
- * console.log(route?.id, route?.params);
42
- * ```
43
- */
44
- export function useRoute(): RouteInfo | null {
45
- const state = useRouterState();
46
- return state.currentRoute;
47
- }
48
-
49
- /**
50
- * URL 파라미터 접근
51
- *
52
- * @example
53
- * ```tsx
54
- * // URL: /users/123
55
- * const { id } = useParams<{ id: string }>();
56
- * console.log(id); // "123"
57
- * ```
58
- */
59
- export function useParams<T extends Record<string, string> = Record<string, string>>(): T {
60
- const route = useRoute();
61
- return (route?.params ?? {}) as T;
62
- }
63
-
64
- /**
65
- * 현재 경로명
66
- *
67
- * @example
68
- * ```tsx
69
- * const pathname = usePathname();
70
- * console.log(pathname); // "/users/123"
71
- * ```
72
- */
73
- export function usePathname(): string {
74
- const [pathname, setPathname] = useState(() =>
75
- typeof window !== "undefined" ? window.location.pathname : "/"
76
- );
77
-
78
- useEffect(() => {
79
- const handleChange = () => {
80
- setPathname(window.location.pathname);
81
- };
82
-
83
- window.addEventListener("popstate", handleChange);
84
-
85
- // 라우터 상태 변경 구독
86
- const unsubscribe = subscribe(() => {
87
- setPathname(window.location.pathname);
88
- });
89
-
90
- return () => {
91
- window.removeEventListener("popstate", handleChange);
92
- unsubscribe();
93
- };
94
- }, []);
95
-
96
- return pathname;
97
- }
98
-
99
- /**
100
- * 현재 검색 파라미터 (쿼리 스트링)
101
- *
102
- * @example
103
- * ```tsx
104
- * // URL: /search?q=hello&page=2
105
- * const searchParams = useSearchParams();
106
- * console.log(searchParams.get("q")); // "hello"
107
- * ```
108
- */
109
- export function useSearchParams(): URLSearchParams {
110
- const [searchParams, setSearchParams] = useState(() =>
111
- typeof window !== "undefined"
112
- ? new URLSearchParams(window.location.search)
113
- : new URLSearchParams()
114
- );
115
-
116
- useEffect(() => {
117
- const handleChange = () => {
118
- setSearchParams(new URLSearchParams(window.location.search));
119
- };
120
-
121
- window.addEventListener("popstate", handleChange);
122
-
123
- const unsubscribe = subscribe(() => {
124
- setSearchParams(new URLSearchParams(window.location.search));
125
- });
126
-
127
- return () => {
128
- window.removeEventListener("popstate", handleChange);
129
- unsubscribe();
130
- };
131
- }, []);
132
-
133
- return searchParams;
134
- }
135
-
136
- /**
137
- * Loader 데이터 접근
138
- *
139
- * @example
140
- * ```tsx
141
- * interface UserData { name: string; email: string; }
142
- * const data = useLoaderData<UserData>();
143
- * ```
144
- */
145
- export function useLoaderData<T = unknown>(): T | undefined {
146
- const state = useRouterState();
147
- return state.loaderData as T | undefined;
148
- }
149
-
150
- /**
151
- * 네비게이션 상태 (로딩 여부)
152
- *
153
- * @example
154
- * ```tsx
155
- * const { state, location } = useNavigation();
156
- *
157
- * if (state === "loading") {
158
- * return <Spinner />;
159
- * }
160
- * ```
161
- */
162
- export function useNavigation(): NavigationState {
163
- const state = useRouterState();
164
- return state.navigation;
165
- }
166
-
167
- /**
168
- * 프로그래매틱 네비게이션
169
- *
170
- * @example
171
- * ```tsx
172
- * const navigate = useNavigate();
173
- *
174
- * const handleClick = () => {
175
- * navigate("/dashboard");
176
- * };
177
- *
178
- * const handleSubmit = () => {
179
- * navigate("/success", { replace: true });
180
- * };
181
- * ```
182
- */
183
- export function useNavigate(): (to: string, options?: NavigateOptions) => Promise<void> {
184
- return useCallback((to: string, options?: NavigateOptions) => {
185
- return navigate(to, options);
186
- }, []);
187
- }
188
-
189
- /**
190
- * 라우터 통합 훅 (편의용)
191
- *
192
- * @example
193
- * ```tsx
194
- * const {
195
- * pathname,
196
- * params,
197
- * searchParams,
198
- * navigate,
199
- * isNavigating
200
- * } = useRouter();
201
- * ```
202
- */
203
- export function useRouter() {
204
- const pathname = usePathname();
205
- const params = useParams();
206
- const searchParams = useSearchParams();
207
- const navigation = useNavigation();
208
- const navigateFn = useNavigate();
209
-
210
- return {
211
- /** 현재 경로명 */
212
- pathname,
213
- /** URL 파라미터 */
214
- params,
215
- /** 검색 파라미터 (쿼리 스트링) */
216
- searchParams,
217
- /** 네비게이션 함수 */
218
- navigate: navigateFn,
219
- /** 네비게이션 중 여부 */
220
- isNavigating: navigation.state === "loading",
221
- /** 네비게이션 상태 상세 */
222
- navigation,
223
- };
224
- }
225
-
226
- /**
227
- * 특정 경로와 현재 경로 일치 여부
228
- *
229
- * @example
230
- * ```tsx
231
- * const isActive = useMatch("/about");
232
- * const isUsersPage = useMatch("/users/:id");
233
- * ```
234
- */
235
- export function useMatch(pattern: string): boolean {
236
- const pathname = usePathname();
237
-
238
- // 간단한 패턴 매칭 (파라미터 고려)
239
- const regexStr = pattern
240
- .replace(/:[a-zA-Z_][a-zA-Z0-9_]*/g, "[^/]+")
241
- .replace(/\//g, "\\/");
242
-
243
- const regex = new RegExp(`^${regexStr}$`);
244
- return regex.test(pathname);
245
- }
246
-
247
- /**
248
- * 뒤로 가기
249
- */
250
- export function useGoBack(): () => void {
251
- return useCallback(() => {
252
- if (typeof window !== "undefined") {
253
- window.history.back();
254
- }
255
- }, []);
256
- }
257
-
258
- /**
259
- * 앞으로 가기
260
- */
261
- export function useGoForward(): () => void {
262
- return useCallback(() => {
263
- if (typeof window !== "undefined") {
264
- window.history.forward();
265
- }
266
- }, []);
267
- }
1
+ /**
2
+ * Mandu Router Hooks 🪝
3
+ * React hooks for client-side routing
4
+ */
5
+
6
+ import { useState, useEffect, useCallback, useSyncExternalStore } from "react";
7
+ import {
8
+ subscribe,
9
+ getRouterState,
10
+ getCurrentRoute,
11
+ getLoaderData,
12
+ getNavigationState,
13
+ navigate,
14
+ type RouteInfo,
15
+ type NavigationState,
16
+ type NavigateOptions,
17
+ } from "./router";
18
+
19
+ /**
20
+ * 라우터 상태 전체 접근
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * const { currentRoute, loaderData, navigation } = useRouterState();
25
+ * ```
26
+ */
27
+ export function useRouterState() {
28
+ return useSyncExternalStore(
29
+ subscribe,
30
+ getRouterState,
31
+ getRouterState // SSR에서도 동일
32
+ );
33
+ }
34
+
35
+ /**
36
+ * 현재 라우트 정보
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * const route = useRoute();
41
+ * console.log(route?.id, route?.params);
42
+ * ```
43
+ */
44
+ export function useRoute(): RouteInfo | null {
45
+ const state = useRouterState();
46
+ return state.currentRoute;
47
+ }
48
+
49
+ /**
50
+ * URL 파라미터 접근
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * // URL: /users/123
55
+ * const { id } = useParams<{ id: string }>();
56
+ * console.log(id); // "123"
57
+ * ```
58
+ */
59
+ export function useParams<T extends Record<string, string> = Record<string, string>>(): T {
60
+ const route = useRoute();
61
+ return (route?.params ?? {}) as T;
62
+ }
63
+
64
+ /**
65
+ * 현재 경로명
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * const pathname = usePathname();
70
+ * console.log(pathname); // "/users/123"
71
+ * ```
72
+ */
73
+ export function usePathname(): string {
74
+ const [pathname, setPathname] = useState(() =>
75
+ typeof window !== "undefined" ? window.location.pathname : "/"
76
+ );
77
+
78
+ useEffect(() => {
79
+ const handleChange = () => {
80
+ setPathname(window.location.pathname);
81
+ };
82
+
83
+ window.addEventListener("popstate", handleChange);
84
+
85
+ // 라우터 상태 변경 구독
86
+ const unsubscribe = subscribe(() => {
87
+ setPathname(window.location.pathname);
88
+ });
89
+
90
+ return () => {
91
+ window.removeEventListener("popstate", handleChange);
92
+ unsubscribe();
93
+ };
94
+ }, []);
95
+
96
+ return pathname;
97
+ }
98
+
99
+ /**
100
+ * 현재 검색 파라미터 (쿼리 스트링)
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * // URL: /search?q=hello&page=2
105
+ * const searchParams = useSearchParams();
106
+ * console.log(searchParams.get("q")); // "hello"
107
+ * ```
108
+ */
109
+ export function useSearchParams(): URLSearchParams {
110
+ const [searchParams, setSearchParams] = useState(() =>
111
+ typeof window !== "undefined"
112
+ ? new URLSearchParams(window.location.search)
113
+ : new URLSearchParams()
114
+ );
115
+
116
+ useEffect(() => {
117
+ const handleChange = () => {
118
+ setSearchParams(new URLSearchParams(window.location.search));
119
+ };
120
+
121
+ window.addEventListener("popstate", handleChange);
122
+
123
+ const unsubscribe = subscribe(() => {
124
+ setSearchParams(new URLSearchParams(window.location.search));
125
+ });
126
+
127
+ return () => {
128
+ window.removeEventListener("popstate", handleChange);
129
+ unsubscribe();
130
+ };
131
+ }, []);
132
+
133
+ return searchParams;
134
+ }
135
+
136
+ /**
137
+ * Loader 데이터 접근
138
+ *
139
+ * @example
140
+ * ```tsx
141
+ * interface UserData { name: string; email: string; }
142
+ * const data = useLoaderData<UserData>();
143
+ * ```
144
+ */
145
+ export function useLoaderData<T = unknown>(): T | undefined {
146
+ const state = useRouterState();
147
+ return state.loaderData as T | undefined;
148
+ }
149
+
150
+ /**
151
+ * 네비게이션 상태 (로딩 여부)
152
+ *
153
+ * @example
154
+ * ```tsx
155
+ * const { state, location } = useNavigation();
156
+ *
157
+ * if (state === "loading") {
158
+ * return <Spinner />;
159
+ * }
160
+ * ```
161
+ */
162
+ export function useNavigation(): NavigationState {
163
+ const state = useRouterState();
164
+ return state.navigation;
165
+ }
166
+
167
+ /**
168
+ * 프로그래매틱 네비게이션
169
+ *
170
+ * @example
171
+ * ```tsx
172
+ * const navigate = useNavigate();
173
+ *
174
+ * const handleClick = () => {
175
+ * navigate("/dashboard");
176
+ * };
177
+ *
178
+ * const handleSubmit = () => {
179
+ * navigate("/success", { replace: true });
180
+ * };
181
+ * ```
182
+ */
183
+ export function useNavigate(): (to: string, options?: NavigateOptions) => Promise<void> {
184
+ return useCallback((to: string, options?: NavigateOptions) => {
185
+ return navigate(to, options);
186
+ }, []);
187
+ }
188
+
189
+ /**
190
+ * 라우터 통합 훅 (편의용)
191
+ *
192
+ * @example
193
+ * ```tsx
194
+ * const {
195
+ * pathname,
196
+ * params,
197
+ * searchParams,
198
+ * navigate,
199
+ * isNavigating
200
+ * } = useRouter();
201
+ * ```
202
+ */
203
+ export function useRouter() {
204
+ const pathname = usePathname();
205
+ const params = useParams();
206
+ const searchParams = useSearchParams();
207
+ const navigation = useNavigation();
208
+ const navigateFn = useNavigate();
209
+
210
+ return {
211
+ /** 현재 경로명 */
212
+ pathname,
213
+ /** URL 파라미터 */
214
+ params,
215
+ /** 검색 파라미터 (쿼리 스트링) */
216
+ searchParams,
217
+ /** 네비게이션 함수 */
218
+ navigate: navigateFn,
219
+ /** 네비게이션 중 여부 */
220
+ isNavigating: navigation.state === "loading",
221
+ /** 네비게이션 상태 상세 */
222
+ navigation,
223
+ };
224
+ }
225
+
226
+ /**
227
+ * 특정 경로와 현재 경로 일치 여부
228
+ *
229
+ * @example
230
+ * ```tsx
231
+ * const isActive = useMatch("/about");
232
+ * const isUsersPage = useMatch("/users/:id");
233
+ * ```
234
+ */
235
+ export function useMatch(pattern: string): boolean {
236
+ const pathname = usePathname();
237
+
238
+ // 간단한 패턴 매칭 (파라미터 고려)
239
+ const regexStr = pattern
240
+ .replace(/:[a-zA-Z_][a-zA-Z0-9_]*/g, "[^/]+")
241
+ .replace(/\//g, "\\/");
242
+
243
+ const regex = new RegExp(`^${regexStr}$`);
244
+ return regex.test(pathname);
245
+ }
246
+
247
+ /**
248
+ * 뒤로 가기
249
+ */
250
+ export function useGoBack(): () => void {
251
+ return useCallback(() => {
252
+ if (typeof window !== "undefined") {
253
+ window.history.back();
254
+ }
255
+ }, []);
256
+ }
257
+
258
+ /**
259
+ * 앞으로 가기
260
+ */
261
+ export function useGoForward(): () => void {
262
+ return useCallback(() => {
263
+ if (typeof window !== "undefined") {
264
+ window.history.forward();
265
+ }
266
+ }, []);
267
+ }
@@ -1,6 +1,6 @@
1
- /**
2
- * Mandu Client Module 🏝️
3
- * 클라이언트 사이드 hydration 및 라우팅을 위한 API
1
+ /**
2
+ * Mandu Client Module 🏝️
3
+ * 클라이언트 사이드 hydration 및 라우팅을 위한 API
4
4
  *
5
5
  * @example
6
6
  * ```typescript
@@ -23,8 +23,8 @@
23
23
  * return <Link href="/about">About</Link>;
24
24
  * }
25
25
  * ```
26
- */
27
- import "./globals";
26
+ */
27
+ import "./globals";
28
28
 
29
29
  // Island API
30
30
  export {
@@ -3,8 +3,8 @@
3
3
  * Hydration을 위한 클라이언트 사이드 컴포넌트 정의
4
4
  */
5
5
 
6
- import type { ReactNode } from "react";
7
- import { getServerData as getGlobalServerData } from "./window-state";
6
+ import type { ReactNode } from "react";
7
+ import { getServerData as getGlobalServerData } from "./window-state";
8
8
 
9
9
  /**
10
10
  * Island 정의 타입
@@ -118,12 +118,12 @@ export function island<TServerData, TSetupResult = TServerData>(
118
118
  * SSR 데이터에 안전하게 접근하는 훅
119
119
  * 서버 데이터가 없는 경우 fallback 반환
120
120
  */
121
- export function useServerData<T>(key: string, fallback: T): T {
122
- if (typeof window === "undefined") return fallback;
123
-
124
- const data = getGlobalServerData<T>(key);
125
- return data === undefined ? fallback : data;
126
- }
121
+ export function useServerData<T>(key: string, fallback: T): T {
122
+ if (typeof window === "undefined") return fallback;
123
+
124
+ const data = getGlobalServerData<T>(key);
125
+ return data === undefined ? fallback : data;
126
+ }
127
127
 
128
128
  /**
129
129
  * Hydration 상태를 추적하는 훅