vortez 5.0.0-dev.18 → 5.0.0-dev.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.gitignore +9 -4
  2. package/README.md +681 -176
  3. package/build/Vortez.d.ts +1 -0
  4. package/build/Vortez.js +1 -0
  5. package/build/Vortez.js.map +1 -1
  6. package/build/server/Response.d.ts +1 -1
  7. package/build/server/Response.js +1 -1
  8. package/build/server/Response.js.map +1 -1
  9. package/build/server/Server.d.ts +4 -4
  10. package/build/server/Server.js +5 -5
  11. package/build/server/Server.js.map +1 -1
  12. package/build/server/ServerDebug.d.ts +10 -1
  13. package/build/server/ServerDebug.js +85 -17
  14. package/build/server/ServerDebug.js.map +1 -1
  15. package/build/server/config/Config.d.ts +274 -47
  16. package/build/server/config/Config.js +68 -47
  17. package/build/server/config/Config.js.map +1 -1
  18. package/build/server/config/{ConfigLoader.d.ts → Loader.d.ts} +4 -5
  19. package/build/server/config/{ConfigLoader.js → Loader.js} +7 -10
  20. package/build/server/config/Loader.js.map +1 -0
  21. package/build/server/router/Router.d.ts +87 -30
  22. package/build/server/router/Router.js +110 -48
  23. package/build/server/router/Router.js.map +1 -1
  24. package/build/server/router/algorithm/Algorithm.d.ts +39 -0
  25. package/build/server/router/algorithm/Algorithm.js +20 -0
  26. package/build/server/router/algorithm/Algorithm.js.map +1 -0
  27. package/build/server/router/algorithm/FIFO.d.ts +15 -0
  28. package/build/server/router/algorithm/FIFO.js +24 -0
  29. package/build/server/router/algorithm/FIFO.js.map +1 -0
  30. package/build/server/router/algorithm/Tree.d.ts +38 -0
  31. package/build/server/router/algorithm/Tree.js +126 -0
  32. package/build/server/router/algorithm/Tree.js.map +1 -0
  33. package/build/server/router/middleware/WsMiddleware.js +1 -1
  34. package/build/server/router/middleware/WsMiddleware.js.map +1 -1
  35. package/build/utilities/Flatten.d.ts +56 -0
  36. package/build/utilities/Flatten.js +59 -0
  37. package/build/utilities/Flatten.js.map +1 -0
  38. package/build/utilities/Utilities.d.ts +7 -58
  39. package/build/utilities/Utilities.js +8 -33
  40. package/build/utilities/Utilities.js.map +1 -1
  41. package/build/utilities/schema/Introspection.d.ts +24 -0
  42. package/build/utilities/schema/Introspection.js +87 -0
  43. package/build/utilities/schema/Introspection.js.map +1 -0
  44. package/build/utilities/schema/JSONSchema.d.ts +68 -0
  45. package/build/utilities/schema/JSONSchema.js +13 -0
  46. package/build/utilities/schema/JSONSchema.js.map +1 -0
  47. package/build/utilities/schema/Schema.d.ts +253 -0
  48. package/build/utilities/schema/Schema.js +241 -0
  49. package/build/utilities/schema/Schema.js.map +1 -0
  50. package/build/utilities/schema/SchemaError.d.ts +10 -0
  51. package/build/utilities/schema/SchemaError.js +13 -0
  52. package/build/utilities/schema/SchemaError.js.map +1 -0
  53. package/build/utilities/schema/Validator.d.ts +94 -0
  54. package/build/utilities/schema/Validator.js +246 -0
  55. package/build/utilities/schema/Validator.js.map +1 -0
  56. package/package.json +1 -1
  57. package/tests/config/config.js +233 -0
  58. package/tests/router.js +596 -0
  59. package/tests/schema/schema.js +368 -0
  60. package/tests/test.env +0 -0
  61. package/tests/test.js +3 -3
  62. package/build/server/config/ConfigLoader.js.map +0 -1
  63. package/build/server/config/ConfigValidator.d.ts +0 -71
  64. package/build/server/config/ConfigValidator.js +0 -131
  65. package/build/server/config/ConfigValidator.js.map +0 -1
  66. package/examples/in-docs.js +0 -96
@@ -0,0 +1,246 @@
1
+ /**
2
+ * @author NetFeez <netfeez.dev@gmail.com>
3
+ * @description Provides utilities for validating the structure of a schema, ensuring that property definitions are consistent and valid according to their types and constraints.
4
+ * @license Apache-2.0
5
+ */
6
+ import { SchemaError } from './SchemaError.js';
7
+ export class Validator {
8
+ /**
9
+ * Validates the structure of a schema, used for validating the structure of a schema and nested objects.
10
+ * @param schema The schema to validate
11
+ * @param parentKey The parent key of the schema, used for error messages
12
+ */
13
+ static validateStructure(schema, parentKey) {
14
+ for (const key in schema) {
15
+ const prop = schema[key];
16
+ this.validateProperty(prop, parentKey ? `${parentKey}.${key}` : key);
17
+ }
18
+ }
19
+ /**
20
+ * Validates a property definition, used for validating the structure of a schema and nested objects.
21
+ * @param prop The property definition to validate
22
+ * @param key The key of the property, used for error messages
23
+ */
24
+ static validateProperty(prop, key) {
25
+ switch (prop.type) {
26
+ case 'string':
27
+ this.validateStringProperty(prop, key);
28
+ break;
29
+ case 'number':
30
+ this.validateNumberProperty(prop, key);
31
+ break;
32
+ case 'boolean': break;
33
+ case 'array':
34
+ this.validateArrayProperty(prop, key);
35
+ break;
36
+ case 'object':
37
+ this.validateObjectProperty(prop, key);
38
+ break;
39
+ default: throw new SchemaError(`Unknown type for property '${key}'`);
40
+ }
41
+ if ('default' in prop)
42
+ this.validateDefaultValue(prop, key);
43
+ }
44
+ /**
45
+ * Validates a default value against a property definition, used for validating default values.
46
+ * @param prop The property definition to validate against
47
+ * @param key The key of the property, used for error messages
48
+ */
49
+ static validateDefaultValue(prop, key) {
50
+ if (prop.default === undefined) {
51
+ if (!prop.required)
52
+ return;
53
+ throw new SchemaError(`Property '${key}' default value cannot be undefined`);
54
+ }
55
+ if (prop.default === null) {
56
+ if (prop.nullable)
57
+ return;
58
+ throw new SchemaError(`Property '${key}' default value cannot be null`);
59
+ }
60
+ switch (prop.type) {
61
+ case 'string':
62
+ this.validateString(prop.default, prop, key);
63
+ break;
64
+ case 'number':
65
+ this.validateNumber(prop.default, prop, key);
66
+ break;
67
+ case 'boolean':
68
+ this.validateBoolean(prop.default, prop, key);
69
+ break;
70
+ case 'array':
71
+ this.validateArray(prop.default, prop, key);
72
+ break;
73
+ case 'object':
74
+ this.validateObject(prop.default, prop, key);
75
+ break;
76
+ default: throw new SchemaError(`Unknown type for property '${key}'`);
77
+ }
78
+ }
79
+ /**
80
+ * Validates a string property definition, used for validating nested objects.
81
+ * @param prop The string property definition to validate
82
+ * @param key The key of the property, used for error messages
83
+ */
84
+ static validateStringProperty(prop, key) {
85
+ if (prop.enum !== undefined) {
86
+ if (!Array.isArray(prop.enum) || prop.enum.length === 0) {
87
+ throw new SchemaError(`Property '${key}' enum must be a non-empty array`);
88
+ }
89
+ if (prop.enum.some((value) => typeof value !== 'string')) {
90
+ throw new SchemaError(`Property '${key}' enum values must be strings`);
91
+ }
92
+ }
93
+ if (prop.maxLength !== undefined && prop.minLength !== undefined && prop.maxLength < prop.minLength) {
94
+ throw new SchemaError(`Property '${key}' maxLength must be greater than or equal to minLength`);
95
+ }
96
+ if (prop.pattern !== undefined && !(prop.pattern instanceof RegExp)) {
97
+ throw new SchemaError(`Property '${key}' pattern must be a RegExp`);
98
+ }
99
+ }
100
+ /**
101
+ * Validates a number property definition, used for validating nested objects.
102
+ * @param prop The number property definition to validate
103
+ * @param key The key of the property, used for error messages
104
+ */
105
+ static validateNumberProperty(prop, key) {
106
+ if (prop.maximum !== undefined && prop.minimum !== undefined && prop.maximum < prop.minimum) {
107
+ throw new SchemaError(`Property '${key}' maximum must be greater than or equal to minimum`);
108
+ }
109
+ }
110
+ /**
111
+ * Validates an array property definition, used for validating nested arrays.
112
+ * @param prop The array property definition to validate
113
+ * @param key The key of the property, used for error messages
114
+ */
115
+ static validateArrayProperty(prop, key) {
116
+ if (prop.maximum !== undefined && prop.minimum !== undefined && prop.maximum < prop.minimum) {
117
+ throw new SchemaError(`Property '${key}' maximum must be greater than or equal to minimum`);
118
+ }
119
+ this.validateProperty(prop.property, `${key}[]`);
120
+ }
121
+ /**
122
+ * Validates an object property definition, used for validating nested objects.
123
+ * @param prop The object property definition to validate
124
+ * @param key The key of the property, used for error messages
125
+ */
126
+ static validateObjectProperty(prop, key) {
127
+ this.validateStructure(prop.schema, key);
128
+ }
129
+ /**
130
+ * Validates a string value against a string property definition, used for validating default values and nested objects.
131
+ * @param value The value to validate
132
+ * @param prop The string property definition to validate against
133
+ * @param key The key of the property, used for error messages
134
+ */
135
+ static validateString(value, prop, key) {
136
+ if (value == null && prop.nullable === true)
137
+ return;
138
+ if (typeof value !== 'string')
139
+ throw new SchemaError(`Property ${key} must be a string`);
140
+ if (prop.enum !== undefined && !prop.enum.includes(value)) {
141
+ throw new SchemaError(`Property ${key} must be one of: ${prop.enum.join(', ')}`);
142
+ }
143
+ if (prop.minLength !== undefined && value.length < prop.minLength) {
144
+ throw new SchemaError(`Property ${key} must have a minimum length of ${prop.minLength}`);
145
+ }
146
+ if (prop.maxLength !== undefined && value.length > prop.maxLength) {
147
+ throw new SchemaError(`Property ${key} must have a maximum length of ${prop.maxLength}`);
148
+ }
149
+ if (prop.pattern && !prop.pattern.test(value)) {
150
+ throw new SchemaError(`Property ${key} must match the pattern ${prop.pattern}`);
151
+ }
152
+ }
153
+ /**
154
+ * Validates a number value against a number property definition, used for validating default values.
155
+ * @param value The value to validate
156
+ * @param prop The number property definition to validate against
157
+ * @param key The key of the property, used for error messages
158
+ */
159
+ static validateNumber(value, prop, key) {
160
+ if (value == null && prop.nullable === true)
161
+ return;
162
+ if (typeof value !== 'number')
163
+ throw new SchemaError(`Property ${key} must be a number`);
164
+ if (prop.minimum !== undefined && value < prop.minimum) {
165
+ throw new SchemaError(`Property ${key} must be greater than or equal to ${prop.minimum}`);
166
+ }
167
+ if (prop.maximum !== undefined && value > prop.maximum) {
168
+ throw new SchemaError(`Property ${key} must be less than or equal to ${prop.maximum}`);
169
+ }
170
+ }
171
+ /**
172
+ * Validates a boolean value against a boolean property definition, used for validating default values.
173
+ * @param value The value to validate
174
+ * @param prop The boolean property definition to validate against
175
+ * @param key The key of the property, used for error messages
176
+ */
177
+ static validateBoolean(value, prop, key) {
178
+ if (value == null && prop.nullable === true)
179
+ return;
180
+ if (typeof value !== 'boolean')
181
+ throw new SchemaError(`Property ${key} must be a boolean`);
182
+ }
183
+ /**
184
+ * Validates an object value against an object property definition, used for validating default values and nested objects.
185
+ * @param value The value to validate
186
+ * @param prop The object property definition to validate against
187
+ * @param key The key of the property, used for error messages
188
+ */
189
+ static validateObject(value, prop, key) {
190
+ if (value == null && prop.nullable === true)
191
+ return;
192
+ if (typeof value !== 'object' || Array.isArray(value)) {
193
+ throw new SchemaError(`Property ${key} must be an object`);
194
+ }
195
+ this.validateStructure(prop.schema, key);
196
+ }
197
+ /**
198
+ * Validates an array value against an array property definition, used for validating default values and array items.
199
+ * @param value The value to validate
200
+ * @param prop The array property definition to validate against
201
+ * @param key The key of the property, used for error messages
202
+ */
203
+ static validateArray(value, prop, key) {
204
+ if (value == null && prop.nullable === true)
205
+ return;
206
+ if (!Array.isArray(value))
207
+ throw new SchemaError(`Property ${key} must be an array`);
208
+ if (prop.minimum !== undefined && value.length < prop.minimum) {
209
+ throw new SchemaError(`Property ${key} must have at least ${prop.minimum} items`);
210
+ }
211
+ if (prop.maximum !== undefined && value.length > prop.maximum) {
212
+ throw new SchemaError(`Property ${key} must have at most ${prop.maximum} items`);
213
+ }
214
+ value.forEach((item, index) => {
215
+ this.validateValue(item, prop.property, `${key}[${index}]`);
216
+ });
217
+ }
218
+ /**
219
+ * Validates a value against a property definition, used for validating default values and array items.
220
+ * @param value The value to validate
221
+ * @param prop The property definition to validate against
222
+ * @param key The key of the property, used for error messages
223
+ */
224
+ static validateValue(value, prop, key) {
225
+ switch (prop.type) {
226
+ case 'string':
227
+ this.validateString(value, prop, key);
228
+ break;
229
+ case 'number':
230
+ this.validateNumber(value, prop, key);
231
+ break;
232
+ case 'boolean':
233
+ this.validateBoolean(value, prop, key);
234
+ break;
235
+ case 'array':
236
+ this.validateArray(value, prop, key);
237
+ break;
238
+ case 'object':
239
+ this.validateObject(value, prop, key);
240
+ break;
241
+ default: throw new SchemaError(`Unknown type for property '${key}'`);
242
+ }
243
+ }
244
+ }
245
+ export default Validator;
246
+ //# sourceMappingURL=Validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Validator.js","sourceRoot":"","sources":["../../../src/utilities/schema/Validator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vortez",
3
- "version": "5.0.0-dev.18",
3
+ "version": "5.0.0-dev.19",
4
4
  "description": "a module for web server creation",
5
5
  "type": "module",
6
6
  "main": "build/Vortez.js",
@@ -0,0 +1,233 @@
1
+ // @ts-check
2
+ import { strict as assert } from 'assert';
3
+ import { promises as FSP } from 'fs';
4
+
5
+ import { Logger } from '../../build/Vortez.js';
6
+ import { Config } from '../../build/server/config/Config.js';
7
+ import { Loader } from '../../build/server/config/Loader.js';
8
+ import { SchemaError } from '../../build/utilities/schema/SchemaError.js';
9
+
10
+ const logger = new Logger({ prefix: 'CONFIG' });
11
+
12
+ let testsPassed = 0;
13
+ let testsFailed = 0;
14
+
15
+ const TMP_DIR = 'tests/.tmp/config-suite';
16
+ const CONFIG_PATH = `${TMP_DIR}/config.json`;
17
+ const BAD_CONFIG_PATH = `${TMP_DIR}/bad.json`;
18
+
19
+ /**
20
+ * Logs test results.
21
+ * @param { string } testName The test name.
22
+ * @param { boolean } passed Whether the test passed.
23
+ * @param { unknown | null } error Optional error object for failures.
24
+ */
25
+ function logTestResult(testName, passed, error = null) {
26
+ if (passed) {
27
+ logger.log(`&C2✓ ${testName}`);
28
+ testsPassed++;
29
+ } else {
30
+ const message = error instanceof Error ? error.message : String(error);
31
+ logger.error(`&C1✗ ${testName}${error ? ': ' + message : ''}`);
32
+ testsFailed++;
33
+ }
34
+ }
35
+
36
+ async function resetTmpDir() {
37
+ await FSP.rm(TMP_DIR, { recursive: true, force: true });
38
+ await FSP.mkdir(TMP_DIR, { recursive: true });
39
+ }
40
+
41
+ /**
42
+ * Ensures constructor applies default values for missing config keys.
43
+ */
44
+ function testDefaultConfigValues() {
45
+ try {
46
+ const config = new Config({});
47
+
48
+ assert.equal(config.get('host'), 'localhost');
49
+ assert.equal(config.get('port'), 80);
50
+ assert.equal(config.get('ssl'), null);
51
+ assert.equal(config.get('templates.folder'), './global/Template/Folder.vhtml');
52
+ assert.equal(config.get('templates.error'), './global/Template/Error.vhtml');
53
+ assert.equal(config.get('routing.algorithm'), 'FIFO');
54
+ assert.equal(config.get('logger.showAll'), false);
55
+ assert.equal(config.get('logger.server.show'), true);
56
+ assert.equal(config.get('logger.server.save'), true);
57
+
58
+ logTestResult('constructor - Applies defaults', true);
59
+ } catch (error) {
60
+ logTestResult('constructor - Applies defaults', false, error);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Ensures nested object defaults are filled when object is partially provided.
66
+ */
67
+ function testNestedSslDefaultPort() {
68
+ try {
69
+ const config = new Config({
70
+ ssl: {
71
+ cert: 'cert-path',
72
+ key: 'key-path'
73
+ }
74
+ });
75
+
76
+ assert.equal(config.get('ssl.cert'), 'cert-path');
77
+ assert.equal(config.get('ssl.key'), 'key-path');
78
+ assert.equal(config.get('ssl.port'), 443);
79
+
80
+ logTestResult('constructor - Nested defaults inside ssl', true);
81
+ } catch (error) {
82
+ logTestResult('constructor - Nested defaults inside ssl', false, error);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Ensures enum constraints are validated.
88
+ */
89
+ function testRoutingEnumValidation() {
90
+ try {
91
+ assert.throws(
92
+ // @ts-expect-error Runtime validation test with invalid enum on purpose.
93
+ () => new Config({ routing: { algorithm: 'BreadthFirst' } }),
94
+ SchemaError
95
+ );
96
+
97
+ logTestResult('validation - Reject invalid routing algorithm', true);
98
+ } catch (error) {
99
+ logTestResult('validation - Reject invalid routing algorithm', false, error);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Ensures get/set use flattened dot-path keys.
105
+ */
106
+ function testGetSetFlattenedPaths() {
107
+ try {
108
+ const config = new Config({});
109
+
110
+ config.set('host', '127.0.0.1');
111
+ config.set('routing.algorithm', 'Tree');
112
+ config.set('logger.server.show', false);
113
+
114
+ assert.equal(config.get('host'), '127.0.0.1');
115
+ assert.equal(config.get('routing.algorithm'), 'Tree');
116
+ assert.equal(config.get('logger.server.show'), false);
117
+
118
+ logTestResult('api - Get/Set flattened paths', true);
119
+ } catch (error) {
120
+ logTestResult('api - Get/Set flattened paths', false, error);
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Ensures save writes nested JSON and creates missing folders.
126
+ */
127
+ async function testSaveCreatesFileAndNestedData() {
128
+ try {
129
+ await resetTmpDir();
130
+
131
+ const config = new Config({});
132
+ config.set('host', '0.0.0.0');
133
+ config.set('logger.request.save', false);
134
+ await config.save(CONFIG_PATH);
135
+
136
+ const content = await FSP.readFile(CONFIG_PATH, 'utf8');
137
+ const data = JSON.parse(content);
138
+
139
+ assert.equal(data.host, '0.0.0.0');
140
+ assert.equal(data.logger.request.save, false);
141
+
142
+ logTestResult('save - Writes file and nested json', true);
143
+ } catch (error) {
144
+ logTestResult('save - Writes file and nested json', false, error);
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Ensures Loader creates a new file when it does not exist.
150
+ */
151
+ async function testLoaderCreatesMissingFile() {
152
+ try {
153
+ await resetTmpDir();
154
+
155
+ const loaded = await Loader.load(CONFIG_PATH);
156
+
157
+ assert.ok(loaded instanceof Config);
158
+ assert.equal(loaded.get('host'), 'localhost');
159
+
160
+ const content = await FSP.readFile(CONFIG_PATH, 'utf8');
161
+ const data = JSON.parse(content);
162
+ assert.equal(data.port, 80);
163
+
164
+ logTestResult('loader - Creates missing file with defaults', true);
165
+ } catch (error) {
166
+ logTestResult('loader - Creates missing file with defaults', false, error);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Ensures Loader reads and validates existing config files.
172
+ */
173
+ async function testLoaderReadsExistingFile() {
174
+ try {
175
+ await resetTmpDir();
176
+
177
+ await FSP.writeFile(
178
+ CONFIG_PATH,
179
+ JSON.stringify({ host: 'example.com', routing: { algorithm: 'Tree' } }, null, 4),
180
+ 'utf8'
181
+ );
182
+
183
+ const loaded = await Loader.load(CONFIG_PATH);
184
+
185
+ assert.equal(loaded.get('host'), 'example.com');
186
+ assert.equal(loaded.get('routing.algorithm'), 'Tree');
187
+
188
+ logTestResult('loader - Loads existing file', true);
189
+ } catch (error) {
190
+ logTestResult('loader - Loads existing file', false, error);
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Ensures Loader throws when the file contains invalid JSON.
196
+ */
197
+ async function testLoaderRejectsInvalidJson() {
198
+ try {
199
+ await resetTmpDir();
200
+ await FSP.writeFile(BAD_CONFIG_PATH, '{ "host": "localhost", ', 'utf8');
201
+
202
+ await assert.rejects(() => Loader.load(BAD_CONFIG_PATH));
203
+
204
+ logTestResult('loader - Rejects invalid json file', true);
205
+ } catch (error) {
206
+ logTestResult('loader - Rejects invalid json file', false, error);
207
+ }
208
+ }
209
+
210
+ async function runTests() {
211
+ logger.log('\n&C6=== Config Test Suite ===\n');
212
+
213
+ testDefaultConfigValues();
214
+ testNestedSslDefaultPort();
215
+ testRoutingEnumValidation();
216
+ testGetSetFlattenedPaths();
217
+
218
+ await testSaveCreatesFileAndNestedData();
219
+ await testLoaderCreatesMissingFile();
220
+ await testLoaderReadsExistingFile();
221
+ await testLoaderRejectsInvalidJson();
222
+
223
+ await FSP.rm(TMP_DIR, { recursive: true, force: true });
224
+
225
+ logger.log('\n&C6=== Results ===');
226
+ logger.log(`&C2✓ Passed: ${testsPassed}`);
227
+ logger.log(`&C1✗ Failed: ${testsFailed}`);
228
+ logger.log(`&C3Total: ${testsPassed + testsFailed}\n`);
229
+
230
+ process.exit(testsFailed > 0 ? 1 : 0);
231
+ }
232
+
233
+ runTests();