create-fluxstack 1.4.0 ā 1.5.0
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.
- package/.env.example +8 -1
- package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +475 -0
- package/CRYPTO-AUTH-MIDDLEWARES.md +473 -0
- package/CRYPTO-AUTH-USAGE.md +491 -0
- package/EXEMPLO-ROTA-PROTEGIDA.md +347 -0
- package/QUICK-START-CRYPTO-AUTH.md +221 -0
- package/app/client/src/App.tsx +4 -1
- package/app/client/src/pages/CryptoAuthPage.tsx +394 -0
- package/app/server/index.ts +4 -0
- package/app/server/routes/crypto-auth-demo.routes.ts +167 -0
- package/app/server/routes/example-with-crypto-auth.routes.ts +235 -0
- package/app/server/routes/exemplo-posts.routes.ts +161 -0
- package/app/server/routes/index.ts +5 -1
- package/config/index.ts +9 -1
- package/core/cli/generators/index.ts +5 -2
- package/core/cli/generators/plugin.ts +580 -0
- package/core/cli/generators/template-engine.ts +5 -0
- package/core/cli/index.ts +88 -3
- package/core/cli/plugin-discovery.ts +33 -12
- package/core/framework/server.ts +10 -0
- package/core/plugins/dependency-manager.ts +89 -22
- package/core/plugins/index.ts +4 -0
- package/core/plugins/manager.ts +3 -2
- package/core/plugins/module-resolver.ts +216 -0
- package/core/plugins/registry.ts +28 -1
- package/core/utils/logger/index.ts +4 -0
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +117 -8
- package/fluxstack.config.ts +253 -114
- package/package.json +117 -117
- package/plugins/crypto-auth/README.md +722 -172
- package/plugins/crypto-auth/ai-context.md +1282 -0
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +383 -0
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +136 -159
- package/plugins/crypto-auth/client/components/AuthProvider.tsx +35 -94
- package/plugins/crypto-auth/client/components/LoginButton.tsx +36 -53
- package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +17 -37
- package/plugins/crypto-auth/client/components/index.ts +1 -4
- package/plugins/crypto-auth/client/index.ts +1 -1
- package/plugins/crypto-auth/config/index.ts +34 -0
- package/plugins/crypto-auth/index.ts +84 -152
- package/plugins/crypto-auth/package.json +65 -64
- package/plugins/crypto-auth/server/AuthMiddleware.ts +19 -75
- package/plugins/crypto-auth/server/CryptoAuthService.ts +60 -167
- package/plugins/crypto-auth/server/index.ts +15 -2
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +65 -0
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +26 -0
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +76 -0
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +45 -0
- package/plugins/crypto-auth/server/middlewares/helpers.ts +140 -0
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -0
- package/plugins/crypto-auth/server/middlewares.ts +19 -0
- package/test-crypto-auth.ts +101 -0
- package/plugins/crypto-auth/client/components/SessionInfo.tsx +0 -242
- package/plugins/crypto-auth/plugin.json +0 -29
|
@@ -0,0 +1,580 @@
|
|
|
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. Configure plugin in plugins/${options.name}/config/index.ts`)
|
|
37
|
+
console.log(` 2. Set environment variables (optional): ${options.name.toUpperCase().replace(/-/g, '_')}_*`)
|
|
38
|
+
console.log(` 3. Implement your plugin logic in plugins/${options.name}/index.ts`)
|
|
39
|
+
console.log(` 4. Add server-side code in plugins/${options.name}/server/ (optional)`)
|
|
40
|
+
console.log(` 5. Add client-side code in plugins/${options.name}/client/ (optional)`)
|
|
41
|
+
console.log(` 6. Run: bun run dev`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private getTemplate(templateName?: string): Template {
|
|
45
|
+
switch (templateName) {
|
|
46
|
+
case 'full':
|
|
47
|
+
return this.getFullTemplate()
|
|
48
|
+
case 'server':
|
|
49
|
+
return this.getServerOnlyTemplate()
|
|
50
|
+
case 'client':
|
|
51
|
+
return this.getClientOnlyTemplate()
|
|
52
|
+
default:
|
|
53
|
+
return this.getBasicTemplate()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private getBasicTemplate(): Template {
|
|
58
|
+
return {
|
|
59
|
+
name: 'basic-plugin',
|
|
60
|
+
description: 'Basic plugin template with essential files',
|
|
61
|
+
files: [
|
|
62
|
+
{
|
|
63
|
+
path: 'plugins/{{name}}/package.json',
|
|
64
|
+
content: `{
|
|
65
|
+
"name": "@fluxstack/{{name}}-plugin",
|
|
66
|
+
"version": "1.0.0",
|
|
67
|
+
"description": "{{description}}",
|
|
68
|
+
"main": "index.ts",
|
|
69
|
+
"types": "index.ts",
|
|
70
|
+
"exports": {
|
|
71
|
+
".": {
|
|
72
|
+
"import": "./index.ts",
|
|
73
|
+
"types": "./index.ts"
|
|
74
|
+
},
|
|
75
|
+
"./config": {
|
|
76
|
+
"import": "./config/index.ts",
|
|
77
|
+
"types": "./config/index.ts"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"keywords": [
|
|
81
|
+
"fluxstack",
|
|
82
|
+
"plugin",
|
|
83
|
+
"{{name}}",
|
|
84
|
+
"typescript"
|
|
85
|
+
],
|
|
86
|
+
"author": "FluxStack Developer",
|
|
87
|
+
"license": "MIT",
|
|
88
|
+
"peerDependencies": {},
|
|
89
|
+
"dependencies": {},
|
|
90
|
+
"devDependencies": {
|
|
91
|
+
"typescript": "^5.0.0"
|
|
92
|
+
},
|
|
93
|
+
"fluxstack": {
|
|
94
|
+
"plugin": true,
|
|
95
|
+
"version": "^1.0.0",
|
|
96
|
+
"hooks": [
|
|
97
|
+
"setup",
|
|
98
|
+
"onServerStart"
|
|
99
|
+
],
|
|
100
|
+
"category": "utility",
|
|
101
|
+
"tags": ["{{name}}"]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
`
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
path: 'plugins/{{name}}/config/index.ts',
|
|
108
|
+
content: `/**
|
|
109
|
+
* {{pascalName}} Plugin Configuration
|
|
110
|
+
* Declarative config using FluxStack config system
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
import { defineConfig, config } from '@/core/utils/config-schema'
|
|
114
|
+
|
|
115
|
+
const {{camelName}}ConfigSchema = {
|
|
116
|
+
// Enable/disable plugin
|
|
117
|
+
enabled: config.boolean('{{constantName}}_ENABLED', true),
|
|
118
|
+
|
|
119
|
+
// Add your configuration options here
|
|
120
|
+
// Example:
|
|
121
|
+
// apiKey: config.string('{{constantName}}_API_KEY', ''),
|
|
122
|
+
// timeout: config.number('{{constantName}}_TIMEOUT', 5000),
|
|
123
|
+
// debug: config.boolean('{{constantName}}_DEBUG', false),
|
|
124
|
+
} as const
|
|
125
|
+
|
|
126
|
+
export const {{camelName}}Config = defineConfig({{camelName}}ConfigSchema)
|
|
127
|
+
|
|
128
|
+
export type {{pascalName}}Config = typeof {{camelName}}Config
|
|
129
|
+
export default {{camelName}}Config
|
|
130
|
+
`
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
path: 'plugins/{{name}}/index.ts',
|
|
134
|
+
content: `import type { FluxStackPlugin, PluginContext } from '@/core/types/plugin'
|
|
135
|
+
// ā
Plugin imports its own configuration
|
|
136
|
+
import { {{camelName}}Config } from './config'
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* {{pascalName}} Plugin
|
|
140
|
+
* {{description}}
|
|
141
|
+
*/
|
|
142
|
+
export class {{pascalName}}Plugin implements FluxStackPlugin {
|
|
143
|
+
name = '{{name}}'
|
|
144
|
+
version = '1.0.0'
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Setup hook - called when plugin is loaded
|
|
148
|
+
*/
|
|
149
|
+
async setup(context: PluginContext): Promise<void> {
|
|
150
|
+
// Check if plugin is enabled
|
|
151
|
+
if (!{{camelName}}Config.enabled) {
|
|
152
|
+
context.logger.info(\`[{{name}}] Plugin disabled by configuration\`)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(\`[{{name}}] Plugin initialized\`)
|
|
157
|
+
|
|
158
|
+
// Add your initialization logic here
|
|
159
|
+
// Example: Register middleware, setup database connections, etc.
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Server start hook - called when server starts
|
|
164
|
+
*/
|
|
165
|
+
async onServerStart?(context: PluginContext): Promise<void> {
|
|
166
|
+
if (!{{camelName}}Config.enabled) return
|
|
167
|
+
|
|
168
|
+
console.log(\`[{{name}}] Server started\`)
|
|
169
|
+
|
|
170
|
+
// Add logic to run when server starts
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Request hook - called on each request
|
|
175
|
+
*/
|
|
176
|
+
async onRequest?(context: PluginContext, request: Request): Promise<void> {
|
|
177
|
+
if (!{{camelName}}Config.enabled) return
|
|
178
|
+
|
|
179
|
+
// Add request processing logic
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Response hook - called on each response
|
|
184
|
+
*/
|
|
185
|
+
async onResponse?(context: PluginContext, response: Response): Promise<void> {
|
|
186
|
+
if (!{{camelName}}Config.enabled) return
|
|
187
|
+
|
|
188
|
+
// Add response processing logic
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Error hook - called when errors occur
|
|
193
|
+
*/
|
|
194
|
+
async onError?(context: PluginContext, error: Error): Promise<void> {
|
|
195
|
+
console.error(\`[{{name}}] Error:\`, error)
|
|
196
|
+
|
|
197
|
+
// Add error handling logic
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Export plugin instance
|
|
202
|
+
export default new {{pascalName}}Plugin()
|
|
203
|
+
`
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
path: 'plugins/{{name}}/README.md',
|
|
207
|
+
content: `# {{pascalName}} Plugin
|
|
208
|
+
|
|
209
|
+
{{description}}
|
|
210
|
+
|
|
211
|
+
## Installation
|
|
212
|
+
|
|
213
|
+
This plugin is already in your FluxStack project. To use it:
|
|
214
|
+
|
|
215
|
+
1. Make sure the plugin is enabled in your configuration
|
|
216
|
+
2. Install any additional dependencies (if needed):
|
|
217
|
+
\`\`\`bash
|
|
218
|
+
bun run cli plugin:deps install
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
## Configuration
|
|
222
|
+
|
|
223
|
+
This plugin uses FluxStack's declarative configuration system. Configure it by editing \`config/index.ts\` or by setting environment variables:
|
|
224
|
+
|
|
225
|
+
\`\`\`bash
|
|
226
|
+
# Enable/disable plugin
|
|
227
|
+
{{constantName}}_ENABLED=true
|
|
228
|
+
|
|
229
|
+
# Add your environment variables here
|
|
230
|
+
# Example:
|
|
231
|
+
# {{constantName}}_API_KEY=your-api-key
|
|
232
|
+
# {{constantName}}_TIMEOUT=5000
|
|
233
|
+
\`\`\`
|
|
234
|
+
|
|
235
|
+
The plugin's configuration is located in \`plugins/{{name}}/config/index.ts\` and is self-contained, making the plugin fully portable.
|
|
236
|
+
|
|
237
|
+
## Usage
|
|
238
|
+
|
|
239
|
+
\`\`\`typescript
|
|
240
|
+
// The plugin is automatically loaded by FluxStack
|
|
241
|
+
// It imports its own configuration from ./config
|
|
242
|
+
\`\`\`
|
|
243
|
+
|
|
244
|
+
## API
|
|
245
|
+
|
|
246
|
+
Document your plugin's API here.
|
|
247
|
+
|
|
248
|
+
## Hooks
|
|
249
|
+
|
|
250
|
+
This plugin uses the following hooks:
|
|
251
|
+
- \`setup\`: Initialize plugin resources
|
|
252
|
+
- \`onServerStart\`: Run when server starts (optional)
|
|
253
|
+
- \`onRequest\`: Process incoming requests (optional)
|
|
254
|
+
- \`onResponse\`: Process outgoing responses (optional)
|
|
255
|
+
- \`onError\`: Handle errors (optional)
|
|
256
|
+
|
|
257
|
+
## Development
|
|
258
|
+
|
|
259
|
+
To modify this plugin:
|
|
260
|
+
|
|
261
|
+
1. Edit \`config/index.ts\` to add configuration options
|
|
262
|
+
2. Edit \`index.ts\` with your logic
|
|
263
|
+
3. Test with: \`bun run dev\`
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
MIT
|
|
268
|
+
`
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private getServerOnlyTemplate(): Template {
|
|
275
|
+
const basic = this.getBasicTemplate()
|
|
276
|
+
return {
|
|
277
|
+
...basic,
|
|
278
|
+
name: 'server-plugin',
|
|
279
|
+
description: 'Plugin with server-side code',
|
|
280
|
+
files: [
|
|
281
|
+
{
|
|
282
|
+
path: 'plugins/{{name}}/package.json',
|
|
283
|
+
content: `{
|
|
284
|
+
"name": "@fluxstack/{{name}}-plugin",
|
|
285
|
+
"version": "1.0.0",
|
|
286
|
+
"description": "{{description}}",
|
|
287
|
+
"main": "index.ts",
|
|
288
|
+
"types": "index.ts",
|
|
289
|
+
"exports": {
|
|
290
|
+
".": {
|
|
291
|
+
"import": "./index.ts",
|
|
292
|
+
"types": "./index.ts"
|
|
293
|
+
},
|
|
294
|
+
"./config": {
|
|
295
|
+
"import": "./config/index.ts",
|
|
296
|
+
"types": "./config/index.ts"
|
|
297
|
+
},
|
|
298
|
+
"./server": {
|
|
299
|
+
"import": "./server/index.ts",
|
|
300
|
+
"types": "./server/index.ts"
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"keywords": [
|
|
304
|
+
"fluxstack",
|
|
305
|
+
"plugin",
|
|
306
|
+
"{{name}}",
|
|
307
|
+
"server",
|
|
308
|
+
"typescript"
|
|
309
|
+
],
|
|
310
|
+
"author": "FluxStack Developer",
|
|
311
|
+
"license": "MIT",
|
|
312
|
+
"peerDependencies": {
|
|
313
|
+
"elysia": "^1.0.0"
|
|
314
|
+
},
|
|
315
|
+
"dependencies": {},
|
|
316
|
+
"devDependencies": {
|
|
317
|
+
"typescript": "^5.0.0"
|
|
318
|
+
},
|
|
319
|
+
"fluxstack": {
|
|
320
|
+
"plugin": true,
|
|
321
|
+
"version": "^1.0.0",
|
|
322
|
+
"hooks": [
|
|
323
|
+
"setup",
|
|
324
|
+
"onServerStart",
|
|
325
|
+
"onRequest",
|
|
326
|
+
"onResponse"
|
|
327
|
+
],
|
|
328
|
+
"category": "utility",
|
|
329
|
+
"tags": ["{{name}}", "server"]
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
`
|
|
333
|
+
},
|
|
334
|
+
...basic.files.slice(1), // Skip package.json from basic
|
|
335
|
+
{
|
|
336
|
+
path: 'plugins/{{name}}/server/index.ts',
|
|
337
|
+
content: `/**
|
|
338
|
+
* Server-side logic for {{pascalName}} plugin
|
|
339
|
+
*/
|
|
340
|
+
|
|
341
|
+
export class {{pascalName}}Service {
|
|
342
|
+
async initialize() {
|
|
343
|
+
console.log(\`[{{name}}] Server service initialized\`)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Add your server-side methods here
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export const {{camelName}}Service = new {{pascalName}}Service()
|
|
350
|
+
`
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private getClientOnlyTemplate(): Template {
|
|
357
|
+
const basic = this.getBasicTemplate()
|
|
358
|
+
return {
|
|
359
|
+
...basic,
|
|
360
|
+
name: 'client-plugin',
|
|
361
|
+
description: 'Plugin with client-side code',
|
|
362
|
+
files: [
|
|
363
|
+
{
|
|
364
|
+
path: 'plugins/{{name}}/package.json',
|
|
365
|
+
content: `{
|
|
366
|
+
"name": "@fluxstack/{{name}}-plugin",
|
|
367
|
+
"version": "1.0.0",
|
|
368
|
+
"description": "{{description}}",
|
|
369
|
+
"main": "index.ts",
|
|
370
|
+
"types": "index.ts",
|
|
371
|
+
"exports": {
|
|
372
|
+
".": {
|
|
373
|
+
"import": "./index.ts",
|
|
374
|
+
"types": "./index.ts"
|
|
375
|
+
},
|
|
376
|
+
"./config": {
|
|
377
|
+
"import": "./config/index.ts",
|
|
378
|
+
"types": "./config/index.ts"
|
|
379
|
+
},
|
|
380
|
+
"./client": {
|
|
381
|
+
"import": "./client/index.ts",
|
|
382
|
+
"types": "./client/index.ts"
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
"keywords": [
|
|
386
|
+
"fluxstack",
|
|
387
|
+
"plugin",
|
|
388
|
+
"{{name}}",
|
|
389
|
+
"react",
|
|
390
|
+
"client",
|
|
391
|
+
"typescript"
|
|
392
|
+
],
|
|
393
|
+
"author": "FluxStack Developer",
|
|
394
|
+
"license": "MIT",
|
|
395
|
+
"peerDependencies": {
|
|
396
|
+
"react": ">=16.8.0"
|
|
397
|
+
},
|
|
398
|
+
"peerDependenciesMeta": {
|
|
399
|
+
"react": {
|
|
400
|
+
"optional": true
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
"dependencies": {},
|
|
404
|
+
"devDependencies": {
|
|
405
|
+
"@types/react": "^18.0.0",
|
|
406
|
+
"typescript": "^5.0.0"
|
|
407
|
+
},
|
|
408
|
+
"fluxstack": {
|
|
409
|
+
"plugin": true,
|
|
410
|
+
"version": "^1.0.0",
|
|
411
|
+
"hooks": [
|
|
412
|
+
"setup",
|
|
413
|
+
"onServerStart"
|
|
414
|
+
],
|
|
415
|
+
"category": "utility",
|
|
416
|
+
"tags": ["{{name}}", "client", "react"]
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
`
|
|
420
|
+
},
|
|
421
|
+
...basic.files.slice(1), // Skip package.json from basic
|
|
422
|
+
{
|
|
423
|
+
path: 'plugins/{{name}}/client/index.ts',
|
|
424
|
+
content: `/**
|
|
425
|
+
* Client-side logic for {{pascalName}} plugin
|
|
426
|
+
*/
|
|
427
|
+
|
|
428
|
+
export class {{pascalName}}Client {
|
|
429
|
+
initialize() {
|
|
430
|
+
console.log(\`[{{name}}] Client initialized\`)
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Add your client-side methods here
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export const {{camelName}}Client = new {{pascalName}}Client()
|
|
437
|
+
`
|
|
438
|
+
}
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private getFullTemplate(): Template {
|
|
444
|
+
const basic = this.getBasicTemplate()
|
|
445
|
+
const server = this.getServerOnlyTemplate()
|
|
446
|
+
const client = this.getClientOnlyTemplate()
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
...basic,
|
|
450
|
+
name: 'full-plugin',
|
|
451
|
+
description: 'Complete plugin with server and client code',
|
|
452
|
+
files: [
|
|
453
|
+
{
|
|
454
|
+
path: 'plugins/{{name}}/package.json',
|
|
455
|
+
content: `{
|
|
456
|
+
"name": "@fluxstack/{{name}}-plugin",
|
|
457
|
+
"version": "1.0.0",
|
|
458
|
+
"description": "{{description}}",
|
|
459
|
+
"main": "index.ts",
|
|
460
|
+
"types": "index.ts",
|
|
461
|
+
"exports": {
|
|
462
|
+
".": {
|
|
463
|
+
"import": "./index.ts",
|
|
464
|
+
"types": "./index.ts"
|
|
465
|
+
},
|
|
466
|
+
"./config": {
|
|
467
|
+
"import": "./config/index.ts",
|
|
468
|
+
"types": "./config/index.ts"
|
|
469
|
+
},
|
|
470
|
+
"./server": {
|
|
471
|
+
"import": "./server/index.ts",
|
|
472
|
+
"types": "./server/index.ts"
|
|
473
|
+
},
|
|
474
|
+
"./client": {
|
|
475
|
+
"import": "./client/index.ts",
|
|
476
|
+
"types": "./client/index.ts"
|
|
477
|
+
},
|
|
478
|
+
"./types": {
|
|
479
|
+
"import": "./types.ts",
|
|
480
|
+
"types": "./types.ts"
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
"keywords": [
|
|
484
|
+
"fluxstack",
|
|
485
|
+
"plugin",
|
|
486
|
+
"{{name}}",
|
|
487
|
+
"react",
|
|
488
|
+
"server",
|
|
489
|
+
"client",
|
|
490
|
+
"typescript"
|
|
491
|
+
],
|
|
492
|
+
"author": "FluxStack Developer",
|
|
493
|
+
"license": "MIT",
|
|
494
|
+
"peerDependencies": {
|
|
495
|
+
"react": ">=16.8.0",
|
|
496
|
+
"elysia": "^1.0.0"
|
|
497
|
+
},
|
|
498
|
+
"peerDependenciesMeta": {
|
|
499
|
+
"react": {
|
|
500
|
+
"optional": true
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
"dependencies": {},
|
|
504
|
+
"devDependencies": {
|
|
505
|
+
"@types/react": "^18.0.0",
|
|
506
|
+
"typescript": "^5.0.0"
|
|
507
|
+
},
|
|
508
|
+
"fluxstack": {
|
|
509
|
+
"plugin": true,
|
|
510
|
+
"version": "^1.0.0",
|
|
511
|
+
"hooks": [
|
|
512
|
+
"setup",
|
|
513
|
+
"onServerStart",
|
|
514
|
+
"onRequest",
|
|
515
|
+
"onResponse",
|
|
516
|
+
"onError"
|
|
517
|
+
],
|
|
518
|
+
"category": "utility",
|
|
519
|
+
"tags": ["{{name}}", "server", "client", "react"]
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
`
|
|
523
|
+
},
|
|
524
|
+
...basic.files.slice(1), // Skip package.json from basic
|
|
525
|
+
{
|
|
526
|
+
path: 'plugins/{{name}}/server/index.ts',
|
|
527
|
+
content: `/**
|
|
528
|
+
* Server-side logic for {{pascalName}} plugin
|
|
529
|
+
*/
|
|
530
|
+
|
|
531
|
+
export class {{pascalName}}Service {
|
|
532
|
+
async initialize() {
|
|
533
|
+
console.log(\`[{{name}}] Server service initialized\`)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Add your server-side methods here
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export const {{camelName}}Service = new {{pascalName}}Service()
|
|
540
|
+
`
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
path: 'plugins/{{name}}/client/index.ts',
|
|
544
|
+
content: `/**
|
|
545
|
+
* Client-side logic for {{pascalName}} plugin
|
|
546
|
+
*/
|
|
547
|
+
|
|
548
|
+
export class {{pascalName}}Client {
|
|
549
|
+
initialize() {
|
|
550
|
+
console.log(\`[{{name}}] Client initialized\`)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Add your client-side methods here
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export const {{camelName}}Client = new {{pascalName}}Client()
|
|
557
|
+
`
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
path: 'plugins/{{name}}/types.ts',
|
|
561
|
+
content: `/**
|
|
562
|
+
* Type definitions for {{pascalName}} plugin
|
|
563
|
+
*/
|
|
564
|
+
|
|
565
|
+
// Config types are exported from ./config/index.ts
|
|
566
|
+
// Import them like: import type { {{pascalName}}Config } from './config'
|
|
567
|
+
|
|
568
|
+
export interface {{pascalName}}Options {
|
|
569
|
+
// Add your runtime options types here
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export interface {{pascalName}}Event {
|
|
573
|
+
// Add your event types here
|
|
574
|
+
}
|
|
575
|
+
`
|
|
576
|
+
}
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
@@ -85,6 +85,7 @@ export class TemplateEngine {
|
|
|
85
85
|
camelName: this.toCamelCase(options.name),
|
|
86
86
|
pascalName: this.toPascalCase(options.name),
|
|
87
87
|
snakeName: this.toSnakeCase(options.name),
|
|
88
|
+
constantName: this.toConstantCase(options.name), // SCREAMING_SNAKE_CASE
|
|
88
89
|
timestamp: new Date().toISOString(),
|
|
89
90
|
date: new Date().toLocaleDateString(),
|
|
90
91
|
year: new Date().getFullYear(),
|
|
@@ -149,6 +150,10 @@ export class TemplateEngine {
|
|
|
149
150
|
.replace(/[\s-]+/g, '_')
|
|
150
151
|
.toLowerCase()
|
|
151
152
|
}
|
|
153
|
+
|
|
154
|
+
private toConstantCase(str: string): string {
|
|
155
|
+
return this.toSnakeCase(str).toUpperCase()
|
|
156
|
+
}
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
export const templateEngine = new TemplateEngine()
|
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
|