@flexireact/core 1.0.2 → 2.0.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 (37) hide show
  1. package/README.md +112 -112
  2. package/bin/flexireact.js +23 -0
  3. package/cli/index.ts +9 -21
  4. package/core/cli/{logger.js → logger.ts} +8 -2
  5. package/core/client/{hydration.js → hydration.ts} +10 -0
  6. package/core/client/{islands.js → islands.ts} +6 -1
  7. package/core/client/{navigation.js → navigation.ts} +10 -2
  8. package/core/client/{runtime.js → runtime.ts} +16 -0
  9. package/core/{config.js → config.ts} +7 -4
  10. package/core/{index.js → index.ts} +6 -2
  11. package/core/islands/{index.js → index.ts} +16 -4
  12. package/core/{logger.js → logger.ts} +1 -1
  13. package/core/middleware/{index.js → index.ts} +32 -9
  14. package/core/plugins/{index.js → index.ts} +9 -6
  15. package/core/render/index.ts +1069 -0
  16. package/core/{render.js → render.ts} +7 -5
  17. package/core/router/index.ts +543 -0
  18. package/core/rsc/{index.js → index.ts} +6 -5
  19. package/core/server/{index.js → index.ts} +25 -6
  20. package/core/{server.js → server.ts} +8 -2
  21. package/core/ssg/{index.js → index.ts} +30 -5
  22. package/core/start-dev.ts +6 -0
  23. package/core/start-prod.ts +6 -0
  24. package/core/tsconfig.json +28 -0
  25. package/core/types.ts +239 -0
  26. package/package.json +20 -15
  27. package/cli/index.js +0 -992
  28. package/core/render/index.js +0 -773
  29. package/core/router/index.js +0 -296
  30. /package/core/{api.js → api.ts} +0 -0
  31. /package/core/build/{index.js → index.ts} +0 -0
  32. /package/core/client/{index.js → index.ts} +0 -0
  33. /package/core/{context.js → context.ts} +0 -0
  34. /package/core/{dev.js → dev.ts} +0 -0
  35. /package/core/{loader.js → loader.ts} +0 -0
  36. /package/core/{router.js → router.ts} +0 -0
  37. /package/core/{utils.js → utils.ts} +0 -0
package/README.md CHANGED
@@ -2,24 +2,33 @@
2
2
  <img src="./assets/flexireact.webp" alt="FlexiReact Logo" width="400" />
3
3
  </p>
4
4
 
5
- <h1 align="center">FlexiReact</h1>
5
+ <h1 align="center">FlexiReact v2</h1>
6
6
 
7
7
  <p align="center">
8
8
  <strong>The Modern React Framework</strong>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- A blazing-fast React framework with TypeScript, Tailwind CSS, SSR, SSG, Islands architecture, and file-based routing.<br/>
12
+ A blazing-fast React framework with TypeScript, Tailwind CSS v4, SSR, SSG, Islands architecture, and file-based routing.<br/>
13
13
  Inspired by Next.js, Remix, Astro, and TanStack Start — but simpler and lighter.
14
14
  </p>
15
15
 
16
16
  <p align="center">
17
17
  <a href="https://www.npmjs.com/package/@flexireact/core"><img src="https://img.shields.io/npm/v/@flexireact/core.svg" alt="npm version" /></a>
18
18
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
19
- <a href="#"><img src="https://img.shields.io/badge/TypeScript-Ready-blue.svg" alt="TypeScript Ready" /></a>
20
- <a href="#"><img src="https://img.shields.io/badge/Tailwind-CSS-38B2AC.svg" alt="Tailwind CSS" /></a>
19
+ <a href="#"><img src="https://img.shields.io/badge/TypeScript-Native-blue.svg" alt="TypeScript Native" /></a>
20
+ <a href="#"><img src="https://img.shields.io/badge/Tailwind-v4-38B2AC.svg" alt="Tailwind CSS v4" /></a>
21
21
  </p>
22
22
 
23
+ ## 🆕 What's New in v2
24
+
25
+ - **TypeScript Native** — Core rewritten in TypeScript for better DX
26
+ - **Tailwind CSS v4** — New `@import "tailwindcss"` and `@theme` syntax
27
+ - **Routes Directory** — New `routes/` directory with route groups, dynamic segments
28
+ - **Modern 404 Page** — Beautiful, interactive error pages
29
+ - **Enhanced DevTools** — Precise error messages with color-coded render times
30
+ - **Improved CLI** — TypeScript-based CLI with better templates
31
+
23
32
  ## ✨ Features
24
33
 
25
34
  ### 🏗️ Core Framework
@@ -156,51 +165,73 @@ npm run start
156
165
 
157
166
  Open http://localhost:3000
158
167
 
159
- ## 📁 Project Structure
168
+ ## 📁 Project Structure (v2)
169
+
170
+ FlexiReact v2 introduces a new `routes/` directory with enhanced routing capabilities:
160
171
 
161
172
  ```
162
173
  myapp/
163
- ├── app/ # App directory
164
- │ ├── components/ # Reusable components
165
- │ │ ├── Button.tsx # Button component
166
- │ │ ├── Card.tsx # Card component
167
- │ │ ├── Navbar.tsx # Navigation bar
168
- │ │ └── index.ts # Component exports
174
+ ├── app/ # App directory (layout, components, styles)
175
+ │ ├── components/
176
+ │ │ ├── ui/ # UI components (Button, Card, etc.)
177
+ │ │ └── layout/ # Layout components (Navbar, Footer)
169
178
  │ ├── styles/
170
- │ │ └── globals.css # Global styles + Tailwind
171
- └── layout.tsx # Root layout
172
- ├── pages/ # Routes (file-based)
173
- ├── index.tsx # /
174
- │ ├── about.tsx # /about
179
+ │ │ └── globals.css # Global styles + Tailwind v4
180
+ ├── providers/ # React context providers
181
+ │ └── layout.tsx # Root layout
182
+ ├── routes/ # FlexiReact v2 file-based routing
183
+ │ ├── (public)/ # Route groups (don't affect URL)
184
+ │ │ ├── home.tsx # → /
185
+ │ │ └── about.tsx # → /about
175
186
  │ ├── blog/
176
- │ │ ├── index.tsx # → /blog
177
- │ │ └── [slug].tsx # → /blog/:slug
187
+ │ │ ├── index.tsx # → /blog
188
+ │ │ └── [slug].tsx # → /blog/:slug
178
189
  │ └── api/
179
- │ └── hello.ts # → /api/hello
180
- ├── public/ # Static assets
181
- ├── tailwind.config.js # Tailwind configuration
182
- ├── tsconfig.json # TypeScript configuration
183
- ├── flexireact.config.ts # FlexiReact configuration
190
+ │ └── hello.ts # → /api/hello
191
+ ├── lib/ # Utilities
192
+ │ └── utils.ts
193
+ ├── public/ # Static assets
194
+ ├── tsconfig.json # TypeScript configuration
195
+ ├── flexireact.config.ts # FlexiReact configuration
184
196
  └── package.json
185
197
  ```
186
198
 
187
- ## 🛣️ Routing
199
+ ## 🛣️ Routing (v2)
200
+
201
+ FlexiReact v2 supports three routing conventions (in priority order):
202
+
203
+ ### 1. Routes Directory (Recommended)
204
+
205
+ | File | Route |
206
+ |------|-------|
207
+ | `routes/(public)/home.tsx` | `/` |
208
+ | `routes/(public)/about.tsx` | `/about` |
209
+ | `routes/blog/index.tsx` | `/blog` |
210
+ | `routes/blog/[slug].tsx` | `/blog/:slug` |
211
+ | `routes/[...path].tsx` | Catch-all route |
212
+ | `routes/api/hello.ts` | `/api/hello` |
213
+
214
+ ### 2. App Directory (Next.js style)
215
+
216
+ | File | Route |
217
+ |------|-------|
218
+ | `app/page.tsx` | `/` |
219
+ | `app/about/page.tsx` | `/about` |
220
+ | `app/blog/[slug]/page.tsx` | `/blog/:slug` |
188
221
 
189
- ### Page Routes
222
+ ### 3. Pages Directory (Legacy)
190
223
 
191
224
  | File | Route |
192
225
  |------|-------|
193
- | `pages/index.jsx` | `/` |
194
- | `pages/about.jsx` | `/about` |
195
- | `pages/blog/[slug].jsx` | `/blog/:slug` |
196
- | `pages/[...path].jsx` | Catch-all route |
226
+ | `pages/index.tsx` | `/` |
227
+ | `pages/about.tsx` | `/about` |
197
228
 
198
229
  ### Dynamic Routes
199
230
 
200
- ```jsx
201
- // pages/users/[id].jsx
202
- export default function User({ params }) {
203
- return <h1>User: {params.id}</h1>;
231
+ ```tsx
232
+ // routes/blog/[slug].tsx
233
+ export default function BlogPost({ params }: { params: { slug: string } }) {
234
+ return <h1>Post: {params.slug}</h1>;
204
235
  }
205
236
  ```
206
237
 
@@ -209,42 +240,62 @@ export default function User({ params }) {
209
240
  Use parentheses to group routes without affecting the URL:
210
241
 
211
242
  ```
212
- pages/
213
- (marketing)/
214
- about.jsx # → /about
215
- contact.jsx # → /contact
216
- (app)/
217
- dashboard.jsx # → /dashboard
243
+ routes/
244
+ (public)/
245
+ home.tsx # → /
246
+ about.tsx # → /about
247
+ (dashboard)/
248
+ settings.tsx # → /settings
218
249
  ```
219
250
 
220
251
  ## 📐 Layouts
221
252
 
222
- Create persistent layouts in `layouts/`:
253
+ Create layouts in `app/layout.tsx` or within route directories:
223
254
 
224
- ```jsx
225
- // layouts/root.jsx
226
- export default function RootLayout({ children }) {
255
+ ```tsx
256
+ // app/layout.tsx
257
+ import { Navbar } from './components/layout/Navbar';
258
+ import { Footer } from './components/layout/Footer';
259
+
260
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
227
261
  return (
228
- <div>
229
- <header>My App</header>
230
- <main>{children}</main>
231
- <footer>© 2024</footer>
232
- </div>
262
+ <html lang="en" className="dark">
263
+ <head>
264
+ <link rel="stylesheet" href="/styles.css" />
265
+ </head>
266
+ <body className="bg-background text-foreground">
267
+ <Navbar />
268
+ <main>{children}</main>
269
+ <Footer />
270
+ </body>
271
+ </html>
233
272
  );
234
273
  }
235
274
  ```
236
275
 
237
276
  ## ⏳ Loading & Error States
238
277
 
239
- ```jsx
240
- // pages/loading.jsx
278
+ ```tsx
279
+ // routes/loading.tsx
241
280
  export default function Loading() {
242
- return <div>Loading...</div>;
281
+ return (
282
+ <div className="flex items-center justify-center min-h-screen">
283
+ <div className="w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin" />
284
+ </div>
285
+ );
243
286
  }
244
287
 
245
- // pages/error.jsx
246
- export default function Error({ error }) {
247
- return <div>Error: {error.message}</div>;
288
+ // routes/error.tsx
289
+ export default function Error({ error, reset }: { error: Error; reset: () => void }) {
290
+ return (
291
+ <div className="flex flex-col items-center justify-center min-h-screen">
292
+ <h1 className="text-4xl font-bold text-red-500">Something went wrong</h1>
293
+ <p className="text-gray-400 mt-4">{error.message}</p>
294
+ <button onClick={reset} className="mt-8 px-6 py-3 bg-primary text-black rounded-lg">
295
+ Try again
296
+ </button>
297
+ </div>
298
+ );
248
299
  }
249
300
  ```
250
301
 
@@ -480,63 +531,6 @@ Islands provide partial hydration:
480
531
  - **Better performance** — less code to parse/execute
481
532
  - **Selective loading** — hydrate on visibility, interaction, etc.
482
533
 
483
- ## 🎨 FlexiUI - Official UI Library
484
-
485
- FlexiReact comes with an official UI component library: **@flexireact/flexi-ui**
486
-
487
- ```bash
488
- npm install @flexireact/flexi-ui
489
- ```
490
-
491
- ### Features
492
- - 🌙 **Dark-first design** with neon emerald accents
493
- - ♿ **Fully accessible** (ARIA-compliant, Radix UI primitives)
494
- - 🎯 **TypeScript native** with full type safety
495
- - 🌳 **Tree-shakeable** — import only what you need
496
- - ⚡ **SSR ready** — works with FlexiReact SSR
497
-
498
- ### Quick Setup
499
-
500
- ```js
501
- // tailwind.config.js
502
- const { flexiUIPlugin } = require('@flexireact/flexi-ui/tailwind');
503
-
504
- module.exports = {
505
- darkMode: 'class',
506
- content: [
507
- './pages/**/*.{js,ts,jsx,tsx}',
508
- './node_modules/@flexireact/flexi-ui/dist/**/*.js',
509
- ],
510
- plugins: [flexiUIPlugin],
511
- };
512
- ```
513
-
514
- ### Usage
515
-
516
- ```jsx
517
- import { Button, Card, Badge, Input } from '@flexireact/flexi-ui';
518
-
519
- export default function MyPage() {
520
- return (
521
- <Card>
522
- <Badge variant="success">New</Badge>
523
- <h2>Welcome!</h2>
524
- <Input placeholder="Enter your email" />
525
- <Button>Get Started</Button>
526
- </Card>
527
- );
528
- }
529
- ```
530
-
531
- ### Available Components
532
- - **Core**: Button, Input, Textarea, Checkbox, Switch, Select
533
- - **Display**: Card, Badge, Avatar, Tooltip
534
- - **Feedback**: Alert, Toast, Spinner, Skeleton, Progress
535
- - **Overlay**: Modal, Drawer, Dropdown
536
- - **Layout**: Separator, Tabs
537
-
538
- 📖 [FlexiUI Documentation](https://github.com/flexireact/flexi-ui)
539
-
540
534
  ---
541
535
 
542
536
  ## 📋 Requirements
@@ -544,7 +538,13 @@ export default function MyPage() {
544
538
  - Node.js 18+
545
539
  - React 18+
546
540
 
541
+ ## 🔗 Links
542
+
543
+ - [GitHub Repository](https://github.com/flexireact/flexireact)
544
+ - [npm Package](https://www.npmjs.com/package/@flexireact/core)
545
+ - [Issues](https://github.com/flexireact/flexireact/issues)
546
+
547
547
  ## 📄 License
548
548
 
549
- MIT
549
+ MIT © [FlexiReact Team](https://github.com/flexireact)
550
550
 
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * FlexiReact CLI Entry Point
5
+ * Uses tsx to run TypeScript CLI directly
6
+ */
7
+
8
+ import { spawnSync } from 'child_process';
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, join } from 'path';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+
15
+ const cliPath = join(__dirname, '..', 'cli', 'index.ts');
16
+
17
+ // Run the CLI with tsx
18
+ const result = spawnSync('npx', ['tsx', cliPath, ...process.argv.slice(2)], {
19
+ stdio: 'inherit',
20
+ shell: true,
21
+ });
22
+
23
+ process.exit(result.status ?? 0);
package/cli/index.ts CHANGED
@@ -112,7 +112,7 @@ async function createProject(projectName?: string): Promise<void> {
112
112
  name: 'projectName',
113
113
  message: 'Project name:',
114
114
  initial: 'my-flexi-app',
115
- validate: (value) => value.length > 0 || 'Project name is required'
115
+ validate: (value: string) => value.length > 0 || 'Project name is required'
116
116
  });
117
117
  name = response.projectName;
118
118
  if (!name) process.exit(1);
@@ -830,21 +830,15 @@ ${pc.cyan(' │')} ${pc.cyan('│')}
830
830
  ${pc.cyan(' ╰─────────────────────────────────────────╯')}
831
831
  `);
832
832
 
833
- const loaderPath = path.join(__dirname, '..', 'core', 'loader.js');
834
- const serverPath = path.join(__dirname, '..', 'core', 'server', 'index.js');
835
- const loaderUrl = pathToFileURL(loaderPath).href;
833
+ const startDevPath = path.join(__dirname, '..', 'core', 'start-dev.ts');
836
834
 
837
835
  const child = spawn(
838
- process.execPath,
839
- [
840
- '--import',
841
- `data:text/javascript,import { register } from 'node:module'; register('${loaderUrl}', import.meta.url);`,
842
- '-e',
843
- `import('${pathToFileURL(serverPath).href}').then(m => m.createServer({ mode: 'development' }))`
844
- ],
836
+ 'npx',
837
+ ['tsx', startDevPath],
845
838
  {
846
839
  stdio: 'inherit',
847
840
  cwd: process.cwd(),
841
+ shell: true,
848
842
  env: { ...process.env, NODE_ENV: 'development', FORCE_COLOR: '1' }
849
843
  }
850
844
  );
@@ -909,21 +903,15 @@ async function runStart(): Promise<void> {
909
903
  log.info('Starting production server...');
910
904
  log.blank();
911
905
 
912
- const loaderPath = path.join(__dirname, '..', 'core', 'loader.js');
913
- const serverPath = path.join(__dirname, '..', 'core', 'server', 'index.js');
914
- const loaderUrl = pathToFileURL(loaderPath).href;
906
+ const startProdPath = path.join(__dirname, '..', 'core', 'start-prod.ts');
915
907
 
916
908
  const child = spawn(
917
- process.execPath,
918
- [
919
- '--import',
920
- `data:text/javascript,import { register } from 'node:module'; register('${loaderUrl}', import.meta.url);`,
921
- '-e',
922
- `import('${pathToFileURL(serverPath).href}').then(m => m.createServer({ mode: 'production' }))`
923
- ],
909
+ 'npx',
910
+ ['tsx', startProdPath],
924
911
  {
925
912
  stdio: 'inherit',
926
913
  cwd: process.cwd(),
914
+ shell: true,
927
915
  env: { ...process.env, NODE_ENV: 'production' }
928
916
  }
929
917
  );
@@ -65,7 +65,13 @@ const box = {
65
65
  verticalLeft: '┤',
66
66
  };
67
67
 
68
- function createBox(content, options = {}) {
68
+ interface BoxOptions {
69
+ padding?: number;
70
+ borderColor?: (s: string) => string;
71
+ width?: number;
72
+ }
73
+
74
+ function createBox(content: string, options: BoxOptions = {}) {
69
75
  const {
70
76
  padding = 1,
71
77
  borderColor = colors.primary,
@@ -180,7 +186,7 @@ function pluginLoader(plugins = []) {
180
186
  // HTTP Request Logger
181
187
  // ============================================================================
182
188
 
183
- function request(method, path, statusCode, duration, options = {}) {
189
+ function request(method: string, path: string, statusCode: number, duration: number, options: { type?: string } = {}) {
184
190
  const { type = 'dynamic' } = options;
185
191
 
186
192
  // Method colors
@@ -6,6 +6,16 @@
6
6
  import React from 'react';
7
7
  import { hydrateRoot, createRoot } from 'react-dom/client';
8
8
 
9
+ // Extend Window interface for __FLEXI_DATA__
10
+ declare global {
11
+ interface Window {
12
+ __FLEXI_DATA__?: {
13
+ islands?: any[];
14
+ props?: Record<string, any>;
15
+ };
16
+ }
17
+ }
18
+
9
19
  /**
10
20
  * Hydrates a specific island component
11
21
  */
@@ -40,7 +40,12 @@ export function IslandBoundary({ children, fallback = null, name = 'island' }) {
40
40
  /**
41
41
  * Creates a lazy-loaded island
42
42
  */
43
- export function createClientIsland(loader, options = {}) {
43
+ interface LazyIslandOptions {
44
+ fallback?: React.ReactNode;
45
+ name?: string;
46
+ }
47
+
48
+ export function createClientIsland(loader: () => Promise<any>, options: LazyIslandOptions = {}) {
44
49
  const { fallback = null, name = 'lazy-island' } = options;
45
50
 
46
51
  return function LazyIsland(props) {
@@ -6,7 +6,10 @@
6
6
  import React from 'react';
7
7
 
8
8
  // Navigation state
9
- const navigationState = {
9
+ const navigationState: {
10
+ listeners: Set<(url: string) => void>;
11
+ prefetched: Set<string>;
12
+ } = {
10
13
  listeners: new Set(),
11
14
  prefetched: new Set()
12
15
  };
@@ -14,7 +17,12 @@ const navigationState = {
14
17
  /**
15
18
  * Navigates to a new URL
16
19
  */
17
- export function navigate(url, options = {}) {
20
+ interface NavigateOptions {
21
+ replace?: boolean;
22
+ scroll?: boolean;
23
+ }
24
+
25
+ export function navigate(url: string, options: NavigateOptions = {}) {
18
26
  const { replace = false, scroll = true } = options;
19
27
 
20
28
  if (replace) {
@@ -6,6 +6,22 @@
6
6
  import { hydrateAllIslands, setupProgressiveHydration } from './hydration.js';
7
7
  import { navigate, prefetch } from './navigation.js';
8
8
 
9
+ // Extend Window interface
10
+ declare global {
11
+ interface Window {
12
+ FlexiReact: {
13
+ navigate: typeof navigate;
14
+ prefetch: typeof prefetch;
15
+ hydrateAllIslands: typeof hydrateAllIslands;
16
+ setupProgressiveHydration: typeof setupProgressiveHydration;
17
+ };
18
+ __FLEXI_DATA__?: {
19
+ islands?: any[];
20
+ props?: Record<string, any>;
21
+ };
22
+ }
23
+ }
24
+
9
25
  // Expose to global scope
10
26
  window.FlexiReact = {
11
27
  navigate,
@@ -63,8 +63,11 @@ export const defaultConfig = {
63
63
  * @param {string} projectRoot - Path to project root
64
64
  * @returns {Object} Merged configuration
65
65
  */
66
- export async function loadConfig(projectRoot) {
67
- const configPath = path.join(projectRoot, 'flexireact.config.js');
66
+ export async function loadConfig(projectRoot: string) {
67
+ // Try .ts first, then .js
68
+ const configPathTs = path.join(projectRoot, 'flexireact.config.ts');
69
+ const configPathJs = path.join(projectRoot, 'flexireact.config.js');
70
+ const configPath = fs.existsSync(configPathTs) ? configPathTs : configPathJs;
68
71
 
69
72
  let userConfig = {};
70
73
 
@@ -73,8 +76,8 @@ export async function loadConfig(projectRoot) {
73
76
  const configUrl = pathToFileURL(configPath).href;
74
77
  const module = await import(`${configUrl}?t=${Date.now()}`);
75
78
  userConfig = module.default || module;
76
- } catch (error) {
77
- console.warn('Warning: Failed to load flexireact.config.js:', error.message);
79
+ } catch (error: any) {
80
+ console.warn('Warning: Failed to load flexireact config:', error.message);
78
81
  }
79
82
  }
80
83
 
@@ -3,6 +3,9 @@
3
3
  * A modern React framework with RSC, SSG, Islands, and more
4
4
  */
5
5
 
6
+ // Types
7
+ export type { FlexiConfig, Route, RouteType as RouteTypeEnum, PageProps, LayoutProps } from './types.js';
8
+
6
9
  // Core exports
7
10
  export { loadConfig, defaultConfig, resolvePaths } from './config.js';
8
11
  export { createRequestContext, useRequest, useParams, useQuery, usePathname } from './context.js';
@@ -15,7 +18,8 @@ export { buildRouteTree, matchRoute, findRouteLayouts, RouteType } from './route
15
18
  export { renderPage, renderError, renderLoading } from './render/index.js';
16
19
 
17
20
  // Server
18
- export { createServer } from './server/index.js';
21
+ import { createServer } from './server/index.js';
22
+ export { createServer };
19
23
 
20
24
  // Build
21
25
  export { build, buildDev, BuildMode } from './build/index.js';
@@ -67,7 +71,7 @@ export {
67
71
  } from './plugins/index.js';
68
72
 
69
73
  // Version
70
- export const VERSION = '2.0.0';
74
+ export const VERSION = '2.0.1';
71
75
 
72
76
  // Default export
73
77
  export default {
@@ -63,8 +63,13 @@ export function getRegisteredIslands() {
63
63
  /**
64
64
  * Creates an island component wrapper
65
65
  */
66
- export function createIsland(Component, options = {}) {
67
- const { name = Component.name || 'Island', clientPath } = options;
66
+ interface IslandOptions {
67
+ name?: string;
68
+ clientPath?: string;
69
+ }
70
+
71
+ export function createIsland(Component: React.ComponentType<any>, options: IslandOptions = {}) {
72
+ const { name = (Component as any).name || 'Island', clientPath } = options;
68
73
 
69
74
  function IslandWrapper(props) {
70
75
  return Island({
@@ -148,9 +153,16 @@ export const LoadStrategy = {
148
153
  /**
149
154
  * Creates a lazy island that hydrates based on strategy
150
155
  */
151
- export function createLazyIsland(Component, options = {}) {
156
+ interface LazyIslandOptions {
157
+ name?: string;
158
+ clientPath?: string;
159
+ strategy?: string;
160
+ media?: string | null;
161
+ }
162
+
163
+ export function createLazyIsland(Component: React.ComponentType<any>, options: LazyIslandOptions = {}) {
152
164
  const {
153
- name = Component.name || 'LazyIsland',
165
+ name = (Component as any).name || 'LazyIsland',
154
166
  clientPath,
155
167
  strategy = LoadStrategy.VISIBLE,
156
168
  media = null
@@ -122,7 +122,7 @@ export const logger = {
122
122
  },
123
123
 
124
124
  // HTTP request log - Compact single line like Next.js
125
- request(method, path, status, time, extra = {}) {
125
+ request(method: string, path: string, status: number, time: number, extra: { type?: string } = {}) {
126
126
  const methodColor = getMethodColor(method);
127
127
  const statusColor = getStatusColor(status);
128
128
  const timeStr = formatTime(time);