@reldens/cms 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Damian A. Pastorini
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ [![Reldens - GitHub - Release](https://www.dwdeveloper.com/media/reldens/reldens-mmorpg-platform.png)](https://github.com/damian-pastorini/reldens)
2
+
3
+ # Reldens - CMS
4
+
5
+ ## About
6
+
7
+ Reldens CMS is a straightforward content management system designed for easy setup and extensibility.
8
+ It provides both an administration panel for content management and a frontend for content delivery.
9
+
10
+ ## Features
11
+
12
+ - Simple installation process
13
+ - Administration panel for content management
14
+ - Support for multiple database drivers (Prisma, Objection.js)
15
+ - Template-based content rendering
16
+ - SEO-friendly routes and meta data
17
+ - Modular architecture
18
+
19
+ ## Installation
20
+
21
+ ### Option 1: NPX Installation (Recommended)
22
+
23
+ The easiest way to install Reldens CMS is using NPX:
24
+
25
+ ```bash
26
+ npx @reldens/cms [directory]
27
+ ```
28
+
29
+ This will start the installer in your browser, allowing you to configure your CMS installation.
30
+
31
+ ### Option 2: Manual Installation
32
+
33
+ 1. Install the package:
34
+
35
+ ```bash
36
+ npm install @reldens/cms
37
+ ```
38
+
39
+ 2. Create a basic implementation:
40
+
41
+ ```javascript
42
+ const { Manager } = require('@reldens/cms');
43
+
44
+ const manager = new Manager({
45
+ projectRoot: './your-project-root',
46
+ authenticationMethod: 'db-users' // or 'callback'
47
+ });
48
+
49
+ manager.start().catch(console.error);
50
+ ```
51
+
52
+ ## Authentication Methods
53
+
54
+ Reldens CMS supports two authentication methods:
55
+
56
+ 1. **db-users**: Uses the built-in users table for authentication
57
+ 2. **callback**: Use a custom authentication function
58
+
59
+ Example with custom authentication:
60
+
61
+ ```javascript
62
+ const manager = new Manager({
63
+ authenticationMethod: 'callback',
64
+ authenticationCallback: async (email, password, roleId) => {
65
+ // Your custom authentication logic
66
+ // Must return a user object or false
67
+ }
68
+ });
69
+ ```
70
+
71
+ ## Extending with Custom Entities
72
+
73
+ You can extend the CMS with your own entities:
74
+
75
+ ```javascript
76
+ const manager = new Manager({
77
+ entities: {
78
+ products: {
79
+ config: {
80
+ listProperties: ['id', 'name', 'price', 'status'],
81
+ showProperties: ['id', 'name', 'price', 'description', 'status', 'created_at'],
82
+ filterProperties: ['name', 'status'],
83
+ editProperties: ['name', 'price', 'description', 'status'],
84
+ properties: {
85
+ id: { isId: true },
86
+ name: { isRequired: true },
87
+ price: { type: 'number', isRequired: true },
88
+ description: { type: 'textarea' },
89
+ status: { type: 'boolean' },
90
+ created_at: { type: 'datetime' }
91
+ },
92
+ titleProperty: 'name',
93
+ navigationPosition: 100
94
+ }
95
+ }
96
+ }
97
+ });
98
+ ```
99
+
100
+ ## Templates
101
+
102
+ Reldens CMS uses templates for rendering content. Templates are stored in the `templates` directory and use Mustache for rendering.
103
+
104
+ Default templates include:
105
+ - `layout.html`: The main layout template
106
+ - `page.html`: Default page template
107
+ - `404.html`: Not found page
108
+
109
+ You can create custom templates for different content types or override the default ones.
110
+
111
+ ---
112
+
113
+ Need something specific?
114
+
115
+ [Request a feature here: https://www.reldens.com/features-request](https://www.reldens.com/features-request)
116
+
117
+ ## Documentation
118
+
119
+ [https://www.reldens.com/documentation/cms](https://www.reldens.com/documentation/cms)
120
+
121
+ ---
122
+
123
+ ### [Reldens](https://github.com/damian-pastorini/reldens/ "Reldens")
124
+
125
+ ##### [By DwDeveloper](https://www.dwdeveloper.com/ "DwDeveloper")
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ *
5
+ * Reldens - CMS - CLI Installer
6
+ *
7
+ */
8
+
9
+ const { Manager } = require('../index');
10
+
11
+ let args = process.argv.slice(2);
12
+ let projectRoot = args[0] || './';
13
+
14
+ let manager = new Manager({
15
+ projectRoot
16
+ });
17
+
18
+ manager.start().catch((error) => {
19
+ console.error('Failed to start CMS:', error);
20
+ process.exit(1);
21
+ });
package/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ *
3
+ * Reldens - CMS - Index
4
+ *
5
+ */
6
+
7
+ const { Manager } = require('./lib/manager');
8
+ const { Installer } = require('./lib/installer');
9
+ const { Storefront } = require('./lib/storefront');
10
+
11
+ module.exports = {
12
+ Manager,
13
+ Installer,
14
+ Storefront
15
+ };
@@ -0,0 +1,117 @@
1
+ /* Installer styles */
2
+ body {
3
+ font-family: 'Open Sans', sans-serif;
4
+ line-height: 1.6;
5
+ color: #333;
6
+ margin: 0;
7
+ padding: 0;
8
+ background-color: #f7f8fa;
9
+ }
10
+
11
+ .wrapper {
12
+ max-width: 1000px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ }
16
+
17
+ .header {
18
+ text-align: center;
19
+ margin-bottom: 30px;
20
+ }
21
+
22
+ .title {
23
+ color: #1a2b49;
24
+ }
25
+
26
+ .content {
27
+ background-color: #fff;
28
+ padding: 30px;
29
+ border-radius: 8px;
30
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
31
+ }
32
+
33
+ .form-title {
34
+ border-bottom: 1px solid #eee;
35
+ padding-bottom: 10px;
36
+ margin-top: 30px;
37
+ }
38
+
39
+ .input-box {
40
+ margin-bottom: 15px;
41
+ }
42
+
43
+ label {
44
+ display: block;
45
+ margin-bottom: 5px;
46
+ font-weight: bold;
47
+ }
48
+
49
+ input[type="text"],
50
+ input[type="password"],
51
+ select {
52
+ width: 100%;
53
+ padding: 10px;
54
+ border: 1px solid #ddd;
55
+ border-radius: 4px;
56
+ box-sizing: border-box;
57
+ }
58
+
59
+ input[type="checkbox"] {
60
+ margin-right: 10px;
61
+ }
62
+
63
+ .submit-container {
64
+ margin-top: 30px;
65
+ text-align: center;
66
+ }
67
+
68
+ input[type="submit"] {
69
+ background-color: #3498db;
70
+ color: white;
71
+ padding: 12px 24px;
72
+ border: none;
73
+ border-radius: 4px;
74
+ cursor: pointer;
75
+ font-size: 16px;
76
+ font-weight: 600;
77
+ }
78
+
79
+ input[type="submit"]:hover {
80
+ background-color: #2980b9;
81
+ }
82
+
83
+ .error {
84
+ color: #e74c3c;
85
+ font-weight: bold;
86
+ display: none;
87
+ }
88
+
89
+ .hidden {
90
+ display: none;
91
+ }
92
+
93
+ .installation-successful {
94
+ display: block;
95
+ text-align: center;
96
+ font-size: 18px;
97
+ color: #2ecc71;
98
+ margin: 20px 0;
99
+ padding: 15px;
100
+ background-color: #f1f9f1;
101
+ border-radius: 4px;
102
+ text-decoration: none;
103
+ }
104
+
105
+ .install-loading {
106
+ width: 24px;
107
+ height: 24px;
108
+ margin-right: 10px;
109
+ vertical-align: middle;
110
+ }
111
+
112
+ .footer {
113
+ text-align: center;
114
+ margin-top: 30px;
115
+ color: #666;
116
+ font-size: 14px;
117
+ }
@@ -0,0 +1,100 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Reldens CMS - Installation</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
6
+ <link rel="stylesheet" href="/install-assets/css/installer.css">
7
+ <script src="/install-assets/js/installer.js"></script>
8
+ </head>
9
+ <body>
10
+ <div class="wrapper">
11
+ <div class="header">
12
+ <h1 class="title">
13
+ <strong>Reldens CMS</strong> - Installation
14
+ </h1>
15
+ </div>
16
+ <div class="content">
17
+ <div class="forms-container">
18
+ <div class="row">
19
+ <form name="install-form" id="install-form" class="install-form" action="/install" method="post">
20
+ <h3 class="form-title">- Server Configuration -</h3>
21
+ <div class="input-box app-host">
22
+ <label for="app-host">Host</label>
23
+ <input type="text" name="app-host" id="app-host" value="{{app-host}}" class="required" required/>
24
+ </div>
25
+ <div class="input-box app-port">
26
+ <label for="app-port">Port</label>
27
+ <input type="text" name="app-port" id="app-port" value="{{app-port}}" class="required" required/>
28
+ </div>
29
+ <div class="input-box app-admin-path">
30
+ <label for="app-admin-path">Admin Panel Path</label>
31
+ <input type="text" name="app-admin-path" id="app-admin-path" value="{{app-admin-path}}"/>
32
+ </div>
33
+ <div class="input-box app-error">
34
+ <p class="error installation-process-failed">There was an error during the installation process.</p>
35
+ </div>
36
+ <h3 class="form-title">- Database Configuration -</h3>
37
+ <div class="db-basic-config-notice">
38
+ <span>
39
+ Default configuration:
40
+ <ul>
41
+ <li>Client: mysql2 - Port: 3306</li>
42
+ <li>Database Driver: prisma</li>
43
+ </ul>
44
+ </span>
45
+ </div>
46
+ <div class="input-box db-storage-driver">
47
+ <label for="db-storage-driver">Storage Driver</label>
48
+ <select name="db-storage-driver" id="db-storage-driver" class="required" required>
49
+ <option value="prisma" selected>Prisma</option>
50
+ <option value="objection-js">Objection JS</option>
51
+ </select>
52
+ </div>
53
+ <div class="input-box db-client">
54
+ <label for="db-client">Client</label>
55
+ <input type="text" name="db-client" id="db-client" value="{{db-client}}" class="required" required/>
56
+ </div>
57
+ <div class="input-box db-host">
58
+ <label for="db-host">Host</label>
59
+ <input type="text" name="db-host" id="db-host" value="{{db-host}}" class="required" required/>
60
+ </div>
61
+ <div class="input-box db-port">
62
+ <label for="db-port">Port</label>
63
+ <input type="text" name="db-port" id="db-port" value="{{db-port}}" class="required" required/>
64
+ </div>
65
+ <div class="input-box db-name">
66
+ <label for="db-name">Database Name</label>
67
+ <input type="text" name="db-name" id="db-name" value="{{db-name}}" class="required" required/>
68
+ </div>
69
+ <div class="input-box db-username">
70
+ <label for="db-username">Username</label>
71
+ <input type="text" name="db-username" id="db-username" value="{{db-username}}" class="required" required/>
72
+ </div>
73
+ <div class="input-box db-password">
74
+ <label for="db-password">Password</label>
75
+ <input type="password" name="db-password" id="db-password" value="{{db-password}}" class="required" required autocomplete="off"/>
76
+ </div>
77
+ <div class="input-box db-error">
78
+ <p class="error connection-failed">Connection failed, please check the database configuration.</p>
79
+ <p class="error invalid-driver">Invalid storage driver.</p>
80
+ <p class="error raw-query-not-found">Method "rawQuery" not found in the specified storage driver.</p>
81
+ <p class="error sql-file-not-found">SQL installation file not found.</p>
82
+ <p class="error db-installation-process-failed">There was an error during the installation process.</p>
83
+ </div>
84
+ <div class="input-box submit-container">
85
+ <img class="install-loading hidden" src="/install-assets/img/loading.gif"/>
86
+ <input id="install-submit-button" type="submit" value="Install"/>
87
+ </div>
88
+ <div class="input-box response-error"></div>
89
+ </form>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ <div class="footer">
94
+ <div class="copyright">
95
+ &copy; 2025 Reldens CMS
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </body>
100
+ </html>
@@ -0,0 +1,32 @@
1
+
2
+ document.addEventListener('DOMContentLoaded', function() {
3
+ let urlParams = new URL(window.location.href).searchParams;
4
+ if ('1' === urlParams.get('success')) {
5
+ document.querySelector('.forms-container').style.display = 'none';
6
+ let newLink = document.createElement('a');
7
+ newLink.href = '/';
8
+ newLink.innerHTML = 'Installation successful, click here to open your CMS!';
9
+ newLink.classList.add('installation-successful');
10
+ document.querySelector('.content').append(newLink);
11
+ }
12
+
13
+ let errorCode = (urlParams.get('error') || '').toString();
14
+ if ('' !== errorCode) {
15
+ let errorElement = document.querySelector('.' + errorCode);
16
+ if (errorElement) {
17
+ errorElement.style.display = 'block';
18
+ }
19
+ }
20
+
21
+ document.getElementById('install-form').addEventListener('submit', () => {
22
+ let loadingImage = document.querySelector('.install-loading');
23
+ if (loadingImage) {
24
+ loadingImage.classList.remove('hidden');
25
+ }
26
+ let installButton = document.getElementById('install-submit-button');
27
+ if (installButton) {
28
+ installButton.classList.add('disabled');
29
+ installButton.disabled = true;
30
+ }
31
+ });
32
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ *
3
+ * Reldens - AdminDistHelper
4
+ *
5
+ */
6
+
7
+ const { FileHandler } = require('@reldens/server-utils');
8
+ const { Logger, sc } = require('@reldens/utils');
9
+
10
+ class AdminDistHelper
11
+ {
12
+
13
+ static async removeBucketAndDistFiles(distPath, bucket, filesName)
14
+ {
15
+ if('string' !== typeof filesName){
16
+ if(!sc.isArray(filesName)){
17
+ Logger.error('Undefined files.', distPath, bucket, filesName);
18
+ }
19
+ return false;
20
+ }
21
+ let files = filesName.split(',');
22
+ if(0 === files.length){
23
+ return false;
24
+ }
25
+ for(let file of files){
26
+ FileHandler.remove([bucket, file]);
27
+ FileHandler.remove([distPath, file]);
28
+ }
29
+ return true;
30
+ }
31
+
32
+ static async copyBucketFilesToDist(bucket, filesName, distPath)
33
+ {
34
+ if('string' !== typeof filesName){
35
+ if(!sc.isArray(filesName)){
36
+ Logger.error('Undefined files.', distPath, bucket, filesName);
37
+ }
38
+ return false;
39
+ }
40
+ let files = filesName.split(',');
41
+ if(0 === files.length){
42
+ return false;
43
+ }
44
+ for(let file of files){
45
+ let result = FileHandler.copyFile([bucket, file], [distPath, file]);
46
+ if(!result){
47
+ Logger.error('File copy error.', FileHandler.error);
48
+ return false;
49
+ }
50
+ }
51
+ return true;
52
+ }
53
+
54
+ }
55
+
56
+ module.exports.AdminDistHelper = AdminDistHelper;
@@ -0,0 +1,32 @@
1
+ /**
2
+ *
3
+ * Reldens - AdminEntitiesGenerator
4
+ *
5
+ */
6
+
7
+ const { Logger } = require('@reldens/utils');
8
+
9
+ class AdminEntitiesGenerator
10
+ {
11
+
12
+ generate(loadedEntities, generatedDrivers)
13
+ {
14
+ let rawEntitiesKeys = Object.keys(loadedEntities);
15
+ let driverEntitiesKeys = Object.keys(generatedDrivers);
16
+ if(rawEntitiesKeys.length !== driverEntitiesKeys.length){
17
+ Logger.error('Raw entities and driver entities mismatch.', rawEntitiesKeys, driverEntitiesKeys);
18
+ return {};
19
+ }
20
+ let generatedEntities = {};
21
+ for(let i of rawEntitiesKeys){
22
+ generatedEntities[i] = {
23
+ rawEntity: generatedDrivers[i],
24
+ config: loadedEntities[i].config
25
+ }
26
+ }
27
+ return generatedEntities;
28
+ }
29
+
30
+ }
31
+
32
+ module.exports.AdminEntitiesGenerator = AdminEntitiesGenerator;
@@ -0,0 +1,37 @@
1
+ /**
2
+ *
3
+ * Reldens - AdminManagerValidator
4
+ *
5
+ */
6
+ const { ValidatorInterface, Logger } = require('@reldens/utils');
7
+
8
+ class AdminManagerValidator extends ValidatorInterface
9
+ {
10
+
11
+ validate(adminManager)
12
+ {
13
+ let requiredProperties = [
14
+ 'events',
15
+ 'dataServer',
16
+ 'app',
17
+ 'applicationFramework',
18
+ 'renderCallback',
19
+ 'bodyParser',
20
+ 'session',
21
+ 'entities',
22
+ 'adminFilesContents',
23
+ 'mimeTypes',
24
+ 'allowedExtensions'
25
+ ];
26
+ for(let propName of requiredProperties){
27
+ if(!adminManager[propName]){
28
+ Logger.error('Missing required property in AdminManager:', propName);
29
+ return false;
30
+ }
31
+ }
32
+ return true
33
+ }
34
+
35
+ }
36
+
37
+ module.exports.AdminManagerValidator = AdminManagerValidator;