create-fluxstack 1.9.1 → 1.12.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.
Files changed (259) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LIVE_COMPONENTS_REVIEW.md +781 -0
  4. package/LLMD/INDEX.md +64 -0
  5. package/LLMD/MAINTENANCE.md +197 -0
  6. package/LLMD/MIGRATION.md +156 -0
  7. package/LLMD/config/.gitkeep +1 -0
  8. package/LLMD/config/declarative-system.md +268 -0
  9. package/LLMD/config/environment-vars.md +327 -0
  10. package/LLMD/config/runtime-reload.md +401 -0
  11. package/LLMD/core/.gitkeep +1 -0
  12. package/LLMD/core/build-system.md +599 -0
  13. package/LLMD/core/framework-lifecycle.md +229 -0
  14. package/LLMD/core/plugin-system.md +451 -0
  15. package/LLMD/patterns/.gitkeep +1 -0
  16. package/LLMD/patterns/anti-patterns.md +297 -0
  17. package/LLMD/patterns/project-structure.md +264 -0
  18. package/LLMD/patterns/type-safety.md +440 -0
  19. package/LLMD/reference/.gitkeep +1 -0
  20. package/LLMD/reference/cli-commands.md +250 -0
  21. package/LLMD/reference/plugin-hooks.md +357 -0
  22. package/LLMD/reference/routing.md +39 -0
  23. package/LLMD/reference/troubleshooting.md +364 -0
  24. package/LLMD/resources/.gitkeep +1 -0
  25. package/LLMD/resources/controllers.md +465 -0
  26. package/LLMD/resources/live-components.md +703 -0
  27. package/LLMD/resources/live-rooms.md +482 -0
  28. package/LLMD/resources/live-upload.md +130 -0
  29. package/LLMD/resources/plugins-external.md +617 -0
  30. package/LLMD/resources/routes-eden.md +254 -0
  31. package/README.md +37 -17
  32. package/app/client/index.html +0 -1
  33. package/app/client/src/App.tsx +109 -156
  34. package/app/client/src/components/AppLayout.tsx +68 -0
  35. package/app/client/src/components/BackButton.tsx +13 -0
  36. package/app/client/src/components/DemoPage.tsx +20 -0
  37. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  38. package/app/client/src/lib/eden-api.ts +85 -65
  39. package/app/client/src/live/ChatDemo.tsx +107 -0
  40. package/app/client/src/live/CounterDemo.tsx +206 -0
  41. package/app/client/src/live/FormDemo.tsx +119 -0
  42. package/app/client/src/live/RoomChatDemo.tsx +242 -0
  43. package/app/client/src/live/UploadDemo.tsx +21 -0
  44. package/app/client/src/main.tsx +13 -10
  45. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  46. package/app/client/src/pages/HomePage.tsx +76 -0
  47. package/app/client/src/vite-env.d.ts +1 -1
  48. package/app/server/app.ts +1 -4
  49. package/app/server/controllers/users.controller.ts +36 -44
  50. package/app/server/index.ts +24 -107
  51. package/app/server/live/LiveChat.ts +77 -0
  52. package/app/server/live/LiveCounter.ts +67 -0
  53. package/app/server/live/LiveForm.ts +63 -0
  54. package/app/server/live/LiveLocalCounter.ts +32 -0
  55. package/app/server/live/LiveRoomChat.ts +285 -0
  56. package/app/server/live/LiveUpload.ts +81 -0
  57. package/app/server/live/register-components.ts +19 -19
  58. package/app/server/routes/index.ts +3 -1
  59. package/app/server/routes/room.routes.ts +117 -0
  60. package/app/server/routes/users.routes.ts +35 -27
  61. package/app/shared/types/index.ts +14 -2
  62. package/config/app.config.ts +2 -62
  63. package/config/client.config.ts +2 -95
  64. package/config/database.config.ts +2 -99
  65. package/config/fluxstack.config.ts +25 -45
  66. package/config/index.ts +57 -38
  67. package/config/monitoring.config.ts +2 -114
  68. package/config/plugins.config.ts +2 -80
  69. package/config/server.config.ts +2 -68
  70. package/config/services.config.ts +2 -130
  71. package/config/system/app.config.ts +29 -0
  72. package/config/system/build.config.ts +49 -0
  73. package/config/system/client.config.ts +68 -0
  74. package/config/system/database.config.ts +17 -0
  75. package/config/system/fluxstack.config.ts +114 -0
  76. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  77. package/config/system/monitoring.config.ts +114 -0
  78. package/config/system/plugins.config.ts +84 -0
  79. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  80. package/config/system/server.config.ts +68 -0
  81. package/config/system/services.config.ts +46 -0
  82. package/config/{system.config.ts → system/system.config.ts} +1 -1
  83. package/core/build/bundler.ts +4 -1
  84. package/core/build/flux-plugins-generator.ts +325 -325
  85. package/core/build/index.ts +159 -27
  86. package/core/build/live-components-generator.ts +70 -3
  87. package/core/build/optimizer.ts +235 -235
  88. package/core/cli/command-registry.ts +6 -4
  89. package/core/cli/commands/build.ts +79 -0
  90. package/core/cli/commands/create.ts +54 -0
  91. package/core/cli/commands/dev.ts +101 -0
  92. package/core/cli/commands/help.ts +34 -0
  93. package/core/cli/commands/index.ts +34 -0
  94. package/core/cli/commands/make-plugin.ts +90 -0
  95. package/core/cli/commands/plugin-add.ts +197 -0
  96. package/core/cli/commands/plugin-deps.ts +2 -2
  97. package/core/cli/commands/plugin-list.ts +208 -0
  98. package/core/cli/commands/plugin-remove.ts +170 -0
  99. package/core/cli/generators/component.ts +769 -769
  100. package/core/cli/generators/controller.ts +1 -1
  101. package/core/cli/generators/index.ts +146 -146
  102. package/core/cli/generators/interactive.ts +227 -227
  103. package/core/cli/generators/plugin.ts +2 -2
  104. package/core/cli/generators/prompts.ts +82 -82
  105. package/core/cli/generators/route.ts +6 -6
  106. package/core/cli/generators/service.ts +2 -2
  107. package/core/cli/generators/template-engine.ts +4 -3
  108. package/core/cli/generators/types.ts +2 -2
  109. package/core/cli/generators/utils.ts +191 -191
  110. package/core/cli/index.ts +115 -558
  111. package/core/cli/plugin-discovery.ts +2 -2
  112. package/core/client/LiveComponentsProvider.tsx +63 -17
  113. package/core/client/api/eden.ts +183 -0
  114. package/core/client/api/index.ts +11 -0
  115. package/core/client/components/Live.tsx +104 -0
  116. package/core/client/fluxstack.ts +1 -9
  117. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
  118. package/core/client/hooks/state-validator.ts +1 -1
  119. package/core/client/hooks/useAuth.ts +48 -48
  120. package/core/client/hooks/useChunkedUpload.ts +170 -69
  121. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  122. package/core/client/hooks/useLiveComponent.ts +800 -0
  123. package/core/client/hooks/useLiveUpload.ts +71 -0
  124. package/core/client/hooks/useRoom.ts +409 -0
  125. package/core/client/hooks/useRoomProxy.ts +382 -0
  126. package/core/client/index.ts +18 -51
  127. package/core/client/standalone-entry.ts +8 -0
  128. package/core/client/standalone.ts +74 -53
  129. package/core/client/state/createStore.ts +192 -192
  130. package/core/client/state/index.ts +14 -14
  131. package/core/config/index.ts +70 -291
  132. package/core/config/schema.ts +42 -723
  133. package/core/framework/client.ts +131 -131
  134. package/core/framework/index.ts +7 -7
  135. package/core/framework/server.ts +227 -47
  136. package/core/framework/types.ts +2 -2
  137. package/core/index.ts +23 -4
  138. package/core/live/ComponentRegistry.ts +7 -3
  139. package/core/live/types.ts +77 -0
  140. package/core/plugins/built-in/index.ts +134 -131
  141. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1074
  142. package/core/plugins/built-in/live-components/index.ts +1 -1
  143. package/core/plugins/built-in/monitoring/index.ts +111 -47
  144. package/core/plugins/built-in/static/index.ts +1 -1
  145. package/core/plugins/built-in/swagger/index.ts +68 -265
  146. package/core/plugins/built-in/vite/index.ts +94 -306
  147. package/core/plugins/built-in/vite/vite-dev.ts +82 -0
  148. package/core/plugins/config.ts +9 -7
  149. package/core/plugins/dependency-manager.ts +31 -1
  150. package/core/plugins/discovery.ts +19 -7
  151. package/core/plugins/executor.ts +2 -2
  152. package/core/plugins/index.ts +203 -203
  153. package/core/plugins/manager.ts +27 -39
  154. package/core/plugins/module-resolver.ts +19 -8
  155. package/core/plugins/registry.ts +309 -21
  156. package/core/plugins/types.ts +106 -55
  157. package/core/server/framework.ts +66 -43
  158. package/core/server/index.ts +15 -16
  159. package/core/server/live/ComponentRegistry.ts +91 -75
  160. package/core/server/live/FileUploadManager.ts +41 -31
  161. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  162. package/core/server/live/LiveRoomManager.ts +261 -0
  163. package/core/server/live/RoomEventBus.ts +234 -0
  164. package/core/server/live/RoomStateManager.ts +172 -0
  165. package/core/server/live/StateSignature.ts +643 -643
  166. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  167. package/core/server/live/auto-generated-components.ts +41 -26
  168. package/core/server/live/index.ts +14 -0
  169. package/core/server/live/websocket-plugin.ts +233 -72
  170. package/core/server/middleware/elysia-helpers.ts +7 -2
  171. package/core/server/middleware/errorHandling.ts +1 -1
  172. package/core/server/middleware/index.ts +31 -31
  173. package/core/server/plugins/database.ts +180 -180
  174. package/core/server/plugins/static-files-plugin.ts +69 -260
  175. package/core/server/plugins/swagger.ts +33 -33
  176. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  177. package/core/server/rooms/RoomSystem.ts +463 -0
  178. package/core/server/rooms/index.ts +13 -0
  179. package/core/server/services/BaseService.ts +1 -1
  180. package/core/server/services/ServiceContainer.ts +1 -1
  181. package/core/server/services/index.ts +8 -8
  182. package/core/templates/create-project.ts +12 -12
  183. package/core/testing/index.ts +9 -9
  184. package/core/testing/setup.ts +73 -73
  185. package/core/types/api.ts +168 -168
  186. package/core/types/build.ts +219 -218
  187. package/core/types/config.ts +56 -26
  188. package/core/types/index.ts +4 -4
  189. package/core/types/plugin.ts +107 -99
  190. package/core/types/types.ts +490 -14
  191. package/core/utils/build-logger.ts +324 -324
  192. package/core/utils/config-schema.ts +480 -480
  193. package/core/utils/env.ts +2 -8
  194. package/core/utils/errors/codes.ts +114 -114
  195. package/core/utils/errors/handlers.ts +36 -1
  196. package/core/utils/errors/index.ts +49 -5
  197. package/core/utils/errors/middleware.ts +113 -113
  198. package/core/utils/helpers.ts +6 -16
  199. package/core/utils/index.ts +17 -17
  200. package/core/utils/logger/colors.ts +114 -114
  201. package/core/utils/logger/config.ts +13 -9
  202. package/core/utils/logger/formatter.ts +82 -82
  203. package/core/utils/logger/group-logger.ts +101 -101
  204. package/core/utils/logger/index.ts +6 -1
  205. package/core/utils/logger/stack-trace.ts +3 -1
  206. package/core/utils/logger/startup-banner.ts +82 -66
  207. package/core/utils/logger/winston-logger.ts +152 -152
  208. package/core/utils/monitoring/index.ts +211 -211
  209. package/core/utils/sync-version.ts +66 -66
  210. package/core/utils/version.ts +1 -1
  211. package/create-fluxstack.ts +8 -7
  212. package/eslint.config.js +23 -23
  213. package/package.json +14 -15
  214. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  215. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  216. package/plugins/crypto-auth/client/components/index.ts +11 -11
  217. package/plugins/crypto-auth/client/index.ts +11 -11
  218. package/plugins/crypto-auth/config/index.ts +1 -1
  219. package/plugins/crypto-auth/index.ts +4 -4
  220. package/plugins/crypto-auth/package.json +65 -65
  221. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  222. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  223. package/plugins/crypto-auth/server/index.ts +21 -21
  224. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  225. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  226. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  227. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  228. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  229. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  230. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  231. package/tsconfig.api-strict.json +16 -0
  232. package/tsconfig.json +10 -14
  233. package/{app/client/tsconfig.node.json → tsconfig.node.json} +1 -1
  234. package/types/global.d.ts +29 -29
  235. package/types/vitest.d.ts +8 -8
  236. package/vite.config.ts +38 -62
  237. package/vitest.config.live.ts +10 -9
  238. package/vitest.config.ts +29 -17
  239. package/workspace.json +5 -5
  240. package/app/client/README.md +0 -69
  241. package/app/client/SIMPLIFICATION.md +0 -140
  242. package/app/client/frontend-only.ts +0 -12
  243. package/app/client/tsconfig.app.json +0 -44
  244. package/app/client/tsconfig.json +0 -7
  245. package/app/client/zustand-setup.md +0 -65
  246. package/app/server/backend-only.ts +0 -18
  247. package/app/server/live/LiveClockComponent.ts +0 -215
  248. package/app/server/routes/env-test.ts +0 -110
  249. package/core/client/hooks/index.ts +0 -7
  250. package/core/client/hooks/useHybridLiveComponent.ts +0 -631
  251. package/core/client/hooks/useWebSocket.ts +0 -373
  252. package/core/config/env.ts +0 -546
  253. package/core/config/loader.ts +0 -522
  254. package/core/config/runtime-config.ts +0 -327
  255. package/core/config/validator.ts +0 -540
  256. package/core/server/backend-entry.ts +0 -51
  257. package/core/server/standalone.ts +0 -106
  258. package/core/utils/regenerate-files.ts +0 -69
  259. package/fluxstack.config.ts +0 -354
@@ -54,8 +54,8 @@ export class ServiceGenerator implements Generator {
54
54
  path: 'app/server/services/{{kebabName}}.service.ts',
55
55
  content: `import { {{pascalName}}, Create{{pascalName}}, Update{{pascalName}} } from '../schemas/{{kebabName}}.schema'
56
56
  import { {{pascalName}}Repository } from '../repositories/{{kebabName}}.repository'
57
- import { ValidationError, NotFoundError } from '@/core/utils/errors'
58
- import { logger } from '@/core/utils/logger'
57
+ import { ValidationError, NotFoundError } from '@core/utils/errors'
58
+ import { logger } from '@core/utils/logger'
59
59
 
60
60
  export class {{pascalName}}Service {
61
61
  private repository: {{pascalName}}Repository
@@ -77,7 +77,9 @@ export class TemplateEngine {
77
77
  options: GeneratorOptions
78
78
  ): Promise<Record<string, any>> {
79
79
  const variables: Record<string, any> = {
80
- // Built-in variables
80
+ // Spread options first so built-in variables take precedence
81
+ ...options,
82
+ // Built-in variables (override any same-named keys from options)
81
83
  name: options.name,
82
84
  Name: this.capitalize(options.name),
83
85
  NAME: options.name.toUpperCase(),
@@ -90,8 +92,7 @@ export class TemplateEngine {
90
92
  date: new Date().toLocaleDateString(),
91
93
  year: new Date().getFullYear(),
92
94
  author: 'FluxStack Developer',
93
- projectName: context.config.app?.name || 'fluxstack-app',
94
- ...options
95
+ projectName: context.config.app?.name || 'fluxstack-app'
95
96
  }
96
97
 
97
98
  // Process template-specific variables
@@ -1,5 +1,5 @@
1
- import type { FluxStackConfig } from "../../config/schema"
2
- import type { Logger } from "@/core/utils/logger/index"
1
+ import type { FluxStackConfig } from "@config"
2
+ import type { Logger } from "@core/utils/logger/index"
3
3
  import type { PluginUtils } from "../../plugins/types"
4
4
 
5
5
  export interface GeneratorContext {
@@ -1,192 +1,192 @@
1
- import { existsSync } from "fs"
2
- import { join } from "path"
3
-
4
- export class GeneratorUtils {
5
- static validateName(name: string): { valid: boolean; error?: string } {
6
- if (!name || typeof name !== 'string') {
7
- return { valid: false, error: 'Name is required' }
8
- }
9
-
10
- const trimmed = name.trim()
11
- if (trimmed.length === 0) {
12
- return { valid: false, error: 'Name cannot be empty' }
13
- }
14
-
15
- if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(trimmed)) {
16
- return { valid: false, error: 'Name must start with a letter and contain only letters, numbers, hyphens, and underscores' }
17
- }
18
-
19
- if (trimmed.length > 100) {
20
- return { valid: false, error: 'Name must be less than 100 characters' }
21
- }
22
-
23
- return { valid: true }
24
- }
25
-
26
- static validatePath(path: string): { valid: boolean; error?: string } {
27
- if (!path || typeof path !== 'string') {
28
- return { valid: true } // Path is optional
29
- }
30
-
31
- const trimmed = path.trim()
32
- if (trimmed.length === 0) {
33
- return { valid: true }
34
- }
35
-
36
- // Check for invalid characters
37
- if (/[<>:"|?*]/.test(trimmed)) {
38
- return { valid: false, error: 'Path contains invalid characters' }
39
- }
40
-
41
- // Check for absolute paths (should be relative)
42
- if (trimmed.startsWith('/') || /^[a-zA-Z]:/.test(trimmed)) {
43
- return { valid: false, error: 'Path should be relative to project root' }
44
- }
45
-
46
- return { valid: true }
47
- }
48
-
49
- static checkFileExists(workingDir: string, filePath: string): boolean {
50
- const fullPath = join(workingDir, filePath)
51
- return existsSync(fullPath)
52
- }
53
-
54
- static getDefaultPath(type: string, name: string): string {
55
- const kebabName = this.toKebabCase(name)
56
- const pascalName = this.toPascalCase(name)
57
-
58
- switch (type) {
59
- case 'controller':
60
- return `app/server/controllers/${kebabName}.controller.ts`
61
- case 'service':
62
- return `app/server/services/${kebabName}.service.ts`
63
- case 'route':
64
- return `app/server/routes/${kebabName}.routes.ts`
65
- case 'component':
66
- return `app/client/src/components/${pascalName}/${pascalName}.tsx`
67
- default:
68
- return `${kebabName}.ts`
69
- }
70
- }
71
-
72
- static getRelatedFiles(type: string, name: string): string[] {
73
- const kebabName = this.toKebabCase(name)
74
- const pascalName = this.toPascalCase(name)
75
-
76
- switch (type) {
77
- case 'controller':
78
- return [
79
- `app/server/services/${kebabName}.service.ts`,
80
- `app/server/schemas/${kebabName}.schema.ts`,
81
- `app/server/routes/${kebabName}.routes.ts`
82
- ]
83
- case 'service':
84
- return [
85
- `app/server/repositories/${kebabName}.repository.ts`,
86
- `app/server/controllers/${kebabName}.controller.ts`
87
- ]
88
- case 'component':
89
- return [
90
- `app/client/src/components/${pascalName}/${pascalName}.css`,
91
- `app/client/src/components/${pascalName}/index.ts`,
92
- `app/client/src/components/${pascalName}/${pascalName}.test.tsx`,
93
- `app/client/src/components/${pascalName}/${pascalName}.stories.tsx`
94
- ]
95
- case 'route':
96
- return [
97
- `app/server/controllers/${kebabName}.controller.ts`,
98
- `app/server/middleware/${kebabName}.middleware.ts`
99
- ]
100
- default:
101
- return []
102
- }
103
- }
104
-
105
- static formatFileSize(bytes: number): string {
106
- const units = ['B', 'KB', 'MB', 'GB']
107
- let size = bytes
108
- let unitIndex = 0
109
-
110
- while (size >= 1024 && unitIndex < units.length - 1) {
111
- size /= 1024
112
- unitIndex++
113
- }
114
-
115
- return `${size.toFixed(1)} ${units[unitIndex]}`
116
- }
117
-
118
- static getTemplateVariables(name: string, additionalVars: Record<string, any> = {}): Record<string, any> {
119
- return {
120
- name,
121
- Name: this.capitalize(name),
122
- NAME: name.toUpperCase(),
123
- kebabName: this.toKebabCase(name),
124
- camelName: this.toCamelCase(name),
125
- pascalName: this.toPascalCase(name),
126
- snakeName: this.toSnakeCase(name),
127
- timestamp: new Date().toISOString(),
128
- date: new Date().toLocaleDateString(),
129
- time: new Date().toLocaleTimeString(),
130
- year: new Date().getFullYear(),
131
- month: new Date().getMonth() + 1,
132
- day: new Date().getDate(),
133
- ...additionalVars
134
- }
135
- }
136
-
137
- // String transformation utilities
138
- static capitalize(str: string): string {
139
- return str.charAt(0).toUpperCase() + str.slice(1)
140
- }
141
-
142
- static toCamelCase(str: string): string {
143
- return str
144
- .replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '')
145
- .replace(/^[A-Z]/, char => char.toLowerCase())
146
- }
147
-
148
- static toPascalCase(str: string): string {
149
- return this.capitalize(this.toCamelCase(str))
150
- }
151
-
152
- static toKebabCase(str: string): string {
153
- return str
154
- .replace(/([a-z])([A-Z])/g, '$1-$2')
155
- .replace(/[\s_]+/g, '-')
156
- .toLowerCase()
157
- }
158
-
159
- static toSnakeCase(str: string): string {
160
- return str
161
- .replace(/([a-z])([A-Z])/g, '$1_$2')
162
- .replace(/[\s-]+/g, '_')
163
- .toLowerCase()
164
- }
165
-
166
- static pluralize(str: string): string {
167
- // Simple pluralization - in a real implementation you'd use a proper library
168
- if (str.endsWith('y')) {
169
- return str.slice(0, -1) + 'ies'
170
- }
171
- if (str.endsWith('s') || str.endsWith('sh') || str.endsWith('ch') || str.endsWith('x') || str.endsWith('z')) {
172
- return str + 'es'
173
- }
174
- return str + 's'
175
- }
176
-
177
- static singularize(str: string): string {
178
- // Simple singularization - in a real implementation you'd use a proper library
179
- if (str.endsWith('ies')) {
180
- return str.slice(0, -3) + 'y'
181
- }
182
- if (str.endsWith('es')) {
183
- return str.slice(0, -2)
184
- }
185
- if (str.endsWith('s') && !str.endsWith('ss')) {
186
- return str.slice(0, -1)
187
- }
188
- return str
189
- }
190
- }
191
-
1
+ import { existsSync } from "fs"
2
+ import { join } from "path"
3
+
4
+ export class GeneratorUtils {
5
+ static validateName(name: string): { valid: boolean; error?: string } {
6
+ if (!name || typeof name !== 'string') {
7
+ return { valid: false, error: 'Name is required' }
8
+ }
9
+
10
+ const trimmed = name.trim()
11
+ if (trimmed.length === 0) {
12
+ return { valid: false, error: 'Name cannot be empty' }
13
+ }
14
+
15
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(trimmed)) {
16
+ return { valid: false, error: 'Name must start with a letter and contain only letters, numbers, hyphens, and underscores' }
17
+ }
18
+
19
+ if (trimmed.length > 100) {
20
+ return { valid: false, error: 'Name must be less than 100 characters' }
21
+ }
22
+
23
+ return { valid: true }
24
+ }
25
+
26
+ static validatePath(path: string): { valid: boolean; error?: string } {
27
+ if (!path || typeof path !== 'string') {
28
+ return { valid: true } // Path is optional
29
+ }
30
+
31
+ const trimmed = path.trim()
32
+ if (trimmed.length === 0) {
33
+ return { valid: true }
34
+ }
35
+
36
+ // Check for invalid characters
37
+ if (/[<>:"|?*]/.test(trimmed)) {
38
+ return { valid: false, error: 'Path contains invalid characters' }
39
+ }
40
+
41
+ // Check for absolute paths (should be relative)
42
+ if (trimmed.startsWith('/') || /^[a-zA-Z]:/.test(trimmed)) {
43
+ return { valid: false, error: 'Path should be relative to project root' }
44
+ }
45
+
46
+ return { valid: true }
47
+ }
48
+
49
+ static checkFileExists(workingDir: string, filePath: string): boolean {
50
+ const fullPath = join(workingDir, filePath)
51
+ return existsSync(fullPath)
52
+ }
53
+
54
+ static getDefaultPath(type: string, name: string): string {
55
+ const kebabName = this.toKebabCase(name)
56
+ const pascalName = this.toPascalCase(name)
57
+
58
+ switch (type) {
59
+ case 'controller':
60
+ return `app/server/controllers/${kebabName}.controller.ts`
61
+ case 'service':
62
+ return `app/server/services/${kebabName}.service.ts`
63
+ case 'route':
64
+ return `app/server/routes/${kebabName}.routes.ts`
65
+ case 'component':
66
+ return `app/client/src/components/${pascalName}/${pascalName}.tsx`
67
+ default:
68
+ return `${kebabName}.ts`
69
+ }
70
+ }
71
+
72
+ static getRelatedFiles(type: string, name: string): string[] {
73
+ const kebabName = this.toKebabCase(name)
74
+ const pascalName = this.toPascalCase(name)
75
+
76
+ switch (type) {
77
+ case 'controller':
78
+ return [
79
+ `app/server/services/${kebabName}.service.ts`,
80
+ `app/server/schemas/${kebabName}.schema.ts`,
81
+ `app/server/routes/${kebabName}.routes.ts`
82
+ ]
83
+ case 'service':
84
+ return [
85
+ `app/server/repositories/${kebabName}.repository.ts`,
86
+ `app/server/controllers/${kebabName}.controller.ts`
87
+ ]
88
+ case 'component':
89
+ return [
90
+ `app/client/src/components/${pascalName}/${pascalName}.css`,
91
+ `app/client/src/components/${pascalName}/index.ts`,
92
+ `app/client/src/components/${pascalName}/${pascalName}.test.tsx`,
93
+ `app/client/src/components/${pascalName}/${pascalName}.stories.tsx`
94
+ ]
95
+ case 'route':
96
+ return [
97
+ `app/server/controllers/${kebabName}.controller.ts`,
98
+ `app/server/middleware/${kebabName}.middleware.ts`
99
+ ]
100
+ default:
101
+ return []
102
+ }
103
+ }
104
+
105
+ static formatFileSize(bytes: number): string {
106
+ const units = ['B', 'KB', 'MB', 'GB']
107
+ let size = bytes
108
+ let unitIndex = 0
109
+
110
+ while (size >= 1024 && unitIndex < units.length - 1) {
111
+ size /= 1024
112
+ unitIndex++
113
+ }
114
+
115
+ return `${size.toFixed(1)} ${units[unitIndex]}`
116
+ }
117
+
118
+ static getTemplateVariables(name: string, additionalVars: Record<string, any> = {}): Record<string, any> {
119
+ return {
120
+ name,
121
+ Name: this.capitalize(name),
122
+ NAME: name.toUpperCase(),
123
+ kebabName: this.toKebabCase(name),
124
+ camelName: this.toCamelCase(name),
125
+ pascalName: this.toPascalCase(name),
126
+ snakeName: this.toSnakeCase(name),
127
+ timestamp: new Date().toISOString(),
128
+ date: new Date().toLocaleDateString(),
129
+ time: new Date().toLocaleTimeString(),
130
+ year: new Date().getFullYear(),
131
+ month: new Date().getMonth() + 1,
132
+ day: new Date().getDate(),
133
+ ...additionalVars
134
+ }
135
+ }
136
+
137
+ // String transformation utilities
138
+ static capitalize(str: string): string {
139
+ return str.charAt(0).toUpperCase() + str.slice(1)
140
+ }
141
+
142
+ static toCamelCase(str: string): string {
143
+ return str
144
+ .replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '')
145
+ .replace(/^[A-Z]/, char => char.toLowerCase())
146
+ }
147
+
148
+ static toPascalCase(str: string): string {
149
+ return this.capitalize(this.toCamelCase(str))
150
+ }
151
+
152
+ static toKebabCase(str: string): string {
153
+ return str
154
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
155
+ .replace(/[\s_]+/g, '-')
156
+ .toLowerCase()
157
+ }
158
+
159
+ static toSnakeCase(str: string): string {
160
+ return str
161
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
162
+ .replace(/[\s-]+/g, '_')
163
+ .toLowerCase()
164
+ }
165
+
166
+ static pluralize(str: string): string {
167
+ // Simple pluralization - in a real implementation you'd use a proper library
168
+ if (str.endsWith('y')) {
169
+ return str.slice(0, -1) + 'ies'
170
+ }
171
+ if (str.endsWith('s') || str.endsWith('sh') || str.endsWith('ch') || str.endsWith('x') || str.endsWith('z')) {
172
+ return str + 'es'
173
+ }
174
+ return str + 's'
175
+ }
176
+
177
+ static singularize(str: string): string {
178
+ // Simple singularization - in a real implementation you'd use a proper library
179
+ if (str.endsWith('ies')) {
180
+ return str.slice(0, -3) + 'y'
181
+ }
182
+ if (str.endsWith('es')) {
183
+ return str.slice(0, -2)
184
+ }
185
+ if (str.endsWith('s') && !str.endsWith('ss')) {
186
+ return str.slice(0, -1)
187
+ }
188
+ return str
189
+ }
190
+ }
191
+
192
192
  export const generatorUtils = GeneratorUtils