create-fluxstack 1.4.0 → 1.4.1

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.
@@ -3,6 +3,7 @@ import { ControllerGenerator } from "./controller.js"
3
3
  import { RouteGenerator } from "./route.js"
4
4
  import { ComponentGenerator } from "./component.js"
5
5
  import { ServiceGenerator } from "./service.js"
6
+ import { PluginGenerator } from "./plugin.js"
6
7
  import type { GeneratorContext, GeneratorOptions } from "./types.js"
7
8
 
8
9
  export interface Generator {
@@ -23,6 +24,7 @@ export class GeneratorRegistry {
23
24
  this.register(new RouteGenerator())
24
25
  this.register(new ComponentGenerator())
25
26
  this.register(new ServiceGenerator())
27
+ this.register(new PluginGenerator())
26
28
  }
27
29
 
28
30
  register(generator: Generator): void {
@@ -58,7 +60,8 @@ export const generateCommand: CliCommand = {
58
60
  'flux generate controller user',
59
61
  'flux generate component UserCard',
60
62
  'flux generate service auth',
61
- 'flux generate route api/users'
63
+ 'flux generate route api/users',
64
+ 'flux generate plugin my-plugin'
62
65
  ],
63
66
  arguments: [
64
67
  {
@@ -66,7 +69,7 @@ export const generateCommand: CliCommand = {
66
69
  description: 'Type of code to generate',
67
70
  required: true,
68
71
  type: 'string',
69
- choices: ['controller', 'route', 'component', 'service']
72
+ choices: ['controller', 'route', 'component', 'service', 'plugin']
70
73
  },
71
74
  {
72
75
  name: 'name',
@@ -0,0 +1,290 @@
1
+ import type { Generator } from "./index.js"
2
+ import type { GeneratorContext, GeneratorOptions, Template } from "./types.js"
3
+ import { templateEngine } from "./template-engine.js"
4
+ import { join } from "path"
5
+
6
+ export class PluginGenerator implements Generator {
7
+ name = 'plugin'
8
+ description = 'Generate a new FluxStack plugin'
9
+
10
+ async generate(context: GeneratorContext, options: GeneratorOptions): Promise<void> {
11
+ const template = this.getTemplate(options.template)
12
+
13
+ if (template.hooks?.beforeGenerate) {
14
+ await template.hooks.beforeGenerate(context, options)
15
+ }
16
+
17
+ const files = await templateEngine.processTemplate(template, context, options)
18
+
19
+ if (options.dryRun) {
20
+ console.log(`\nšŸ“‹ Would generate plugin '${options.name}':\n`)
21
+ for (const file of files) {
22
+ console.log(`${file.action === 'create' ? 'šŸ“„' : 'āœļø'} ${file.path}`)
23
+ }
24
+ return
25
+ }
26
+
27
+ await templateEngine.generateFiles(files, options.dryRun)
28
+
29
+ if (template.hooks?.afterGenerate) {
30
+ const filePaths = files.map(f => f.path)
31
+ await template.hooks.afterGenerate(context, options, filePaths)
32
+ }
33
+
34
+ console.log(`\nāœ… Generated plugin '${options.name}' with ${files.length} files`)
35
+ console.log(`\nšŸ“¦ Next steps:`)
36
+ console.log(` 1. Edit plugins/${options.name}/plugin.json with your plugin metadata`)
37
+ console.log(` 2. Implement your plugin logic in plugins/${options.name}/index.ts`)
38
+ console.log(` 3. Add server-side code in plugins/${options.name}/server/ (optional)`)
39
+ console.log(` 4. Add client-side code in plugins/${options.name}/client/ (optional)`)
40
+ console.log(` 5. Run: bun run cli plugin:deps install`)
41
+ }
42
+
43
+ private getTemplate(templateName?: string): Template {
44
+ switch (templateName) {
45
+ case 'full':
46
+ return this.getFullTemplate()
47
+ case 'server':
48
+ return this.getServerOnlyTemplate()
49
+ case 'client':
50
+ return this.getClientOnlyTemplate()
51
+ default:
52
+ return this.getBasicTemplate()
53
+ }
54
+ }
55
+
56
+ private getBasicTemplate(): Template {
57
+ return {
58
+ name: 'basic-plugin',
59
+ description: 'Basic plugin template with essential files',
60
+ files: [
61
+ {
62
+ path: 'plugins/{{name}}/plugin.json',
63
+ content: `{
64
+ "name": "{{name}}",
65
+ "version": "1.0.0",
66
+ "description": "{{description}}",
67
+ "author": "Your Name",
68
+ "type": "fluxstack-plugin",
69
+ "main": "index.ts",
70
+ "dependencies": {},
71
+ "fluxstack": {
72
+ "minVersion": "1.4.0"
73
+ },
74
+ "hooks": {
75
+ "setup": true,
76
+ "onServerStart": false,
77
+ "onRequest": false,
78
+ "onResponse": false,
79
+ "onError": false
80
+ }
81
+ }
82
+ `
83
+ },
84
+ {
85
+ path: 'plugins/{{name}}/index.ts',
86
+ content: `import type { FluxStackPlugin, PluginContext } from '@/core/types/plugin'
87
+
88
+ /**
89
+ * {{pascalName}} Plugin
90
+ * {{description}}
91
+ */
92
+ export class {{pascalName}}Plugin implements FluxStackPlugin {
93
+ name = '{{name}}'
94
+ version = '1.0.0'
95
+
96
+ /**
97
+ * Setup hook - called when plugin is loaded
98
+ */
99
+ async setup(context: PluginContext): Promise<void> {
100
+ console.log(\`[{{name}}] Plugin initialized\`)
101
+
102
+ // Add your initialization logic here
103
+ // Example: Register middleware, setup database connections, etc.
104
+ }
105
+
106
+ /**
107
+ * Server start hook - called when server starts
108
+ */
109
+ async onServerStart?(context: PluginContext): Promise<void> {
110
+ console.log(\`[{{name}}] Server started\`)
111
+
112
+ // Add logic to run when server starts
113
+ }
114
+
115
+ /**
116
+ * Request hook - called on each request
117
+ */
118
+ async onRequest?(context: PluginContext, request: Request): Promise<void> {
119
+ // Add request processing logic
120
+ }
121
+
122
+ /**
123
+ * Response hook - called on each response
124
+ */
125
+ async onResponse?(context: PluginContext, response: Response): Promise<void> {
126
+ // Add response processing logic
127
+ }
128
+
129
+ /**
130
+ * Error hook - called when errors occur
131
+ */
132
+ async onError?(context: PluginContext, error: Error): Promise<void> {
133
+ console.error(\`[{{name}}] Error:\`, error)
134
+
135
+ // Add error handling logic
136
+ }
137
+ }
138
+
139
+ // Export plugin instance
140
+ export default new {{pascalName}}Plugin()
141
+ `
142
+ },
143
+ {
144
+ path: 'plugins/{{name}}/README.md',
145
+ content: `# {{pascalName}} Plugin
146
+
147
+ {{description}}
148
+
149
+ ## Installation
150
+
151
+ This plugin is already in your FluxStack project. To use it:
152
+
153
+ 1. Make sure the plugin is enabled in your configuration
154
+ 2. Install any additional dependencies (if needed):
155
+ \`\`\`bash
156
+ bun run cli plugin:deps install
157
+ \`\`\`
158
+
159
+ ## Usage
160
+
161
+ \`\`\`typescript
162
+ // The plugin is automatically loaded by FluxStack
163
+ // Configure it in your app/server/index.ts if needed
164
+ \`\`\`
165
+
166
+ ## Configuration
167
+
168
+ Add configuration options here.
169
+
170
+ ## API
171
+
172
+ Document your plugin's API here.
173
+
174
+ ## Hooks
175
+
176
+ This plugin uses the following hooks:
177
+ - \`setup\`: Initialize plugin resources
178
+ - \`onServerStart\`: Run when server starts (optional)
179
+ - \`onRequest\`: Process incoming requests (optional)
180
+ - \`onResponse\`: Process outgoing responses (optional)
181
+ - \`onError\`: Handle errors (optional)
182
+
183
+ ## Development
184
+
185
+ To modify this plugin:
186
+
187
+ 1. Edit \`index.ts\` with your logic
188
+ 2. Update \`plugin.json\` with metadata
189
+ 3. Test with: \`bun run dev\`
190
+
191
+ ## License
192
+
193
+ MIT
194
+ `
195
+ }
196
+ ]
197
+ }
198
+ }
199
+
200
+ private getServerOnlyTemplate(): Template {
201
+ const basic = this.getBasicTemplate()
202
+ return {
203
+ ...basic,
204
+ name: 'server-plugin',
205
+ description: 'Plugin with server-side code',
206
+ files: [
207
+ ...basic.files,
208
+ {
209
+ path: 'plugins/{{name}}/server/index.ts',
210
+ content: `/**
211
+ * Server-side logic for {{pascalName}} plugin
212
+ */
213
+
214
+ export class {{pascalName}}Service {
215
+ async initialize() {
216
+ console.log(\`[{{name}}] Server service initialized\`)
217
+ }
218
+
219
+ // Add your server-side methods here
220
+ }
221
+
222
+ export const {{camelName}}Service = new {{pascalName}}Service()
223
+ `
224
+ }
225
+ ]
226
+ }
227
+ }
228
+
229
+ private getClientOnlyTemplate(): Template {
230
+ const basic = this.getBasicTemplate()
231
+ return {
232
+ ...basic,
233
+ name: 'client-plugin',
234
+ description: 'Plugin with client-side code',
235
+ files: [
236
+ ...basic.files,
237
+ {
238
+ path: 'plugins/{{name}}/client/index.ts',
239
+ content: `/**
240
+ * Client-side logic for {{pascalName}} plugin
241
+ */
242
+
243
+ export class {{pascalName}}Client {
244
+ initialize() {
245
+ console.log(\`[{{name}}] Client initialized\`)
246
+ }
247
+
248
+ // Add your client-side methods here
249
+ }
250
+
251
+ export const {{camelName}}Client = new {{pascalName}}Client()
252
+ `
253
+ }
254
+ ]
255
+ }
256
+ }
257
+
258
+ private getFullTemplate(): Template {
259
+ const basic = this.getBasicTemplate()
260
+ const server = this.getServerOnlyTemplate()
261
+ const client = this.getClientOnlyTemplate()
262
+
263
+ return {
264
+ ...basic,
265
+ name: 'full-plugin',
266
+ description: 'Complete plugin with server and client code',
267
+ files: [
268
+ ...basic.files,
269
+ ...server.files.slice(basic.files.length), // Add server files
270
+ ...client.files.slice(basic.files.length), // Add client files
271
+ {
272
+ path: 'plugins/{{name}}/types.ts',
273
+ content: `/**
274
+ * Type definitions for {{pascalName}} plugin
275
+ */
276
+
277
+ export interface {{pascalName}}Config {
278
+ // Add your configuration types here
279
+ enabled: boolean
280
+ }
281
+
282
+ export interface {{pascalName}}Options {
283
+ // Add your options types here
284
+ }
285
+ `
286
+ }
287
+ ]
288
+ }
289
+ }
290
+ }
package/core/cli/index.ts CHANGED
@@ -224,7 +224,7 @@ Examples:
224
224
  }
225
225
  })
226
226
 
227
- // Create command
227
+ // Create command
228
228
  cliRegistry.register({
229
229
  name: 'create',
230
230
  description: 'Create a new FluxStack project',
@@ -252,7 +252,7 @@ Examples:
252
252
  ],
253
253
  handler: async (args, options, context) => {
254
254
  const [projectName, template] = args
255
-
255
+
256
256
  if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) {
257
257
  console.error("āŒ Project name can only contain letters, numbers, hyphens, and underscores")
258
258
  return
@@ -263,7 +263,7 @@ Examples:
263
263
  name: projectName,
264
264
  template: template as 'basic' | 'full' || 'basic'
265
265
  })
266
-
266
+
267
267
  await creator.create()
268
268
  } catch (error) {
269
269
  console.error("āŒ Failed to create project:", error instanceof Error ? error.message : String(error))
@@ -271,6 +271,91 @@ Examples:
271
271
  }
272
272
  }
273
273
  })
274
+
275
+ // Make:plugin command (shortcut for generate plugin)
276
+ cliRegistry.register({
277
+ name: 'make:plugin',
278
+ description: 'Create a new FluxStack plugin',
279
+ category: 'Plugins',
280
+ usage: 'flux make:plugin <name> [options]',
281
+ aliases: ['create:plugin'],
282
+ examples: [
283
+ 'flux make:plugin my-plugin # Create basic plugin',
284
+ 'flux make:plugin my-plugin --template full # Create full plugin with server/client',
285
+ 'flux make:plugin auth --template server # Create server-only plugin'
286
+ ],
287
+ arguments: [
288
+ {
289
+ name: 'name',
290
+ description: 'Name of the plugin to create',
291
+ required: true,
292
+ type: 'string'
293
+ }
294
+ ],
295
+ options: [
296
+ {
297
+ name: 'template',
298
+ short: 't',
299
+ description: 'Plugin template to use',
300
+ type: 'string',
301
+ choices: ['basic', 'full', 'server', 'client'],
302
+ default: 'basic'
303
+ },
304
+ {
305
+ name: 'description',
306
+ short: 'd',
307
+ description: 'Plugin description',
308
+ type: 'string',
309
+ default: 'A FluxStack plugin'
310
+ },
311
+ {
312
+ name: 'force',
313
+ short: 'f',
314
+ description: 'Overwrite existing plugin',
315
+ type: 'boolean',
316
+ default: false
317
+ }
318
+ ],
319
+ handler: async (args, options, context) => {
320
+ const [name] = args
321
+
322
+ if (!/^[a-zA-Z0-9-_]+$/.test(name)) {
323
+ console.error("āŒ Plugin name can only contain letters, numbers, hyphens, and underscores")
324
+ return
325
+ }
326
+
327
+ // Use the plugin generator
328
+ const { generatorRegistry } = await import('./generators/index.js')
329
+ const pluginGenerator = generatorRegistry.get('plugin')
330
+
331
+ if (!pluginGenerator) {
332
+ console.error("āŒ Plugin generator not found")
333
+ return
334
+ }
335
+
336
+ const generatorContext = {
337
+ workingDir: context.workingDir,
338
+ config: context.config,
339
+ logger: context.logger,
340
+ utils: context.utils
341
+ }
342
+
343
+ const generatorOptions = {
344
+ name,
345
+ template: options.template,
346
+ force: options.force,
347
+ dryRun: false,
348
+ description: options.description
349
+ }
350
+
351
+ try {
352
+ await pluginGenerator.generate(generatorContext, generatorOptions)
353
+ } catch (error) {
354
+ console.error("āŒ Failed to create plugin:", error instanceof Error ? error.message : String(error))
355
+ throw error
356
+ }
357
+ }
358
+ })
274
359
  }
275
360
 
276
361
  // Main CLI logic
@@ -2,4 +2,4 @@
2
2
  * FluxStack Framework Version
3
3
  * Single source of truth for version number
4
4
  */
5
- export const FLUXSTACK_VERSION = '1.4.0'
5
+ export const FLUXSTACK_VERSION = '1.4.1'
@@ -5,16 +5,17 @@ import { resolve, join } from 'path'
5
5
  import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs'
6
6
  import chalk from 'chalk'
7
7
  import ora from 'ora'
8
+ import { FLUXSTACK_VERSION } from './core/utils/version'
8
9
 
9
10
  const logo = `
10
- ⚔ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
11
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
12
- ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆ
13
- ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
14
- ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
11
+ ⚔ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
12
+ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
13
+ ā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆ
14
+ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
15
+ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆ ā–ˆā–ˆ ā–ˆā–ˆ
15
16
 
16
17
  ${chalk.cyan('šŸ’« Powered by Bun - The Divine Runtime ⚔')}
17
- ${chalk.gray('Creates FluxStack apps by copying the working framework')}
18
+ ${chalk.gray(`FluxStack v${FLUXSTACK_VERSION} - Creates full-stack TypeScript apps`)}
18
19
  `
19
20
 
20
21
  program
@@ -58,6 +59,7 @@ program
58
59
  'core',
59
60
  'app',
60
61
  'config', // āœ… CRITICAL: Copy config folder with declarative configs
62
+ // 'plugins', // TODO: Copy when crypto-auth plugin is complete
61
63
  'ai-context', // āœ… CRITICAL: Copy AI documentation for users
62
64
  'bun.lock', // āœ… CRITICAL: Copy lockfile to maintain working versions
63
65
  'package.json', // āœ… Copy real package.json from framework
@@ -67,15 +69,122 @@ program
67
69
  'CLAUDE.md', // āœ… Project instructions for AI assistants
68
70
  'README.md'
69
71
  ]
70
-
72
+
71
73
  for (const file of filesToCopy) {
72
74
  const sourcePath = join(frameworkDir, file)
73
75
  const destPath = join(projectPath, file)
74
-
76
+
75
77
  if (existsSync(sourcePath)) {
76
78
  cpSync(sourcePath, destPath, { recursive: true })
77
79
  }
78
80
  }
81
+
82
+ // Create empty plugins directory for user plugins
83
+ const pluginsDir = join(projectPath, 'plugins')
84
+ mkdirSync(pluginsDir, { recursive: true })
85
+
86
+ // Create a README in plugins folder
87
+ const pluginsReadme = `# Plugins
88
+
89
+ This folder is for your custom FluxStack plugins.
90
+
91
+ ## šŸ“– Documentation
92
+
93
+ For complete plugin development guide, see:
94
+ - \`ai-context/development/plugins-guide.md\` - Full plugin documentation
95
+ - \`ai-context/examples/\` - Plugin examples
96
+
97
+ ## šŸ“¦ Available CLI Commands
98
+
99
+ \`\`\`bash
100
+ # Create a new plugin
101
+ bun run cli make:plugin my-plugin # Basic plugin
102
+ bun run cli make:plugin my-plugin --template full # Full plugin (server + client)
103
+ bun run cli make:plugin my-plugin --template server # Server-only plugin
104
+
105
+ # Manage plugin dependencies
106
+ bun run cli plugin:deps install # Install plugin dependencies
107
+ bun run cli plugin:deps list # List plugin dependencies
108
+ bun run cli plugin:deps check # Check for conflicts
109
+ bun run cli plugin:deps clean # Clean unused dependencies
110
+ \`\`\`
111
+
112
+ ## šŸ”Œ Plugin Structure
113
+
114
+ \`\`\`
115
+ plugins/
116
+ ā”œā”€ā”€ my-plugin/
117
+ │ ā”œā”€ā”€ plugin.json # Plugin metadata (name, version, dependencies)
118
+ │ ā”œā”€ā”€ index.ts # Plugin entry point (server-side hooks)
119
+ │ ā”œā”€ā”€ server/ # Server-side code (optional)
120
+ │ └── client/ # Client-side code (optional)
121
+ \`\`\`
122
+
123
+ ## ⚔ Quick Start
124
+
125
+ 1. Create your plugin folder: \`plugins/my-plugin/\`
126
+ 2. Create \`plugin.json\` with metadata
127
+ 3. Create \`index.ts\` with your plugin logic
128
+ 4. Use \`bun run cli plugin:deps install\` if you need extra dependencies
129
+
130
+ ## šŸ”Œ Intercepting Requests
131
+
132
+ Plugins can intercept and modify requests using hooks:
133
+
134
+ \`\`\`typescript
135
+ // plugins/my-plugin/index.ts
136
+ import type { FluxStackPlugin, PluginContext } from '@/core/types/plugin'
137
+
138
+ export class MyPlugin implements FluxStackPlugin {
139
+ name = 'my-plugin'
140
+ version = '1.0.0'
141
+
142
+ // Intercept every request
143
+ async onRequest(context: PluginContext, request: Request): Promise<void> {
144
+ // Example: Add custom headers
145
+ const url = new URL(request.url)
146
+ console.log(\`[\${this.name}] Request to: \${url.pathname}\`)
147
+
148
+ // Example: Validate authentication
149
+ const token = request.headers.get('Authorization')
150
+ if (!token && url.pathname.startsWith('/api/protected')) {
151
+ throw new Error('Unauthorized')
152
+ }
153
+ }
154
+
155
+ // Intercept every response
156
+ async onResponse(context: PluginContext, response: Response): Promise<void> {
157
+ console.log(\`[\${this.name}] Response status: \${response.status}\`)
158
+ }
159
+
160
+ // Handle errors
161
+ async onError(context: PluginContext, error: Error): Promise<void> {
162
+ console.error(\`[\${this.name}] Error:\`, error.message)
163
+ // Example: Send to error tracking service
164
+ }
165
+ }
166
+ \`\`\`
167
+
168
+ ## šŸ“‹ Available Hooks
169
+
170
+ - **\`setup\`**: Initialize plugin resources (called once at startup)
171
+ - **\`onServerStart\`**: Run when server starts
172
+ - **\`onRequest\`**: Intercept incoming requests (before route handlers)
173
+ - **\`onResponse\`**: Intercept outgoing responses (after route handlers)
174
+ - **\`onError\`**: Handle errors globally
175
+
176
+ ## šŸ’” Common Use Cases
177
+
178
+ - **Authentication**: Validate tokens in \`onRequest\`
179
+ - **Logging**: Log requests/responses for analytics
180
+ - **Rate Limiting**: Track request counts per IP
181
+ - **CORS**: Add headers in \`onResponse\`
182
+ - **Request Transformation**: Modify request body/headers
183
+ - **Response Transformation**: Add custom headers, compress responses
184
+
185
+ See the documentation for detailed examples and best practices.
186
+ `
187
+ writeFileSync(join(pluginsDir, 'README.md'), pluginsReadme)
79
188
 
80
189
  // Generate .gitignore using template (instead of copying)
81
190
  const gitignoreContent = `# Dependencies
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fluxstack",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "⚔ Revolutionary full-stack TypeScript framework with Declarative Config System, Elysia + React + Bun",
5
5
  "keywords": [
6
6
  "framework",