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
|
@@ -15,7 +15,7 @@ When you add a `mysql` object to your `config.json`, the system will automatical
|
|
|
15
15
|
}
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Once this is configured, you can directly use `
|
|
18
|
+
Once this is configured, you can directly use `Odac.Mysql` commands to run queries.
|
|
19
19
|
|
|
20
20
|
### Using Environment Variables
|
|
21
21
|
|
|
@@ -4,16 +4,16 @@ Normally, all publicly served files should be in your `public` folder. However,
|
|
|
4
4
|
|
|
5
5
|
```json
|
|
6
6
|
"route": {
|
|
7
|
-
"/assets/js/
|
|
7
|
+
"/assets/js/odac.js": "${odac}/framework/web/odac.js",
|
|
8
8
|
"/css/main.css": "/path/to/your/project/assets/css/main.css"
|
|
9
9
|
}
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
When a user visits a URL that matches a key in the `route` object,
|
|
12
|
+
When a user visits a URL that matches a key in the `route` object, Odac will serve the corresponding file from your filesystem.
|
|
13
13
|
|
|
14
|
-
#### Using the `${
|
|
14
|
+
#### Using the `${odac}` Variable
|
|
15
15
|
|
|
16
|
-
The special variable `${
|
|
16
|
+
The special variable `${odac}` is a shortcut that points to the root directory where Odac is installed. This is helpful for linking to files that are part of the framework itself.
|
|
17
17
|
|
|
18
18
|
#### Absolute Paths
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## 🌍 Environment Variables
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Odac supports environment variables through `.env` files, making it easy to manage sensitive data and environment-specific settings.
|
|
4
4
|
|
|
5
5
|
### Creating a .env File
|
|
6
6
|
|
|
@@ -65,13 +65,13 @@ Reference environment variables using `${VARIABLE_NAME}` syntax:
|
|
|
65
65
|
|
|
66
66
|
You can access environment variables in your controllers in three ways:
|
|
67
67
|
|
|
68
|
-
#### 1. Using
|
|
68
|
+
#### 1. Using Odac.env() (Recommended)
|
|
69
69
|
|
|
70
70
|
```javascript
|
|
71
71
|
module.exports = function() {
|
|
72
|
-
const apiKey =
|
|
73
|
-
const debug =
|
|
74
|
-
const port =
|
|
72
|
+
const apiKey = Odac.env('API_KEY')
|
|
73
|
+
const debug = Odac.env('DEBUG', 'false')
|
|
74
|
+
const port = Odac.env('PORT', '3000')
|
|
75
75
|
|
|
76
76
|
if (debug === 'true') {
|
|
77
77
|
console.log('Debug mode enabled')
|
|
@@ -91,12 +91,12 @@ module.exports = function() {
|
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
#### 3. From
|
|
94
|
+
#### 3. From Odac.Config (if defined in config.json)
|
|
95
95
|
|
|
96
96
|
```javascript
|
|
97
97
|
module.exports = function() {
|
|
98
|
-
const dbHost =
|
|
99
|
-
const apiKey =
|
|
98
|
+
const dbHost = Odac.Config.mysql.host
|
|
99
|
+
const apiKey = Odac.Config.api.stripe.key
|
|
100
100
|
}
|
|
101
101
|
```
|
|
102
102
|
|
|
@@ -107,15 +107,15 @@ module.exports = function() {
|
|
|
107
107
|
```javascript
|
|
108
108
|
// controller/home.js
|
|
109
109
|
module.exports = function() {
|
|
110
|
-
const betaEnabled =
|
|
111
|
-
const maintenance =
|
|
110
|
+
const betaEnabled = Odac.env('FEATURE_BETA', 'false') === 'true'
|
|
111
|
+
const maintenance = Odac.env('MAINTENANCE_MODE', 'false') === 'true'
|
|
112
112
|
|
|
113
113
|
if (maintenance) {
|
|
114
|
-
return
|
|
114
|
+
return Odac.abort(503)
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
return
|
|
117
|
+
Odac.set('betaEnabled', betaEnabled)
|
|
118
|
+
return Odac.View.render('home')
|
|
119
119
|
}
|
|
120
120
|
```
|
|
121
121
|
|
|
@@ -124,8 +124,8 @@ module.exports = function() {
|
|
|
124
124
|
```javascript
|
|
125
125
|
// controller/payment.js
|
|
126
126
|
module.exports = async function() {
|
|
127
|
-
const stripeKey =
|
|
128
|
-
const webhookSecret =
|
|
127
|
+
const stripeKey = Odac.env('STRIPE_SECRET_KEY')
|
|
128
|
+
const webhookSecret = Odac.env('STRIPE_WEBHOOK_SECRET')
|
|
129
129
|
|
|
130
130
|
const stripe = require('stripe')(stripeKey)
|
|
131
131
|
|
|
@@ -138,16 +138,16 @@ module.exports = async function() {
|
|
|
138
138
|
```javascript
|
|
139
139
|
// controller/contact.js
|
|
140
140
|
module.exports = async function() {
|
|
141
|
-
const mail =
|
|
141
|
+
const mail = Odac.Mail()
|
|
142
142
|
|
|
143
|
-
mail.from(
|
|
144
|
-
mail.to(
|
|
143
|
+
mail.from(Odac.env('MAIL_FROM', 'noreply@example.com'))
|
|
144
|
+
mail.to(Odac.request('email'))
|
|
145
145
|
mail.subject('Thank you for contacting us')
|
|
146
146
|
mail.html('<h1>We received your message!</h1>')
|
|
147
147
|
|
|
148
148
|
await mail.send()
|
|
149
149
|
|
|
150
|
-
return
|
|
150
|
+
return Odac.return({ success: true })
|
|
151
151
|
}
|
|
152
152
|
```
|
|
153
153
|
|
|
@@ -224,4 +224,4 @@ MAIL_FROM='noreply@example.com'
|
|
|
224
224
|
- Changes to `.env` require restarting the application
|
|
225
225
|
- The `.env` file is **optional** - you can use direct values in `config.json` if preferred
|
|
226
226
|
- Variables defined in `.env` are available throughout your entire application
|
|
227
|
-
- If a variable is not found, `
|
|
227
|
+
- If a variable is not found, `Odac.env()` returns the default value or `undefined`
|
|
@@ -17,7 +17,7 @@ You don't need to do anything - it just works!
|
|
|
17
17
|
|
|
18
18
|
### Automatic Resource Detection
|
|
19
19
|
|
|
20
|
-
When your application starts,
|
|
20
|
+
When your application starts, Odac scans your `view/` and `skeleton/` directories and builds a manifest of critical resources:
|
|
21
21
|
|
|
22
22
|
```html
|
|
23
23
|
<!-- skeleton/main.html -->
|
|
@@ -139,7 +139,7 @@ If you want to prevent specific resources from being preloaded, use the `defer`
|
|
|
139
139
|
|
|
140
140
|
The `defer` attribute works consistently for both CSS and JavaScript:
|
|
141
141
|
- **For JS**: Browser's native defer behavior (execute after DOM is ready)
|
|
142
|
-
- **For CSS**:
|
|
142
|
+
- **For CSS**: Odac-specific (exclude from Early Hints, but still loads normally)
|
|
143
143
|
|
|
144
144
|
This is useful for:
|
|
145
145
|
- Non-critical styles (animations, print styles)
|
|
@@ -199,9 +199,9 @@ At startup, the framework builds an in-memory manifest:
|
|
|
199
199
|
|
|
200
200
|
### Proxy Integration
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
Odac's architecture uses a proxy layer. Early Hints are:
|
|
203
203
|
1. Generated in the framework
|
|
204
|
-
2. Sent via `X-
|
|
204
|
+
2. Sent via `X-Odac-Early-Hints` header to proxy
|
|
205
205
|
3. Forwarded to client as `103 Early Hints` by proxy
|
|
206
206
|
|
|
207
207
|
This ensures Early Hints work correctly in the multi-domain hosting environment.
|
|
@@ -8,17 +8,17 @@ This is the most common method. It maps a URL path to a controller that is expec
|
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
10
|
// When a user visits yoursite.com/
|
|
11
|
-
|
|
11
|
+
Odac.Route.page('/', 'index');
|
|
12
12
|
|
|
13
13
|
// When a user visits yoursite.com/contact
|
|
14
|
-
|
|
14
|
+
Odac.Route.page('/contact', 'contact-form');
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
**Page Identifier:** The controller filename becomes the page identifier in the frontend. For example, `'contact-form'` becomes accessible as `
|
|
17
|
+
**Page Identifier:** The controller filename becomes the page identifier in the frontend. For example, `'contact-form'` becomes accessible as `Odac.page()` returning `"contact-form"`. This allows you to run page-specific JavaScript:
|
|
18
18
|
|
|
19
19
|
```javascript
|
|
20
20
|
// Frontend
|
|
21
|
-
|
|
21
|
+
Odac.action({
|
|
22
22
|
page: {
|
|
23
23
|
'contact-form': function() {
|
|
24
24
|
console.log('Contact form page loaded')
|
|
@@ -6,7 +6,7 @@ For simple pages that don't require complex logic in a controller, you can rende
|
|
|
6
6
|
This defines a page and immediately tells it which view components to render.
|
|
7
7
|
|
|
8
8
|
```javascript
|
|
9
|
-
|
|
9
|
+
Odac.Route.page("/users", {
|
|
10
10
|
skeleton: "dashboard",
|
|
11
11
|
header: "dashboard.main",
|
|
12
12
|
sidebar: "dashboard.main",
|
|
@@ -14,13 +14,13 @@ Candy.Route.page("/users", {
|
|
|
14
14
|
content: "users"
|
|
15
15
|
});
|
|
16
16
|
```
|
|
17
|
-
This example tells
|
|
17
|
+
This example tells Odac to render the `/users` page by assembling a view from multiple parts, likely using a main `dashboard` skeleton and filling it with different content blocks.
|
|
18
18
|
|
|
19
|
-
**Page Identifier:** When using view objects, the page identifier (accessible via `
|
|
19
|
+
**Page Identifier:** When using view objects, the page identifier (accessible via `Odac.page()` in frontend) is automatically set to the `content` or `all` value. In this example, the page identifier would be `"users"`, allowing you to run page-specific JavaScript:
|
|
20
20
|
|
|
21
21
|
```javascript
|
|
22
22
|
// Frontend
|
|
23
|
-
|
|
23
|
+
Odac.action({
|
|
24
24
|
page: {
|
|
25
25
|
users: function() {
|
|
26
26
|
console.log('Users page loaded')
|
|
@@ -34,7 +34,7 @@ Similar to `page()`, but requires authentication. Only authenticated users can a
|
|
|
34
34
|
|
|
35
35
|
```javascript
|
|
36
36
|
// Only authenticated users can see the dashboard
|
|
37
|
-
|
|
37
|
+
Odac.Route.auth.page('/', {
|
|
38
38
|
skeleton: 'main',
|
|
39
39
|
content: 'dashboard'
|
|
40
40
|
});
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
#### `get(path, controller, options)`
|
|
4
4
|
Defines a route that responds to `GET` requests. This is ideal for API endpoints that return data (like JSON).
|
|
5
5
|
|
|
6
|
-
- `options`: By default,
|
|
6
|
+
- `options`: By default, Odac protects routes from CSRF attacks by checking for a token. For a public API or stateless endpoint, you must disable this by passing `{ token: false }`. If you don't, the server will expect a token and will not return a response if one isn't provided.
|
|
7
7
|
|
|
8
8
|
```javascript
|
|
9
9
|
// An API endpoint at GET /api/users/123
|
|
10
10
|
// We disable the token check as this is a public API.
|
|
11
|
-
|
|
11
|
+
Odac.Route.get('/api/users/{id}', 'api/users.get', { token: false });
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
#### `post(path, controller, options)`
|
|
@@ -16,5 +16,5 @@ Defines a route that responds to `POST` requests, typically used for form submis
|
|
|
16
16
|
|
|
17
17
|
```javascript
|
|
18
18
|
// A form that posts data to /login
|
|
19
|
-
|
|
19
|
+
Odac.Route.post('/login', 'auth.login');
|
|
20
20
|
```
|
|
@@ -7,7 +7,7 @@ Defines a page route that requires authentication.
|
|
|
7
7
|
|
|
8
8
|
```javascript
|
|
9
9
|
// Only authenticated users can access the dashboard
|
|
10
|
-
|
|
10
|
+
Odac.Route.auth.page('/dashboard', 'dashboard.index');
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
#### `auth.page(path, viewConfig)`
|
|
@@ -15,7 +15,7 @@ Defines a controller-less page route that requires authentication.
|
|
|
15
15
|
|
|
16
16
|
```javascript
|
|
17
17
|
// Only authenticated users can see this view
|
|
18
|
-
|
|
18
|
+
Odac.Route.auth.page('/profile', {
|
|
19
19
|
skeleton: 'main',
|
|
20
20
|
head: 'profile.head',
|
|
21
21
|
content: 'profile',
|
|
@@ -28,7 +28,7 @@ Defines a GET route that requires authentication.
|
|
|
28
28
|
|
|
29
29
|
```javascript
|
|
30
30
|
// API endpoint for authenticated users only
|
|
31
|
-
|
|
31
|
+
Odac.Route.auth.get('/api/user/profile', 'api.user.profile');
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
#### `auth.post(path, controller, options)`
|
|
@@ -36,7 +36,7 @@ Defines a POST route that requires authentication.
|
|
|
36
36
|
|
|
37
37
|
```javascript
|
|
38
38
|
// Only authenticated users can update their profile
|
|
39
|
-
|
|
39
|
+
Odac.Route.auth.post('/api/user/update', 'api.user.update');
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
#### CSRF Token Protection
|
|
@@ -44,5 +44,5 @@ By default, all POST and GET routes have CSRF token protection enabled. You can
|
|
|
44
44
|
|
|
45
45
|
```javascript
|
|
46
46
|
// Disable CSRF token check for this route
|
|
47
|
-
|
|
47
|
+
Odac.Route.auth.post('/api/webhook', 'api.webhook', {token: false});
|
|
48
48
|
```
|
|
@@ -6,9 +6,9 @@ This is the powerful base method that all other routing methods use internally.
|
|
|
6
6
|
- `type`: A string defining the route type (e.g., `page`, `post`, `#page` for authenticated pages, etc.).
|
|
7
7
|
|
|
8
8
|
```javascript
|
|
9
|
-
// This is equivalent to
|
|
10
|
-
|
|
9
|
+
// This is equivalent to Odac.Route.post('/register', 'auth.register')
|
|
10
|
+
Odac.Route.set('post', '/register', 'auth.register');
|
|
11
11
|
|
|
12
12
|
// This creates an authenticated page route
|
|
13
|
-
|
|
13
|
+
Odac.Route.set('#page', '/account', 'account.settings');
|
|
14
14
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## 🚨 Error Pages
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Odac framework provides built-in error handling with customizable error pages for different HTTP status codes. You can define custom error pages to provide a better user experience when things go wrong.
|
|
4
4
|
|
|
5
5
|
#### `error(statusCode, controller)`
|
|
6
6
|
Maps HTTP error status codes to custom controller handlers. This allows you to create branded error pages instead of showing generic browser error messages.
|
|
@@ -10,13 +10,13 @@ Maps HTTP error status codes to custom controller handlers. This allows you to c
|
|
|
10
10
|
|
|
11
11
|
```javascript
|
|
12
12
|
// Custom 404 Not Found page
|
|
13
|
-
|
|
13
|
+
Odac.Route.error(404, 'errors/not-found');
|
|
14
14
|
|
|
15
15
|
// Custom 500 Internal Server Error page
|
|
16
|
-
|
|
16
|
+
Odac.Route.error(500, 'errors/server-error');
|
|
17
17
|
|
|
18
18
|
// Custom 403 Forbidden page
|
|
19
|
-
|
|
19
|
+
Odac.Route.error(403, 'errors/forbidden');
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
#### Common Error Status Codes
|
|
@@ -34,8 +34,8 @@ Create error controllers in your `controller/errors/` directory:
|
|
|
34
34
|
```javascript
|
|
35
35
|
// controller/errors/not-found.js
|
|
36
36
|
module.exports = function() {
|
|
37
|
-
|
|
38
|
-
return
|
|
37
|
+
Odac.response.status(404);
|
|
38
|
+
return Odac.view('errors/404', {
|
|
39
39
|
title: 'Page Not Found',
|
|
40
40
|
message: 'The page you are looking for could not be found.'
|
|
41
41
|
});
|
|
@@ -45,8 +45,8 @@ module.exports = function() {
|
|
|
45
45
|
```javascript
|
|
46
46
|
// controller/errors/server-error.js
|
|
47
47
|
module.exports = function() {
|
|
48
|
-
|
|
49
|
-
return
|
|
48
|
+
Odac.response.status(500);
|
|
49
|
+
return Odac.view('errors/500', {
|
|
50
50
|
title: 'Server Error',
|
|
51
51
|
message: 'Something went wrong on our end. Please try again later.'
|
|
52
52
|
});
|
|
@@ -74,26 +74,26 @@ Create corresponding view templates in your `view/errors/` directory:
|
|
|
74
74
|
|
|
75
75
|
#### Default Error Handling
|
|
76
76
|
|
|
77
|
-
If no custom error page is defined,
|
|
77
|
+
If no custom error page is defined, Odac will fall back to its built-in error responses. It's recommended to at least define custom 404 and 500 error pages for a professional user experience.
|
|
78
78
|
|
|
79
79
|
#### Error Context
|
|
80
80
|
|
|
81
|
-
Error controllers receive the same
|
|
81
|
+
Error controllers receive the same Odac context as regular controllers, allowing you to:
|
|
82
82
|
|
|
83
|
-
- Access request information (`
|
|
84
|
-
- Use database connections (`
|
|
85
|
-
- Render views with data (`
|
|
86
|
-
- Redirect users (`
|
|
83
|
+
- Access request information (`Odac.request`)
|
|
84
|
+
- Use database connections (`Odac.db`)
|
|
85
|
+
- Render views with data (`Odac.view`)
|
|
86
|
+
- Redirect users (`Odac.redirect`)
|
|
87
87
|
- Log error details for debugging
|
|
88
88
|
|
|
89
89
|
```javascript
|
|
90
90
|
// controller/errors/server-error.js
|
|
91
91
|
module.exports = function() {
|
|
92
92
|
// Log the error for debugging
|
|
93
|
-
console.error('Server error occurred:',
|
|
93
|
+
console.error('Server error occurred:', Odac.request.url);
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
return
|
|
95
|
+
Odac.response.status(500);
|
|
96
|
+
return Odac.view('errors/500', {
|
|
97
97
|
title: 'Oops! Something went wrong',
|
|
98
98
|
supportEmail: 'support@yoursite.com'
|
|
99
99
|
});
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Cron Jobs
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The Odac framework provides a built-in cron system for running automated tasks. This system checks every minute and executes jobs based on specified conditions.
|
|
4
4
|
|
|
5
5
|
## Basic Usage
|
|
6
6
|
|
|
7
|
-
Use the `
|
|
7
|
+
Use the `Odac.Route.cron()` method to define cron jobs:
|
|
8
8
|
|
|
9
9
|
```javascript
|
|
10
10
|
// With controller file
|
|
11
|
-
|
|
11
|
+
Odac.Route.cron('backup').everyDay(1) // Runs every day
|
|
12
12
|
|
|
13
13
|
// With direct function
|
|
14
|
-
|
|
14
|
+
Odac.Route.cron(() => {
|
|
15
15
|
console.log('Task executed!')
|
|
16
16
|
}).everyHour(2) // Runs every 2 hours
|
|
17
17
|
```
|
|
@@ -37,7 +37,7 @@ module.exports = () => {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Usage
|
|
40
|
-
|
|
40
|
+
Odac.Route.cron('admin.cleanup').everyDay(1)
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
## Direct Function Usage
|
|
@@ -46,10 +46,10 @@ You can also define cron jobs with inline functions:
|
|
|
46
46
|
|
|
47
47
|
```javascript
|
|
48
48
|
// Simple inline function
|
|
49
|
-
|
|
49
|
+
Odac.Route.cron(() => console.log('Simple task running')).everyMinute(5)
|
|
50
50
|
|
|
51
51
|
// Async function
|
|
52
|
-
|
|
52
|
+
Odac.Route.cron(async () => {
|
|
53
53
|
const data = await fetchSomeData()
|
|
54
54
|
console.log('Async task completed', data)
|
|
55
55
|
}).everyHour(1)
|
|
@@ -60,7 +60,7 @@ const cleanupTask = (directory) => {
|
|
|
60
60
|
// Cleanup logic...
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Odac.Route.cron(() => cleanupTask('/tmp')).everyDay(1)
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
## Time Conditions
|
|
@@ -68,7 +68,7 @@ Candy.Route.cron(() => cleanupTask('/tmp')).everyDay(1)
|
|
|
68
68
|
### Specific Time Values
|
|
69
69
|
|
|
70
70
|
```javascript
|
|
71
|
-
|
|
71
|
+
Odac.Route.cron('task')
|
|
72
72
|
|
|
73
73
|
// Minute (0-59)
|
|
74
74
|
.minute(30) // At 30th minute
|
|
@@ -95,7 +95,7 @@ Candy.Route.cron('task')
|
|
|
95
95
|
### Periodic Execution
|
|
96
96
|
|
|
97
97
|
```javascript
|
|
98
|
-
|
|
98
|
+
Odac.Route.cron('periodic')
|
|
99
99
|
|
|
100
100
|
// Every N minutes
|
|
101
101
|
.everyMinute(5) // Every 5 minutes
|
|
@@ -122,18 +122,18 @@ You can combine multiple conditions:
|
|
|
122
122
|
|
|
123
123
|
```javascript
|
|
124
124
|
// Every day at 14:30
|
|
125
|
-
|
|
125
|
+
Odac.Route.cron('daily-report')
|
|
126
126
|
.hour(14)
|
|
127
127
|
.minute(30)
|
|
128
128
|
|
|
129
129
|
// Mondays at 09:00
|
|
130
|
-
|
|
130
|
+
Odac.Route.cron('weekly-task')
|
|
131
131
|
.weekDay(1)
|
|
132
132
|
.hour(9)
|
|
133
133
|
.minute(0)
|
|
134
134
|
|
|
135
135
|
// First day of every month at midnight
|
|
136
|
-
|
|
136
|
+
Odac.Route.cron('monthly-cleanup')
|
|
137
137
|
.day(1)
|
|
138
138
|
.hour(0)
|
|
139
139
|
.minute(0)
|