@reldens/cms 0.85.0 → 0.86.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.
@@ -1,225 +1,225 @@
1
- # Advanced Installation Guide
2
-
3
- ## Subprocess Installation Handling
4
-
5
- The installer supports complex operations through subprocess management:
6
-
7
- ```javascript
8
- const { Installer } = require('@reldens/cms');
9
- const { Logger } = require('@reldens/utils');
10
-
11
- let installer = new Installer({
12
- projectRoot: process.cwd(),
13
- subprocessMaxAttempts: 1800,
14
- postInstallCallback: async (props) => {
15
- Logger.info('Entities loaded: '+Object.keys(props.loadedEntities.rawRegisteredEntities).length);
16
- return true;
17
- }
18
- });
19
- ```
20
-
21
- **The installer automatically handles:**
22
-
23
- - Package dependency checking and installation
24
- - Database schema creation via subprocess
25
- - Prisma client generation with progress tracking
26
- - Entity generation with validation
27
- - Environment file creation
28
- - Directory structure setup
29
-
30
- ## Enhanced Manager Initialization
31
-
32
- The Manager class provides comprehensive service initialization:
33
-
34
- ```javascript
35
- let cms = new Manager({
36
- app: customExpressApp,
37
- appServer: customAppServer,
38
- dataServer: customDataServer,
39
- adminManager: customAdmin,
40
- frontend: customFrontend,
41
- adminRoleId: 99,
42
- authenticationMethod: 'db-users',
43
- authenticationCallback: async (email, password, roleId) => {
44
- return await yourAuthService.validate(email, password, roleId);
45
- },
46
- cache: true,
47
- reloadTime: -1,
48
- defaultDomain: 'example.com',
49
- domainMapping: {'dev.example.com': 'development'},
50
- siteKeyMapping: {'example.com': 'main'}
51
- });
52
- ```
53
-
54
- **Manager automatically:**
55
-
56
- - Validates all provided instances
57
- - Initializes missing services
58
- - Auto-creates `PrismaClient` via `PrismaClientLoader` from `@reldens/storage` when `RELDENS_STORAGE_DRIVER=prisma` and no `prismaClient` is passed in — no Prisma imports needed in your entry point
59
- - Sets up entity access control
60
- - Generates admin entities
61
- - Configures template reloading
62
-
63
- ## Development Mode Detection
64
-
65
- The CMS automatically detects development environments based on domain patterns.
66
-
67
- **Default Development Patterns:**
68
-
69
- ```javascript
70
- let patterns = [
71
- 'localhost',
72
- '127.0.0.1',
73
- '.local',
74
- '.test',
75
- '.dev',
76
- '.acc',
77
- '.staging',
78
- 'local.',
79
- 'test.',
80
- 'dev.',
81
- 'acc.',
82
- 'staging.'
83
- ];
84
- ```
85
-
86
- **Override Development Patterns:**
87
-
88
- ```javascript
89
- let cms = new Manager({
90
- developmentPatterns: [
91
- 'localhost',
92
- '127.0.0.1',
93
- '.local'
94
- ],
95
- domainMapping: {
96
- 'www.example.com': 'example.com',
97
- 'new.example.com': 'example.com'
98
- }
99
- });
100
- ```
101
-
102
- **Important Notes:**
103
-
104
- - Domain patterns only match at the start or end of domains, not arbitrary positions
105
- - Override `developmentPatterns` in production to prevent staging/acc domains from enabling development mode
106
-
107
- ## Security Configuration
108
-
109
- ### External Domains for CSP
110
-
111
- Configure external domains for CSP directives (kebab-case or camelCase):
112
-
113
- ```javascript
114
- let cms = new Manager({
115
- appServerConfig: {
116
- developmentExternalDomains: {
117
- 'scriptSrc': ['https://cdn.example.com'],
118
- 'script-src': ['https://analytics.example.com'],
119
- 'styleSrc': ['https://fonts.googleapis.com'],
120
- 'font-src': ['https://fonts.gstatic.com']
121
- }
122
- }
123
- });
124
- ```
125
-
126
- **The system automatically:**
127
-
128
- - Converts kebab-case keys to camelCase
129
- - Adds domains to both the base directive and the -elem variant
130
-
131
- ### CSP Directive Merging vs Override
132
-
133
- **Default (merge with base directives):**
134
-
135
- ```javascript
136
- let cms = new Manager({
137
- appServerConfig: {
138
- helmetConfig: {
139
- contentSecurityPolicy: {
140
- directives: {
141
- scriptSrc: ['https://cdn.example.com']
142
- }
143
- }
144
- }
145
- }
146
- });
147
- ```
148
-
149
- **Default Base Directives:**
150
-
151
- ```javascript
152
- {
153
- defaultSrc: ["'self'"],
154
- scriptSrc: ["'self'"],
155
- scriptSrcElem: ["'self'"],
156
- styleSrc: ["'self'", "'unsafe-inline'"],
157
- styleSrcElem: ["'self'", "'unsafe-inline'"],
158
- imgSrc: ["'self'", "data:", "https:"],
159
- fontSrc: ["'self'"],
160
- connectSrc: ["'self'"],
161
- frameAncestors: ["'none'"],
162
- baseUri: ["'self'"],
163
- formAction: ["'self'"]
164
- }
165
- ```
166
-
167
- **Complete Replacement:**
168
-
169
- ```javascript
170
- let cms = new Manager({
171
- appServerConfig: {
172
- helmetConfig: {
173
- contentSecurityPolicy: {
174
- overrideDirectives: true,
175
- directives: {
176
- defaultSrc: ["'self'"],
177
- scriptSrc: ["'self'", "https://trusted-cdn.com"],
178
- styleSrc: ["'self'", "'unsafe-inline'"],
179
- imgSrc: ["'self'", "data:", "https:"],
180
- fontSrc: ["'self'"],
181
- connectSrc: ["'self'"],
182
- frameAncestors: ["'none'"],
183
- baseUri: ["'self'"],
184
- formAction: ["'self'"]
185
- }
186
- }
187
- }
188
- }
189
- });
190
- ```
191
-
192
- ### Additional Helmet Security Headers
193
-
194
- ```javascript
195
- let cms = new Manager({
196
- appServerConfig: {
197
- helmetConfig: {
198
- hsts: {
199
- maxAge: 31536000,
200
- includeSubDomains: true,
201
- preload: true
202
- },
203
- crossOriginOpenerPolicy: {
204
- policy: "same-origin"
205
- },
206
- crossOriginResourcePolicy: {
207
- policy: "same-origin"
208
- },
209
- crossOriginEmbedderPolicy: {
210
- policy: "require-corp"
211
- }
212
- }
213
- }
214
- });
215
- ```
216
-
217
- **Note:** In development mode, CSP and HSTS are automatically disabled. Security headers are only enforced in production.
218
-
219
- **Trusted Types:** To enable Trusted Types for enhanced XSS protection:
220
-
221
- ```javascript
222
- requireTrustedTypesFor: ["'script'"]
223
- ```
224
-
225
- However, this requires updating all JavaScript code to use the Trusted Types API.
1
+ # Advanced Installation Guide
2
+
3
+ ## Subprocess Installation Handling
4
+
5
+ The installer supports complex operations through subprocess management:
6
+
7
+ ```javascript
8
+ const { Installer } = require('@reldens/cms');
9
+ const { Logger } = require('@reldens/utils');
10
+
11
+ let installer = new Installer({
12
+ projectRoot: process.cwd(),
13
+ subprocessMaxAttempts: 1800,
14
+ postInstallCallback: async (props) => {
15
+ Logger.info('Entities loaded: '+Object.keys(props.loadedEntities.rawRegisteredEntities).length);
16
+ return true;
17
+ }
18
+ });
19
+ ```
20
+
21
+ **The installer automatically handles:**
22
+
23
+ - Package dependency checking and installation
24
+ - Database schema creation via subprocess
25
+ - Prisma client generation with progress tracking
26
+ - Entity generation with validation
27
+ - Environment file creation
28
+ - Directory structure setup
29
+
30
+ ## Enhanced Manager Initialization
31
+
32
+ The Manager class provides comprehensive service initialization:
33
+
34
+ ```javascript
35
+ let cms = new Manager({
36
+ app: customExpressApp,
37
+ appServer: customAppServer,
38
+ dataServer: customDataServer,
39
+ adminManager: customAdmin,
40
+ frontend: customFrontend,
41
+ adminRoleId: 99,
42
+ authenticationMethod: 'db-users',
43
+ authenticationCallback: async (email, password, roleId) => {
44
+ return await yourAuthService.validate(email, password, roleId);
45
+ },
46
+ cache: true,
47
+ reloadTime: -1,
48
+ defaultDomain: 'example.com',
49
+ domainMapping: {'dev.example.com': 'development'},
50
+ siteKeyMapping: {'example.com': 'main'}
51
+ });
52
+ ```
53
+
54
+ **Manager automatically:**
55
+
56
+ - Validates all provided instances
57
+ - Initializes missing services
58
+ - Auto-loads the Prisma modules via `PrismaClientLoader` from `@reldens/storage` when `RELDENS_STORAGE_DRIVER=prisma` and no `prismaModules` is passed in, resolving the adapter from `prismaAdapter` / `prismaAdapterClass` props (defaults from `RELDENS_PRISMA_ADAPTER` / `RELDENS_PRISMA_ADAPTER_CLASS`) — no Prisma imports needed in your entry point
59
+ - Sets up entity access control
60
+ - Generates admin entities
61
+ - Configures template reloading
62
+
63
+ ## Development Mode Detection
64
+
65
+ The CMS automatically detects development environments based on domain patterns.
66
+
67
+ **Default Development Patterns:**
68
+
69
+ ```javascript
70
+ let patterns = [
71
+ 'localhost',
72
+ '127.0.0.1',
73
+ '.local',
74
+ '.test',
75
+ '.dev',
76
+ '.acc',
77
+ '.staging',
78
+ 'local.',
79
+ 'test.',
80
+ 'dev.',
81
+ 'acc.',
82
+ 'staging.'
83
+ ];
84
+ ```
85
+
86
+ **Override Development Patterns:**
87
+
88
+ ```javascript
89
+ let cms = new Manager({
90
+ developmentPatterns: [
91
+ 'localhost',
92
+ '127.0.0.1',
93
+ '.local'
94
+ ],
95
+ domainMapping: {
96
+ 'www.example.com': 'example.com',
97
+ 'new.example.com': 'example.com'
98
+ }
99
+ });
100
+ ```
101
+
102
+ **Important Notes:**
103
+
104
+ - Domain patterns only match at the start or end of domains, not arbitrary positions
105
+ - Override `developmentPatterns` in production to prevent staging/acc domains from enabling development mode
106
+
107
+ ## Security Configuration
108
+
109
+ ### External Domains for CSP
110
+
111
+ Configure external domains for CSP directives (kebab-case or camelCase):
112
+
113
+ ```javascript
114
+ let cms = new Manager({
115
+ appServerConfig: {
116
+ developmentExternalDomains: {
117
+ 'scriptSrc': ['https://cdn.example.com'],
118
+ 'script-src': ['https://analytics.example.com'],
119
+ 'styleSrc': ['https://fonts.googleapis.com'],
120
+ 'font-src': ['https://fonts.gstatic.com']
121
+ }
122
+ }
123
+ });
124
+ ```
125
+
126
+ **The system automatically:**
127
+
128
+ - Converts kebab-case keys to camelCase
129
+ - Adds domains to both the base directive and the -elem variant
130
+
131
+ ### CSP Directive Merging vs Override
132
+
133
+ **Default (merge with base directives):**
134
+
135
+ ```javascript
136
+ let cms = new Manager({
137
+ appServerConfig: {
138
+ helmetConfig: {
139
+ contentSecurityPolicy: {
140
+ directives: {
141
+ scriptSrc: ['https://cdn.example.com']
142
+ }
143
+ }
144
+ }
145
+ }
146
+ });
147
+ ```
148
+
149
+ **Default Base Directives:**
150
+
151
+ ```javascript
152
+ {
153
+ defaultSrc: ["'self'"],
154
+ scriptSrc: ["'self'"],
155
+ scriptSrcElem: ["'self'"],
156
+ styleSrc: ["'self'", "'unsafe-inline'"],
157
+ styleSrcElem: ["'self'", "'unsafe-inline'"],
158
+ imgSrc: ["'self'", "data:", "https:"],
159
+ fontSrc: ["'self'"],
160
+ connectSrc: ["'self'"],
161
+ frameAncestors: ["'none'"],
162
+ baseUri: ["'self'"],
163
+ formAction: ["'self'"]
164
+ }
165
+ ```
166
+
167
+ **Complete Replacement:**
168
+
169
+ ```javascript
170
+ let cms = new Manager({
171
+ appServerConfig: {
172
+ helmetConfig: {
173
+ contentSecurityPolicy: {
174
+ overrideDirectives: true,
175
+ directives: {
176
+ defaultSrc: ["'self'"],
177
+ scriptSrc: ["'self'", "https://trusted-cdn.com"],
178
+ styleSrc: ["'self'", "'unsafe-inline'"],
179
+ imgSrc: ["'self'", "data:", "https:"],
180
+ fontSrc: ["'self'"],
181
+ connectSrc: ["'self'"],
182
+ frameAncestors: ["'none'"],
183
+ baseUri: ["'self'"],
184
+ formAction: ["'self'"]
185
+ }
186
+ }
187
+ }
188
+ }
189
+ });
190
+ ```
191
+
192
+ ### Additional Helmet Security Headers
193
+
194
+ ```javascript
195
+ let cms = new Manager({
196
+ appServerConfig: {
197
+ helmetConfig: {
198
+ hsts: {
199
+ maxAge: 31536000,
200
+ includeSubDomains: true,
201
+ preload: true
202
+ },
203
+ crossOriginOpenerPolicy: {
204
+ policy: "same-origin"
205
+ },
206
+ crossOriginResourcePolicy: {
207
+ policy: "same-origin"
208
+ },
209
+ crossOriginEmbedderPolicy: {
210
+ policy: "require-corp"
211
+ }
212
+ }
213
+ }
214
+ });
215
+ ```
216
+
217
+ **Note:** In development mode, CSP and HSTS are automatically disabled. Security headers are only enforced in production.
218
+
219
+ **Trusted Types:** To enable Trusted Types for enhanced XSS protection:
220
+
221
+ ```javascript
222
+ requireTrustedTypesFor: ["'script'"]
223
+ ```
224
+
225
+ However, this requires updating all JavaScript code to use the Trusted Types API.
@@ -102,9 +102,9 @@ npx reldens-cms-update-password --email=admin@example.com --password=newPassword
102
102
  #### How It Works
103
103
 
104
104
  The CLI tool is **driver-agnostic** and works with any storage driver:
105
- 1. Reads `RELDENS_STORAGE_DRIVER` from .env (defaults to 'prisma')
105
+ 1. Reads `RELDENS_STORAGE_DRIVER` from .env (defaults to 'mikro-orm')
106
106
  2. Uses `EntitiesLoader` to load entities for the detected driver
107
- 3. If driver is 'prisma', automatically loads Prisma client from `./prisma/client`
107
+ 3. If driver is 'prisma', automatically loads the Prisma modules from `./prisma/client` using the adapter from `RELDENS_PRISMA_ADAPTER` / `RELDENS_PRISMA_ADAPTER_CLASS`
108
108
  4. Initializes Manager and dataServer with the correct driver
109
109
  5. Updates password using the driver's entity repository
110
110
 
package/CLAUDE.md CHANGED
@@ -99,7 +99,7 @@ RELDENS_APP_PORT=8080
99
99
  RELDENS_ADMIN_ROUTE_PATH=/admin
100
100
  RELDENS_ADMIN_SECRET=your-secret-key
101
101
  RELDENS_DB_CLIENT=mysql
102
- RELDENS_STORAGE_DRIVER=prisma
102
+ RELDENS_STORAGE_DRIVER=mikro-orm
103
103
  ```
104
104
 
105
105
  **Manager Configuration:**
package/README.md CHANGED
@@ -45,7 +45,7 @@ A powerful, flexible Content Management System built with Node.js, featuring an
45
45
  - **Template-driven UI** with customizable admin themes
46
46
 
47
47
  ### -️ Database & Entities
48
- - **Multiple database drivers** (Prisma by default, others via DriversMap)
48
+ - **Multiple database drivers** (MikroORM by default, others via DriversMap)
49
49
  - **Automatic entity generation** from a database schema
50
50
  - **Relationship mapping** and foreign key handling
51
51
  - **Custom entity configuration** with validation rules
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  *
@@ -7,8 +7,11 @@
7
7
  */
8
8
 
9
9
  const { Manager } = require('../index');
10
- const { PrismaClientLoader } = require('@reldens/storage');
10
+ const { ManagerConfigLoader } = require('../lib/manager-config-loader');
11
+ const { ManagerServicesInitializer } = require('../lib/manager-services-initializer');
11
12
  const { Logger, sc } = require('@reldens/utils');
13
+ const { FileHandler } = require('@reldens/server-utils');
14
+ const dotenv = require('dotenv');
12
15
  const readline = require('readline');
13
16
 
14
17
  class CmsEntitiesGenerator
@@ -58,7 +61,7 @@ class CmsEntitiesGenerator
58
61
  Logger.info('');
59
62
  Logger.info('Options:');
60
63
  Logger.info(' --prisma-client=[path] Path to Prisma client (e.g., ./prisma/client)');
61
- Logger.info(' --driver=[driver] Storage driver (default: prisma)');
64
+ Logger.info(' --driver=[driver] Storage driver (default: mikro-orm)');
62
65
  Logger.info(' --override Force regeneration and overwrite existing files');
63
66
  Logger.info(' --dry-prisma Skip Prisma schema generation');
64
67
  Logger.info(' --help, -h Show this help message');
@@ -87,7 +90,7 @@ class CmsEntitiesGenerator
87
90
 
88
91
  get driver()
89
92
  {
90
- return sc.get(this.config, 'driver', process.env.RELDENS_STORAGE_DRIVER || 'prisma');
93
+ return sc.get(this.config, 'driver', process.env.RELDENS_STORAGE_DRIVER || 'mikro-orm');
91
94
  }
92
95
 
93
96
  async run()
@@ -107,10 +110,18 @@ class CmsEntitiesGenerator
107
110
  Logger.info('Running in dry-prisma mode - skipping Prisma schema generation.');
108
111
  }
109
112
  let managerConfig = {projectRoot: this.projectRoot};
113
+ dotenv.config({path: FileHandler.joinPaths(this.projectRoot, '.env')});
110
114
  if('prisma' === this.driver){
111
- let prismaClient = PrismaClientLoader.load(this.projectRoot, this.prismaClientPath, null);
112
- if(prismaClient){
113
- managerConfig.prismaClient = prismaClient;
115
+ let databaseConfig = ManagerConfigLoader.loadFromEnv().database;
116
+ let prismaModules = ManagerServicesInitializer.loadPrismaModules(
117
+ this.projectRoot,
118
+ this.prismaClientPath,
119
+ null,
120
+ databaseConfig.prismaAdapter,
121
+ databaseConfig.prismaAdapterClass
122
+ );
123
+ if(prismaModules){
124
+ managerConfig.prismaModules = prismaModules;
114
125
  }
115
126
  }
116
127
  let manager = new Manager(managerConfig);
@@ -119,7 +130,7 @@ class CmsEntitiesGenerator
119
130
  return false;
120
131
  }
121
132
  Logger.debug('Reldens CMS Manager instance created for entities generation.');
122
- await manager.initializeDataServer();
133
+ await manager.servicesInitializer.initializeDataServer();
123
134
  let success = await manager.installer.generateEntities(
124
135
  manager.dataServer,
125
136
  this.isOverride,
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  *
@@ -8,7 +8,8 @@
8
8
 
9
9
  const { Manager } = require('../index');
10
10
  const { EntitiesLoader } = require('../lib/entities-loader');
11
- const { PrismaClientLoader } = require('@reldens/storage');
11
+ const { ManagerConfigLoader } = require('../lib/manager-config-loader');
12
+ const { ManagerServicesInitializer } = require('../lib/manager-services-initializer');
12
13
  const { Logger, sc } = require('@reldens/utils');
13
14
  const { FileHandler, Encryptor } = require('@reldens/server-utils');
14
15
  const dotenv = require('dotenv');
@@ -111,7 +112,8 @@ class CmsPasswordUpdater
111
112
  }
112
113
  let envFilePath = FileHandler.joinPaths(this.projectRoot, '.env');
113
114
  dotenv.config({path: envFilePath});
114
- let storageDriver = process.env.RELDENS_STORAGE_DRIVER || 'prisma';
115
+ let databaseConfig = ManagerConfigLoader.loadFromEnv().database;
116
+ let storageDriver = databaseConfig.driver;
115
117
  Logger.debug('Using storage driver: '+storageDriver);
116
118
  let entitiesLoader = new EntitiesLoader({projectRoot: this.projectRoot});
117
119
  let loadedEntities = entitiesLoader.loadEntities(storageDriver);
@@ -128,10 +130,16 @@ class CmsPasswordUpdater
128
130
  entitiesTranslations: loadedEntities.entitiesTranslations
129
131
  };
130
132
  if('prisma' === storageDriver){
131
- let prismaClient = PrismaClientLoader.load(this.projectRoot, null, null);
132
- if(prismaClient){
133
- managerConfig.prismaClient = prismaClient;
134
- Logger.debug('Prisma client loaded and configured.');
133
+ let prismaModules = ManagerServicesInitializer.loadPrismaModules(
134
+ this.projectRoot,
135
+ null,
136
+ null,
137
+ databaseConfig.prismaAdapter,
138
+ databaseConfig.prismaAdapterClass
139
+ );
140
+ if(prismaModules){
141
+ managerConfig.prismaModules = prismaModules;
142
+ Logger.debug('Prisma modules loaded and configured.');
135
143
  }
136
144
  }
137
145
  let manager = new Manager(managerConfig);
@@ -140,7 +148,7 @@ class CmsPasswordUpdater
140
148
  return false;
141
149
  }
142
150
  Logger.debug('Reldens CMS Manager instance created for password update.');
143
- let initResult = await manager.initializeDataServer();
151
+ let initResult = await manager.servicesInitializer.initializeDataServer();
144
152
  if(!initResult){
145
153
  Logger.error('Failed to initialize data server.');
146
154
  return false;