@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
@@ -1,161 +0,0 @@
1
- /**
2
- * FlexiReact Universal Edge Runtime
3
- *
4
- * Works on:
5
- * - Node.js
6
- * - Bun
7
- * - Deno
8
- * - Cloudflare Workers
9
- * - Vercel Edge
10
- * - Any Web-standard runtime
11
- */
12
-
13
- // Detect runtime environment
14
- export type RuntimeEnvironment =
15
- | 'node'
16
- | 'bun'
17
- | 'deno'
18
- | 'cloudflare'
19
- | 'vercel-edge'
20
- | 'netlify-edge'
21
- | 'fastly'
22
- | 'unknown';
23
-
24
- export function detectRuntime(): RuntimeEnvironment {
25
- // Bun
26
- if (typeof globalThis.Bun !== 'undefined') {
27
- return 'bun';
28
- }
29
-
30
- // Deno
31
- if (typeof globalThis.Deno !== 'undefined') {
32
- return 'deno';
33
- }
34
-
35
- // Cloudflare Workers
36
- if (typeof globalThis.caches !== 'undefined' && typeof (globalThis as any).WebSocketPair !== 'undefined') {
37
- return 'cloudflare';
38
- }
39
-
40
- // Vercel Edge
41
- if (typeof process !== 'undefined' && process.env?.VERCEL_EDGE === '1') {
42
- return 'vercel-edge';
43
- }
44
-
45
- // Netlify Edge
46
- if (typeof globalThis.Netlify !== 'undefined') {
47
- return 'netlify-edge';
48
- }
49
-
50
- // Node.js
51
- if (typeof process !== 'undefined' && process.versions?.node) {
52
- return 'node';
53
- }
54
-
55
- return 'unknown';
56
- }
57
-
58
- // Runtime capabilities
59
- export interface RuntimeCapabilities {
60
- hasFileSystem: boolean;
61
- hasWebCrypto: boolean;
62
- hasWebStreams: boolean;
63
- hasFetch: boolean;
64
- hasWebSocket: boolean;
65
- hasKV: boolean;
66
- hasCache: boolean;
67
- maxExecutionTime: number; // ms, 0 = unlimited
68
- maxMemory: number; // bytes, 0 = unlimited
69
- }
70
-
71
- export function getRuntimeCapabilities(): RuntimeCapabilities {
72
- const runtime = detectRuntime();
73
-
74
- switch (runtime) {
75
- case 'cloudflare':
76
- return {
77
- hasFileSystem: false,
78
- hasWebCrypto: true,
79
- hasWebStreams: true,
80
- hasFetch: true,
81
- hasWebSocket: true,
82
- hasKV: true,
83
- hasCache: true,
84
- maxExecutionTime: 30000, // 30s for paid, 10ms for free
85
- maxMemory: 128 * 1024 * 1024 // 128MB
86
- };
87
-
88
- case 'vercel-edge':
89
- return {
90
- hasFileSystem: false,
91
- hasWebCrypto: true,
92
- hasWebStreams: true,
93
- hasFetch: true,
94
- hasWebSocket: false,
95
- hasKV: true, // Vercel KV
96
- hasCache: true,
97
- maxExecutionTime: 30000,
98
- maxMemory: 128 * 1024 * 1024
99
- };
100
-
101
- case 'deno':
102
- return {
103
- hasFileSystem: true,
104
- hasWebCrypto: true,
105
- hasWebStreams: true,
106
- hasFetch: true,
107
- hasWebSocket: true,
108
- hasKV: true, // Deno KV
109
- hasCache: true,
110
- maxExecutionTime: 0,
111
- maxMemory: 0
112
- };
113
-
114
- case 'bun':
115
- return {
116
- hasFileSystem: true,
117
- hasWebCrypto: true,
118
- hasWebStreams: true,
119
- hasFetch: true,
120
- hasWebSocket: true,
121
- hasKV: false,
122
- hasCache: false,
123
- maxExecutionTime: 0,
124
- maxMemory: 0
125
- };
126
-
127
- case 'node':
128
- default:
129
- return {
130
- hasFileSystem: true,
131
- hasWebCrypto: true,
132
- hasWebStreams: true,
133
- hasFetch: true,
134
- hasWebSocket: true,
135
- hasKV: false,
136
- hasCache: false,
137
- maxExecutionTime: 0,
138
- maxMemory: 0
139
- };
140
- }
141
- }
142
-
143
- // Runtime info
144
- export const runtime = {
145
- name: detectRuntime(),
146
- capabilities: getRuntimeCapabilities(),
147
-
148
- get isEdge(): boolean {
149
- return ['cloudflare', 'vercel-edge', 'netlify-edge', 'fastly'].includes(this.name);
150
- },
151
-
152
- get isServer(): boolean {
153
- return ['node', 'bun', 'deno'].includes(this.name);
154
- },
155
-
156
- get supportsStreaming(): boolean {
157
- return this.capabilities.hasWebStreams;
158
- }
159
- };
160
-
161
- export default runtime;
@@ -1,306 +0,0 @@
1
- /**
2
- * FlexiReact Font Optimization
3
- *
4
- * Optimized font loading with:
5
- * - Automatic font subsetting
6
- * - Preload hints generation
7
- * - Font-display: swap by default
8
- * - Self-hosted Google Fonts
9
- * - Variable font support
10
- * - CSS variable generation
11
- */
12
-
13
- import fs from 'fs';
14
- import path from 'path';
15
- import crypto from 'crypto';
16
-
17
- // Font configuration
18
- export interface FontConfig {
19
- family: string;
20
- weight?: string | number | (string | number)[];
21
- style?: 'normal' | 'italic' | 'oblique';
22
- subsets?: string[];
23
- display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
24
- preload?: boolean;
25
- fallback?: string[];
26
- variable?: string;
27
- adjustFontFallback?: boolean;
28
- }
29
-
30
- export interface FontResult {
31
- className: string;
32
- style: {
33
- fontFamily: string;
34
- fontWeight?: number | string;
35
- fontStyle?: string;
36
- };
37
- variable?: string;
38
- }
39
-
40
- // Google Fonts API
41
- const GOOGLE_FONTS_API = 'https://fonts.googleapis.com/css2';
42
-
43
- // Popular Google Fonts with their weights
44
- export const googleFonts = {
45
- Inter: {
46
- weights: [100, 200, 300, 400, 500, 600, 700, 800, 900],
47
- variable: true,
48
- subsets: ['latin', 'latin-ext', 'cyrillic', 'greek', 'vietnamese']
49
- },
50
- Roboto: {
51
- weights: [100, 300, 400, 500, 700, 900],
52
- variable: false,
53
- subsets: ['latin', 'latin-ext', 'cyrillic', 'greek', 'vietnamese']
54
- },
55
- 'Open Sans': {
56
- weights: [300, 400, 500, 600, 700, 800],
57
- variable: true,
58
- subsets: ['latin', 'latin-ext', 'cyrillic', 'greek', 'vietnamese']
59
- },
60
- Poppins: {
61
- weights: [100, 200, 300, 400, 500, 600, 700, 800, 900],
62
- variable: false,
63
- subsets: ['latin', 'latin-ext']
64
- },
65
- Montserrat: {
66
- weights: [100, 200, 300, 400, 500, 600, 700, 800, 900],
67
- variable: true,
68
- subsets: ['latin', 'latin-ext', 'cyrillic', 'vietnamese']
69
- },
70
- 'Fira Code': {
71
- weights: [300, 400, 500, 600, 700],
72
- variable: true,
73
- subsets: ['latin', 'latin-ext', 'cyrillic', 'greek']
74
- },
75
- 'JetBrains Mono': {
76
- weights: [100, 200, 300, 400, 500, 600, 700, 800],
77
- variable: true,
78
- subsets: ['latin', 'latin-ext', 'cyrillic', 'greek']
79
- },
80
- Geist: {
81
- weights: [100, 200, 300, 400, 500, 600, 700, 800, 900],
82
- variable: true,
83
- subsets: ['latin', 'latin-ext']
84
- },
85
- 'Geist Mono': {
86
- weights: [100, 200, 300, 400, 500, 600, 700, 800, 900],
87
- variable: true,
88
- subsets: ['latin', 'latin-ext']
89
- }
90
- };
91
-
92
- // Generate font CSS
93
- export function generateFontCSS(config: FontConfig): string {
94
- const {
95
- family,
96
- weight = 400,
97
- style = 'normal',
98
- display = 'swap',
99
- fallback = ['system-ui', 'sans-serif'],
100
- variable
101
- } = config;
102
-
103
- const weights = Array.isArray(weight) ? weight : [weight];
104
- const fallbackStr = fallback.map(f => f.includes(' ') ? `"${f}"` : f).join(', ');
105
-
106
- let css = '';
107
-
108
- // Generate @font-face for each weight
109
- for (const w of weights) {
110
- css += `
111
- @font-face {
112
- font-family: '${family}';
113
- font-style: ${style};
114
- font-weight: ${w};
115
- font-display: ${display};
116
- src: local('${family}'),
117
- url('/_flexi/font/${encodeURIComponent(family)}?weight=${w}&style=${style}') format('woff2');
118
- }
119
- `;
120
- }
121
-
122
- // Generate CSS variable if specified
123
- if (variable) {
124
- css += `
125
- :root {
126
- ${variable}: '${family}', ${fallbackStr};
127
- }
128
- `;
129
- }
130
-
131
- return css;
132
- }
133
-
134
- // Generate preload link tags
135
- export function generateFontPreloadTags(fonts: FontConfig[]): string {
136
- return fonts
137
- .filter(f => f.preload !== false)
138
- .map(f => {
139
- const weights = Array.isArray(f.weight) ? f.weight : [f.weight || 400];
140
- return weights.map(w =>
141
- `<link rel="preload" href="/_flexi/font/${encodeURIComponent(f.family)}?weight=${w}&style=${f.style || 'normal'}" as="font" type="font/woff2" crossorigin>`
142
- ).join('\n');
143
- })
144
- .join('\n');
145
- }
146
-
147
- // Create a font loader function (like next/font)
148
- export function createFont(config: FontConfig): FontResult {
149
- const {
150
- family,
151
- weight = 400,
152
- style = 'normal',
153
- fallback = ['system-ui', 'sans-serif'],
154
- variable
155
- } = config;
156
-
157
- // Generate unique class name
158
- const hash = crypto
159
- .createHash('md5')
160
- .update(`${family}-${weight}-${style}`)
161
- .digest('hex')
162
- .slice(0, 8);
163
-
164
- const className = `__font_${hash}`;
165
- const fallbackStr = fallback.map(f => f.includes(' ') ? `"${f}"` : f).join(', ');
166
-
167
- return {
168
- className,
169
- style: {
170
- fontFamily: `'${family}', ${fallbackStr}`,
171
- fontWeight: Array.isArray(weight) ? undefined : weight,
172
- fontStyle: style
173
- },
174
- variable: variable || undefined
175
- };
176
- }
177
-
178
- // Google Font loader
179
- export function googleFont(config: FontConfig): FontResult {
180
- return createFont({
181
- ...config,
182
- // Google Fonts are always preloaded
183
- preload: true
184
- });
185
- }
186
-
187
- // Local font loader
188
- export function localFont(config: FontConfig & { src: string | { path: string; weight?: string | number; style?: string }[] }): FontResult {
189
- return createFont(config);
190
- }
191
-
192
- // Handle font requests
193
- export async function handleFontRequest(
194
- req: any,
195
- res: any
196
- ): Promise<void> {
197
- const url = new URL(req.url, `http://${req.headers.host}`);
198
- const pathParts = url.pathname.split('/');
199
- const fontFamily = decodeURIComponent(pathParts[pathParts.length - 1] || '');
200
- const weight = url.searchParams.get('weight') || '400';
201
- const style = url.searchParams.get('style') || 'normal';
202
-
203
- if (!fontFamily) {
204
- res.writeHead(400, { 'Content-Type': 'text/plain' });
205
- res.end('Missing font family');
206
- return;
207
- }
208
-
209
- try {
210
- // Check local cache first
211
- const cacheDir = path.join(process.cwd(), '.flexi', 'font-cache');
212
- const cacheKey = crypto
213
- .createHash('md5')
214
- .update(`${fontFamily}-${weight}-${style}`)
215
- .digest('hex');
216
- const cachePath = path.join(cacheDir, `${cacheKey}.woff2`);
217
-
218
- if (fs.existsSync(cachePath)) {
219
- const fontData = fs.readFileSync(cachePath);
220
- res.writeHead(200, {
221
- 'Content-Type': 'font/woff2',
222
- 'Cache-Control': 'public, max-age=31536000, immutable',
223
- 'X-Flexi-Font-Cache': 'HIT'
224
- });
225
- res.end(fontData);
226
- return;
227
- }
228
-
229
- // Fetch from Google Fonts
230
- const googleUrl = `${GOOGLE_FONTS_API}?family=${encodeURIComponent(fontFamily)}:wght@${weight}&display=swap`;
231
-
232
- const cssResponse = await fetch(googleUrl, {
233
- headers: {
234
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
235
- }
236
- });
237
-
238
- if (!cssResponse.ok) {
239
- throw new Error('Failed to fetch font CSS');
240
- }
241
-
242
- const css = await cssResponse.text();
243
-
244
- // Extract woff2 URL from CSS
245
- const woff2Match = css.match(/url\((https:\/\/fonts\.gstatic\.com[^)]+\.woff2)\)/);
246
-
247
- if (!woff2Match) {
248
- throw new Error('Could not find woff2 URL');
249
- }
250
-
251
- // Fetch the actual font file
252
- const fontResponse = await fetch(woff2Match[1]);
253
-
254
- if (!fontResponse.ok) {
255
- throw new Error('Failed to fetch font file');
256
- }
257
-
258
- const fontBuffer = Buffer.from(await fontResponse.arrayBuffer());
259
-
260
- // Cache the font
261
- if (!fs.existsSync(cacheDir)) {
262
- fs.mkdirSync(cacheDir, { recursive: true });
263
- }
264
- fs.writeFileSync(cachePath, fontBuffer);
265
-
266
- // Serve the font
267
- res.writeHead(200, {
268
- 'Content-Type': 'font/woff2',
269
- 'Cache-Control': 'public, max-age=31536000, immutable',
270
- 'X-Flexi-Font-Cache': 'MISS'
271
- });
272
- res.end(fontBuffer);
273
-
274
- } catch (error: any) {
275
- console.error('Font loading error:', error);
276
- res.writeHead(500, { 'Content-Type': 'text/plain' });
277
- res.end('Font loading failed');
278
- }
279
- }
280
-
281
- // Pre-built font configurations
282
- export const fonts = {
283
- // Sans-serif
284
- inter: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Inter', variable: '--font-inter', ...config }),
285
- roboto: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Roboto', variable: '--font-roboto', ...config }),
286
- openSans: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Open Sans', variable: '--font-open-sans', ...config }),
287
- poppins: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Poppins', variable: '--font-poppins', ...config }),
288
- montserrat: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Montserrat', variable: '--font-montserrat', ...config }),
289
- geist: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Geist', variable: '--font-geist', ...config }),
290
-
291
- // Monospace
292
- firaCode: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Fira Code', variable: '--font-fira-code', fallback: ['monospace'], ...config }),
293
- jetbrainsMono: (config: Partial<FontConfig> = {}) => googleFont({ family: 'JetBrains Mono', variable: '--font-jetbrains', fallback: ['monospace'], ...config }),
294
- geistMono: (config: Partial<FontConfig> = {}) => googleFont({ family: 'Geist Mono', variable: '--font-geist-mono', fallback: ['monospace'], ...config })
295
- };
296
-
297
- export default {
298
- createFont,
299
- googleFont,
300
- localFont,
301
- generateFontCSS,
302
- generateFontPreloadTags,
303
- handleFontRequest,
304
- fonts,
305
- googleFonts
306
- };