@xeno-js/cli 0.1.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 (172) hide show
  1. package/.github/.copilot-instruction.md +73 -0
  2. package/.github/agents/git-operator.agent.md +86 -0
  3. package/.github/agents/unit-tester.agent.md +68 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +1 -0
  6. package/.husky/pre-push +1 -0
  7. package/.prettierignore +7 -0
  8. package/.prettierrc.json +37 -0
  9. package/LICENSE +15 -0
  10. package/README.md +236 -0
  11. package/commitlint.config.cjs +39 -0
  12. package/dist/domain/contracts/icommand-cli.contracts.js +2 -0
  13. package/dist/domain/contracts/icommand-runner.contracts.js +2 -0
  14. package/dist/domain/contracts/idispatch.contracts.js +2 -0
  15. package/dist/domain/contracts/ifile-service.contracts.js +2 -0
  16. package/dist/domain/contracts/igenerator.contracts.js +2 -0
  17. package/dist/domain/contracts/index.js +2 -0
  18. package/dist/domain/contracts/iscaffold-strategy.contracts.js +2 -0
  19. package/dist/domain/index.js +2 -0
  20. package/dist/generator.contracts.js +13 -0
  21. package/dist/index.js +31 -0
  22. package/dist/infrastructure/bootstrap/bootstrapper.js +32 -0
  23. package/dist/infrastructure/bootstrap/index.js +17 -0
  24. package/dist/infrastructure/builder/builder.js +16 -0
  25. package/dist/infrastructure/builder/builder.test.js +30 -0
  26. package/dist/infrastructure/builder/index.js +17 -0
  27. package/dist/infrastructure/command_launcher/command.utils.js +30 -0
  28. package/dist/infrastructure/command_launcher/index.js +2 -0
  29. package/dist/infrastructure/commands/command-runner.service.js +36 -0
  30. package/dist/infrastructure/commands/generate.command.js +48 -0
  31. package/dist/infrastructure/commands/help.command.js +44 -0
  32. package/dist/infrastructure/commands/index.js +20 -0
  33. package/dist/infrastructure/commands/new-project.command.js +43 -0
  34. package/dist/infrastructure/dispatcher/dispatcher.js +39 -0
  35. package/dist/infrastructure/dispatcher/index.js +17 -0
  36. package/dist/infrastructure/file/file.service.js +13 -0
  37. package/dist/infrastructure/file/index.js +17 -0
  38. package/dist/infrastructure/generators/bootstrap.generator.js +118 -0
  39. package/dist/infrastructure/generators/core/bootstrap.generator.js +118 -0
  40. package/dist/infrastructure/generators/core/command/cqrs.generator.js +49 -0
  41. package/dist/infrastructure/generators/core/command/generate-command.generator.js +163 -0
  42. package/dist/infrastructure/generators/core/command/generate-query.generator.js +131 -0
  43. package/dist/infrastructure/generators/core/drizzle-sql-lite.generator.js +78 -0
  44. package/dist/infrastructure/generators/core/drizzle.generator.js +85 -0
  45. package/dist/infrastructure/generators/core/env.generator.js +69 -0
  46. package/dist/infrastructure/generators/core/index.js +25 -0
  47. package/dist/infrastructure/generators/core/main.generator.js +45 -0
  48. package/dist/infrastructure/generators/core/packagejson.generator.js +78 -0
  49. package/dist/infrastructure/generators/core/readme.generator.js +431 -0
  50. package/dist/infrastructure/generators/core/registry.generator.js +46 -0
  51. package/dist/infrastructure/generators/core/tsconfig.generator.js +41 -0
  52. package/dist/infrastructure/generators/core-packagejson.generator.js +78 -0
  53. package/dist/infrastructure/generators/drizzle-sql-lite.generator.js +78 -0
  54. package/dist/infrastructure/generators/drizzle.generator.js +85 -0
  55. package/dist/infrastructure/generators/env-vue.generator.js +40 -0
  56. package/dist/infrastructure/generators/env.generator.js +71 -0
  57. package/dist/infrastructure/generators/gitignore.generator.js +62 -0
  58. package/dist/infrastructure/generators/index.js +26 -0
  59. package/dist/infrastructure/generators/main.generator.js +45 -0
  60. package/dist/infrastructure/generators/readme.generator.js +431 -0
  61. package/dist/infrastructure/generators/registry.generator.js +46 -0
  62. package/dist/infrastructure/generators/tsconfig-vue.generator.js +39 -0
  63. package/dist/infrastructure/generators/tsconfig.generator.js +41 -0
  64. package/dist/infrastructure/generators/vite-config.generator.js +39 -0
  65. package/dist/infrastructure/generators/vue/app-vue.generator.js +26 -0
  66. package/dist/infrastructure/generators/vue/bootstrap-ts.generator.js +59 -0
  67. package/dist/infrastructure/generators/vue/command_query/cqrs.generator.js +36 -0
  68. package/dist/infrastructure/generators/vue/command_query/generate-command-vue.generator.js +139 -0
  69. package/dist/infrastructure/generators/vue/command_query/generate-query-vue.generator.js +147 -0
  70. package/dist/infrastructure/generators/vue/env.generator.js +40 -0
  71. package/dist/infrastructure/generators/vue/index-html.generator.js +29 -0
  72. package/dist/infrastructure/generators/vue/index.js +28 -0
  73. package/dist/infrastructure/generators/vue/main.generator.js +45 -0
  74. package/dist/infrastructure/generators/vue/packagejson.generator.js +59 -0
  75. package/dist/infrastructure/generators/vue/readme.generator.js +394 -0
  76. package/dist/infrastructure/generators/vue/registry-ts.generator.js +28 -0
  77. package/dist/infrastructure/generators/vue/router.generator.js +33 -0
  78. package/dist/infrastructure/generators/vue/tailwind.generator.js +19 -0
  79. package/dist/infrastructure/generators/vue/tsconfig.generator.js +39 -0
  80. package/dist/infrastructure/generators/vue/use-app.generator.js +43 -0
  81. package/dist/infrastructure/generators/vue/vite-config.generator.js +39 -0
  82. package/dist/infrastructure/generators/vue-packagejson.generator.js +59 -0
  83. package/dist/infrastructure/generators/vue-readme.generator.js +53 -0
  84. package/dist/infrastructure/generators/vue-source-files.generator.js +136 -0
  85. package/dist/infrastructure/index.js +21 -0
  86. package/dist/infrastructure/strategies/core-scaffold.strategy.js +99 -0
  87. package/dist/infrastructure/strategies/index.js +18 -0
  88. package/dist/infrastructure/strategies/vue-scaffold.strategy.js +79 -0
  89. package/dist/scaffolding.engine.js +60 -0
  90. package/dist/shared/constants/command.constants.js +19 -0
  91. package/dist/shared/constants/core.constants.js +10 -0
  92. package/dist/shared/constants/index.js +18 -0
  93. package/dist/shared/index.js +18 -0
  94. package/dist/shared/types/common.types.js +2 -0
  95. package/dist/shared/types/index.js +2 -0
  96. package/dist/shared/utils/guards.utils.js +310 -0
  97. package/dist/shared/utils/index.js +18 -0
  98. package/dist/shared/utils/string.utils.js +62 -0
  99. package/eslint.config.mjs +305 -0
  100. package/lint-staged.config.mjs +5 -0
  101. package/logo/logo.png +0 -0
  102. package/package.json +65 -0
  103. package/src/domain/contracts/icommand-cli.contracts.ts +13 -0
  104. package/src/domain/contracts/icommand-runner.contracts.ts +3 -0
  105. package/src/domain/contracts/idispatch.contracts.ts +3 -0
  106. package/src/domain/contracts/ifile-service.contracts.ts +3 -0
  107. package/src/domain/contracts/igenerator.contracts.ts +5 -0
  108. package/src/domain/contracts/index.ts +6 -0
  109. package/src/domain/contracts/iscaffold-strategy.contracts.ts +7 -0
  110. package/src/domain/index.ts +1 -0
  111. package/src/index.ts +30 -0
  112. package/src/infrastructure/bootstrap/bootstrapper.ts +30 -0
  113. package/src/infrastructure/bootstrap/index.ts +1 -0
  114. package/src/infrastructure/builder/builder.test.ts +36 -0
  115. package/src/infrastructure/builder/builder.ts +15 -0
  116. package/src/infrastructure/builder/index.ts +1 -0
  117. package/src/infrastructure/command_launcher/command.utils.ts +31 -0
  118. package/src/infrastructure/command_launcher/index.ts +0 -0
  119. package/src/infrastructure/commands/command-runner.service.ts +36 -0
  120. package/src/infrastructure/commands/generate.command.ts +55 -0
  121. package/src/infrastructure/commands/help.command.ts +63 -0
  122. package/src/infrastructure/commands/index.ts +4 -0
  123. package/src/infrastructure/commands/new-project.command.ts +47 -0
  124. package/src/infrastructure/dispatcher/dispatcher.ts +45 -0
  125. package/src/infrastructure/dispatcher/index.ts +1 -0
  126. package/src/infrastructure/file/file.service.ts +14 -0
  127. package/src/infrastructure/file/index.ts +1 -0
  128. package/src/infrastructure/generators/core/bootstrap.generator.ts +118 -0
  129. package/src/infrastructure/generators/core/command/cqrs.generator.ts +63 -0
  130. package/src/infrastructure/generators/core/command/generate-command.generator.ts +191 -0
  131. package/src/infrastructure/generators/core/command/generate-query.generator.ts +150 -0
  132. package/src/infrastructure/generators/core/drizzle-sql-lite.generator.ts +76 -0
  133. package/src/infrastructure/generators/core/drizzle.generator.ts +86 -0
  134. package/src/infrastructure/generators/core/env.generator.ts +69 -0
  135. package/src/infrastructure/generators/core/index.ts +9 -0
  136. package/src/infrastructure/generators/core/main.generator.ts +41 -0
  137. package/src/infrastructure/generators/core/packagejson.generator.ts +70 -0
  138. package/src/infrastructure/generators/core/readme.generator.ts +427 -0
  139. package/src/infrastructure/generators/core/registry.generator.ts +40 -0
  140. package/src/infrastructure/generators/core/tsconfig.generator.ts +39 -0
  141. package/src/infrastructure/generators/gitignore.generator.ts +60 -0
  142. package/src/infrastructure/generators/vue/app-vue.generator.ts +21 -0
  143. package/src/infrastructure/generators/vue/bootstrap-ts.generator.ts +60 -0
  144. package/src/infrastructure/generators/vue/command_query/cqrs.generator.ts +36 -0
  145. package/src/infrastructure/generators/vue/command_query/generate-command-vue.generator.ts +153 -0
  146. package/src/infrastructure/generators/vue/command_query/generate-query-vue.generator.ts +161 -0
  147. package/src/infrastructure/generators/vue/env.generator.ts +39 -0
  148. package/src/infrastructure/generators/vue/index-html.generator.ts +24 -0
  149. package/src/infrastructure/generators/vue/index.ts +12 -0
  150. package/src/infrastructure/generators/vue/main.generator.ts +41 -0
  151. package/src/infrastructure/generators/vue/packagejson.generator.ts +50 -0
  152. package/src/infrastructure/generators/vue/readme.generator.ts +389 -0
  153. package/src/infrastructure/generators/vue/registry-ts.generator.ts +26 -0
  154. package/src/infrastructure/generators/vue/router.generator.ts +35 -0
  155. package/src/infrastructure/generators/vue/tailwind.generator.ts +17 -0
  156. package/src/infrastructure/generators/vue/tsconfig.generator.ts +38 -0
  157. package/src/infrastructure/generators/vue/use-app.generator.ts +38 -0
  158. package/src/infrastructure/generators/vue/vite-config.generator.ts +35 -0
  159. package/src/infrastructure/index.ts +5 -0
  160. package/src/infrastructure/strategies/core-scaffold.strategy.ts +100 -0
  161. package/src/infrastructure/strategies/index.ts +2 -0
  162. package/src/infrastructure/strategies/vue-scaffold.strategy.ts +79 -0
  163. package/src/shared/constants/command.constants.ts +18 -0
  164. package/src/shared/constants/core.constants.ts +7 -0
  165. package/src/shared/constants/index.ts +2 -0
  166. package/src/shared/index.ts +3 -0
  167. package/src/shared/types/common.types.ts +68 -0
  168. package/src/shared/types/index.ts +1 -0
  169. package/src/shared/utils/guards.utils.ts +334 -0
  170. package/src/shared/utils/index.ts +2 -0
  171. package/src/shared/utils/string.utils.ts +60 -0
  172. package/tsconfig.json +15 -0
@@ -0,0 +1,431 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ReadmeGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class ReadmeGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(projectPath, _options) {
14
+ const content = `
15
+ <div align="center">
16
+ <img src="logo/logo.png" alt="Xeno Logo" width="140" />
17
+
18
+ <h1>Xeno</h1>
19
+
20
+ <p><em>Enterprise-grade DDD & CQRS framework for Node.js</em></p>
21
+
22
+ <p>
23
+ <a href="https://github.com/Mattia-Carcione/xeno-js">
24
+ <img src="https://img.shields.io/badge/Powered%20by-Xeno-blueviolet?style=flat-square" alt="Powered by Xeno" />
25
+ </a>
26
+ <a href="https://github.com/Mattia-Carcione/xeno-js/blob/main/LICENSE">
27
+ <img src="https://img.shields.io/npm/l/@xeno?style=flat-square" alt="License: ISC" />
28
+ </a>
29
+ <a href="https://www.npmjs.com/package/@xeno/core">
30
+ <img src="https://img.shields.io/npm/v/@xeno/core?style=flat-square" alt="NPM Version" />
31
+ </a>
32
+ <a href="https://buymeacoffee.com/xenojs">
33
+ <img src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-Support-FFdd00?style=flat-square&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me A Coffee" />
34
+ </a>
35
+ </p>
36
+ </div>
37
+
38
+ ---
39
+
40
+ ## What is Xeno?
41
+
42
+ **Xeno** is an enterprise-grade, runtime-agnostic architectural framework for
43
+ Node.js built natively with TypeScript. It provides structural primitives for
44
+ implementing robust **Domain-Driven Design (DDD)** and **Command Query
45
+ Responsibility Segregation (CQRS)** patterns. By shifting operational logic away
46
+ from delivery mechanisms and transport frameworks, Xeno ensures your core
47
+ application architecture remains pristine, testable, and completely isolated
48
+ from external infrastructural churn.
49
+
50
+ ---
51
+
52
+ ## 💡 Why Choose Xeno?
53
+
54
+ Modern Node.js frameworks often tie business workflows tightly to HTTP server
55
+ abstractions or rely heavily on experimental language features. Xeno fixes this
56
+ with an emphasis on developer experience, type safety, and clean separation of
57
+ concerns.
58
+
59
+ - **Zero Decorators**: Xeno eliminates reliance on experimental or unstable TS
60
+ decorator specifications (\`reflect-metadata\`). The IoC container
61
+ (\`ServiceContainer\`) uses pure, explicit functional factories that optimize
62
+ compilation speeds and eliminate runtime black-box behaviors.
63
+ - **Complete Server Decoupling**: Xeno does not care if you use Fastify, Hono,
64
+ Express, Koa, or AWS Lambda. The presentation layer handles incoming data
65
+ using plain, primitive contracts, making migration or multi-runtime hosting
66
+ completely seamless.
67
+ - **Pay-For-What-You-Use (Opt-in Modularity)**: Core dependencies are
68
+ strategically classified as optional peer dependencies. If your architecture
69
+ doesn't use Redis, Sentry, or Supabase, you do not pull them into your node
70
+ modules.
71
+ - **Enterprise-Grade Resiliency & Cross-Cutting Pipelines**: Address complex
72
+ distributed patterns natively without code duplication. Xeno provides
73
+ out-of-the-box composite behaviors:
74
+ - **Idempotency**: Implements multi-tenant logic keyspaces matching advanced
75
+ SaaS factory patterns for logical partitioning.
76
+ - **Concurrency Control**: Mitigates thundering herd impacts via advanced
77
+ backoff retry strategies coupled with randomized jitter.
78
+ - **Resilience Policies**: Deep integration with circuit breakers, bulkheads,
79
+ and fallbacks.
80
+ - **Deterministic Type Safety**: Strong infrastructure validation strategies
81
+ using Zod schemas.
82
+
83
+ ---
84
+
85
+ ## 📖 Documentation & Getting Started
86
+
87
+ To explore the architecture, programmatic configurations, and extension
88
+ workflows of Xeno, read the full technical manuals located inside the main
89
+ documentation hub:
90
+
91
+ - **[Framework Documentation Repository](https://www.xeno-js.it/introduction)**
92
+
93
+ Inside, you will find exhaustive, step-by-step assembly guides covering core
94
+ host building (\`AppBuilder\`), isolated request middleware lifecycles, functional
95
+ \`Result\` monads, and zero-trust authorization pipeline behavior tracks.
96
+
97
+ ---
98
+
99
+ ## 🚀 Live Executable Demos
100
+
101
+ Want to see how Xeno works? Check out the functional example application
102
+ showcasing end-to-end command/query segregation, multi-tenant databases, and
103
+ resilient schema handling.
104
+
105
+ You can dive straight into the explicit source code modules of specialized
106
+ sandbox environments:
107
+
108
+ - **[\`pipelines_middleware_demo/\`](https://www.xeno-js.it/demo)**: Traces
109
+ an execution thread from the raw HTTP transport presentation layer, executing
110
+ automated header extraction and anchoring metadata variables into
111
+ \`AsyncLocalStorage\` thread boundaries.
112
+
113
+ ---
114
+
115
+ ## 📦 Installation
116
+
117
+ Install the core package:
118
+
119
+ \`\`\`bash
120
+ npm install @xeno-js/core
121
+
122
+ \`\`\`
123
+
124
+ Xeno uses **Optional Peer Dependencies**. You only install the external
125
+ libraries you actually need. Node.js will strictly lazy-load only the modules
126
+ you enable in the configuration.
127
+
128
+ \`\`\`bash
129
+ # Example: Install tools only if you enable them in the builder
130
+ npm install zod pino cockatiel drizzle-orm
131
+
132
+ \`\`\`
133
+
134
+ ---
135
+
136
+ ## ⚡ Bootstrapping & Middleware Example
137
+
138
+ Below is an architectural example of how to configure the Xeno
139
+ \`ServiceContainer\`, load core modules, and process an incoming application
140
+ payload natively inside a server middleware wrapper.
141
+
142
+ ### 1. Initialize the Container and Configure Modules
143
+
144
+ \`\`\`typescript
145
+ import { AppBuilder, LOG_LEVEL, TOKENS, XenoRegistry } from '@xeno-js/core'
146
+ import { FindUserQueryHandler } from './user/cqrs/handlers/index'
147
+ import { FindUserController } from './user/controllers/index'
148
+ import { UserMapper } from './user/mappers/user.mapper'
149
+ import { UserWriteRepository } from './user/repositories/user-write.repository'
150
+ import { UserDataSource } from './user/datasources/user.datasource'
151
+
152
+ // Map your registry token with XenoRegistry<TSchemaDb, TExtension>
153
+ type MyRegistry = XenoRegistry<{ /** Your Db Schema here **/}, {
154
+ USER_MAPPER_TOKEN: UserMapper
155
+ USER_DS_TOKEN: UserDataSource
156
+ USER_REPOSITORY_TOKEN: UserWriteRepository
157
+ FIND_USER_QUERY_HANDLER_TOKEN: FindUserQueryHandler
158
+ FIND_USER_CONTROLLER_TOKEN: FindUserController
159
+ }>
160
+
161
+ // Create the root IoC container context
162
+ export const bootstrap = new AppBuilder<MyRegistry>()
163
+ // Configure middleware and only PUBLIC routes
164
+ .addMiddlewares(opts => {
165
+ opts.routeRegistry = {
166
+ '/api/user/:id': ['GET', 'POST'],
167
+ }
168
+ })
169
+ // Configure the CQRS pipeline
170
+ // Can register Policies for your intent
171
+ .addPipeline((config) => {
172
+ config.authorization.policies = {
173
+ 'FIND_USER_QUERY_HANDLER_TOKEN': {
174
+ // Add authz by user id
175
+ userId: true
176
+ // Add authz by tenant id
177
+ tenantId: true
178
+ // Add authz by roles
179
+ roles: ['admin']
180
+ // Add authz by perissions
181
+ permissions: ['read'],
182
+ }
183
+ }
184
+ // Can add idempotency pipeline for command
185
+ config.commandBus.idempotency = { lockTtlSeconds: 30, processedTtlSeconds: 60 }
186
+ // Can add concurrency pipeline for command
187
+ config.commandBus.concurrency = { delayConfig: { baseDelayMs: 100, maxJitterMs: 500 }, maxRetries: 3 }
188
+ // Can add caching pipeline for query
189
+ config.queryBus.isEnabled = true
190
+ })
191
+ // Configure Database with drizzle
192
+ .addDb((opts, config) => {
193
+ opts.connectionString = config.getOrThrow('DATABASE_URL')
194
+ })
195
+ // Configure Authentication with supabase
196
+ .addAuth((opts, config) => {
197
+ opts.key = 'demo-key'
198
+ opts.url = config.getOrThrow('API_BASE_URL')
199
+ })
200
+ // Configure your logger (e.g. Console, Sentry, Pino or custom logger)
201
+ .addLogger((config) => {
202
+ config.level = LOG_LEVEL.INFO
203
+ config.console = true
204
+ })
205
+ // Register your services
206
+ .addServices((services) => {
207
+ // REGISTER MAPPER
208
+ services.addScoped('USER_MAPPER_TOKEN', () => new UserMapper())
209
+
210
+ // REGISTER DATASOURCES
211
+ services.addScoped('USER_DS_TOKEN', (c) => new UserDataSource(c.resolve(TOKENS.DB_CONTEXT)))
212
+
213
+ // REGISTER REPOSITORIES
214
+ services.addScoped('USER_REPOSITORY_TOKEN', (c) => new UserWriteRepository(c.resolve('USER_DS_TOKEN'), c.resolve('USER_MAPPER_TOKEN')))
215
+
216
+ // REGISTER HANDLERS
217
+ services.addScoped('FIND_USER_QUERY_HANDLER_TOKEN', (c) => {
218
+ const requestcontext = c.resolve('USER_CONTEXT_FACTORY')
219
+ const repository = c.resolve('USER_READ_REPOSITORY')
220
+ return new FindUserQueryHandler(repository, requestcontext)
221
+ })
222
+
223
+ // REGISTER CONTROLLERS
224
+ services.addTransient('FIND_USER_CONTROLLER_TOKEN', (c) => {
225
+ return new FindUserController(c.resolve('CONTEXT_ACCESSOR'), c.resolve('MEDIATOR'))
226
+ })
227
+ })
228
+
229
+ \`\`\`
230
+
231
+ ### 2. Wrap and Run within Server Middleware (e.g., Fastify / Hono)
232
+
233
+ \`\`\`typescript
234
+ import 'dotenv/config'
235
+ import { ContainerUtils } from '@xeno-js/core'
236
+ import fastify from 'fastify'
237
+ import { bootstrap } from './bootstrap'
238
+
239
+ async function runDemo() {
240
+ console.log('⚙️ Initialized Xeno Container...')
241
+ try {
242
+ // 1. Bootstrap the application and get the service container
243
+ const xenoApp = await bootstrap.build()
244
+
245
+ console.log('🚀 Starting Fastify server on http://localhost:3000...')
246
+
247
+ // 2. Resolve the middleware from the container
248
+ const middleware = xeno.resolve('MIDDLEWARE')
249
+ // 3. Create a Fastify instance to handle HTTP requests
250
+ const app = fastify()
251
+
252
+ // ─── ENDPOINT 2: QUERY ────────────────────────────────────────────
253
+ app.get('/api/user/:id', async (request, reply) => {
254
+ // 4. Execute the middleware to handle the request context and authentication, then call the StatusController's handle method with the request payload.
255
+ const responseDto = await middleware.execute(
256
+ { path: '/api/user/:id', method: 'GET', transport: { res: reply, req: request } },
257
+ { ...request.headers },
258
+ async () => {
259
+ const { id } = request.params as any
260
+ const controller = ContainerUtils.resolveServiceScoped('FIND_USER_CONTROLLER_TOKEN', xenoApp)
261
+ return await controller.handle({ id: id ?? '123' });
262
+ }
263
+ );
264
+
265
+ return reply
266
+ .status(responseDto.status)
267
+ .type('application/json')
268
+ .send(responseDto.data)
269
+ })
270
+
271
+ console.log('✅ Routes set up. Ready to accept requests.')
272
+
273
+ // ─── START SERVER ─────────────────────────────────────────────────
274
+ try {
275
+ await app.listen({ port: 3000 })
276
+ console.log('🚀 Application running on http://localhost:3000')
277
+ console.log('👉 GET /api/user/:id (GET: api/user/1)')
278
+ } catch (err) {
279
+ console.error('Error starting Fastify server:', err)
280
+ app.log.error(err)
281
+ process.exit(1)
282
+ }
283
+ } catch (error) {
284
+ console.error('Error during bootstrap or server setup:', error)
285
+ process.exit(1)
286
+ }
287
+ }
288
+
289
+ runDemo()
290
+ \`\`\`
291
+
292
+ ---
293
+
294
+ ## 🛠 Scaffold your project with CLI
295
+
296
+ Xeno includes an official CLI tool, \`@xeno-js/cli\`, designed to bootstrap your
297
+ new application in seconds. It offers an interactive setup to select exactly the
298
+ modules you need (Database, HTTP, Auth, Logging, etc.), ensuring you start with
299
+ a clean, pre-configured architecture tailored to your specific requirements.
300
+
301
+ If you want to learn how to use it, see the full options available, or
302
+ understand how the scaffolding engine works, check the
303
+ **[CLI Documentation](https://www.xeno-js.it/cli/overview)**.
304
+
305
+ ---
306
+
307
+ ## 🤝 For Contributors
308
+
309
+ We welcome contributions to Xeno! To maintain the highest code quality and
310
+ stability of the core framework, **direct pushes to the \`main\` and \`develop\`
311
+ branches are strictly prohibited.** Please follow this Git Flow to contribute:
312
+
313
+ 1. **Branch off from \`develop\`**: Create a new branch for your feature or
314
+ bugfix.
315
+
316
+ \`\`\`bash
317
+ git checkout develop
318
+ git pull origin develop
319
+ git checkout -b feat/your-awesome-feature
320
+ \`\`\`
321
+
322
+ 2. **Make your changes**: Write your code and ensure it passes all local checks
323
+ (linting, types, and tests).
324
+
325
+ \`\`\`bash
326
+ npm run check
327
+ \`\`\`
328
+
329
+ 3. **Commit your changes**: We enforce
330
+ [Conventional Commits](https://www.conventionalcommits.org/). Husky will
331
+ verify your commit message format.
332
+
333
+ 4. **Commit Format:**
334
+
335
+ \`\`\`bash
336
+ feat(scope): add new feature
337
+ fix(scope): resolve bug
338
+ chore(scope): update dependencies
339
+ \`\`\`
340
+
341
+ 5. **Submit a Pull Request (PR)**: Push your branch to GitHub and open a Pull
342
+ Request targeting the **\`develop\`** branch.
343
+
344
+ 6. **Review**: The repository owner will review your code, run pipeline tests,
345
+ and merge it into \`develop\`.
346
+
347
+ _Note: The \`main\` branch is strictly reserved for production releases. Code
348
+ flows from feature branches ➡️ \`develop\` ➡️ \`main\`._
349
+
350
+ ### Scripts
351
+
352
+ | Command | Description |
353
+ | ----------------------- | ---------------------------------------------- |
354
+ | \`npm run build\` | Builds the TypeScript source code into \`dist/\` |
355
+ | \`npm run typecheck\` | Checks types without emitting files |
356
+ | \`npm run lint\` | Runs ESLint |
357
+ | \`npm run format\` | Formats code with Prettier |
358
+ | \`npm run test\` | Runs the Vitest test suite |
359
+ | \`npm run test:coverage\` | Runs tests and generates a coverage report |
360
+
361
+ ### Code Quality (Husky & Git Hooks)
362
+
363
+ This project strictly enforces code quality rules before pushing to the
364
+ repository:
365
+
366
+ - **\`pre-commit\`**: Runs \`lint-staged\` on staged files (ESLint + Prettier).
367
+ - **\`commit-msg\`**: Checks commit messages with \`commitlint\` (we use
368
+ Conventional Commits).
369
+ - **\`pre-push\`**: Runs type checking, linting, and testing before code leaves
370
+ your machine.
371
+
372
+ ---
373
+
374
+ ## 🌱 Support & Appreciation
375
+
376
+ Building, benchmarking, and maintaining a progressive, enterprise-ready
377
+ open-source framework requires a massive amount of continuous dedication and
378
+ architectural engineering.
379
+
380
+ If Xeno has brought value to your development workflows, helped decouple your
381
+ core business logic, or simplified your system infrastructure layout, consider
382
+ supporting its open-source lifecycle. Your backing directly accelerates our
383
+ strategic roadmap for new out-of-the-box transport integrations (such as gRPC,
384
+ RabbitMQ, and GraphQL) and keeps the documentation pristine.
385
+
386
+ **Want to know how you can contribute or sponsor Xeno?** We rely on the
387
+ commitment of our community to keep the project independent and thriving.
388
+ Whether you are an individual developer or a business using Xeno, your support
389
+ makes a real difference.
390
+
391
+ 👉
392
+ **[Read our support guidelines and find out how to help](https://www.xeno-js.it/support-us)**
393
+
394
+ Thank you for being part of this decoupled open-source journey!
395
+
396
+ <amp-bounce>
397
+ </amp-bounce>
398
+ <a href="https://www.buymeacoffee.com/xenojs" target="_blank">
399
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="42" style="height: 42px !important;" />
400
+ </a>
401
+
402
+ ---
403
+
404
+ ## 🛡️ Powered by Xeno
405
+
406
+ If you are using Xeno in your project, let the world know! Add this badge to
407
+ your README:
408
+
409
+ \`\`\`html
410
+ <a
411
+ href="[https://github.com/Mattia-Carcione/xeno-js](https://github.com/Mattia-Carcione/xeno-js)"
412
+ target="_blank"
413
+ >
414
+ <img
415
+ src="[https://img.shields.io/badge/Powered%20by-Xeno-black?style=flat-square](https://img.shields.io/badge/Powered%20by-Xeno-black?style=flat-square)"
416
+ alt="Powered by Xeno"
417
+ height="20"
418
+ />
419
+ </a>
420
+ \`\`\`
421
+
422
+ ## 📄 License
423
+
424
+ Copyright (c) 2026 Xeno. Licensed under the [ISC License](LICENSE).
425
+
426
+ `;
427
+ const filePath = node_path_1.default.join(projectPath, 'readme');
428
+ await this._fileService.writeFileRecursive(filePath, content);
429
+ }
430
+ }
431
+ exports.ReadmeGenerator = ReadmeGenerator;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RegistryGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const shared_1 = require("../../shared");
9
+ class RegistryGenerator {
10
+ _fileService;
11
+ constructor(_fileService) {
12
+ this._fileService = _fileService;
13
+ }
14
+ async generate(projectPath, options) {
15
+ let dbImport = '';
16
+ let registryType = '';
17
+ if (options.database !== shared_1.CORE_CONSTANTS.NONE) {
18
+ if (options.database === shared_1.CORE_CONSTANTS.DRIZZLE) {
19
+ dbImport = `import type { DbSchema } from './schema';`;
20
+ registryType = `XenoRegistry<DbSchema>`;
21
+ }
22
+ else if (options.database === shared_1.CORE_CONSTANTS.SQL_LITE) {
23
+ dbImport = `import type { SqliteSchema } from './schema';`;
24
+ registryType = `XenoRegistry<SqliteSchema>`;
25
+ }
26
+ }
27
+ else {
28
+ registryType = `XenoRegistry`;
29
+ }
30
+ const content = `import type { XenoRegistry } from '@xeno-js/core';
31
+ ${dbImport}
32
+
33
+ /**
34
+ * @file registry.ts
35
+ * @description Centralized Type Contract for Dependency Injection.
36
+ */
37
+ export interface MyRegistry extends ${registryType} {
38
+ // Add your application injection tokens here
39
+ // e.g., USER_REPOSITORY: IUserRepository;
40
+ }
41
+ `;
42
+ const filePath = node_path_1.default.join(projectPath, 'src', 'registry.ts');
43
+ await this._fileService.writeFileRecursive(filePath, content);
44
+ }
45
+ }
46
+ exports.RegistryGenerator = RegistryGenerator;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TsconfigVueGenerator = void 0;
7
+ // src/infrastructure/generators/tsconfig-vue.generator.ts
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ class TsconfigVueGenerator {
10
+ _fileService;
11
+ constructor(_fileService) {
12
+ this._fileService = _fileService;
13
+ }
14
+ async generate(projectPath, _options) {
15
+ const tsconfig = {
16
+ compilerOptions: {
17
+ target: 'ES2022',
18
+ useDefineForClassFields: true,
19
+ module: 'ESNext',
20
+ moduleResolution: 'bundler',
21
+ strict: true,
22
+ jsx: 'preserve',
23
+ resolveJsonModule: true,
24
+ isolatedModules: true,
25
+ esModuleInterop: true,
26
+ lib: ['ES2022', 'DOM', 'DOM.Iterable'],
27
+ skipLibCheck: true,
28
+ noEmit: true,
29
+ types: ['vite/client'],
30
+ paths: {
31
+ '@/*': ['./src/*'],
32
+ },
33
+ },
34
+ include: ['src/**/*.ts', 'src/**/*.d.ts', 'src/**/*.tsx', 'src/**/*.vue'],
35
+ };
36
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
37
+ }
38
+ }
39
+ exports.TsconfigVueGenerator = TsconfigVueGenerator;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TsconfigGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const shared_1 = require("../../shared");
9
+ class TsconfigGenerator {
10
+ _fileService;
11
+ constructor(_fileService) {
12
+ this._fileService = _fileService;
13
+ }
14
+ async generate(projectPath, options) {
15
+ const tsconfig = {
16
+ compilerOptions: {
17
+ target: 'ES2022',
18
+ module: 'ESNext',
19
+ moduleResolution: 'bundler',
20
+ strict: true,
21
+ esModuleInterop: true,
22
+ skipLibCheck: true,
23
+ forceConsistentCasingInFileNames: true,
24
+ outDir: './dist',
25
+ rootDir: './src',
26
+ types: ['node'],
27
+ paths: {
28
+ '@/*': ['./src/*'],
29
+ },
30
+ },
31
+ include: ['src/**/*.ts'],
32
+ };
33
+ if (options.database === shared_1.CORE_CONSTANTS.DRIZZLE ||
34
+ options.database === shared_1.CORE_CONSTANTS.SQL_LITE) {
35
+ tsconfig.include.push('drizzle.config.ts');
36
+ }
37
+ const filePath = node_path_1.default.join(projectPath, 'tsconfig.json');
38
+ await this._fileService.writeFileRecursive(filePath, JSON.stringify(tsconfig, null, 2));
39
+ }
40
+ }
41
+ exports.TsconfigGenerator = TsconfigGenerator;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ViteconfigGenerator = void 0;
7
+ // src/infrastructure/generators/viteconfig.generator.ts
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ class ViteconfigGenerator {
10
+ _fileService;
11
+ constructor(_fileService) {
12
+ this._fileService = _fileService;
13
+ }
14
+ async generate(projectPath, options) {
15
+ const tailwindImport = options.tailwind ? `\nimport tailwindcss from '@tailwindcss/vite';` : '';
16
+ const tailwindPlugin = options.tailwind ? `\n tailwindcss(),` : '';
17
+ const content = `import { defineConfig } from 'vite';
18
+ import vue from '@vitejs/plugin-vue';${tailwindImport}
19
+ import path from 'node:path';
20
+
21
+ export default defineConfig({
22
+ plugins: [
23
+ vue(),${tailwindPlugin}
24
+ ],
25
+ resolve: {
26
+ alias: {
27
+ '@': path.resolve(__dirname, './src'),
28
+ },
29
+ },
30
+ server: {
31
+ port: 5173,
32
+ }
33
+ });
34
+ `;
35
+ const filePath = node_path_1.default.join(projectPath, 'vite.config.ts');
36
+ await this._fileService.writeFileRecursive(filePath, content);
37
+ }
38
+ }
39
+ exports.ViteconfigGenerator = ViteconfigGenerator;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AppVueGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class AppVueGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(projectPath, options) {
14
+ // 2. src/App.vue
15
+ const appVue = `<script setup lang="ts">
16
+ </script>
17
+
18
+ <template>
19
+ <div id="xeno-app">
20
+ ${options.router ? '<router-view />' : '<h1>Welcome to Xeno Vue App</h1>'}
21
+ </div>
22
+ </template>`;
23
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, 'src', 'App.vue'), appVue);
24
+ }
25
+ }
26
+ exports.AppVueGenerator = AppVueGenerator;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BootstrapGenerator = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ class BootstrapGenerator {
9
+ _fileService;
10
+ constructor(_fileService) {
11
+ this._fileService = _fileService;
12
+ }
13
+ async generate(projectPath, options) {
14
+ // 4. src/bootstrap.ts
15
+ let builderNodes = ` const builder = XenoAppBuilder.create<MyRegistry>()\n .addContext(() => {})`;
16
+ if (options.supabase) {
17
+ builderNodes += `\n .addAuth((opts, config) => {
18
+ opts.url = config.getOrThrow('VITE_SUPABASE_URL');
19
+ opts.key = config.getOrThrow('VITE_SUPABASE_KEY');
20
+ })`;
21
+ }
22
+ if (options.sentry) {
23
+ builderNodes += `\n .addLogger((opts, config) => {
24
+ const env = config.get(COMMON_CONSTANTS.ENV) ?? 'development'
25
+ const isDev = env.toLowerCase() === 'development'
26
+ opts.console = isDev
27
+ if (!isDev) {
28
+ opts.sentry = {
29
+ dsn: config.getOrThrow('VITE_SENTRY_DSN'),
30
+ env,
31
+ app,
32
+ router,
33
+ tracesSampleRate: 0.2,
34
+ level: LOG_LEVEL.WARN,
35
+ };
36
+ }
37
+ })`;
38
+ }
39
+ else {
40
+ builderNodes += `\n .addLogger((opts, config) => {
41
+ opts.console = config.get('VITE_APP_ENV') === 'development';
42
+ })`;
43
+ }
44
+ builderNodes += `\n .addServices((config, register) => {
45
+ // Register custom stores, API clients, and CQRS services here
46
+ })`;
47
+ const bootstrapTs = `import { XenoAppBuilder, LOG_LEVEL } from '@xeno-js/vue';
48
+ import type { MyRegistry } from './registry';
49
+
50
+ export async function bootstrap(app: any, router: any) {
51
+ ${builderNodes}
52
+
53
+ return await builder.build();
54
+ }
55
+ `;
56
+ await this._fileService.writeFileRecursive(node_path_1.default.join(projectPath, 'src', 'bootstrap.ts'), bootstrapTs);
57
+ }
58
+ }
59
+ exports.BootstrapGenerator = BootstrapGenerator;