odac 0.9.0 → 1.0.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/workflows/auto-pr-description.yml +0 -2
- package/.github/workflows/codeql.yml +46 -0
- package/.github/workflows/release.yml +13 -6
- package/.github/workflows/test-coverage.yml +10 -9
- package/.releaserc.js +9 -6
- package/CHANGELOG.md +62 -150
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTING.md +8 -8
- package/LICENSE +21 -661
- package/README.md +12 -12
- package/SECURITY.md +4 -4
- package/bin/odac.js +101 -0
- package/{framework/web/candy.js → client/odac.js} +310 -44
- package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
- package/docs/backend/01-overview/03-development-server.md +11 -11
- package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +1 -1
- package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
- package/docs/backend/03-config/04-environment-variables.md +20 -20
- package/docs/backend/03-config/05-early-hints.md +4 -4
- package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
- package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
- package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
- package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
- package/docs/backend/04-routing/05-advanced-routing.md +3 -3
- package/docs/backend/04-routing/06-error-pages.md +17 -17
- package/docs/backend/04-routing/07-cron-jobs.md +13 -13
- package/docs/backend/04-routing/08-middleware.md +214 -0
- package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
- package/docs/backend/04-routing/09-websocket-examples.md +381 -0
- package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
- package/docs/backend/04-routing/09-websocket.md +298 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
- package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
- package/docs/backend/05-controllers/03-controller-classes.md +19 -19
- package/docs/backend/05-forms/01-custom-forms.md +114 -114
- package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
- package/docs/backend/07-views/01-the-view-directory.md +1 -1
- package/docs/backend/07-views/02-rendering-a-view.md +22 -22
- package/docs/backend/07-views/03-template-syntax.md +52 -52
- package/docs/backend/07-views/03-variables.md +84 -84
- package/docs/backend/07-views/04-request-data.md +57 -57
- package/docs/backend/07-views/05-conditionals.md +78 -78
- package/docs/backend/07-views/06-loops.md +114 -114
- package/docs/backend/07-views/07-translations.md +66 -66
- package/docs/backend/07-views/08-backend-javascript.md +103 -103
- package/docs/backend/07-views/09-comments.md +71 -71
- package/docs/backend/08-database/01-database-connection.md +8 -8
- package/docs/backend/08-database/02-using-mysql.md +49 -49
- package/docs/backend/09-validation/01-the-validator-service.md +38 -38
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
- package/docs/backend/10-authentication/03-register.md +12 -12
- package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
- package/docs/backend/10-authentication/05-session-management.md +10 -10
- package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
- package/docs/backend/11-mail/01-the-mail-service.md +5 -5
- package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
- package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
- package/docs/frontend/01-overview/01-introduction.md +30 -30
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
- package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
- package/docs/frontend/03-forms/01-form-handling.md +32 -32
- package/docs/frontend/04-api-requests/01-get-post.md +33 -33
- package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
- package/docs/frontend/06-websocket/00-overview.md +76 -0
- package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
- package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
- package/docs/index.json +49 -11
- package/eslint.config.mjs +6 -6
- package/{framework/index.js → index.js} +1 -1
- package/package.json +14 -39
- package/{framework/src → src}/Auth.js +59 -59
- package/{framework/src → src}/Config.js +3 -3
- package/{framework/src → src}/Lang.js +7 -7
- package/{framework/src → src}/Mail.js +5 -5
- package/{framework/src → src}/Mysql.js +42 -42
- package/src/Odac.js +112 -0
- package/{framework/src → src}/Request.js +38 -36
- package/{framework/src → src}/Route/Internal.js +116 -116
- package/src/Route/Middleware.js +75 -0
- package/src/Route.js +621 -0
- package/src/Server.js +22 -0
- package/{framework/src → src}/Stream.js +11 -3
- package/{framework/src → src}/Validator.js +21 -21
- package/{framework/src → src}/Var.js +5 -5
- package/{framework/src → src}/View/EarlyHints.js +1 -1
- package/{framework/src → src}/View/Form.js +69 -69
- package/{framework/src → src}/View.js +78 -81
- package/src/WebSocket.js +403 -0
- package/template/config.json +5 -0
- package/{web → template}/controller/page/about.js +6 -6
- package/{web → template}/controller/page/index.js +9 -9
- package/{web → template}/package.json +4 -5
- package/{web → template}/public/assets/css/style.css +4 -4
- package/{web → template}/public/assets/js/app.js +6 -6
- package/{web → template}/route/www.js +6 -6
- package/{web → template}/skeleton/main.html +1 -1
- package/{web → template}/view/content/about.html +5 -5
- package/{web → template}/view/content/home.html +12 -12
- package/template/view/footer/main.html +11 -0
- package/{web → template}/view/head/main.html +1 -1
- package/{web → template}/view/header/main.html +2 -2
- package/test/core/Candy.test.js +58 -58
- package/test/core/Commands.test.js +7 -7
- package/test/core/Config.test.js +82 -85
- package/test/core/Lang.test.js +2 -2
- package/test/core/Process.test.js +6 -6
- package/test/framework/Route.test.js +56 -37
- package/test/framework/View/EarlyHints.test.js +2 -2
- package/test/framework/WebSocket.test.js +100 -0
- package/test/framework/middleware.test.js +85 -0
- package/test/server/Api.test.js +31 -31
- package/test/server/DNS.test.js +11 -11
- package/test/server/Hub.test.js +497 -0
- package/test/server/Mail.account.test_.js +3 -3
- package/test/server/Mail.init.test_.js +10 -10
- package/test/server/Mail.test_.js +20 -20
- package/test/server/SSL.test_.js +54 -54
- package/test/server/Server.test.js +39 -39
- package/test/server/Service.test_.js +7 -7
- package/test/server/Subdomain.test.js +7 -7
- package/test/server/Web/Firewall.test.js +87 -87
- package/test/server/Web/Proxy.test.js +397 -0
- package/test/server/{Web.test_.js → Web.test.js} +137 -205
- package/test/server/__mocks__/fs.js +2 -2
- package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
- package/test/server/__mocks__/index.js +6 -6
- package/test/server/__mocks__/testFactories.js +1 -1
- package/test/server/__mocks__/testHelpers.js +7 -7
- package/.husky/pre-commit +0 -2
- package/.kiro/steering/code-style.md +0 -56
- package/.kiro/steering/product.md +0 -20
- package/.kiro/steering/structure.md +0 -77
- package/.kiro/steering/tech.md +0 -87
- package/AGENTS.md +0 -84
- package/bin/candy +0 -10
- package/bin/candypack +0 -10
- package/cli/index.js +0 -3
- package/cli/src/Cli.js +0 -348
- package/cli/src/Connector.js +0 -93
- package/cli/src/Monitor.js +0 -416
- package/core/Candy.js +0 -87
- package/core/Commands.js +0 -239
- package/core/Config.js +0 -1094
- package/core/Lang.js +0 -52
- package/core/Log.js +0 -43
- package/core/Process.js +0 -26
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
- package/docs/server/01-installation/01-quick-install.md +0 -19
- package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
- package/docs/server/02-get-started/01-core-concepts.md +0 -7
- package/docs/server/02-get-started/02-basic-commands.md +0 -57
- package/docs/server/02-get-started/03-cli-reference.md +0 -276
- package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
- package/docs/server/03-service/01-start-a-new-service.md +0 -57
- package/docs/server/03-service/02-delete-a-service.md +0 -48
- package/docs/server/04-web/01-create-a-website.md +0 -36
- package/docs/server/04-web/02-list-websites.md +0 -9
- package/docs/server/04-web/03-delete-a-website.md +0 -29
- package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
- package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
- package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
- package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
- package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
- package/docs/server/07-mail/04-change-account-password.md +0 -23
- package/framework/src/Candy.js +0 -81
- package/framework/src/Route.js +0 -455
- package/framework/src/Server.js +0 -15
- package/locale/de-DE.json +0 -80
- package/locale/en-US.json +0 -79
- package/locale/es-ES.json +0 -80
- package/locale/fr-FR.json +0 -80
- package/locale/pt-BR.json +0 -80
- package/locale/ru-RU.json +0 -80
- package/locale/tr-TR.json +0 -85
- package/locale/zh-CN.json +0 -80
- package/server/index.js +0 -5
- package/server/src/Api.js +0 -88
- package/server/src/DNS.js +0 -940
- package/server/src/Hub.js +0 -535
- package/server/src/Mail.js +0 -571
- package/server/src/SSL.js +0 -180
- package/server/src/Server.js +0 -27
- package/server/src/Service.js +0 -248
- package/server/src/Subdomain.js +0 -64
- package/server/src/Web/Firewall.js +0 -170
- package/server/src/Web/Proxy.js +0 -134
- package/server/src/Web.js +0 -451
- package/server/src/mail/imap.js +0 -1091
- package/server/src/mail/server.js +0 -32
- package/server/src/mail/smtp.js +0 -786
- package/test/server/Client.test.js +0 -338
- package/test/server/__mocks__/http-proxy.js +0 -105
- package/watchdog/index.js +0 -3
- package/watchdog/src/Watchdog.js +0 -156
- package/web/config.json +0 -5
- package/web/view/footer/main.html +0 -11
- /package/{framework/src → src}/Env.js +0 -0
- /package/{framework/src → src}/Route/Cron.js +0 -0
- /package/{framework/src → src}/Token.js +0 -0
|
@@ -59,8 +59,8 @@ class Mysql {
|
|
|
59
59
|
|
|
60
60
|
async #define(table) {
|
|
61
61
|
return new Promise(resolve => {
|
|
62
|
-
if (!
|
|
63
|
-
this.#table[table] =
|
|
62
|
+
if (!Odac.Mysql.db[this.#database]) Odac.Mysql.db[this.#database] = {}
|
|
63
|
+
this.#table[table] = Odac.Mysql.db[this.#database][table]
|
|
64
64
|
if (this.#table[table]) {
|
|
65
65
|
this.#defining = false
|
|
66
66
|
return resolve(true)
|
|
@@ -81,7 +81,7 @@ class Mysql {
|
|
|
81
81
|
}
|
|
82
82
|
if (!this.#table[table]) this.#table[table] = {}
|
|
83
83
|
this.#table[table].columns = columns
|
|
84
|
-
|
|
84
|
+
Odac.Mysql.db[this.#database][table] = this.#table[table]
|
|
85
85
|
this.#defining = false
|
|
86
86
|
return resolve(true)
|
|
87
87
|
})
|
|
@@ -98,11 +98,11 @@ class Mysql {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
#error(err, query) {
|
|
101
|
-
err = '
|
|
101
|
+
err = 'Odac Mysql Error: ' + (err?.message ?? 'Unknown error').trim() + '\n'
|
|
102
102
|
if (query) err += 'Query: ' + query + '\n'
|
|
103
103
|
while (this.#stack.length > 0) {
|
|
104
104
|
let line = this.#stack.shift().replace('at', '')
|
|
105
|
-
if (line.includes('/node_modules/
|
|
105
|
+
if (line.includes('/node_modules/odac/framework/src/')) break
|
|
106
106
|
else if (!line.includes('(node:')) err += line + '\n'
|
|
107
107
|
}
|
|
108
108
|
console.error(err)
|
|
@@ -163,7 +163,7 @@ class Mysql {
|
|
|
163
163
|
// $md5_query = md5($query);
|
|
164
164
|
// $md5_table = md5($this->arr['table']);
|
|
165
165
|
// $file = "cache/mysql/".md5(Mysql::$name)."/$md5_table"."_$md5_query";
|
|
166
|
-
// $cache =
|
|
166
|
+
// $cache = Odac::storage($file)->get('cache');
|
|
167
167
|
// if(isset($cache->date) && ($cache->date >= (time() - $this->arr['cache']))) return $cache->data;
|
|
168
168
|
// }
|
|
169
169
|
let query = this.query('get')
|
|
@@ -182,7 +182,7 @@ class Mysql {
|
|
|
182
182
|
// if(isset($cache)){
|
|
183
183
|
// $cache->data = $data;
|
|
184
184
|
// $cache->date = time();
|
|
185
|
-
//
|
|
185
|
+
// Odac::storage($file)->set('cache', $cache);
|
|
186
186
|
// }
|
|
187
187
|
return data
|
|
188
188
|
}
|
|
@@ -244,7 +244,7 @@ class Mysql {
|
|
|
244
244
|
// $md5_query = md5($query);
|
|
245
245
|
// $md5_table = md5($this->arr['table']);
|
|
246
246
|
// $file = "cache/mysql/".md5(Mysql::$name)."/$md5_table"."_$md5_query"."_r";
|
|
247
|
-
// $cache =
|
|
247
|
+
// $cache = Odac::storage($file)->get('cache');
|
|
248
248
|
// if(isset($cache->date) && ($cache->date >= (time() - $this->arr['cache']))) return $cache->data;
|
|
249
249
|
// }
|
|
250
250
|
let query = this.query('get')
|
|
@@ -254,7 +254,7 @@ class Mysql {
|
|
|
254
254
|
// if(isset($cache)){
|
|
255
255
|
// $cache->data = $rows;
|
|
256
256
|
// $cache->date = time();
|
|
257
|
-
//
|
|
257
|
+
// Odac::storage($file)->set('cache', $cache);
|
|
258
258
|
// }
|
|
259
259
|
return rows
|
|
260
260
|
}
|
|
@@ -263,7 +263,7 @@ class Mysql {
|
|
|
263
263
|
return new Promise(resolve => {
|
|
264
264
|
if (!query) return resolve(false)
|
|
265
265
|
if (!this.#conn) return resolve(false)
|
|
266
|
-
if (this.#conn.state == 'disconnected')
|
|
266
|
+
if (this.#conn.state == 'disconnected') Odac.Mysql.init()
|
|
267
267
|
const args = params ? [query, params] : [query]
|
|
268
268
|
args.push((err, result) => {
|
|
269
269
|
if (err) return resolve(this.#error(err, query))
|
|
@@ -309,7 +309,7 @@ class Mysql {
|
|
|
309
309
|
|
|
310
310
|
groupBy(...args) {
|
|
311
311
|
this.#arr['group by'] = this.#arr['group by'] ?? ''
|
|
312
|
-
let select = this.#arr['group by'].split(',')
|
|
312
|
+
let select = this.#arr['group by'] ? this.#arr['group by'].split(',') : []
|
|
313
313
|
// if(count(func_get_args())==1 && is_array(func_get_args()[0])){
|
|
314
314
|
// if(isset(func_get_args()[0]['ct']) && isset(func_get_args()[0]['v']) && func_get_args()[0]['ct'] == $GLOBALS['candy_token_mysql']){
|
|
315
315
|
// $select[] = func_get_args()[0]['v'];
|
|
@@ -407,33 +407,33 @@ class Mysql {
|
|
|
407
407
|
break
|
|
408
408
|
} else if (!this.#arr.select) {
|
|
409
409
|
continue
|
|
410
|
-
} else if (
|
|
410
|
+
} else if (Odac.Var(this.#arr.select).contains(' AS "' + col + '"')) {
|
|
411
411
|
// $exp = explode(' ,',explode(" AS \"$col\"",$this->arr['select'])[0]);
|
|
412
|
-
// $real_col = explode('.',
|
|
412
|
+
// $real_col = explode('.',Odac::var(trim(end($exp)))->clear('`'));
|
|
413
413
|
// $real_table = trim($real_col[0]);
|
|
414
414
|
// $real_col = trim($real_col[1]);
|
|
415
415
|
// $this->types[$col] = $this->types[$col] = $this->table[$real_table]['columns'][$real_col]['Type'] ?? $this->types[$col];
|
|
416
416
|
break
|
|
417
|
-
} else if (
|
|
417
|
+
} else if (Odac.Var(this.#arr.select).containsAny(' `' + col + '`', ' `' + key + '`.`' + col + '`')) {
|
|
418
418
|
this.types[col] = this.#table[key].columns[col].Type ?? this.types[col]
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
if (action == 'decode') {
|
|
423
|
-
if (
|
|
424
|
-
else if (
|
|
425
|
-
else if (
|
|
426
|
-
else if (
|
|
427
|
-
else if (
|
|
428
|
-
else if (
|
|
423
|
+
if (Odac.Var(this.types[col]).isBegin('tinyint(1)')) value = value ? true : false
|
|
424
|
+
else if (Odac.Var(this.types[col]).isBegin('int')) value = parseInt(value)
|
|
425
|
+
else if (Odac.Var(this.types[col]).isBegin('double')) value = parseFloat(value)
|
|
426
|
+
else if (Odac.Var(this.types[col]).isBegin('float')) value = parseFloat(value)
|
|
427
|
+
else if (Odac.Var(this.types[col]).isBegin('boolean')) value = parseInt(value)
|
|
428
|
+
else if (Odac.Var(this.types[col]).isBegin('json')) value = JSON.parse(value)
|
|
429
429
|
} else if (!(value instanceof Raw)) {
|
|
430
|
-
if (
|
|
431
|
-
else if (
|
|
432
|
-
else if (
|
|
433
|
-
else if (
|
|
434
|
-
else if (
|
|
435
|
-
else if (
|
|
436
|
-
else if (
|
|
430
|
+
if (Odac.Var(this.types[col]).isBegin('tinyint(1)')) value = parseInt(value)
|
|
431
|
+
else if (Odac.Var(this.types[col]).isBegin('int')) value = parseInt(value)
|
|
432
|
+
else if (Odac.Var(this.types[col]).isBegin('double')) value = parseFloat(value)
|
|
433
|
+
else if (Odac.Var(this.types[col]).isBegin('float')) value = parseFloat(value)
|
|
434
|
+
else if (Odac.Var(this.types[col]).isBegin('boolean')) value = parseInt(value)
|
|
435
|
+
else if (Odac.Var(this.types[col]).isBegin('json')) value = JSON.stringify(value)
|
|
436
|
+
else if (Odac.Var(this.types[col]).isBegin('date', 'datetime', 'timestamp')) value = Odac.Var(value).date('Y-m-d H:i:s')
|
|
437
437
|
}
|
|
438
438
|
return value
|
|
439
439
|
}
|
|
@@ -513,22 +513,22 @@ module.exports = {
|
|
|
513
513
|
db: {},
|
|
514
514
|
init: function () {
|
|
515
515
|
return new Promise(resolve => {
|
|
516
|
-
if (!
|
|
517
|
-
let multiple = typeof
|
|
518
|
-
let dbs = multiple ?
|
|
516
|
+
if (!Odac.Config.database) return resolve(false)
|
|
517
|
+
let multiple = typeof Odac.Config.database[Object.keys(Odac.Config.database)[0]] === 'object'
|
|
518
|
+
let dbs = multiple ? Odac.Config.database : {default: Odac.Config.database}
|
|
519
519
|
for (let key of Object.keys(dbs)) {
|
|
520
520
|
let db = dbs[key]
|
|
521
521
|
if (db.type && db.type != 'mysql') continue
|
|
522
|
-
|
|
522
|
+
Odac.Mysql.conn[key] = mysql.createConnection({
|
|
523
523
|
host: db.host ?? '127.0.0.1',
|
|
524
524
|
user: db.user,
|
|
525
525
|
password: db.password,
|
|
526
526
|
database: db.database,
|
|
527
527
|
stringifyObjects: true
|
|
528
528
|
})
|
|
529
|
-
|
|
529
|
+
Odac.Mysql.conn[key].connect(err => {
|
|
530
530
|
if (err) {
|
|
531
|
-
console.error(`
|
|
531
|
+
console.error(`Odac Mysql Error: Failed to connect to database '${key}'`)
|
|
532
532
|
console.error(`Host: ${db.host ?? '127.0.0.1'}`)
|
|
533
533
|
console.error(`User: ${db.user}`)
|
|
534
534
|
console.error(`Database: ${db.database}`)
|
|
@@ -536,16 +536,16 @@ module.exports = {
|
|
|
536
536
|
return resolve(false)
|
|
537
537
|
}
|
|
538
538
|
})
|
|
539
|
-
|
|
539
|
+
Odac.Mysql.conn[key].query('SHOW TABLES', (err, result) => {
|
|
540
540
|
if (err) {
|
|
541
|
-
console.error(`
|
|
541
|
+
console.error(`Odac Mysql Error: Failed to query tables from database '${key}'`)
|
|
542
542
|
console.error(`Error: ${err.message}`)
|
|
543
543
|
return resolve(false)
|
|
544
544
|
}
|
|
545
545
|
for (let table of result)
|
|
546
546
|
for (let key of Object.keys(table)) {
|
|
547
547
|
let t = () => {
|
|
548
|
-
new Mysql(table[key],
|
|
548
|
+
new Mysql(table[key], Odac.Mysql.conn['default'])
|
|
549
549
|
}
|
|
550
550
|
t()
|
|
551
551
|
}
|
|
@@ -555,16 +555,16 @@ module.exports = {
|
|
|
555
555
|
})
|
|
556
556
|
},
|
|
557
557
|
database: function (name) {
|
|
558
|
-
if (!
|
|
559
|
-
return new Mysql(name,
|
|
558
|
+
if (!Odac.Mysql.conn[name]) return null
|
|
559
|
+
return new Mysql(name, Odac.Mysql.conn[name])
|
|
560
560
|
},
|
|
561
561
|
run: function (query, params) {
|
|
562
|
-
if (!
|
|
563
|
-
return new Mysql(null,
|
|
562
|
+
if (!Odac.Mysql.conn['default']) return Promise.resolve(false)
|
|
563
|
+
return new Mysql(null, Odac.Mysql.conn['default']).run(query, params)
|
|
564
564
|
},
|
|
565
565
|
table: function (name) {
|
|
566
|
-
if (!
|
|
567
|
-
return new Mysql(name,
|
|
566
|
+
if (!Odac.Mysql.conn['default']) return null
|
|
567
|
+
return new Mysql(name, Odac.Mysql.conn['default'])
|
|
568
568
|
},
|
|
569
569
|
raw: function (query) {
|
|
570
570
|
if (typeof query !== 'string') {
|
package/src/Odac.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
init: async function () {
|
|
3
|
+
global.Odac = this.instance()
|
|
4
|
+
await global.Odac.Env.init()
|
|
5
|
+
await global.Odac.Config.init()
|
|
6
|
+
await global.Odac.Mysql.init()
|
|
7
|
+
await global.Odac.Route.init()
|
|
8
|
+
await global.Odac.Server.init()
|
|
9
|
+
global.Odac.instance = this.instance
|
|
10
|
+
global.__ = value => {
|
|
11
|
+
return value
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
instance(id, req, res) {
|
|
16
|
+
let _odac = {}
|
|
17
|
+
|
|
18
|
+
_odac.Config = require('./Config.js')
|
|
19
|
+
_odac.Env = require('./Env.js')
|
|
20
|
+
_odac.Mail = (...args) => new (require('./Mail.js'))(...args)
|
|
21
|
+
_odac.Mysql = require('./Mysql.js')
|
|
22
|
+
_odac.Route = global.Odac?.Route ?? new (require('./Route.js'))()
|
|
23
|
+
_odac.Server = require('./Server.js')
|
|
24
|
+
_odac.Var = (...args) => new (require('./Var.js'))(...args)
|
|
25
|
+
|
|
26
|
+
if (req) {
|
|
27
|
+
_odac.Request = new (require('./Request.js'))(id, req, res, _odac)
|
|
28
|
+
_odac.Auth = new (require('./Auth.js'))(_odac.Request)
|
|
29
|
+
_odac.Token = new (require('./Token.js'))(_odac.Request)
|
|
30
|
+
_odac.Lang = new (require('./Lang.js'))(_odac)
|
|
31
|
+
if (res) {
|
|
32
|
+
_odac.View = new (require('./View.js'))(_odac)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_odac._intervals = []
|
|
36
|
+
_odac._timeouts = []
|
|
37
|
+
_odac.setInterval = function (callback, delay, ...args) {
|
|
38
|
+
const id = setInterval(callback, delay, ...args)
|
|
39
|
+
_odac._intervals.push(id)
|
|
40
|
+
return id
|
|
41
|
+
}
|
|
42
|
+
_odac.setTimeout = function (callback, delay, ...args) {
|
|
43
|
+
const id = setTimeout(callback, delay, ...args)
|
|
44
|
+
_odac._timeouts.push(id)
|
|
45
|
+
return id
|
|
46
|
+
}
|
|
47
|
+
_odac.clearInterval = function (id) {
|
|
48
|
+
const index = _odac._intervals.indexOf(id)
|
|
49
|
+
if (index > -1) _odac._intervals.splice(index, 1)
|
|
50
|
+
clearInterval(id)
|
|
51
|
+
}
|
|
52
|
+
_odac.clearTimeout = function (id) {
|
|
53
|
+
const index = _odac._timeouts.indexOf(id)
|
|
54
|
+
if (index > -1) _odac._timeouts.splice(index, 1)
|
|
55
|
+
clearTimeout(id)
|
|
56
|
+
}
|
|
57
|
+
_odac.cleanup = function () {
|
|
58
|
+
for (const id of _odac._intervals) clearInterval(id)
|
|
59
|
+
for (const id of _odac._timeouts) clearTimeout(id)
|
|
60
|
+
_odac._intervals = []
|
|
61
|
+
_odac._timeouts = []
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (global.Odac?.Route?.class) {
|
|
65
|
+
for (const name in global.Odac.Route.class) {
|
|
66
|
+
const Module = global.Odac.Route.class[name].module
|
|
67
|
+
_odac[name] = typeof Module === 'function' ? new Module(_odac) : Module
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_odac.__ = function (...args) {
|
|
72
|
+
return _odac.Lang.get(...args)
|
|
73
|
+
}
|
|
74
|
+
_odac.abort = function (code) {
|
|
75
|
+
return _odac.Request.abort(code)
|
|
76
|
+
}
|
|
77
|
+
_odac.cookie = function (key, value, options) {
|
|
78
|
+
return _odac.Request.cookie(key, value, options)
|
|
79
|
+
}
|
|
80
|
+
_odac.direct = function (url) {
|
|
81
|
+
return _odac.Request.redirect(url)
|
|
82
|
+
}
|
|
83
|
+
_odac.env = function (key, defaultValue) {
|
|
84
|
+
return _odac.Env.get(key, defaultValue)
|
|
85
|
+
}
|
|
86
|
+
_odac.return = function (data) {
|
|
87
|
+
return _odac.Request.end(data)
|
|
88
|
+
}
|
|
89
|
+
_odac.request = function (key) {
|
|
90
|
+
return _odac.Request.request(key)
|
|
91
|
+
}
|
|
92
|
+
_odac.set = function (key, value) {
|
|
93
|
+
return _odac.Request.set(key, value)
|
|
94
|
+
}
|
|
95
|
+
_odac.token = function (hash) {
|
|
96
|
+
return hash ? _odac.Token.check(hash) : _odac.Token.generate()
|
|
97
|
+
}
|
|
98
|
+
_odac.validator = function () {
|
|
99
|
+
return new (require('./Validator.js'))(_odac.Request)
|
|
100
|
+
}
|
|
101
|
+
_odac.write = function (value) {
|
|
102
|
+
return _odac.Request.write(value)
|
|
103
|
+
}
|
|
104
|
+
_odac.stream = function (input) {
|
|
105
|
+
_odac.Request.clearTimeout()
|
|
106
|
+
return new (require('./Stream'))(_odac.Request.req, _odac.Request.res, input, _odac)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return _odac
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const nodeCrypto = require('crypto')
|
|
2
2
|
|
|
3
|
-
class
|
|
4
|
-
#
|
|
3
|
+
class OdacRequest {
|
|
4
|
+
#odac
|
|
5
5
|
#complete = false
|
|
6
6
|
#cookies = {received: [], sent: []}
|
|
7
7
|
data = {post: {}, get: {}, url: {}}
|
|
8
8
|
#event = {data: [], end: []}
|
|
9
|
-
#headers = {Server: '
|
|
9
|
+
#headers = {Server: 'Odac'}
|
|
10
10
|
#status = 200
|
|
11
11
|
#timeout = null
|
|
12
12
|
#earlyHints = null
|
|
@@ -16,30 +16,32 @@ class CandyRequest {
|
|
|
16
16
|
clientSkeleton = null
|
|
17
17
|
page = null
|
|
18
18
|
|
|
19
|
-
constructor(id, req, res,
|
|
19
|
+
constructor(id, req, res, odac) {
|
|
20
20
|
this.id = id
|
|
21
21
|
this.req = req
|
|
22
22
|
this.res = res
|
|
23
|
-
this.#
|
|
23
|
+
this.#odac = odac
|
|
24
24
|
this.method = req.method.toLowerCase()
|
|
25
25
|
this.url = req.url
|
|
26
26
|
this.host = req.headers.host
|
|
27
|
-
this.ssl = this.header('x-
|
|
28
|
-
this.ip = (this.header('x-
|
|
29
|
-
delete this.req.headers['x-
|
|
30
|
-
delete this.req.headers['x-
|
|
27
|
+
this.ssl = this.header('x-odac-connection-ssl') === 'true'
|
|
28
|
+
this.ip = (this.header('x-odac-connection-remoteaddress') ?? req.connection.remoteAddress).replace('::ffff:', '')
|
|
29
|
+
delete this.req.headers['x-odac-connection-ssl']
|
|
30
|
+
delete this.req.headers['x-odac-connection-remoteaddress']
|
|
31
31
|
let route = req.headers.host.split('.')[0]
|
|
32
|
-
if (!
|
|
32
|
+
if (!Odac.Route.routes[route]) route = 'www'
|
|
33
33
|
this.route = route
|
|
34
|
-
|
|
34
|
+
if (this.res) {
|
|
35
|
+
this.#timeout = setTimeout(() => !this.res.finished && this.abort(408), Odac.Config.request.timeout)
|
|
36
|
+
}
|
|
35
37
|
this.#data()
|
|
36
|
-
if (!
|
|
37
|
-
if (!this.cookie('
|
|
38
|
+
if (!Odac.Request) Odac.Request = {}
|
|
39
|
+
if (!this.cookie('odac_client') || !this.session('_client') || this.session('_client') !== this.cookie('odac_client')) {
|
|
38
40
|
let client = nodeCrypto
|
|
39
41
|
.createHash('md5')
|
|
40
42
|
.update(this.ip + this.id + Date.now().toString() + Math.random().toString())
|
|
41
43
|
.digest('hex')
|
|
42
|
-
this.cookie('
|
|
44
|
+
this.cookie('odac_client', client, {expires: null, httpOnly: false})
|
|
43
45
|
this.session('_client', client)
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -48,8 +50,8 @@ class CandyRequest {
|
|
|
48
50
|
async abort(code) {
|
|
49
51
|
this.status(code)
|
|
50
52
|
let result = {401: 'Unauthorized', 404: 'Not Found', 408: 'Request Timeout'}[code] ?? null
|
|
51
|
-
if (
|
|
52
|
-
result = await
|
|
53
|
+
if (Odac.Route.routes[this.route].error && Odac.Route.routes[this.route].error[code])
|
|
54
|
+
result = await Odac.Route.routes[this.route].error[code].cache(this.#odac)
|
|
53
55
|
this.end(result)
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -179,8 +181,8 @@ class CandyRequest {
|
|
|
179
181
|
print() {
|
|
180
182
|
if (this.res.headersSent) return
|
|
181
183
|
|
|
182
|
-
if (this.#earlyHints && this.#earlyHints.length > 0 && global.
|
|
183
|
-
global.
|
|
184
|
+
if (this.#earlyHints && this.#earlyHints.length > 0 && global.Odac?.View?.EarlyHints) {
|
|
185
|
+
global.Odac.View.EarlyHints.send(this.res, this.#earlyHints)
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
this.#headers['Set-Cookie'] = this.#cookies.sent
|
|
@@ -225,8 +227,8 @@ class CandyRequest {
|
|
|
225
227
|
|
|
226
228
|
// - SESSION
|
|
227
229
|
session(key, value) {
|
|
228
|
-
if (!
|
|
229
|
-
if (!
|
|
230
|
+
if (!Odac.Request.session) Odac.Request.session = {}
|
|
231
|
+
if (!Odac.Request.sessionLocks) Odac.Request.sessionLocks = {}
|
|
230
232
|
|
|
231
233
|
let pri = nodeCrypto
|
|
232
234
|
.createHash('md5')
|
|
@@ -234,45 +236,45 @@ class CandyRequest {
|
|
|
234
236
|
.digest('hex')
|
|
235
237
|
let pub = this.cookie('candy_session')
|
|
236
238
|
|
|
237
|
-
if (!pub || !
|
|
239
|
+
if (!pub || !Odac.Request.session[pub + '-' + pri]) {
|
|
238
240
|
const lockKey = `${this.ip}-${pri}`
|
|
239
241
|
const now = Date.now()
|
|
240
242
|
|
|
241
|
-
if (
|
|
242
|
-
const lock =
|
|
243
|
-
if (now - lock.timestamp < 5000 &&
|
|
243
|
+
if (Odac.Request.sessionLocks[lockKey]) {
|
|
244
|
+
const lock = Odac.Request.sessionLocks[lockKey]
|
|
245
|
+
if (now - lock.timestamp < 5000 && Odac.Request.session[`${lock.sessionId}-${pri}`]) {
|
|
244
246
|
pub = lock.sessionId
|
|
245
247
|
} else {
|
|
246
|
-
delete
|
|
248
|
+
delete Odac.Request.sessionLocks[lockKey]
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
251
|
|
|
250
252
|
if (!pub) {
|
|
251
|
-
const sessionLockValues = Object.values(
|
|
253
|
+
const sessionLockValues = Object.values(Odac.Request.sessionLocks)
|
|
252
254
|
const activeSessions = new Set(sessionLockValues.map(l => l.sessionId))
|
|
253
255
|
do {
|
|
254
256
|
pub = nodeCrypto
|
|
255
257
|
.createHash('md5')
|
|
256
258
|
.update(this.ip + this.id + Date.now().toString() + Math.random().toString())
|
|
257
259
|
.digest('hex')
|
|
258
|
-
} while (
|
|
260
|
+
} while (Odac.Request.session[`${pub}-${pri}`] || activeSessions.has(pub))
|
|
259
261
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
Odac.Request.sessionLocks[lockKey] = {sessionId: pub, timestamp: now}
|
|
263
|
+
Odac.Request.session[`${pub}-${pri}`] = {}
|
|
262
264
|
this.cookie('candy_session', `${pub}`)
|
|
263
265
|
|
|
264
266
|
setTimeout(() => {
|
|
265
|
-
if (
|
|
266
|
-
delete
|
|
267
|
+
if (Odac.Request.sessionLocks[lockKey]?.timestamp === now) {
|
|
268
|
+
delete Odac.Request.sessionLocks[lockKey]
|
|
267
269
|
}
|
|
268
270
|
}, 5000)
|
|
269
271
|
}
|
|
270
272
|
}
|
|
271
273
|
|
|
272
|
-
if (!
|
|
273
|
-
if (value === undefined) return
|
|
274
|
-
else if (value === null) delete
|
|
275
|
-
else
|
|
274
|
+
if (!Odac.Request.session[pub + '-' + pri]) Odac.Request.session[pub + '-' + pri] = {}
|
|
275
|
+
if (value === undefined) return Odac.Request.session[pub + '-' + pri][key] ?? null
|
|
276
|
+
else if (value === null) delete Odac.Request.session[pub + '-' + pri][key]
|
|
277
|
+
else Odac.Request.session[pub + '-' + pri][key] = value
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
// - SET
|
|
@@ -298,4 +300,4 @@ class CandyRequest {
|
|
|
298
300
|
}
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
module.exports =
|
|
303
|
+
module.exports = OdacRequest
|