@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/helpers.ts DELETED
@@ -1,494 +0,0 @@
1
- /**
2
- * FlexiReact Server Helpers
3
- * Utility functions for server-side operations
4
- */
5
-
6
- // ============================================================================
7
- // Response Helpers
8
- // ============================================================================
9
-
10
- /**
11
- * Custom error classes for control flow
12
- */
13
- export class RedirectError extends Error {
14
- public readonly url: string;
15
- public readonly statusCode: number;
16
- public readonly type = 'redirect' as const;
17
-
18
- constructor(url: string, statusCode: number = 307) {
19
- super(`Redirect to ${url}`);
20
- this.name = 'RedirectError';
21
- this.url = url;
22
- this.statusCode = statusCode;
23
- }
24
- }
25
-
26
- export class NotFoundError extends Error {
27
- public readonly type = 'notFound' as const;
28
-
29
- constructor(message: string = 'Page not found') {
30
- super(message);
31
- this.name = 'NotFoundError';
32
- }
33
- }
34
-
35
- /**
36
- * Redirect to a different URL
37
- * @param url - The URL to redirect to
38
- * @param type - 'replace' (307) or 'push' (308) for permanent
39
- *
40
- * @example
41
- * ```tsx
42
- * import { redirect } from '@flexireact/core';
43
- *
44
- * export default function ProtectedPage() {
45
- * const user = getUser();
46
- * if (!user) {
47
- * redirect('/login');
48
- * }
49
- * return <Dashboard user={user} />;
50
- * }
51
- * ```
52
- */
53
- export function redirect(url: string, type: 'replace' | 'permanent' = 'replace'): never {
54
- const statusCode = type === 'permanent' ? 308 : 307;
55
- throw new RedirectError(url, statusCode);
56
- }
57
-
58
- /**
59
- * Trigger a 404 Not Found response
60
- *
61
- * @example
62
- * ```tsx
63
- * import { notFound } from '@flexireact/core';
64
- *
65
- * export default function ProductPage({ params }) {
66
- * const product = getProduct(params.id);
67
- * if (!product) {
68
- * notFound();
69
- * }
70
- * return <Product data={product} />;
71
- * }
72
- * ```
73
- */
74
- export function notFound(message?: string): never {
75
- throw new NotFoundError(message);
76
- }
77
-
78
- /**
79
- * Create a JSON response
80
- *
81
- * @example
82
- * ```ts
83
- * // In API route
84
- * export function GET() {
85
- * return json({ message: 'Hello' });
86
- * }
87
- *
88
- * export function POST() {
89
- * return json({ error: 'Bad request' }, { status: 400 });
90
- * }
91
- * ```
92
- */
93
- export function json<T>(
94
- data: T,
95
- options: {
96
- status?: number;
97
- headers?: Record<string, string>;
98
- } = {}
99
- ): Response {
100
- const { status = 200, headers = {} } = options;
101
-
102
- return new Response(JSON.stringify(data), {
103
- status,
104
- headers: {
105
- 'Content-Type': 'application/json',
106
- ...headers
107
- }
108
- });
109
- }
110
-
111
- /**
112
- * Create an HTML response
113
- */
114
- export function html(
115
- content: string,
116
- options: {
117
- status?: number;
118
- headers?: Record<string, string>;
119
- } = {}
120
- ): Response {
121
- const { status = 200, headers = {} } = options;
122
-
123
- return new Response(content, {
124
- status,
125
- headers: {
126
- 'Content-Type': 'text/html; charset=utf-8',
127
- ...headers
128
- }
129
- });
130
- }
131
-
132
- /**
133
- * Create a text response
134
- */
135
- export function text(
136
- content: string,
137
- options: {
138
- status?: number;
139
- headers?: Record<string, string>;
140
- } = {}
141
- ): Response {
142
- const { status = 200, headers = {} } = options;
143
-
144
- return new Response(content, {
145
- status,
146
- headers: {
147
- 'Content-Type': 'text/plain; charset=utf-8',
148
- ...headers
149
- }
150
- });
151
- }
152
-
153
- // ============================================================================
154
- // Cookies API
155
- // ============================================================================
156
-
157
- export interface CookieOptions {
158
- /** Max age in seconds */
159
- maxAge?: number;
160
- /** Expiration date */
161
- expires?: Date;
162
- /** Cookie path */
163
- path?: string;
164
- /** Cookie domain */
165
- domain?: string;
166
- /** Secure flag (HTTPS only) */
167
- secure?: boolean;
168
- /** HttpOnly flag */
169
- httpOnly?: boolean;
170
- /** SameSite policy */
171
- sameSite?: 'strict' | 'lax' | 'none';
172
- }
173
-
174
- /**
175
- * Cookie utilities for server-side operations
176
- */
177
- export const cookies = {
178
- /**
179
- * Parse cookies from a cookie header string
180
- */
181
- parse(cookieHeader: string): Record<string, string> {
182
- const cookies: Record<string, string> = {};
183
- if (!cookieHeader) return cookies;
184
-
185
- cookieHeader.split(';').forEach(cookie => {
186
- const [name, ...rest] = cookie.split('=');
187
- if (name) {
188
- const value = rest.join('=');
189
- cookies[name.trim()] = decodeURIComponent(value.trim());
190
- }
191
- });
192
-
193
- return cookies;
194
- },
195
-
196
- /**
197
- * Get a cookie value from request headers
198
- */
199
- get(request: Request, name: string): string | undefined {
200
- const cookieHeader = request.headers.get('cookie') || '';
201
- const parsed = this.parse(cookieHeader);
202
- return parsed[name];
203
- },
204
-
205
- /**
206
- * Get all cookies from request
207
- */
208
- getAll(request: Request): Record<string, string> {
209
- const cookieHeader = request.headers.get('cookie') || '';
210
- return this.parse(cookieHeader);
211
- },
212
-
213
- /**
214
- * Serialize a cookie for Set-Cookie header
215
- */
216
- serialize(name: string, value: string, options: CookieOptions = {}): string {
217
- let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
218
-
219
- if (options.maxAge !== undefined) {
220
- cookie += `; Max-Age=${options.maxAge}`;
221
- }
222
- if (options.expires) {
223
- cookie += `; Expires=${options.expires.toUTCString()}`;
224
- }
225
- if (options.path) {
226
- cookie += `; Path=${options.path}`;
227
- }
228
- if (options.domain) {
229
- cookie += `; Domain=${options.domain}`;
230
- }
231
- if (options.secure) {
232
- cookie += '; Secure';
233
- }
234
- if (options.httpOnly) {
235
- cookie += '; HttpOnly';
236
- }
237
- if (options.sameSite) {
238
- cookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;
239
- }
240
-
241
- return cookie;
242
- },
243
-
244
- /**
245
- * Create a Set-Cookie header value
246
- */
247
- set(name: string, value: string, options: CookieOptions = {}): string {
248
- return this.serialize(name, value, {
249
- path: '/',
250
- httpOnly: true,
251
- secure: process.env.NODE_ENV === 'production',
252
- sameSite: 'lax',
253
- ...options
254
- });
255
- },
256
-
257
- /**
258
- * Create a cookie deletion header
259
- */
260
- delete(name: string, options: Omit<CookieOptions, 'maxAge' | 'expires'> = {}): string {
261
- return this.serialize(name, '', {
262
- ...options,
263
- path: '/',
264
- maxAge: 0
265
- });
266
- }
267
- };
268
-
269
- // ============================================================================
270
- // Headers API
271
- // ============================================================================
272
-
273
- /**
274
- * Headers utilities for server-side operations
275
- */
276
- export const headers = {
277
- /**
278
- * Create a new Headers object with common defaults
279
- */
280
- create(init?: HeadersInit): Headers {
281
- return new Headers(init);
282
- },
283
-
284
- /**
285
- * Get a header value from request
286
- */
287
- get(request: Request, name: string): string | null {
288
- return request.headers.get(name);
289
- },
290
-
291
- /**
292
- * Get all headers as an object
293
- */
294
- getAll(request: Request): Record<string, string> {
295
- const result: Record<string, string> = {};
296
- request.headers.forEach((value, key) => {
297
- result[key] = value;
298
- });
299
- return result;
300
- },
301
-
302
- /**
303
- * Check if request has a specific header
304
- */
305
- has(request: Request, name: string): boolean {
306
- return request.headers.has(name);
307
- },
308
-
309
- /**
310
- * Get content type from request
311
- */
312
- contentType(request: Request): string | null {
313
- return request.headers.get('content-type');
314
- },
315
-
316
- /**
317
- * Check if request accepts JSON
318
- */
319
- acceptsJson(request: Request): boolean {
320
- const accept = request.headers.get('accept') || '';
321
- return accept.includes('application/json') || accept.includes('*/*');
322
- },
323
-
324
- /**
325
- * Check if request is AJAX/fetch
326
- */
327
- isAjax(request: Request): boolean {
328
- return request.headers.get('x-requested-with') === 'XMLHttpRequest' ||
329
- this.acceptsJson(request);
330
- },
331
-
332
- /**
333
- * Get authorization header
334
- */
335
- authorization(request: Request): { type: string; credentials: string } | null {
336
- const auth = request.headers.get('authorization');
337
- if (!auth) return null;
338
-
339
- const [type, ...rest] = auth.split(' ');
340
- return {
341
- type: type.toLowerCase(),
342
- credentials: rest.join(' ')
343
- };
344
- },
345
-
346
- /**
347
- * Get bearer token from authorization header
348
- */
349
- bearerToken(request: Request): string | null {
350
- const auth = this.authorization(request);
351
- if (auth?.type === 'bearer') {
352
- return auth.credentials;
353
- }
354
- return null;
355
- },
356
-
357
- /**
358
- * Common security headers
359
- */
360
- security(): Record<string, string> {
361
- return {
362
- 'X-Content-Type-Options': 'nosniff',
363
- 'X-Frame-Options': 'DENY',
364
- 'X-XSS-Protection': '1; mode=block',
365
- 'Referrer-Policy': 'strict-origin-when-cross-origin',
366
- 'Permissions-Policy': 'camera=(), microphone=(), geolocation=()'
367
- };
368
- },
369
-
370
- /**
371
- * CORS headers
372
- */
373
- cors(options: {
374
- origin?: string;
375
- methods?: string[];
376
- headers?: string[];
377
- credentials?: boolean;
378
- maxAge?: number;
379
- } = {}): Record<string, string> {
380
- const {
381
- origin = '*',
382
- methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
383
- headers: allowHeaders = ['Content-Type', 'Authorization'],
384
- credentials = false,
385
- maxAge = 86400
386
- } = options;
387
-
388
- const corsHeaders: Record<string, string> = {
389
- 'Access-Control-Allow-Origin': origin,
390
- 'Access-Control-Allow-Methods': methods.join(', '),
391
- 'Access-Control-Allow-Headers': allowHeaders.join(', '),
392
- 'Access-Control-Max-Age': String(maxAge)
393
- };
394
-
395
- if (credentials) {
396
- corsHeaders['Access-Control-Allow-Credentials'] = 'true';
397
- }
398
-
399
- return corsHeaders;
400
- },
401
-
402
- /**
403
- * Cache control headers
404
- */
405
- cache(options: {
406
- maxAge?: number;
407
- sMaxAge?: number;
408
- staleWhileRevalidate?: number;
409
- private?: boolean;
410
- noStore?: boolean;
411
- } = {}): Record<string, string> {
412
- if (options.noStore) {
413
- return { 'Cache-Control': 'no-store, no-cache, must-revalidate' };
414
- }
415
-
416
- const directives: string[] = [];
417
-
418
- if (options.private) {
419
- directives.push('private');
420
- } else {
421
- directives.push('public');
422
- }
423
-
424
- if (options.maxAge !== undefined) {
425
- directives.push(`max-age=${options.maxAge}`);
426
- }
427
-
428
- if (options.sMaxAge !== undefined) {
429
- directives.push(`s-maxage=${options.sMaxAge}`);
430
- }
431
-
432
- if (options.staleWhileRevalidate !== undefined) {
433
- directives.push(`stale-while-revalidate=${options.staleWhileRevalidate}`);
434
- }
435
-
436
- return { 'Cache-Control': directives.join(', ') };
437
- }
438
- };
439
-
440
- // ============================================================================
441
- // Request Helpers
442
- // ============================================================================
443
-
444
- /**
445
- * Parse JSON body from request
446
- */
447
- export async function parseJson<T = unknown>(request: Request): Promise<T> {
448
- try {
449
- return await request.json();
450
- } catch {
451
- throw new Error('Invalid JSON body');
452
- }
453
- }
454
-
455
- /**
456
- * Parse form data from request
457
- */
458
- export async function parseFormData(request: Request): Promise<FormData> {
459
- return await request.formData();
460
- }
461
-
462
- /**
463
- * Parse URL search params
464
- */
465
- export function parseSearchParams(request: Request): URLSearchParams {
466
- const url = new URL(request.url);
467
- return url.searchParams;
468
- }
469
-
470
- /**
471
- * Get request method
472
- */
473
- export function getMethod(request: Request): string {
474
- return request.method.toUpperCase();
475
- }
476
-
477
- /**
478
- * Get request pathname
479
- */
480
- export function getPathname(request: Request): string {
481
- const url = new URL(request.url);
482
- return url.pathname;
483
- }
484
-
485
- /**
486
- * Check if request method matches
487
- */
488
- export function isMethod(request: Request, method: string | string[]): boolean {
489
- const reqMethod = getMethod(request);
490
- if (Array.isArray(method)) {
491
- return method.map(m => m.toUpperCase()).includes(reqMethod);
492
- }
493
- return reqMethod === method.toUpperCase();
494
- }