@reldens/cms 0.64.0 → 0.66.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.
@@ -4,14 +4,39 @@
4
4
 
5
5
  - `start()` - Initialize and start the CMS
6
6
  - `isInstalled()` - Check if CMS is installed
7
- - `initializeServices()` - Initialize all services
8
- - `validateProvidedServer()` - Validate provided server instance
9
- - `validateProvidedDataServer()` - Validate provided data server
10
- - `validateProvidedAdminManager()` - Validate provided admin manager
11
- - `validateProvidedFrontend()` - Validate provided frontend
12
7
  - `buildAppServerConfiguration()` - Build server configuration
8
+ - `validateCdnMappingsInDevelopment()` - Warn when CDN domains are missing from CSP directives
9
+ - `isCdnUrlInDirectives(cdnUrlWithProtocol, cdnHostname)` - Check if a CDN URL appears in any CSP directive
13
10
  - `initializeCmsAfterInstall(props)` - Post-installation callback
14
11
 
12
+ ## ManagerComponentValidator Class (lib/manager-component-validator.js)
13
+
14
+ Static validators called from the Manager constructor:
15
+
16
+ - `validateProvidedServer(app, appServer)` - Validate provided Express app and server
17
+ - `validateProvidedDataServer(dataServer)` - Validate provided data server
18
+ - `validateProvidedAdminManager(adminManager)` - Validate provided admin manager
19
+ - `validateProvidedFrontend(frontend)` - Validate provided frontend
20
+
21
+ ## ManagerConfigLoader Class (lib/manager-config-loader.js)
22
+
23
+ - `loadFromEnv()` - Build config object from `RELDENS_*` environment variables
24
+
25
+ ## ManagerServicesInitializer Class (lib/manager-services-initializer.js)
26
+
27
+ Receives the Manager instance via constructor and handles all service initialization:
28
+
29
+ - `initializeServices()` - Orchestrate full service initialization sequence
30
+ - `initializeDataServer()` - Create data server; auto-creates PrismaClient via PrismaClientLoader when driver is `prisma` and no client provided
31
+ - `setupEntityAccess()` - Sync entity access rules to database
32
+ - `loadProcessedEntities()` - Apply config overrides and process raw entities
33
+ - `generateAdminEntities()` - Generate admin panel entity definitions
34
+ - `initializeAdminManager()` - Set up admin routes and authentication
35
+ - `initializePasswordEncryptionHandler()` - Register password encryption event listeners
36
+ - `initializeCmsPagesRouteManager()` - Wire CMS page routes to the data server
37
+ - `initializeFrontend()` - Create and initialize Frontend instance
38
+ - `renderCallback(template, params)` - Render a template via the configured render engine
39
+
15
40
  ## Installer Class
16
41
 
17
42
  - `isInstalled()` - Check installation status
@@ -8,14 +8,20 @@
8
8
 
9
9
  Main CMS orchestrator that:
10
10
 
11
- - Initializes all services (data server, admin, frontend)
12
- - Handles configuration and environment variables
13
- - Manages multi-domain setup and security
14
- - Coordinates service lifecycle
15
- - Initializes password encryption handler
11
+ - Coordinates service lifecycle and startup
12
+ - Manages multi-domain setup and CDN validation
13
+ - Builds app server configuration
14
+ - Delegates service initialization to `ManagerServicesInitializer`
16
15
  - Defines default templateExtensions: `['.html', '.mustache', '.template', '.txt', '.xml', '.json']`
17
16
  - Passes templateExtensions to all frontend components ensuring consistency
18
17
 
18
+ Responsibilities are split across four files:
19
+
20
+ - `lib/manager.js` — orchestration, server config, lifecycle
21
+ - `lib/manager-component-validator.js` — static validation of provided server/dataServer/adminManager/frontend instances
22
+ - `lib/manager-config-loader.js` — static `loadFromEnv()` reading all `RELDENS_*` env vars into a config object
23
+ - `lib/manager-services-initializer.js` — data server, admin, frontend, entity and route manager initialization; auto-creates `PrismaClient` via `PrismaClientLoader` from `@reldens/storage` when driver is `prisma` and no client is provided
24
+
19
25
  ### Frontend
20
26
 
21
27
  **File:** `lib/frontend.js`
@@ -6,12 +6,13 @@ The installer supports complex operations through subprocess management:
6
6
 
7
7
  ```javascript
8
8
  const { Installer } = require('@reldens/cms');
9
+ const { Logger } = require('@reldens/utils');
9
10
 
10
- const installer = new Installer({
11
+ let installer = new Installer({
11
12
  projectRoot: process.cwd(),
12
13
  subprocessMaxAttempts: 1800,
13
14
  postInstallCallback: async (props) => {
14
- console.log('Entities loaded:', Object.keys(props.loadedEntities.rawRegisteredEntities));
15
+ Logger.info('Entities loaded: '+Object.keys(props.loadedEntities.rawRegisteredEntities).length);
15
16
  return true;
16
17
  }
17
18
  });
@@ -31,7 +32,7 @@ const installer = new Installer({
31
32
  The Manager class provides comprehensive service initialization:
32
33
 
33
34
  ```javascript
34
- const cms = new Manager({
35
+ let cms = new Manager({
35
36
  app: customExpressApp,
36
37
  appServer: customAppServer,
37
38
  dataServer: customDataServer,
@@ -54,6 +55,7 @@ const cms = new Manager({
54
55
 
55
56
  - Validates all provided instances
56
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
57
59
  - Sets up entity access control
58
60
  - Generates admin entities
59
61
  - Configures template reloading
@@ -65,7 +67,7 @@ The CMS automatically detects development environments based on domain patterns.
65
67
  **Default Development Patterns:**
66
68
 
67
69
  ```javascript
68
- const patterns = [
70
+ let patterns = [
69
71
  'localhost',
70
72
  '127.0.0.1',
71
73
  '.local',
@@ -84,7 +86,7 @@ const patterns = [
84
86
  **Override Development Patterns:**
85
87
 
86
88
  ```javascript
87
- const cms = new Manager({
89
+ let cms = new Manager({
88
90
  developmentPatterns: [
89
91
  'localhost',
90
92
  '127.0.0.1',
@@ -109,7 +111,7 @@ const cms = new Manager({
109
111
  Configure external domains for CSP directives (kebab-case or camelCase):
110
112
 
111
113
  ```javascript
112
- const cms = new Manager({
114
+ let cms = new Manager({
113
115
  appServerConfig: {
114
116
  developmentExternalDomains: {
115
117
  'scriptSrc': ['https://cdn.example.com'],
@@ -131,7 +133,7 @@ const cms = new Manager({
131
133
  **Default (merge with base directives):**
132
134
 
133
135
  ```javascript
134
- const cms = new Manager({
136
+ let cms = new Manager({
135
137
  appServerConfig: {
136
138
  helmetConfig: {
137
139
  contentSecurityPolicy: {
@@ -165,7 +167,7 @@ const cms = new Manager({
165
167
  **Complete Replacement:**
166
168
 
167
169
  ```javascript
168
- const cms = new Manager({
170
+ let cms = new Manager({
169
171
  appServerConfig: {
170
172
  helmetConfig: {
171
173
  contentSecurityPolicy: {
@@ -190,7 +192,7 @@ const cms = new Manager({
190
192
  ### Additional Helmet Security Headers
191
193
 
192
194
  ```javascript
193
- const cms = new Manager({
195
+ let cms = new Manager({
194
196
  appServerConfig: {
195
197
  helmetConfig: {
196
198
  hsts: {
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  *
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  *
@@ -9,30 +9,24 @@
9
9
  const { Manager } = require('../index');
10
10
  const { Logger } = require('@reldens/utils');
11
11
  const { FileHandler } = require('@reldens/server-utils');
12
- const readline = require('readline');
12
+ const { PrismaClientLoader } = require('@reldens/storage');
13
+ const readline = require('readline/promises');
13
14
  const dotenv = require('dotenv');
14
15
 
15
16
  let args = process.argv.slice(2);
16
17
  let projectRoot = args[0] || process.cwd();
17
18
  let indexPath = FileHandler.joinPaths(projectRoot, 'index.js');
18
19
 
19
- if(FileHandler.exists(indexPath)){
20
- require(indexPath);
21
- return;
22
- }
23
-
24
20
  async function checkRequiredPackages(projectRoot)
25
21
  {
26
22
  let requiredPackages = ['@reldens/cms'];
27
23
  let missingPackages = [];
28
24
  for(let packageName of requiredPackages){
29
- let packagePath = FileHandler.joinPaths(projectRoot, 'node_modules', packageName);
30
- if(!FileHandler.exists(packagePath)){
25
+ if(!FileHandler.exists(FileHandler.joinPaths(projectRoot, 'node_modules', packageName))){
31
26
  missingPackages.push(packageName);
32
27
  }
33
28
  }
34
- let packagePath = FileHandler.joinPaths(projectRoot, 'node_modules', '@prisma/client');
35
- if(!FileHandler.exists(packagePath)){
29
+ if(!FileHandler.exists(FileHandler.joinPaths(projectRoot, 'node_modules', '@prisma/client'))){
36
30
  missingPackages.push('@prisma/client');
37
31
  }
38
32
  return missingPackages;
@@ -44,14 +38,11 @@ async function promptUserConfirmation(packages)
44
38
  input: process.stdin,
45
39
  output: process.stdout
46
40
  });
47
- return new Promise((resolve) => {
48
- Logger.info('Missing required packages: '+packages.join(', '));
49
- Logger.info('These packages are required for the CMS to function properly.');
50
- rl.question('Would you like to install them automatically? (y/N): ', (answer) => {
51
- rl.close();
52
- resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
53
- });
54
- });
41
+ Logger.info('Missing required packages: '+packages.join(', '));
42
+ Logger.info('These packages are required for the CMS to function properly.');
43
+ let answer = await rl.question('Would you like to install them automatically? (y/N): ');
44
+ rl.close();
45
+ return 'y' === answer.toLowerCase() || 'yes' === answer.toLowerCase();
55
46
  }
56
47
 
57
48
  async function installPackages(packages, projectRoot)
@@ -59,8 +50,7 @@ async function installPackages(packages, projectRoot)
59
50
  try {
60
51
  Logger.info('Installing packages: npm install '+packages.join(' '));
61
52
  let {execSync} = require('child_process');
62
- let installCommand = 'npm install '+packages.join(' ');
63
- execSync(installCommand, {stdio: 'inherit', cwd: projectRoot});
53
+ execSync('npm install '+packages.join(' '), {stdio: 'inherit', cwd: projectRoot});
64
54
  Logger.info('Dependencies installed successfully.');
65
55
  return true;
66
56
  } catch(error) {
@@ -94,42 +84,35 @@ async function createPrismaClientIfNeeded(projectRoot)
94
84
  }
95
85
  let clientPath = FileHandler.joinPaths(projectRoot, 'prisma', 'client');
96
86
  if(!FileHandler.exists(clientPath)){
97
- Logger.critical('Prisma client not found at: '+clientPath);
98
- Logger.critical('Please run "npx prisma generate" to generate the Prisma client.');
99
- return false;
100
- }
101
- try {
102
- let { PrismaClient } = require(clientPath);
103
- return new PrismaClient();
104
- } catch(error) {
105
- Logger.critical('Failed to initialize Prisma client: '+error.message);
106
87
  return false;
107
88
  }
89
+ return PrismaClientLoader.load(projectRoot, null, null) || false;
108
90
  }
109
91
 
110
- async function startManagerProcess()
92
+ async function main()
111
93
  {
94
+ if(FileHandler.exists(indexPath)){
95
+ require(indexPath);
96
+ return;
97
+ }
112
98
  let packageInstallResult = await handlePackageInstallation(projectRoot);
113
99
  if(!packageInstallResult){
114
100
  process.exit(1);
115
101
  }
116
-
117
- let managerConfig = {projectRoot};
118
- let entitiesPath = FileHandler.joinPaths(
119
- projectRoot,
120
- 'generated-entities',
121
- 'models',
122
- 'prisma',
123
- 'registered-models-prisma.js'
124
- );
125
-
126
- if(FileHandler.exists(entitiesPath)){
127
- let entitiesModule = require(entitiesPath);
128
- managerConfig.rawRegisteredEntities = entitiesModule.rawRegisteredEntities;
129
- managerConfig.entitiesConfig = entitiesModule.entitiesConfig;
130
- managerConfig.entitiesTranslations = entitiesModule.entitiesTranslations;
131
- }
132
-
102
+ let managerConfig = {projectRoot};
103
+ let entitiesPath = FileHandler.joinPaths(
104
+ projectRoot,
105
+ 'generated-entities',
106
+ 'models',
107
+ 'prisma',
108
+ 'registered-models-prisma.js'
109
+ );
110
+ if(FileHandler.exists(entitiesPath)){
111
+ let entitiesModule = require(entitiesPath);
112
+ managerConfig.rawRegisteredEntities = entitiesModule.rawRegisteredEntities;
113
+ managerConfig.entitiesConfig = entitiesModule.entitiesConfig;
114
+ managerConfig.entitiesTranslations = entitiesModule.entitiesTranslations;
115
+ }
133
116
  let prismaClient = await createPrismaClientIfNeeded(projectRoot);
134
117
  if(prismaClient){
135
118
  managerConfig.prismaClient = prismaClient;
@@ -149,7 +132,7 @@ if(FileHandler.exists(entitiesPath)){
149
132
  });
150
133
  }
151
134
 
152
- startManagerProcess().catch((error) => {
135
+ main().catch((error) => {
153
136
  Logger.critical('Failed to handle package installation:', error);
154
137
  process.exit(1);
155
138
  });
@@ -0,0 +1,72 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - Manager Component Validator
4
+ *
5
+ */
6
+
7
+ const { Logger } = require('@reldens/utils');
8
+
9
+ class ManagerComponentValidator
10
+ {
11
+
12
+ static validateProvidedServer(app, appServer)
13
+ {
14
+ if(!app){
15
+ return false;
16
+ }
17
+ if(!appServer){
18
+ return false;
19
+ }
20
+ if('function' !== typeof app.use){
21
+ Logger.critical('Invalid app instance provided - missing use method.');
22
+ return false;
23
+ }
24
+ if('function' !== typeof appServer.listen){
25
+ Logger.critical('Invalid appServer instance provided - missing listen method.');
26
+ return false;
27
+ }
28
+ return true;
29
+ }
30
+
31
+ static validateProvidedDataServer(dataServer)
32
+ {
33
+ if(!dataServer){
34
+ return false;
35
+ }
36
+ if('function' !== typeof dataServer.connect){
37
+ Logger.critical('Invalid dataServer instance provided - missing connect method.');
38
+ return false;
39
+ }
40
+ if('function' !== typeof dataServer.generateEntities){
41
+ Logger.critical('Invalid dataServer instance provided - missing generateEntities method.');
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+
47
+ static validateProvidedAdminManager(adminManager)
48
+ {
49
+ if(!adminManager){
50
+ return false;
51
+ }
52
+ if('function' !== typeof adminManager.setupAdmin){
53
+ Logger.critical('Invalid adminManager instance provided - missing setupAdmin method.');
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+
59
+ static validateProvidedFrontend(frontend)
60
+ {
61
+ if(!frontend){
62
+ return false;
63
+ }
64
+ if('function' !== typeof frontend.initialize){
65
+ Logger.critical('Invalid frontend instance provided - missing initialize method.');
66
+ return false;
67
+ }
68
+ return true;
69
+ }
70
+ }
71
+
72
+ module.exports.ManagerComponentValidator = ManagerComponentValidator;
@@ -0,0 +1,33 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - Manager Config Loader
4
+ *
5
+ */
6
+
7
+ const { sc } = require('@reldens/utils');
8
+
9
+ class ManagerConfigLoader
10
+ {
11
+
12
+ static loadFromEnv()
13
+ {
14
+ return {
15
+ host: sc.get(process.env, 'RELDENS_APP_HOST', 'http://localhost'),
16
+ port: Number(sc.get(process.env, 'RELDENS_APP_PORT', 8080)),
17
+ adminPath: sc.get(process.env, 'RELDENS_ADMIN_ROUTE_PATH', '/reldens-admin'),
18
+ adminSecret: sc.get(process.env, 'RELDENS_ADMIN_SECRET', ''),
19
+ database: {
20
+ client: sc.get(process.env, 'RELDENS_DB_CLIENT', 'mysql'),
21
+ host: sc.get(process.env, 'RELDENS_DB_HOST', 'localhost'),
22
+ port: Number(sc.get(process.env, 'RELDENS_DB_PORT', 3306)),
23
+ name: sc.get(process.env, 'RELDENS_DB_NAME', 'reldens_cms'),
24
+ user: sc.get(process.env, 'RELDENS_DB_USER', ''),
25
+ password: sc.get(process.env, 'RELDENS_DB_PASSWORD', ''),
26
+ driver: sc.get(process.env, 'RELDENS_STORAGE_DRIVER', 'prisma')
27
+ },
28
+ publicUrl: sc.get(process.env, 'RELDENS_PUBLIC_URL', '')
29
+ };
30
+ }
31
+ }
32
+
33
+ module.exports.ManagerConfigLoader = ManagerConfigLoader;