@flexireact/core 3.0.1 → 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 (55) hide show
  1. package/dist/cli/index.js +1514 -0
  2. package/dist/cli/index.js.map +1 -0
  3. package/dist/core/client/index.js +373 -0
  4. package/dist/core/client/index.js.map +1 -0
  5. package/dist/core/index.js +6415 -0
  6. package/dist/core/index.js.map +1 -0
  7. package/dist/core/server/index.js +3094 -0
  8. package/dist/core/server/index.js.map +1 -0
  9. package/package.json +80 -80
  10. package/bin/flexireact.js +0 -23
  11. package/cli/generators.ts +0 -616
  12. package/cli/index.ts +0 -1182
  13. package/core/actions/index.ts +0 -364
  14. package/core/api.ts +0 -143
  15. package/core/build/index.ts +0 -425
  16. package/core/cli/logger.ts +0 -353
  17. package/core/client/Link.tsx +0 -345
  18. package/core/client/hydration.ts +0 -147
  19. package/core/client/index.ts +0 -12
  20. package/core/client/islands.ts +0 -143
  21. package/core/client/navigation.ts +0 -212
  22. package/core/client/runtime.ts +0 -52
  23. package/core/config.ts +0 -116
  24. package/core/context.ts +0 -83
  25. package/core/dev.ts +0 -47
  26. package/core/devtools/index.ts +0 -644
  27. package/core/edge/cache.ts +0 -344
  28. package/core/edge/fetch-polyfill.ts +0 -247
  29. package/core/edge/handler.ts +0 -248
  30. package/core/edge/index.ts +0 -81
  31. package/core/edge/ppr.ts +0 -264
  32. package/core/edge/runtime.ts +0 -161
  33. package/core/font/index.ts +0 -306
  34. package/core/helpers.ts +0 -494
  35. package/core/image/index.ts +0 -413
  36. package/core/index.ts +0 -218
  37. package/core/islands/index.ts +0 -293
  38. package/core/loader.ts +0 -111
  39. package/core/logger.ts +0 -242
  40. package/core/metadata/index.ts +0 -622
  41. package/core/middleware/index.ts +0 -416
  42. package/core/plugins/index.ts +0 -373
  43. package/core/render/index.ts +0 -1243
  44. package/core/render.ts +0 -136
  45. package/core/router/index.ts +0 -551
  46. package/core/router.ts +0 -141
  47. package/core/rsc/index.ts +0 -199
  48. package/core/server/index.ts +0 -779
  49. package/core/server.ts +0 -203
  50. package/core/ssg/index.ts +0 -346
  51. package/core/start-dev.ts +0 -6
  52. package/core/start-prod.ts +0 -6
  53. package/core/tsconfig.json +0 -30
  54. package/core/types.ts +0 -239
  55. 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
- }