@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,373 +0,0 @@
1
- /**
2
- * FlexiReact Plugin System
3
- *
4
- * Plugins can extend FlexiReact's functionality by hooking into various lifecycle events.
5
- *
6
- * Usage:
7
- * Create a flexireact.plugin.js file:
8
- *
9
- * export default {
10
- * name: 'my-plugin',
11
- *
12
- * // Called when the server starts
13
- * onServerStart(server) {},
14
- *
15
- * // Called before each request
16
- * onRequest(req, res) {},
17
- *
18
- * // Called before rendering a page
19
- * onBeforeRender(page, props) {},
20
- *
21
- * // Called after rendering a page
22
- * onAfterRender(html, page) {},
23
- *
24
- * // Called during build
25
- * onBuild(config) {},
26
- *
27
- * // Modify esbuild config
28
- * esbuildConfig(config) {},
29
- * };
30
- */
31
-
32
- import fs from 'fs';
33
- import path from 'path';
34
- import { pathToFileURL } from 'url';
35
-
36
- /**
37
- * Plugin lifecycle hooks
38
- */
39
- export const PluginHooks = {
40
- // Server lifecycle
41
- SERVER_START: 'onServerStart',
42
- SERVER_STOP: 'onServerStop',
43
-
44
- // Request lifecycle
45
- REQUEST: 'onRequest',
46
- RESPONSE: 'onResponse',
47
-
48
- // Render lifecycle
49
- BEFORE_RENDER: 'onBeforeRender',
50
- AFTER_RENDER: 'onAfterRender',
51
-
52
- // Build lifecycle
53
- BUILD_START: 'onBuildStart',
54
- BUILD_END: 'onBuildEnd',
55
-
56
- // Route lifecycle
57
- ROUTES_LOADED: 'onRoutesLoaded',
58
-
59
- // Config
60
- CONFIG: 'onConfig',
61
- ESBUILD_CONFIG: 'esbuildConfig'
62
- };
63
-
64
- /**
65
- * Plugin manager class
66
- */
67
- export class PluginManager {
68
- plugins: any[];
69
- hooks: Map<string, any[]>;
70
-
71
- constructor() {
72
- this.plugins = [];
73
- this.hooks = new Map();
74
-
75
- // Initialize hook arrays
76
- for (const hook of Object.values(PluginHooks)) {
77
- this.hooks.set(hook as string, []);
78
- }
79
- }
80
-
81
- /**
82
- * Registers a plugin
83
- */
84
- register(plugin) {
85
- if (!plugin.name) {
86
- throw new Error('Plugin must have a name');
87
- }
88
-
89
- // Check for duplicate
90
- if (this.plugins.find(p => p.name === plugin.name)) {
91
- console.warn(`Plugin "${plugin.name}" is already registered`);
92
- return;
93
- }
94
-
95
- this.plugins.push(plugin);
96
-
97
- // Register hooks
98
- for (const [hookName, handlers] of this.hooks) {
99
- if (typeof plugin[hookName] === 'function') {
100
- handlers.push({
101
- plugin: plugin.name,
102
- handler: plugin[hookName].bind(plugin)
103
- });
104
- }
105
- }
106
-
107
- console.log(` ✓ Plugin loaded: ${plugin.name}`);
108
- }
109
-
110
- /**
111
- * Unregisters a plugin
112
- */
113
- unregister(pluginName) {
114
- const index = this.plugins.findIndex(p => p.name === pluginName);
115
- if (index === -1) return;
116
-
117
- this.plugins.splice(index, 1);
118
-
119
- // Remove hooks
120
- for (const handlers of this.hooks.values()) {
121
- const hookIndex = handlers.findIndex(h => h.plugin === pluginName);
122
- if (hookIndex !== -1) {
123
- handlers.splice(hookIndex, 1);
124
- }
125
- }
126
- }
127
-
128
- /**
129
- * Runs a hook with all registered handlers
130
- */
131
- async runHook(hookName, ...args) {
132
- const handlers = this.hooks.get(hookName) || [];
133
- const results = [];
134
-
135
- for (const { plugin, handler } of handlers) {
136
- try {
137
- const result = await handler(...args);
138
- results.push({ plugin, result });
139
- } catch (error) {
140
- console.error(`Plugin "${plugin}" error in ${hookName}:`, error);
141
- results.push({ plugin, error });
142
- }
143
- }
144
-
145
- return results;
146
- }
147
-
148
- /**
149
- * Runs a hook that can modify a value (waterfall)
150
- */
151
- async runWaterfallHook(hookName, initialValue, ...args) {
152
- const handlers = this.hooks.get(hookName) || [];
153
- let value = initialValue;
154
-
155
- for (const { plugin, handler } of handlers) {
156
- try {
157
- const result = await handler(value, ...args);
158
- if (result !== undefined) {
159
- value = result;
160
- }
161
- } catch (error) {
162
- console.error(`Plugin "${plugin}" error in ${hookName}:`, error);
163
- }
164
- }
165
-
166
- return value;
167
- }
168
-
169
- /**
170
- * Checks if any plugin handles a hook
171
- */
172
- hasHook(hookName) {
173
- const handlers = this.hooks.get(hookName) || [];
174
- return handlers.length > 0;
175
- }
176
-
177
- /**
178
- * Gets all registered plugins
179
- */
180
- getPlugins() {
181
- return [...this.plugins];
182
- }
183
- }
184
-
185
- // Global plugin manager instance
186
- export const pluginManager = new PluginManager();
187
-
188
- /**
189
- * Loads plugins from project and config
190
- */
191
- export async function loadPlugins(projectRoot, config) {
192
- console.log('\n📦 Loading plugins...\n');
193
-
194
- // Load from flexireact.plugin.js
195
- const pluginPath = path.join(projectRoot, 'flexireact.plugin.js');
196
-
197
- if (fs.existsSync(pluginPath)) {
198
- try {
199
- const url = pathToFileURL(pluginPath).href;
200
- const module = await import(`${url}?t=${Date.now()}`);
201
- const plugin = module.default;
202
-
203
- if (plugin) {
204
- pluginManager.register(plugin);
205
- }
206
- } catch (error) {
207
- console.error('Failed to load flexireact.plugin.js:', error);
208
- }
209
- }
210
-
211
- // Load plugins from config
212
- if (config.plugins && Array.isArray(config.plugins)) {
213
- for (const pluginConfig of config.plugins) {
214
- try {
215
- if (typeof pluginConfig === 'string') {
216
- // Load from node_modules
217
- const module = await import(pluginConfig);
218
- pluginManager.register(module.default);
219
- } else if (typeof pluginConfig === 'object') {
220
- // Inline plugin
221
- pluginManager.register(pluginConfig);
222
- } else if (typeof pluginConfig === 'function') {
223
- // Plugin factory
224
- pluginManager.register(pluginConfig());
225
- }
226
- } catch (error) {
227
- console.error(`Failed to load plugin:`, error);
228
- }
229
- }
230
- }
231
-
232
- console.log(`\n Total plugins: ${pluginManager.getPlugins().length}\n`);
233
-
234
- return pluginManager;
235
- }
236
-
237
- /**
238
- * Creates a plugin
239
- */
240
- export function definePlugin(options) {
241
- return {
242
- name: options.name || 'unnamed-plugin',
243
- ...options
244
- };
245
- }
246
-
247
- /**
248
- * Built-in plugins
249
- */
250
- export const builtinPlugins = {
251
- /**
252
- * Analytics plugin
253
- */
254
- analytics(options: { trackingId?: string } = {}) {
255
- const { trackingId } = options;
256
-
257
- return definePlugin({
258
- name: 'flexi-analytics',
259
-
260
- onAfterRender(html) {
261
- if (!trackingId) return html;
262
-
263
- const script = `
264
- <script async src="https://www.googletagmanager.com/gtag/js?id=${trackingId}"></script>
265
- <script>
266
- window.dataLayer = window.dataLayer || [];
267
- function gtag(){dataLayer.push(arguments);}
268
- gtag('js', new Date());
269
- gtag('config', '${trackingId}');
270
- </script>
271
- `;
272
-
273
- return html.replace('</head>', `${script}</head>`);
274
- }
275
- });
276
- },
277
-
278
- /**
279
- * PWA plugin
280
- */
281
- pwa(options: { manifest?: string; serviceWorker?: string } = {}) {
282
- const { manifest = '/manifest.json', serviceWorker = '/sw.js' } = options;
283
-
284
- return definePlugin({
285
- name: 'flexi-pwa',
286
-
287
- onAfterRender(html) {
288
- const tags = `
289
- <link rel="manifest" href="${manifest}">
290
- <script>
291
- if ('serviceWorker' in navigator) {
292
- navigator.serviceWorker.register('${serviceWorker}');
293
- }
294
- </script>
295
- `;
296
-
297
- return html.replace('</head>', `${tags}</head>`);
298
- }
299
- });
300
- },
301
-
302
- /**
303
- * SEO plugin
304
- */
305
- seo(options: { defaultTitle?: string; titleTemplate?: string; defaultDescription?: string } = {}) {
306
- const { defaultTitle, titleTemplate = '%s', defaultDescription } = options;
307
-
308
- return definePlugin({
309
- name: 'flexi-seo',
310
-
311
- onBeforeRender(page, props) {
312
- const title = props.title || page.title || defaultTitle;
313
- const description = props.description || page.description || defaultDescription;
314
-
315
- return {
316
- ...props,
317
- _seo: {
318
- title: titleTemplate.replace('%s', title),
319
- description
320
- }
321
- };
322
- }
323
- });
324
- },
325
-
326
- /**
327
- * Compression plugin (for production)
328
- */
329
- compression() {
330
- return definePlugin({
331
- name: 'flexi-compression',
332
-
333
- onResponse(req, res, html) {
334
- // Note: Actual compression would require zlib
335
- // This is a placeholder for the concept
336
- res.setHeader('Content-Encoding', 'identity');
337
- return html;
338
- }
339
- });
340
- },
341
-
342
- /**
343
- * Security headers plugin
344
- */
345
- securityHeaders(options: { headers?: Record<string, string> } = {}) {
346
- const headers: Record<string, string> = {
347
- 'X-Content-Type-Options': 'nosniff',
348
- 'X-Frame-Options': 'DENY',
349
- 'X-XSS-Protection': '1; mode=block',
350
- 'Referrer-Policy': 'strict-origin-when-cross-origin',
351
- ...options.headers
352
- };
353
-
354
- return definePlugin({
355
- name: 'flexi-security',
356
-
357
- onRequest(req, res) {
358
- for (const [key, value] of Object.entries(headers)) {
359
- res.setHeader(key, value);
360
- }
361
- }
362
- });
363
- }
364
- };
365
-
366
- export default {
367
- PluginManager,
368
- PluginHooks,
369
- pluginManager,
370
- loadPlugins,
371
- definePlugin,
372
- builtinPlugins
373
- };