@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.
- package/.github/.copilot-instruction.md +73 -0
- package/.github/agents/git-operator.agent.md +86 -0
- package/.github/agents/unit-tester.agent.md +68 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +1 -0
- package/.prettierignore +7 -0
- package/.prettierrc.json +37 -0
- package/LICENSE +15 -0
- package/README.md +236 -0
- package/commitlint.config.cjs +39 -0
- package/dist/domain/contracts/icommand-cli.contracts.js +2 -0
- package/dist/domain/contracts/icommand-runner.contracts.js +2 -0
- package/dist/domain/contracts/idispatch.contracts.js +2 -0
- package/dist/domain/contracts/ifile-service.contracts.js +2 -0
- package/dist/domain/contracts/igenerator.contracts.js +2 -0
- package/dist/domain/contracts/index.js +2 -0
- package/dist/domain/contracts/iscaffold-strategy.contracts.js +2 -0
- package/dist/domain/index.js +2 -0
- package/dist/generator.contracts.js +13 -0
- package/dist/index.js +31 -0
- package/dist/infrastructure/bootstrap/bootstrapper.js +32 -0
- package/dist/infrastructure/bootstrap/index.js +17 -0
- package/dist/infrastructure/builder/builder.js +16 -0
- package/dist/infrastructure/builder/builder.test.js +30 -0
- package/dist/infrastructure/builder/index.js +17 -0
- package/dist/infrastructure/command_launcher/command.utils.js +30 -0
- package/dist/infrastructure/command_launcher/index.js +2 -0
- package/dist/infrastructure/commands/command-runner.service.js +36 -0
- package/dist/infrastructure/commands/generate.command.js +48 -0
- package/dist/infrastructure/commands/help.command.js +44 -0
- package/dist/infrastructure/commands/index.js +20 -0
- package/dist/infrastructure/commands/new-project.command.js +43 -0
- package/dist/infrastructure/dispatcher/dispatcher.js +39 -0
- package/dist/infrastructure/dispatcher/index.js +17 -0
- package/dist/infrastructure/file/file.service.js +13 -0
- package/dist/infrastructure/file/index.js +17 -0
- package/dist/infrastructure/generators/bootstrap.generator.js +118 -0
- package/dist/infrastructure/generators/core/bootstrap.generator.js +118 -0
- package/dist/infrastructure/generators/core/command/cqrs.generator.js +49 -0
- package/dist/infrastructure/generators/core/command/generate-command.generator.js +163 -0
- package/dist/infrastructure/generators/core/command/generate-query.generator.js +131 -0
- package/dist/infrastructure/generators/core/drizzle-sql-lite.generator.js +78 -0
- package/dist/infrastructure/generators/core/drizzle.generator.js +85 -0
- package/dist/infrastructure/generators/core/env.generator.js +69 -0
- package/dist/infrastructure/generators/core/index.js +25 -0
- package/dist/infrastructure/generators/core/main.generator.js +45 -0
- package/dist/infrastructure/generators/core/packagejson.generator.js +78 -0
- package/dist/infrastructure/generators/core/readme.generator.js +431 -0
- package/dist/infrastructure/generators/core/registry.generator.js +46 -0
- package/dist/infrastructure/generators/core/tsconfig.generator.js +41 -0
- package/dist/infrastructure/generators/core-packagejson.generator.js +78 -0
- package/dist/infrastructure/generators/drizzle-sql-lite.generator.js +78 -0
- package/dist/infrastructure/generators/drizzle.generator.js +85 -0
- package/dist/infrastructure/generators/env-vue.generator.js +40 -0
- package/dist/infrastructure/generators/env.generator.js +71 -0
- package/dist/infrastructure/generators/gitignore.generator.js +62 -0
- package/dist/infrastructure/generators/index.js +26 -0
- package/dist/infrastructure/generators/main.generator.js +45 -0
- package/dist/infrastructure/generators/readme.generator.js +431 -0
- package/dist/infrastructure/generators/registry.generator.js +46 -0
- package/dist/infrastructure/generators/tsconfig-vue.generator.js +39 -0
- package/dist/infrastructure/generators/tsconfig.generator.js +41 -0
- package/dist/infrastructure/generators/vite-config.generator.js +39 -0
- package/dist/infrastructure/generators/vue/app-vue.generator.js +26 -0
- package/dist/infrastructure/generators/vue/bootstrap-ts.generator.js +59 -0
- package/dist/infrastructure/generators/vue/command_query/cqrs.generator.js +36 -0
- package/dist/infrastructure/generators/vue/command_query/generate-command-vue.generator.js +139 -0
- package/dist/infrastructure/generators/vue/command_query/generate-query-vue.generator.js +147 -0
- package/dist/infrastructure/generators/vue/env.generator.js +40 -0
- package/dist/infrastructure/generators/vue/index-html.generator.js +29 -0
- package/dist/infrastructure/generators/vue/index.js +28 -0
- package/dist/infrastructure/generators/vue/main.generator.js +45 -0
- package/dist/infrastructure/generators/vue/packagejson.generator.js +59 -0
- package/dist/infrastructure/generators/vue/readme.generator.js +394 -0
- package/dist/infrastructure/generators/vue/registry-ts.generator.js +28 -0
- package/dist/infrastructure/generators/vue/router.generator.js +33 -0
- package/dist/infrastructure/generators/vue/tailwind.generator.js +19 -0
- package/dist/infrastructure/generators/vue/tsconfig.generator.js +39 -0
- package/dist/infrastructure/generators/vue/use-app.generator.js +43 -0
- package/dist/infrastructure/generators/vue/vite-config.generator.js +39 -0
- package/dist/infrastructure/generators/vue-packagejson.generator.js +59 -0
- package/dist/infrastructure/generators/vue-readme.generator.js +53 -0
- package/dist/infrastructure/generators/vue-source-files.generator.js +136 -0
- package/dist/infrastructure/index.js +21 -0
- package/dist/infrastructure/strategies/core-scaffold.strategy.js +99 -0
- package/dist/infrastructure/strategies/index.js +18 -0
- package/dist/infrastructure/strategies/vue-scaffold.strategy.js +79 -0
- package/dist/scaffolding.engine.js +60 -0
- package/dist/shared/constants/command.constants.js +19 -0
- package/dist/shared/constants/core.constants.js +10 -0
- package/dist/shared/constants/index.js +18 -0
- package/dist/shared/index.js +18 -0
- package/dist/shared/types/common.types.js +2 -0
- package/dist/shared/types/index.js +2 -0
- package/dist/shared/utils/guards.utils.js +310 -0
- package/dist/shared/utils/index.js +18 -0
- package/dist/shared/utils/string.utils.js +62 -0
- package/eslint.config.mjs +305 -0
- package/lint-staged.config.mjs +5 -0
- package/logo/logo.png +0 -0
- package/package.json +65 -0
- package/src/domain/contracts/icommand-cli.contracts.ts +13 -0
- package/src/domain/contracts/icommand-runner.contracts.ts +3 -0
- package/src/domain/contracts/idispatch.contracts.ts +3 -0
- package/src/domain/contracts/ifile-service.contracts.ts +3 -0
- package/src/domain/contracts/igenerator.contracts.ts +5 -0
- package/src/domain/contracts/index.ts +6 -0
- package/src/domain/contracts/iscaffold-strategy.contracts.ts +7 -0
- package/src/domain/index.ts +1 -0
- package/src/index.ts +30 -0
- package/src/infrastructure/bootstrap/bootstrapper.ts +30 -0
- package/src/infrastructure/bootstrap/index.ts +1 -0
- package/src/infrastructure/builder/builder.test.ts +36 -0
- package/src/infrastructure/builder/builder.ts +15 -0
- package/src/infrastructure/builder/index.ts +1 -0
- package/src/infrastructure/command_launcher/command.utils.ts +31 -0
- package/src/infrastructure/command_launcher/index.ts +0 -0
- package/src/infrastructure/commands/command-runner.service.ts +36 -0
- package/src/infrastructure/commands/generate.command.ts +55 -0
- package/src/infrastructure/commands/help.command.ts +63 -0
- package/src/infrastructure/commands/index.ts +4 -0
- package/src/infrastructure/commands/new-project.command.ts +47 -0
- package/src/infrastructure/dispatcher/dispatcher.ts +45 -0
- package/src/infrastructure/dispatcher/index.ts +1 -0
- package/src/infrastructure/file/file.service.ts +14 -0
- package/src/infrastructure/file/index.ts +1 -0
- package/src/infrastructure/generators/core/bootstrap.generator.ts +118 -0
- package/src/infrastructure/generators/core/command/cqrs.generator.ts +63 -0
- package/src/infrastructure/generators/core/command/generate-command.generator.ts +191 -0
- package/src/infrastructure/generators/core/command/generate-query.generator.ts +150 -0
- package/src/infrastructure/generators/core/drizzle-sql-lite.generator.ts +76 -0
- package/src/infrastructure/generators/core/drizzle.generator.ts +86 -0
- package/src/infrastructure/generators/core/env.generator.ts +69 -0
- package/src/infrastructure/generators/core/index.ts +9 -0
- package/src/infrastructure/generators/core/main.generator.ts +41 -0
- package/src/infrastructure/generators/core/packagejson.generator.ts +70 -0
- package/src/infrastructure/generators/core/readme.generator.ts +427 -0
- package/src/infrastructure/generators/core/registry.generator.ts +40 -0
- package/src/infrastructure/generators/core/tsconfig.generator.ts +39 -0
- package/src/infrastructure/generators/gitignore.generator.ts +60 -0
- package/src/infrastructure/generators/vue/app-vue.generator.ts +21 -0
- package/src/infrastructure/generators/vue/bootstrap-ts.generator.ts +60 -0
- package/src/infrastructure/generators/vue/command_query/cqrs.generator.ts +36 -0
- package/src/infrastructure/generators/vue/command_query/generate-command-vue.generator.ts +153 -0
- package/src/infrastructure/generators/vue/command_query/generate-query-vue.generator.ts +161 -0
- package/src/infrastructure/generators/vue/env.generator.ts +39 -0
- package/src/infrastructure/generators/vue/index-html.generator.ts +24 -0
- package/src/infrastructure/generators/vue/index.ts +12 -0
- package/src/infrastructure/generators/vue/main.generator.ts +41 -0
- package/src/infrastructure/generators/vue/packagejson.generator.ts +50 -0
- package/src/infrastructure/generators/vue/readme.generator.ts +389 -0
- package/src/infrastructure/generators/vue/registry-ts.generator.ts +26 -0
- package/src/infrastructure/generators/vue/router.generator.ts +35 -0
- package/src/infrastructure/generators/vue/tailwind.generator.ts +17 -0
- package/src/infrastructure/generators/vue/tsconfig.generator.ts +38 -0
- package/src/infrastructure/generators/vue/use-app.generator.ts +38 -0
- package/src/infrastructure/generators/vue/vite-config.generator.ts +35 -0
- package/src/infrastructure/index.ts +5 -0
- package/src/infrastructure/strategies/core-scaffold.strategy.ts +100 -0
- package/src/infrastructure/strategies/index.ts +2 -0
- package/src/infrastructure/strategies/vue-scaffold.strategy.ts +79 -0
- package/src/shared/constants/command.constants.ts +18 -0
- package/src/shared/constants/core.constants.ts +7 -0
- package/src/shared/constants/index.ts +2 -0
- package/src/shared/index.ts +3 -0
- package/src/shared/types/common.types.ts +68 -0
- package/src/shared/types/index.ts +1 -0
- package/src/shared/utils/guards.utils.ts +334 -0
- package/src/shared/utils/index.ts +2 -0
- package/src/shared/utils/string.utils.ts +60 -0
- 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;
|