@flexireact/core 3.0.0 → 3.0.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.
Files changed (56) hide show
  1. package/README.md +204 -52
  2. package/dist/cli/index.js +1514 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/core/client/index.js +373 -0
  5. package/dist/core/client/index.js.map +1 -0
  6. package/dist/core/index.js +6415 -0
  7. package/dist/core/index.js.map +1 -0
  8. package/dist/core/server/index.js +3094 -0
  9. package/dist/core/server/index.js.map +1 -0
  10. package/package.json +80 -80
  11. package/bin/flexireact.js +0 -23
  12. package/cli/generators.ts +0 -616
  13. package/cli/index.ts +0 -1182
  14. package/core/actions/index.ts +0 -364
  15. package/core/api.ts +0 -143
  16. package/core/build/index.ts +0 -425
  17. package/core/cli/logger.ts +0 -353
  18. package/core/client/Link.tsx +0 -345
  19. package/core/client/hydration.ts +0 -147
  20. package/core/client/index.ts +0 -12
  21. package/core/client/islands.ts +0 -143
  22. package/core/client/navigation.ts +0 -212
  23. package/core/client/runtime.ts +0 -52
  24. package/core/config.ts +0 -116
  25. package/core/context.ts +0 -83
  26. package/core/dev.ts +0 -47
  27. package/core/devtools/index.ts +0 -644
  28. package/core/edge/cache.ts +0 -344
  29. package/core/edge/fetch-polyfill.ts +0 -247
  30. package/core/edge/handler.ts +0 -248
  31. package/core/edge/index.ts +0 -81
  32. package/core/edge/ppr.ts +0 -264
  33. package/core/edge/runtime.ts +0 -161
  34. package/core/font/index.ts +0 -306
  35. package/core/helpers.ts +0 -494
  36. package/core/image/index.ts +0 -413
  37. package/core/index.ts +0 -218
  38. package/core/islands/index.ts +0 -293
  39. package/core/loader.ts +0 -111
  40. package/core/logger.ts +0 -242
  41. package/core/metadata/index.ts +0 -622
  42. package/core/middleware/index.ts +0 -416
  43. package/core/plugins/index.ts +0 -373
  44. package/core/render/index.ts +0 -1243
  45. package/core/render.ts +0 -136
  46. package/core/router/index.ts +0 -551
  47. package/core/router.ts +0 -141
  48. package/core/rsc/index.ts +0 -199
  49. package/core/server/index.ts +0 -779
  50. package/core/server.ts +0 -203
  51. package/core/ssg/index.ts +0 -346
  52. package/core/start-dev.ts +0 -6
  53. package/core/start-prod.ts +0 -6
  54. package/core/tsconfig.json +0 -30
  55. package/core/types.ts +0 -239
  56. package/core/utils.ts +0 -176
package/core/server.ts DELETED
@@ -1,203 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import http from 'http';
4
- import path from 'path';
5
- import fs from 'fs';
6
- import { fileURLToPath } from 'url';
7
- import { buildRoutes, matchRoute } from './router.js';
8
- import { render, renderError } from './render.js';
9
- import { handleApiRoute } from './api.js';
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
13
-
14
- // Configuration
15
- const PORT = process.env.PORT || 3000;
16
- const HOST = process.env.HOST || 'localhost';
17
-
18
- // Determine the project root (where the user's app is)
19
- const PROJECT_ROOT = process.cwd();
20
- const PAGES_DIR = path.join(PROJECT_ROOT, 'pages');
21
-
22
- // MIME types for static files
23
- const MIME_TYPES = {
24
- '.html': 'text/html',
25
- '.css': 'text/css',
26
- '.js': 'application/javascript',
27
- '.json': 'application/json',
28
- '.png': 'image/png',
29
- '.jpg': 'image/jpeg',
30
- '.jpeg': 'image/jpeg',
31
- '.gif': 'image/gif',
32
- '.svg': 'image/svg+xml',
33
- '.ico': 'image/x-icon',
34
- '.woff': 'font/woff',
35
- '.woff2': 'font/woff2',
36
- '.ttf': 'font/ttf'
37
- };
38
-
39
- /**
40
- * Creates and starts the FlexiReact dev server
41
- */
42
- interface ServerOptions {
43
- port?: number;
44
- host?: string;
45
- pagesDir?: string;
46
- }
47
-
48
- export function createServer(options: ServerOptions = {}) {
49
- const {
50
- port = PORT,
51
- host = HOST,
52
- pagesDir = PAGES_DIR
53
- } = options;
54
-
55
- const server = http.createServer(async (req, res) => {
56
- const startTime = Date.now();
57
-
58
- try {
59
- // Parse URL
60
- const url = new URL(req.url, `http://${req.headers.host}`);
61
- const pathname = url.pathname;
62
-
63
- // Log request
64
- console.log(`${req.method} ${pathname}`);
65
-
66
- // Try to serve static files from public directory
67
- const publicPath = path.join(PROJECT_ROOT, 'public', pathname);
68
- if (fs.existsSync(publicPath) && fs.statSync(publicPath).isFile()) {
69
- return serveStaticFile(res, publicPath);
70
- }
71
-
72
- // Build routes (rebuild on each request for hot reload)
73
- const routes = buildRoutes(pagesDir);
74
-
75
- // Check for API routes first
76
- const apiRoute = matchRoute(pathname, routes.api);
77
- if (apiRoute) {
78
- return await handleApiRoute(req, res, apiRoute);
79
- }
80
-
81
- // Check for page routes
82
- const pageRoute = matchRoute(pathname, routes.pages);
83
- if (pageRoute) {
84
- return await handlePageRoute(req, res, pageRoute);
85
- }
86
-
87
- // 404 Not Found
88
- res.writeHead(404, { 'Content-Type': 'text/html' });
89
- res.end(renderError(404, 'Page not found'));
90
-
91
- } catch (error) {
92
- console.error('Server Error:', error);
93
-
94
- if (!res.headersSent) {
95
- res.writeHead(500, { 'Content-Type': 'text/html' });
96
- res.end(renderError(500, process.env.NODE_ENV === 'development'
97
- ? error.message
98
- : 'Internal Server Error'));
99
- }
100
- } finally {
101
- const duration = Date.now() - startTime;
102
- console.log(` └─ ${res.statusCode} (${duration}ms)`);
103
- }
104
- });
105
-
106
- server.listen(port as number, host as string, () => {
107
- console.log('');
108
- console.log(' ⚡ FlexiReact Dev Server');
109
- console.log(' ─────────────────────────');
110
- console.log(` → Local: http://${host}:${port}`);
111
- console.log(` → Pages: ${pagesDir}`);
112
- console.log('');
113
- console.log(' Ready for requests...');
114
- console.log('');
115
- });
116
-
117
- return server;
118
- }
119
-
120
- /**
121
- * Handles page route requests with SSR
122
- */
123
- async function handlePageRoute(req, res, route) {
124
- try {
125
- // Import the page component with cache busting for hot reload
126
- const modulePath = `file://${route.filePath.replace(/\\/g, '/')}?t=${Date.now()}`;
127
- const pageModule = await import(modulePath);
128
-
129
- // Get the component (default export)
130
- const Component = pageModule.default;
131
-
132
- if (!Component) {
133
- throw new Error(`No default export found in ${route.filePath}`);
134
- }
135
-
136
- // Get page props if getServerSideProps exists
137
- let props = { params: route.params };
138
-
139
- if (pageModule.getServerSideProps) {
140
- const context = {
141
- params: route.params,
142
- req,
143
- res,
144
- query: Object.fromEntries(new URL(req.url, `http://${req.headers.host}`).searchParams)
145
- };
146
-
147
- const result = await pageModule.getServerSideProps(context);
148
-
149
- if (result.redirect) {
150
- res.writeHead(result.redirect.statusCode || 302, {
151
- Location: result.redirect.destination
152
- });
153
- res.end();
154
- return;
155
- }
156
-
157
- if (result.notFound) {
158
- res.writeHead(404, { 'Content-Type': 'text/html' });
159
- res.end(renderError(404, 'Page not found'));
160
- return;
161
- }
162
-
163
- props = { ...props, ...result.props };
164
- }
165
-
166
- // Get page title if defined
167
- const title = pageModule.title || 'FlexiReact App';
168
-
169
- // Render the page
170
- const html = render(Component, props, { title });
171
-
172
- res.writeHead(200, { 'Content-Type': 'text/html' });
173
- res.end(html);
174
-
175
- } catch (error) {
176
- console.error('Page Render Error:', error);
177
- throw error;
178
- }
179
- }
180
-
181
- /**
182
- * Serves static files
183
- */
184
- function serveStaticFile(res, filePath) {
185
- const ext = path.extname(filePath).toLowerCase();
186
- const contentType = MIME_TYPES[ext] || 'application/octet-stream';
187
-
188
- const content = fs.readFileSync(filePath);
189
- res.writeHead(200, { 'Content-Type': contentType });
190
- res.end(content);
191
- }
192
-
193
- // Auto-start server when run directly
194
- const scriptPath = process.argv[1];
195
-
196
- // Check if running directly (handles symlinks on Windows)
197
- const isDirectRun = scriptPath && scriptPath.endsWith('server.js');
198
-
199
- if (isDirectRun) {
200
- createServer();
201
- }
202
-
203
- export default createServer;
package/core/ssg/index.ts DELETED
@@ -1,346 +0,0 @@
1
- /**
2
- * FlexiReact Static Site Generation (SSG)
3
- *
4
- * SSG pre-renders pages at build time, generating static HTML files.
5
- * This provides the fastest possible page loads and enables CDN caching.
6
- *
7
- * Usage:
8
- * - Export getStaticProps() from a page to fetch data at build time
9
- * - Export getStaticPaths() for dynamic routes to specify which paths to pre-render
10
- * - Pages without these exports are rendered as static HTML
11
- */
12
-
13
- import fs from 'fs';
14
- import path from 'path';
15
- import { pathToFileURL } from 'url';
16
- import { renderPage } from '../render/index.js';
17
- import { ensureDir, cleanDir } from '../utils.js';
18
-
19
- /**
20
- * SSG Build Result
21
- */
22
- interface SSGPage {
23
- path: string;
24
- file: string;
25
- size: number;
26
- }
27
-
28
- interface SSGError {
29
- path: string;
30
- error: string;
31
- }
32
-
33
- export class SSGResult {
34
- pages: SSGPage[];
35
- errors: SSGError[];
36
- duration: number;
37
-
38
- constructor() {
39
- this.pages = [];
40
- this.errors = [];
41
- this.duration = 0;
42
- }
43
-
44
- addPage(pagePath: string, file: string, size: number) {
45
- this.pages.push({ path: pagePath, file, size });
46
- }
47
-
48
- addError(pagePath: string, error: Error) {
49
- this.errors.push({ path: pagePath, error: error.message });
50
- }
51
-
52
- get success() {
53
- return this.errors.length === 0;
54
- }
55
-
56
- get totalSize() {
57
- return this.pages.reduce((sum, p) => sum + p.size, 0);
58
- }
59
- }
60
-
61
- /**
62
- * Generates static pages for all routes
63
- */
64
- export async function generateStaticSite(options) {
65
- const {
66
- routes,
67
- outDir,
68
- config,
69
- loadModule
70
- } = options;
71
-
72
- const result = new SSGResult();
73
- const startTime = Date.now();
74
-
75
- // Clean and create output directory
76
- const staticDir = path.join(outDir, 'static');
77
- cleanDir(staticDir);
78
-
79
- console.log('\n📦 Generating static pages...\n');
80
-
81
- for (const route of routes) {
82
- try {
83
- await generateRoutePage(route, staticDir, loadModule, result, config);
84
- } catch (error) {
85
- console.error(` ✗ ${route.path}: ${error.message}`);
86
- result.addError(route.path, error);
87
- }
88
- }
89
-
90
- result.duration = Date.now() - startTime;
91
-
92
- // Generate summary
93
- console.log('\n' + '─'.repeat(50));
94
- console.log(` Generated ${result.pages.length} pages in ${result.duration}ms`);
95
- if (result.errors.length > 0) {
96
- console.log(` ${result.errors.length} errors occurred`);
97
- }
98
- console.log('─'.repeat(50) + '\n');
99
-
100
- return result;
101
- }
102
-
103
- /**
104
- * Generates a single route's static page(s)
105
- */
106
- async function generateRoutePage(route, outDir, loadModule, result, config) {
107
- const module = await loadModule(route.filePath);
108
- const Component = module.default;
109
-
110
- if (!Component) {
111
- throw new Error(`No default export in ${route.filePath}`);
112
- }
113
-
114
- // Check for getStaticPaths (dynamic routes)
115
- let paths = [{ params: {} }];
116
-
117
- if (route.path.includes(':') || route.path.includes('*')) {
118
- if (!module.getStaticPaths) {
119
- console.log(` ⊘ ${route.path} (dynamic, no getStaticPaths)`);
120
- return;
121
- }
122
-
123
- const staticPaths = await module.getStaticPaths();
124
- paths = staticPaths.paths || [];
125
-
126
- if (staticPaths.fallback === false && paths.length === 0) {
127
- console.log(` ⊘ ${route.path} (no paths to generate)`);
128
- return;
129
- }
130
- }
131
-
132
- // Generate page for each path
133
- for (const pathConfig of paths) {
134
- const params = pathConfig.params || {};
135
- const actualPath = substituteParams(route.path, params);
136
-
137
- try {
138
- // Get static props
139
- let props = { params };
140
-
141
- if (module.getStaticProps) {
142
- const staticProps = await module.getStaticProps({ params });
143
-
144
- if (staticProps.notFound) {
145
- console.log(` ⊘ ${actualPath} (notFound)`);
146
- continue;
147
- }
148
-
149
- if (staticProps.redirect) {
150
- // Generate redirect HTML
151
- await generateRedirectPage(actualPath, staticProps.redirect, outDir, result);
152
- continue;
153
- }
154
-
155
- props = { ...props, ...staticProps.props };
156
- }
157
-
158
- // Render the page
159
- const html = await renderPage({
160
- Component,
161
- props,
162
- title: module.title || module.metadata?.title || 'FlexiReact App',
163
- meta: module.metadata || {},
164
- isSSG: true
165
- });
166
-
167
- // Write to file
168
- const filePath = getOutputPath(actualPath, outDir);
169
- ensureDir(path.dirname(filePath));
170
- fs.writeFileSync(filePath, html);
171
-
172
- const size = Buffer.byteLength(html, 'utf8');
173
- result.addPage(actualPath, filePath, size);
174
-
175
- console.log(` ✓ ${actualPath} (${formatSize(size)})`);
176
-
177
- } catch (error) {
178
- result.addError(actualPath, error);
179
- console.error(` ✗ ${actualPath}: ${error.message}`);
180
- }
181
- }
182
- }
183
-
184
- /**
185
- * Generates a redirect page
186
- */
187
- async function generateRedirectPage(fromPath, redirect, outDir, result) {
188
- const { destination, permanent = false } = redirect;
189
- const statusCode = permanent ? 301 : 302;
190
-
191
- const html = `<!DOCTYPE html>
192
- <html>
193
- <head>
194
- <meta charset="utf-8">
195
- <meta http-equiv="refresh" content="0;url=${destination}">
196
- <link rel="canonical" href="${destination}">
197
- <title>Redirecting...</title>
198
- </head>
199
- <body>
200
- <p>Redirecting to <a href="${destination}">${destination}</a></p>
201
- <script>window.location.href = "${destination}";</script>
202
- </body>
203
- </html>`;
204
-
205
- const filePath = getOutputPath(fromPath, outDir);
206
- ensureDir(path.dirname(filePath));
207
- fs.writeFileSync(filePath, html);
208
-
209
- const size = Buffer.byteLength(html, 'utf8');
210
- result.addPage(fromPath, filePath, size);
211
-
212
- console.log(` ↪ ${fromPath} → ${destination}`);
213
- }
214
-
215
- /**
216
- * Substitutes route params into path
217
- */
218
- function substituteParams(routePath, params) {
219
- let result = routePath;
220
-
221
- for (const [key, value] of Object.entries(params)) {
222
- result = result.replace(`:${key}`, value);
223
- result = result.replace(`*${key}`, value);
224
- }
225
-
226
- return result;
227
- }
228
-
229
- /**
230
- * Gets the output file path for a route
231
- */
232
- function getOutputPath(routePath, outDir) {
233
- if (routePath === '/') {
234
- return path.join(outDir, 'index.html');
235
- }
236
-
237
- // Remove leading slash and add index.html
238
- const cleanPath = routePath.replace(/^\//, '');
239
- return path.join(outDir, cleanPath, 'index.html');
240
- }
241
-
242
- /**
243
- * Formats file size
244
- */
245
- function formatSize(bytes) {
246
- if (bytes < 1024) return `${bytes} B`;
247
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
248
- return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
249
- }
250
-
251
- /**
252
- * Incremental Static Regeneration (ISR) support
253
- * Allows pages to be regenerated after a specified interval
254
- */
255
- interface ISRCacheEntry {
256
- html: string;
257
- generatedAt: number;
258
- revalidateAfter: number | null;
259
- }
260
-
261
- export class ISRManager {
262
- cache: Map<string, ISRCacheEntry>;
263
- revalidating: Set<string>;
264
- defaultRevalidate: number;
265
-
266
- constructor(options: { defaultRevalidate?: number } = {}) {
267
- this.cache = new Map();
268
- this.revalidating = new Set();
269
- this.defaultRevalidate = options.defaultRevalidate || 60; // seconds
270
- }
271
-
272
- /**
273
- * Gets a cached page or regenerates it
274
- */
275
- async getPage(routePath, generator) {
276
- const cached = this.cache.get(routePath);
277
- const now = Date.now();
278
-
279
- if (cached) {
280
- // Check if revalidation is needed
281
- if (cached.revalidateAfter && now > cached.revalidateAfter) {
282
- // Trigger background revalidation
283
- this.revalidateInBackground(routePath, generator);
284
- }
285
- return cached.html;
286
- }
287
-
288
- // Generate fresh page
289
- const result = await generator();
290
- this.cache.set(routePath, {
291
- html: result.html,
292
- generatedAt: now,
293
- revalidateAfter: result.revalidate
294
- ? now + (result.revalidate * 1000)
295
- : null
296
- });
297
-
298
- return result.html;
299
- }
300
-
301
- /**
302
- * Revalidates a page in the background
303
- */
304
- async revalidateInBackground(routePath, generator) {
305
- if (this.revalidating.has(routePath)) return;
306
-
307
- this.revalidating.add(routePath);
308
-
309
- try {
310
- const result = await generator();
311
- const now = Date.now();
312
-
313
- this.cache.set(routePath, {
314
- html: result.html,
315
- generatedAt: now,
316
- revalidateAfter: result.revalidate
317
- ? now + (result.revalidate * 1000)
318
- : null
319
- });
320
- } catch (error) {
321
- console.error(`ISR revalidation failed for ${routePath}:`, error);
322
- } finally {
323
- this.revalidating.delete(routePath);
324
- }
325
- }
326
-
327
- /**
328
- * Invalidates a cached page
329
- */
330
- invalidate(routePath) {
331
- this.cache.delete(routePath);
332
- }
333
-
334
- /**
335
- * Clears all cached pages
336
- */
337
- clear() {
338
- this.cache.clear();
339
- }
340
- }
341
-
342
- export default {
343
- generateStaticSite,
344
- SSGResult,
345
- ISRManager
346
- };
package/core/start-dev.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Development server starter
3
- */
4
- import { createServer } from './server/index.js';
5
-
6
- createServer({ mode: 'development' });
@@ -1,6 +0,0 @@
1
- /**
2
- * Production server starter
3
- */
4
- import { createServer } from './server/index.js';
5
-
6
- createServer({ mode: 'production' });
@@ -1,30 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
- "jsx": "react-jsx",
8
- "outDir": "./dist",
9
- "rootDir": ".",
10
- "strict": false,
11
- "noImplicitAny": false,
12
- "strictPropertyInitialization": false,
13
- "useUnknownInCatchVariables": false,
14
- "esModuleInterop": true,
15
- "skipLibCheck": true,
16
- "forceConsistentCasingInFileNames": true,
17
- "resolveJsonModule": true,
18
- "declaration": false,
19
- "sourceMap": true,
20
- "allowJs": true,
21
- "checkJs": false,
22
- "noEmit": true
23
- },
24
- "include": [
25
- "*.ts",
26
- "**/*.ts",
27
- "**/*.tsx"
28
- ],
29
- "exclude": ["node_modules", "dist"]
30
- }