odac 0.9.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.
Files changed (213) hide show
  1. package/.editorconfig +21 -0
  2. package/.github/workflows/auto-pr-description.yml +49 -0
  3. package/.github/workflows/release.yml +32 -0
  4. package/.github/workflows/test-coverage.yml +58 -0
  5. package/.husky/pre-commit +2 -0
  6. package/.kiro/steering/code-style.md +56 -0
  7. package/.kiro/steering/product.md +20 -0
  8. package/.kiro/steering/structure.md +77 -0
  9. package/.kiro/steering/tech.md +87 -0
  10. package/.prettierrc +10 -0
  11. package/.releaserc.js +134 -0
  12. package/AGENTS.md +84 -0
  13. package/CHANGELOG.md +181 -0
  14. package/CODE_OF_CONDUCT.md +83 -0
  15. package/CONTRIBUTING.md +63 -0
  16. package/LICENSE +661 -0
  17. package/README.md +57 -0
  18. package/SECURITY.md +26 -0
  19. package/bin/candy +10 -0
  20. package/bin/candypack +10 -0
  21. package/cli/index.js +3 -0
  22. package/cli/src/Cli.js +348 -0
  23. package/cli/src/Connector.js +93 -0
  24. package/cli/src/Monitor.js +416 -0
  25. package/core/Candy.js +87 -0
  26. package/core/Commands.js +239 -0
  27. package/core/Config.js +1094 -0
  28. package/core/Lang.js +52 -0
  29. package/core/Log.js +43 -0
  30. package/core/Process.js +26 -0
  31. package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
  32. package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
  33. package/docs/backend/01-overview/03-development-server.md +79 -0
  34. package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
  35. package/docs/backend/03-config/00-configuration-overview.md +214 -0
  36. package/docs/backend/03-config/01-database-connection.md +60 -0
  37. package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
  38. package/docs/backend/03-config/03-request-timeout.md +11 -0
  39. package/docs/backend/03-config/04-environment-variables.md +227 -0
  40. package/docs/backend/03-config/05-early-hints.md +352 -0
  41. package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
  42. package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
  43. package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
  44. package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
  45. package/docs/backend/04-routing/05-advanced-routing.md +14 -0
  46. package/docs/backend/04-routing/06-error-pages.md +101 -0
  47. package/docs/backend/04-routing/07-cron-jobs.md +149 -0
  48. package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
  49. package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
  50. package/docs/backend/05-controllers/03-controller-classes.md +93 -0
  51. package/docs/backend/05-forms/01-custom-forms.md +395 -0
  52. package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
  53. package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
  54. package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
  55. package/docs/backend/07-views/01-the-view-directory.md +73 -0
  56. package/docs/backend/07-views/02-rendering-a-view.md +179 -0
  57. package/docs/backend/07-views/03-template-syntax.md +181 -0
  58. package/docs/backend/07-views/03-variables.md +328 -0
  59. package/docs/backend/07-views/04-request-data.md +231 -0
  60. package/docs/backend/07-views/05-conditionals.md +290 -0
  61. package/docs/backend/07-views/06-loops.md +353 -0
  62. package/docs/backend/07-views/07-translations.md +358 -0
  63. package/docs/backend/07-views/08-backend-javascript.md +398 -0
  64. package/docs/backend/07-views/09-comments.md +297 -0
  65. package/docs/backend/08-database/01-database-connection.md +99 -0
  66. package/docs/backend/08-database/02-using-mysql.md +322 -0
  67. package/docs/backend/09-validation/01-the-validator-service.md +424 -0
  68. package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
  69. package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
  70. package/docs/backend/10-authentication/03-register.md +134 -0
  71. package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
  72. package/docs/backend/10-authentication/05-session-management.md +159 -0
  73. package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
  74. package/docs/backend/11-mail/01-the-mail-service.md +42 -0
  75. package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
  76. package/docs/backend/13-utilities/01-candy-var.md +504 -0
  77. package/docs/frontend/01-overview/01-introduction.md +146 -0
  78. package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
  79. package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
  80. package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
  81. package/docs/frontend/03-forms/01-form-handling.md +420 -0
  82. package/docs/frontend/04-api-requests/01-get-post.md +443 -0
  83. package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
  84. package/docs/index.json +452 -0
  85. package/docs/server/01-installation/01-quick-install.md +19 -0
  86. package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
  87. package/docs/server/02-get-started/01-core-concepts.md +7 -0
  88. package/docs/server/02-get-started/02-basic-commands.md +57 -0
  89. package/docs/server/02-get-started/03-cli-reference.md +276 -0
  90. package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
  91. package/docs/server/03-service/01-start-a-new-service.md +57 -0
  92. package/docs/server/03-service/02-delete-a-service.md +48 -0
  93. package/docs/server/04-web/01-create-a-website.md +36 -0
  94. package/docs/server/04-web/02-list-websites.md +9 -0
  95. package/docs/server/04-web/03-delete-a-website.md +29 -0
  96. package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
  97. package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
  98. package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
  99. package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
  100. package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
  101. package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
  102. package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
  103. package/docs/server/07-mail/04-change-account-password.md +23 -0
  104. package/eslint.config.mjs +120 -0
  105. package/framework/index.js +4 -0
  106. package/framework/src/Auth.js +309 -0
  107. package/framework/src/Candy.js +81 -0
  108. package/framework/src/Config.js +79 -0
  109. package/framework/src/Env.js +60 -0
  110. package/framework/src/Lang.js +57 -0
  111. package/framework/src/Mail.js +83 -0
  112. package/framework/src/Mysql.js +575 -0
  113. package/framework/src/Request.js +301 -0
  114. package/framework/src/Route/Cron.js +128 -0
  115. package/framework/src/Route/Internal.js +439 -0
  116. package/framework/src/Route.js +455 -0
  117. package/framework/src/Server.js +15 -0
  118. package/framework/src/Stream.js +163 -0
  119. package/framework/src/Token.js +37 -0
  120. package/framework/src/Validator.js +271 -0
  121. package/framework/src/Var.js +211 -0
  122. package/framework/src/View/EarlyHints.js +190 -0
  123. package/framework/src/View/Form.js +600 -0
  124. package/framework/src/View.js +513 -0
  125. package/framework/web/candy.js +838 -0
  126. package/jest.config.js +22 -0
  127. package/locale/de-DE.json +80 -0
  128. package/locale/en-US.json +79 -0
  129. package/locale/es-ES.json +80 -0
  130. package/locale/fr-FR.json +80 -0
  131. package/locale/pt-BR.json +80 -0
  132. package/locale/ru-RU.json +80 -0
  133. package/locale/tr-TR.json +85 -0
  134. package/locale/zh-CN.json +80 -0
  135. package/package.json +86 -0
  136. package/server/index.js +5 -0
  137. package/server/src/Api.js +88 -0
  138. package/server/src/DNS.js +940 -0
  139. package/server/src/Hub.js +535 -0
  140. package/server/src/Mail.js +571 -0
  141. package/server/src/SSL.js +180 -0
  142. package/server/src/Server.js +27 -0
  143. package/server/src/Service.js +248 -0
  144. package/server/src/Subdomain.js +64 -0
  145. package/server/src/Web/Firewall.js +170 -0
  146. package/server/src/Web/Proxy.js +134 -0
  147. package/server/src/Web.js +451 -0
  148. package/server/src/mail/imap.js +1091 -0
  149. package/server/src/mail/server.js +32 -0
  150. package/server/src/mail/smtp.js +786 -0
  151. package/test/cli/Cli.test.js +36 -0
  152. package/test/core/Candy.test.js +234 -0
  153. package/test/core/Commands.test.js +538 -0
  154. package/test/core/Config.test.js +1435 -0
  155. package/test/core/Lang.test.js +250 -0
  156. package/test/core/Process.test.js +156 -0
  157. package/test/framework/Route.test.js +239 -0
  158. package/test/framework/View/EarlyHints.test.js +282 -0
  159. package/test/scripts/check-coverage.js +132 -0
  160. package/test/server/Api.test.js +647 -0
  161. package/test/server/Client.test.js +338 -0
  162. package/test/server/DNS.test.js +2050 -0
  163. package/test/server/DNS.test.js.bak +2084 -0
  164. package/test/server/Log.test.js +73 -0
  165. package/test/server/Mail.account.test_.js +460 -0
  166. package/test/server/Mail.init.test_.js +411 -0
  167. package/test/server/Mail.test_.js +1340 -0
  168. package/test/server/SSL.test_.js +1491 -0
  169. package/test/server/Server.test.js +765 -0
  170. package/test/server/Service.test_.js +1127 -0
  171. package/test/server/Subdomain.test.js +440 -0
  172. package/test/server/Web/Firewall.test.js +175 -0
  173. package/test/server/Web.test_.js +1562 -0
  174. package/test/server/__mocks__/acme-client.js +17 -0
  175. package/test/server/__mocks__/bcrypt.js +50 -0
  176. package/test/server/__mocks__/child_process.js +389 -0
  177. package/test/server/__mocks__/crypto.js +432 -0
  178. package/test/server/__mocks__/fs.js +450 -0
  179. package/test/server/__mocks__/globalCandy.js +227 -0
  180. package/test/server/__mocks__/http-proxy.js +105 -0
  181. package/test/server/__mocks__/http.js +575 -0
  182. package/test/server/__mocks__/https.js +272 -0
  183. package/test/server/__mocks__/index.js +249 -0
  184. package/test/server/__mocks__/mail/server.js +100 -0
  185. package/test/server/__mocks__/mail/smtp.js +31 -0
  186. package/test/server/__mocks__/mailparser.js +81 -0
  187. package/test/server/__mocks__/net.js +369 -0
  188. package/test/server/__mocks__/node-forge.js +328 -0
  189. package/test/server/__mocks__/os.js +320 -0
  190. package/test/server/__mocks__/path.js +291 -0
  191. package/test/server/__mocks__/selfsigned.js +8 -0
  192. package/test/server/__mocks__/server/src/mail/server.js +100 -0
  193. package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
  194. package/test/server/__mocks__/smtp-server.js +106 -0
  195. package/test/server/__mocks__/sqlite3.js +394 -0
  196. package/test/server/__mocks__/testFactories.js +299 -0
  197. package/test/server/__mocks__/testHelpers.js +363 -0
  198. package/test/server/__mocks__/tls.js +229 -0
  199. package/watchdog/index.js +3 -0
  200. package/watchdog/src/Watchdog.js +156 -0
  201. package/web/config.json +5 -0
  202. package/web/controller/page/about.js +27 -0
  203. package/web/controller/page/index.js +34 -0
  204. package/web/package.json +18 -0
  205. package/web/public/assets/css/style.css +1835 -0
  206. package/web/public/assets/js/app.js +96 -0
  207. package/web/route/www.js +19 -0
  208. package/web/skeleton/main.html +22 -0
  209. package/web/view/content/about.html +65 -0
  210. package/web/view/content/home.html +205 -0
  211. package/web/view/footer/main.html +11 -0
  212. package/web/view/head/main.html +5 -0
  213. package/web/view/header/main.html +14 -0
@@ -0,0 +1,227 @@
1
+ ## 🌍 Environment Variables
2
+
3
+ CandyPack supports environment variables through `.env` files, making it easy to manage sensitive data and environment-specific settings.
4
+
5
+ ### Creating a .env File
6
+
7
+ Create a `.env` file in your website's root directory (same location as `config.json`):
8
+
9
+ ```bash
10
+ # .env
11
+
12
+ # Application
13
+ NODE_ENV=production
14
+ DEBUG=false
15
+ APP_URL=https://myapp.com
16
+
17
+ # Database
18
+ MYSQL_HOST=localhost
19
+ MYSQL_USER=root
20
+ MYSQL_PASSWORD=super_secret_123
21
+ MYSQL_DATABASE=myapp
22
+
23
+ # API Keys
24
+ STRIPE_SECRET_KEY=sk_live_xxxxx
25
+ STRIPE_WEBHOOK_SECRET=whsec_xxxxx
26
+ API_KEY=your_api_key_here
27
+
28
+ # Mail
29
+ MAIL_FROM=noreply@myapp.com
30
+ SMTP_HOST=smtp.gmail.com
31
+ SMTP_PORT=587
32
+ SMTP_USER=user@gmail.com
33
+ SMTP_PASSWORD=app_password
34
+
35
+ # Features
36
+ FEATURE_BETA=true
37
+ MAINTENANCE_MODE=false
38
+ ```
39
+
40
+ ### Using in config.json
41
+
42
+ Reference environment variables using `${VARIABLE_NAME}` syntax:
43
+
44
+ ```json
45
+ {
46
+ "mysql": {
47
+ "host": "${MYSQL_HOST}",
48
+ "user": "${MYSQL_USER}",
49
+ "password": "${MYSQL_PASSWORD}",
50
+ "database": "${MYSQL_DATABASE}"
51
+ },
52
+ "api": {
53
+ "stripe": {
54
+ "key": "${STRIPE_SECRET_KEY}",
55
+ "webhook": "${STRIPE_WEBHOOK_SECRET}"
56
+ }
57
+ },
58
+ "mail": {
59
+ "from": "${MAIL_FROM}"
60
+ }
61
+ }
62
+ ```
63
+
64
+ ### Accessing in Controllers
65
+
66
+ You can access environment variables in your controllers in three ways:
67
+
68
+ #### 1. Using Candy.env() (Recommended)
69
+
70
+ ```javascript
71
+ module.exports = function() {
72
+ const apiKey = Candy.env('API_KEY')
73
+ const debug = Candy.env('DEBUG', 'false')
74
+ const port = Candy.env('PORT', '3000')
75
+
76
+ if (debug === 'true') {
77
+ console.log('Debug mode enabled')
78
+ }
79
+ }
80
+ ```
81
+
82
+ The second parameter is the default value if the variable is not set.
83
+
84
+ #### 2. Using process.env
85
+
86
+ ```javascript
87
+ module.exports = function() {
88
+ const nodeEnv = process.env.NODE_ENV
89
+ const debug = process.env.DEBUG === 'true'
90
+ const apiKey = process.env.API_KEY
91
+ }
92
+ ```
93
+
94
+ #### 3. From Candy.Config (if defined in config.json)
95
+
96
+ ```javascript
97
+ module.exports = function() {
98
+ const dbHost = Candy.Config.mysql.host
99
+ const apiKey = Candy.Config.api.stripe.key
100
+ }
101
+ ```
102
+
103
+ ### Practical Examples
104
+
105
+ #### Feature Flags
106
+
107
+ ```javascript
108
+ // controller/home.js
109
+ module.exports = function() {
110
+ const betaEnabled = Candy.env('FEATURE_BETA', 'false') === 'true'
111
+ const maintenance = Candy.env('MAINTENANCE_MODE', 'false') === 'true'
112
+
113
+ if (maintenance) {
114
+ return Candy.abort(503)
115
+ }
116
+
117
+ Candy.set('betaEnabled', betaEnabled)
118
+ return Candy.View.render('home')
119
+ }
120
+ ```
121
+
122
+ #### API Integration
123
+
124
+ ```javascript
125
+ // controller/payment.js
126
+ module.exports = async function() {
127
+ const stripeKey = Candy.env('STRIPE_SECRET_KEY')
128
+ const webhookSecret = Candy.env('STRIPE_WEBHOOK_SECRET')
129
+
130
+ const stripe = require('stripe')(stripeKey)
131
+
132
+ // Process payment...
133
+ }
134
+ ```
135
+
136
+ #### Mail Configuration
137
+
138
+ ```javascript
139
+ // controller/contact.js
140
+ module.exports = async function() {
141
+ const mail = Candy.Mail()
142
+
143
+ mail.from(Candy.env('MAIL_FROM', 'noreply@example.com'))
144
+ mail.to(Candy.request('email'))
145
+ mail.subject('Thank you for contacting us')
146
+ mail.html('<h1>We received your message!</h1>')
147
+
148
+ await mail.send()
149
+
150
+ return Candy.return({ success: true })
151
+ }
152
+ ```
153
+
154
+ ### Security Best Practices
155
+
156
+ #### 1. Add .env to .gitignore
157
+
158
+ The `.env` file should never be committed to version control:
159
+
160
+ ```gitignore
161
+ # .gitignore
162
+ .env
163
+ .env.local
164
+ .env.*.local
165
+ ```
166
+
167
+ #### 2. Create .env.example
168
+
169
+ Provide a template for other developers:
170
+
171
+ ```bash
172
+ # .env.example
173
+
174
+ # Database
175
+ MYSQL_HOST=localhost
176
+ MYSQL_USER=root
177
+ MYSQL_PASSWORD=your_password_here
178
+ MYSQL_DATABASE=myapp
179
+
180
+ # API Keys
181
+ API_KEY=your_api_key_here
182
+ ```
183
+
184
+ Commit `.env.example` to git, but not `.env`.
185
+
186
+ #### 3. Different Environments
187
+
188
+ Use different `.env` files for different environments:
189
+
190
+ **Development (.env):**
191
+ ```bash
192
+ NODE_ENV=development
193
+ DEBUG=true
194
+ MYSQL_HOST=localhost
195
+ MYSQL_PASSWORD=dev123
196
+ ```
197
+
198
+ **Production (.env):**
199
+ ```bash
200
+ NODE_ENV=production
201
+ DEBUG=false
202
+ MYSQL_HOST=production.db.com
203
+ MYSQL_PASSWORD=super_secure_production_password
204
+ ```
205
+
206
+ ### Comments and Formatting
207
+
208
+ The `.env` file supports:
209
+
210
+ - **Comments:** Lines starting with `#`
211
+ - **Quotes:** Values can be wrapped in single or double quotes
212
+ - **Spaces:** Spaces around `=` are trimmed
213
+
214
+ ```bash
215
+ # This is a comment
216
+ API_KEY=simple_value
217
+ DB_PASSWORD="password with spaces"
218
+ MAIL_FROM='noreply@example.com'
219
+ ```
220
+
221
+ ### Important Notes
222
+
223
+ - Environment variables are loaded when the application starts
224
+ - Changes to `.env` require restarting the application
225
+ - The `.env` file is **optional** - you can use direct values in `config.json` if preferred
226
+ - Variables defined in `.env` are available throughout your entire application
227
+ - If a variable is not found, `Candy.env()` returns the default value or `undefined`
@@ -0,0 +1,352 @@
1
+ # Early Hints (HTTP 103)
2
+
3
+ Early Hints is a performance optimization feature that allows the server to send preliminary HTTP headers to the browser before the final response is ready. This enables browsers to start preloading critical resources (CSS, JavaScript, fonts) while the server is still processing the request.
4
+
5
+ ## Zero-Config Operation
6
+
7
+ Early Hints works automatically without any configuration. The framework:
8
+
9
+ 1. **Detects** critical resources from your HTML files at startup
10
+ 2. **Caches** resource information for fast access
11
+ 3. **Sends** Early Hints on subsequent requests automatically
12
+ 4. **Optimizes** page load performance transparently
13
+
14
+ You don't need to do anything - it just works!
15
+
16
+ ## How It Works
17
+
18
+ ### Automatic Resource Detection
19
+
20
+ When your application starts, CandyPack scans your `view/` and `skeleton/` directories and builds a manifest of critical resources:
21
+
22
+ ```html
23
+ <!-- skeleton/main.html -->
24
+ <html>
25
+ <head>
26
+ <link rel="stylesheet" href="/css/main.css">
27
+ <script src="/js/app.js"></script>
28
+ </head>
29
+ <body>...</body>
30
+ </html>
31
+ ```
32
+
33
+ The framework automatically detects:
34
+ - ✅ CSS files (`<link rel="stylesheet">`)
35
+ - ✅ Blocking JavaScript (`<script src="...">` without `defer` or `async`)
36
+ - ✅ Web fonts (`<link href="...woff2">`)
37
+
38
+ ### Request Flow
39
+
40
+ **First Request:**
41
+ ```
42
+ 1. Browser requests /
43
+ 2. Controller sets view: skeleton('main')
44
+ 3. Framework checks manifest for 'skeleton/main'
45
+ 4. Sends 103 Early Hints with CSS/JS links
46
+ 5. Browser starts downloading resources
47
+ 6. Server processes request (database queries, etc.)
48
+ 7. Sends 200 OK with HTML
49
+ 8. Resources already loaded!
50
+ ```
51
+
52
+ **Subsequent Requests:**
53
+ Same flow - hints are sent from the manifest immediately.
54
+
55
+ ## Configuration (Optional)
56
+
57
+ While Early Hints works automatically, you can customize it in `config.json`:
58
+
59
+ ```json
60
+ {
61
+ "earlyHints": {
62
+ "enabled": true,
63
+ "auto": true,
64
+ "maxResources": 5
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### Options
70
+
71
+ #### `enabled` (boolean, default: `true`)
72
+ Enable or disable Early Hints globally.
73
+
74
+ ```json
75
+ {
76
+ "earlyHints": {
77
+ "enabled": false
78
+ }
79
+ }
80
+ ```
81
+
82
+ #### `auto` (boolean, default: `true`)
83
+ Enable automatic resource detection and hint generation.
84
+
85
+ ```json
86
+ {
87
+ "earlyHints": {
88
+ "auto": false
89
+ }
90
+ }
91
+ ```
92
+
93
+ #### `maxResources` (number, default: `5`)
94
+ Maximum number of resources to include in Early Hints. Limiting this prevents overwhelming the browser with too many preload hints.
95
+
96
+ ```json
97
+ {
98
+ "earlyHints": {
99
+ "maxResources": 3
100
+ }
101
+ }
102
+ ```
103
+
104
+ ## What Gets Preloaded?
105
+
106
+ The framework intelligently selects only **critical resources** from the `<head>` section:
107
+
108
+ ### ✅ Included
109
+ - CSS files: `<link rel="stylesheet" href="/css/main.css">`
110
+ - Blocking JavaScript: `<script src="/js/app.js"></script>`
111
+ - Web fonts: `<link href="/fonts/main.woff2" as="font">` (supports `.woff`, `.woff2`, `.ttf`, `.otf`, `.eot`)
112
+
113
+ ### ❌ Excluded
114
+ - Deferred scripts: `<script src="/js/app.js" defer></script>`
115
+ - Async scripts: `<script src="/js/app.js" async></script>`
116
+ - Deferred CSS: `<link rel="stylesheet" href="/css/non-critical.css" defer>`
117
+ - Resources in `<body>` (not critical for initial render)
118
+ - Images (handled by browser's own optimization)
119
+
120
+ ## Excluding Resources from Early Hints
121
+
122
+ If you want to prevent specific resources from being preloaded, use the `defer` attribute:
123
+
124
+ ```html
125
+ <head>
126
+ <!-- Critical CSS - will be preloaded -->
127
+ <link rel="stylesheet" href="/css/critical.css">
128
+
129
+ <!-- Non-critical CSS - will NOT be preloaded -->
130
+ <link rel="stylesheet" href="/css/non-critical.css" defer>
131
+
132
+ <!-- Critical JS - will be preloaded -->
133
+ <script src="/js/app.js"></script>
134
+
135
+ <!-- Analytics JS - will NOT be preloaded -->
136
+ <script src="/js/analytics.js" defer></script>
137
+ </head>
138
+ ```
139
+
140
+ The `defer` attribute works consistently for both CSS and JavaScript:
141
+ - **For JS**: Browser's native defer behavior (execute after DOM is ready)
142
+ - **For CSS**: CandyPack-specific (exclude from Early Hints, but still loads normally)
143
+
144
+ This is useful for:
145
+ - Non-critical styles (animations, print styles)
146
+ - Analytics and tracking scripts
147
+ - Third-party widgets
148
+ - Below-the-fold content styles
149
+
150
+ ## Performance Impact
151
+
152
+ Early Hints is most effective when:
153
+ - Server-side processing takes time (database queries, API calls)
154
+ - You have critical CSS/JS files in `<head>`
155
+ - Users are on slower connections
156
+
157
+ ### Example Improvement
158
+
159
+ **Without Early Hints:**
160
+ ```
161
+ Server processing: 500ms
162
+ Resource download: 200ms
163
+ Total: 700ms
164
+ ```
165
+
166
+ **With Early Hints:**
167
+ ```
168
+ Server processing: 500ms (resources downloading in parallel)
169
+ Total: 500ms (200ms saved!)
170
+ ```
171
+
172
+ ## Browser Support
173
+
174
+ - Chrome 103+
175
+ - Edge 103+
176
+ - Firefox 103+
177
+ - Safari (partial support)
178
+
179
+ Older browsers simply ignore the `103` response and wait for the `200 OK` - no breaking changes!
180
+
181
+ ## Technical Details
182
+
183
+ ### Manifest System
184
+
185
+ At startup, the framework builds an in-memory manifest:
186
+
187
+ ```javascript
188
+ {
189
+ 'view/header/home': [
190
+ {href: '/css/header.css', as: 'style'},
191
+ {href: '/js/header.js', as: 'script'}
192
+ ],
193
+ 'skeleton/main': [
194
+ {href: '/css/main.css', as: 'style'},
195
+ {href: '/js/app.js', as: 'script'}
196
+ ]
197
+ }
198
+ ```
199
+
200
+ ### Proxy Integration
201
+
202
+ CandyPack's architecture uses a proxy layer. Early Hints are:
203
+ 1. Generated in the framework
204
+ 2. Sent via `X-Candy-Early-Hints` header to proxy
205
+ 3. Forwarded to client as `103 Early Hints` by proxy
206
+
207
+ This ensures Early Hints work correctly in the multi-domain hosting environment.
208
+
209
+ ### Node.js Requirements
210
+
211
+ - Requires Node.js 18+ for `response.writeEarlyHints()` API
212
+ - Automatically disabled on older Node.js versions
213
+ - No errors or warnings - graceful degradation
214
+
215
+ ## Best Practices
216
+
217
+ ### 1. Keep Critical Resources in `<head>`
218
+
219
+ ```html
220
+ <!-- Good: Critical CSS in head -->
221
+ <head>
222
+ <link rel="stylesheet" href="/css/critical.css">
223
+ </head>
224
+
225
+ <!-- Bad: CSS in body -->
226
+ <body>
227
+ <link rel="stylesheet" href="/css/styles.css">
228
+ </body>
229
+ ```
230
+
231
+ ### 2. Use `defer` for Non-Critical Scripts
232
+
233
+ ```html
234
+ <!-- Good: Non-critical scripts deferred -->
235
+ <script src="/js/analytics.js" defer></script>
236
+
237
+ <!-- Bad: Blocking script for non-critical feature -->
238
+ <script src="/js/analytics.js"></script>
239
+ ```
240
+
241
+ ### 3. Minimize Critical Resources
242
+
243
+ Aim for 3-5 critical resources maximum. Combine CSS/JS files if needed:
244
+
245
+ ```html
246
+ <!-- Good: Combined critical CSS -->
247
+ <link rel="stylesheet" href="/css/critical.css">
248
+
249
+ <!-- Bad: Too many separate files -->
250
+ <link rel="stylesheet" href="/css/reset.css">
251
+ <link rel="stylesheet" href="/css/typography.css">
252
+ <link rel="stylesheet" href="/css/layout.css">
253
+ <link rel="stylesheet" href="/css/components.css">
254
+ ```
255
+
256
+ Or use `defer` for non-critical resources:
257
+
258
+ ```html
259
+ <!-- Good: Critical resources only -->
260
+ <link rel="stylesheet" href="/css/critical.css">
261
+ <link rel="stylesheet" href="/css/animations.css" defer>
262
+ <link rel="stylesheet" href="/css/print.css" defer>
263
+ ```
264
+
265
+ ### 4. Preload Fonts
266
+
267
+ If using custom fonts, include them in `<head>`. All common font formats are supported:
268
+
269
+ ```html
270
+ <!-- WOFF2 (recommended, best compression) -->
271
+ <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
272
+
273
+ <!-- WOFF (fallback for older browsers) -->
274
+ <link rel="preload" href="/fonts/main.woff" as="font" type="font/woff" crossorigin>
275
+
276
+ <!-- TrueType/OpenType -->
277
+ <link rel="preload" href="/fonts/main.ttf" as="font" type="font/ttf" crossorigin>
278
+ <link rel="preload" href="/fonts/main.otf" as="font" type="font/otf" crossorigin>
279
+ ```
280
+
281
+ ## Troubleshooting
282
+
283
+ ### Early Hints Not Working?
284
+
285
+ **Check Node.js version:**
286
+ ```bash
287
+ node --version # Should be 18.0.0 or higher
288
+ ```
289
+
290
+ **Verify configuration:**
291
+ ```json
292
+ {
293
+ "earlyHints": {
294
+ "enabled": true // Make sure it's not disabled
295
+ }
296
+ }
297
+ ```
298
+
299
+ **Check browser DevTools:**
300
+ 1. Open Network tab
301
+ 2. Look for `103 Early Hints` status
302
+ 3. Check response headers for `Link:` headers
303
+
304
+ ### No Resources Detected?
305
+
306
+ Make sure resources are in `<head>`:
307
+ ```html
308
+ <!-- This will be detected -->
309
+ <head>
310
+ <link rel="stylesheet" href="/css/main.css">
311
+ </head>
312
+
313
+ <!-- This will NOT be detected -->
314
+ <body>
315
+ <link rel="stylesheet" href="/css/main.css">
316
+ </body>
317
+ ```
318
+
319
+ ### Too Many Resources?
320
+
321
+ Reduce `maxResources` in config:
322
+ ```json
323
+ {
324
+ "earlyHints": {
325
+ "maxResources": 3
326
+ }
327
+ }
328
+ ```
329
+
330
+ ## Disabling Early Hints
331
+
332
+ Removing the `earlyHints` configuration section from your `config.json` is equivalent to using the default settings, which has the feature enabled. To truly disable Early Hints, you must explicitly set `enabled: false` in your configuration:
333
+
334
+ ```json
335
+ {
336
+ "earlyHints": {
337
+ "enabled": false
338
+ }
339
+ }
340
+ ```
341
+
342
+ ## Summary
343
+
344
+ Early Hints is a powerful performance optimization that:
345
+ - ✅ Works automatically (zero-config)
346
+ - ✅ Detects critical resources intelligently
347
+ - ✅ Improves page load times
348
+ - ✅ Requires no code changes
349
+ - ✅ Degrades gracefully on older browsers
350
+ - ✅ Can be customized if needed
351
+
352
+ Just build your app normally, and Early Hints will optimize it for you!
@@ -0,0 +1,28 @@
1
+ ## 📄 Basic Page Routes
2
+
3
+ #### `page(path, controller)`
4
+ This is the most common method. It maps a URL path to a controller that is expected to render a standard HTML page. It handles `GET` requests.
5
+
6
+ - `path`: The URL path to match (e.g., `/about`).
7
+ - `controller`: The name of the controller file.
8
+
9
+ ```javascript
10
+ // When a user visits yoursite.com/
11
+ Candy.Route.page('/', 'index');
12
+
13
+ // When a user visits yoursite.com/contact
14
+ Candy.Route.page('/contact', 'contact-form');
15
+ ```
16
+
17
+ **Page Identifier:** The controller filename becomes the page identifier in the frontend. For example, `'contact-form'` becomes accessible as `Candy.page()` returning `"contact-form"`. This allows you to run page-specific JavaScript:
18
+
19
+ ```javascript
20
+ // Frontend
21
+ Candy.action({
22
+ page: {
23
+ 'contact-form': function() {
24
+ console.log('Contact form page loaded')
25
+ }
26
+ }
27
+ })
28
+ ```
@@ -0,0 +1,43 @@
1
+ ## ⚡ Controller-less View Routes
2
+
3
+ For simple pages that don't require complex logic in a controller, you can render a view directly from your route file by passing a view configuration object as the second parameter.
4
+
5
+ #### `page(path, { ... })`
6
+ This defines a page and immediately tells it which view components to render.
7
+
8
+ ```javascript
9
+ Candy.Route.page("/users", {
10
+ skeleton: "dashboard",
11
+ header: "dashboard.main",
12
+ sidebar: "dashboard.main",
13
+ footer: "dashboard.main",
14
+ content: "users"
15
+ });
16
+ ```
17
+ This example tells CandyPack 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
+
19
+ **Page Identifier:** When using view objects, the page identifier (accessible via `Candy.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
+
21
+ ```javascript
22
+ // Frontend
23
+ Candy.action({
24
+ page: {
25
+ users: function() {
26
+ console.log('Users page loaded')
27
+ }
28
+ }
29
+ })
30
+ ```
31
+
32
+ #### `auth.page(path, { ... })`
33
+ Similar to `page()`, but requires authentication. Only authenticated users can access this route.
34
+
35
+ ```javascript
36
+ // Only authenticated users can see the dashboard
37
+ Candy.Route.auth.page('/', {
38
+ skeleton: 'main',
39
+ content: 'dashboard'
40
+ });
41
+ ```
42
+
43
+ See [Authentication-Aware Routes](04-authentication-aware-routes.md) for more details.
@@ -0,0 +1,20 @@
1
+ ## 📦 API and Data Routes
2
+
3
+ #### `get(path, controller, options)`
4
+ Defines a route that responds to `GET` requests. This is ideal for API endpoints that return data (like JSON).
5
+
6
+ - `options`: By default, CandyPack 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
+
8
+ ```javascript
9
+ // An API endpoint at GET /api/users/123
10
+ // We disable the token check as this is a public API.
11
+ Candy.Route.get('/api/users/{id}', 'api/users.get', { token: false });
12
+ ```
13
+
14
+ #### `post(path, controller, options)`
15
+ Defines a route that responds to `POST` requests, typically used for form submissions. The `{ token: false }` option works here as well, but should be used with caution as POST routes are primary targets for CSRF attacks.
16
+
17
+ ```javascript
18
+ // A form that posts data to /login
19
+ Candy.Route.post('/login', 'auth.login');
20
+ ```