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.
Files changed (208) hide show
  1. package/.github/workflows/auto-pr-description.yml +0 -2
  2. package/.github/workflows/codeql.yml +46 -0
  3. package/.github/workflows/release.yml +13 -6
  4. package/.github/workflows/test-coverage.yml +10 -9
  5. package/.releaserc.js +9 -6
  6. package/CHANGELOG.md +62 -150
  7. package/CODE_OF_CONDUCT.md +1 -1
  8. package/CONTRIBUTING.md +8 -8
  9. package/LICENSE +21 -661
  10. package/README.md +12 -12
  11. package/SECURITY.md +4 -4
  12. package/bin/odac.js +101 -0
  13. package/{framework/web/candy.js → client/odac.js} +310 -44
  14. package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
  15. package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
  16. package/docs/backend/01-overview/03-development-server.md +11 -11
  17. package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
  18. package/docs/backend/03-config/00-configuration-overview.md +6 -6
  19. package/docs/backend/03-config/01-database-connection.md +1 -1
  20. package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
  21. package/docs/backend/03-config/04-environment-variables.md +20 -20
  22. package/docs/backend/03-config/05-early-hints.md +4 -4
  23. package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
  24. package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
  25. package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
  26. package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
  27. package/docs/backend/04-routing/05-advanced-routing.md +3 -3
  28. package/docs/backend/04-routing/06-error-pages.md +17 -17
  29. package/docs/backend/04-routing/07-cron-jobs.md +13 -13
  30. package/docs/backend/04-routing/08-middleware.md +214 -0
  31. package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
  32. package/docs/backend/04-routing/09-websocket-examples.md +381 -0
  33. package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
  34. package/docs/backend/04-routing/09-websocket.md +298 -0
  35. package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
  36. package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
  37. package/docs/backend/05-controllers/03-controller-classes.md +19 -19
  38. package/docs/backend/05-forms/01-custom-forms.md +114 -114
  39. package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
  40. package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
  41. package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
  42. package/docs/backend/07-views/01-the-view-directory.md +1 -1
  43. package/docs/backend/07-views/02-rendering-a-view.md +22 -22
  44. package/docs/backend/07-views/03-template-syntax.md +52 -52
  45. package/docs/backend/07-views/03-variables.md +84 -84
  46. package/docs/backend/07-views/04-request-data.md +57 -57
  47. package/docs/backend/07-views/05-conditionals.md +78 -78
  48. package/docs/backend/07-views/06-loops.md +114 -114
  49. package/docs/backend/07-views/07-translations.md +66 -66
  50. package/docs/backend/07-views/08-backend-javascript.md +103 -103
  51. package/docs/backend/07-views/09-comments.md +71 -71
  52. package/docs/backend/08-database/01-database-connection.md +8 -8
  53. package/docs/backend/08-database/02-using-mysql.md +49 -49
  54. package/docs/backend/09-validation/01-the-validator-service.md +38 -38
  55. package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
  56. package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
  57. package/docs/backend/10-authentication/03-register.md +12 -12
  58. package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
  59. package/docs/backend/10-authentication/05-session-management.md +10 -10
  60. package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
  61. package/docs/backend/11-mail/01-the-mail-service.md +5 -5
  62. package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
  63. package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
  64. package/docs/frontend/01-overview/01-introduction.md +30 -30
  65. package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
  66. package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
  67. package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
  68. package/docs/frontend/03-forms/01-form-handling.md +32 -32
  69. package/docs/frontend/04-api-requests/01-get-post.md +33 -33
  70. package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
  71. package/docs/frontend/06-websocket/00-overview.md +76 -0
  72. package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
  73. package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
  74. package/docs/index.json +49 -11
  75. package/eslint.config.mjs +6 -6
  76. package/{framework/index.js → index.js} +1 -1
  77. package/package.json +14 -39
  78. package/{framework/src → src}/Auth.js +59 -59
  79. package/{framework/src → src}/Config.js +3 -3
  80. package/{framework/src → src}/Lang.js +7 -7
  81. package/{framework/src → src}/Mail.js +5 -5
  82. package/{framework/src → src}/Mysql.js +42 -42
  83. package/src/Odac.js +112 -0
  84. package/{framework/src → src}/Request.js +38 -36
  85. package/{framework/src → src}/Route/Internal.js +116 -116
  86. package/src/Route/Middleware.js +75 -0
  87. package/src/Route.js +621 -0
  88. package/src/Server.js +22 -0
  89. package/{framework/src → src}/Stream.js +11 -3
  90. package/{framework/src → src}/Validator.js +21 -21
  91. package/{framework/src → src}/Var.js +5 -5
  92. package/{framework/src → src}/View/EarlyHints.js +1 -1
  93. package/{framework/src → src}/View/Form.js +69 -69
  94. package/{framework/src → src}/View.js +78 -81
  95. package/src/WebSocket.js +403 -0
  96. package/template/config.json +5 -0
  97. package/{web → template}/controller/page/about.js +6 -6
  98. package/{web → template}/controller/page/index.js +9 -9
  99. package/{web → template}/package.json +4 -5
  100. package/{web → template}/public/assets/css/style.css +4 -4
  101. package/{web → template}/public/assets/js/app.js +6 -6
  102. package/{web → template}/route/www.js +6 -6
  103. package/{web → template}/skeleton/main.html +1 -1
  104. package/{web → template}/view/content/about.html +5 -5
  105. package/{web → template}/view/content/home.html +12 -12
  106. package/template/view/footer/main.html +11 -0
  107. package/{web → template}/view/head/main.html +1 -1
  108. package/{web → template}/view/header/main.html +2 -2
  109. package/test/core/Candy.test.js +58 -58
  110. package/test/core/Commands.test.js +7 -7
  111. package/test/core/Config.test.js +82 -85
  112. package/test/core/Lang.test.js +2 -2
  113. package/test/core/Process.test.js +6 -6
  114. package/test/framework/Route.test.js +56 -37
  115. package/test/framework/View/EarlyHints.test.js +2 -2
  116. package/test/framework/WebSocket.test.js +100 -0
  117. package/test/framework/middleware.test.js +85 -0
  118. package/test/server/Api.test.js +31 -31
  119. package/test/server/DNS.test.js +11 -11
  120. package/test/server/Hub.test.js +497 -0
  121. package/test/server/Mail.account.test_.js +3 -3
  122. package/test/server/Mail.init.test_.js +10 -10
  123. package/test/server/Mail.test_.js +20 -20
  124. package/test/server/SSL.test_.js +54 -54
  125. package/test/server/Server.test.js +39 -39
  126. package/test/server/Service.test_.js +7 -7
  127. package/test/server/Subdomain.test.js +7 -7
  128. package/test/server/Web/Firewall.test.js +87 -87
  129. package/test/server/Web/Proxy.test.js +397 -0
  130. package/test/server/{Web.test_.js → Web.test.js} +137 -205
  131. package/test/server/__mocks__/fs.js +2 -2
  132. package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
  133. package/test/server/__mocks__/index.js +6 -6
  134. package/test/server/__mocks__/testFactories.js +1 -1
  135. package/test/server/__mocks__/testHelpers.js +7 -7
  136. package/.husky/pre-commit +0 -2
  137. package/.kiro/steering/code-style.md +0 -56
  138. package/.kiro/steering/product.md +0 -20
  139. package/.kiro/steering/structure.md +0 -77
  140. package/.kiro/steering/tech.md +0 -87
  141. package/AGENTS.md +0 -84
  142. package/bin/candy +0 -10
  143. package/bin/candypack +0 -10
  144. package/cli/index.js +0 -3
  145. package/cli/src/Cli.js +0 -348
  146. package/cli/src/Connector.js +0 -93
  147. package/cli/src/Monitor.js +0 -416
  148. package/core/Candy.js +0 -87
  149. package/core/Commands.js +0 -239
  150. package/core/Config.js +0 -1094
  151. package/core/Lang.js +0 -52
  152. package/core/Log.js +0 -43
  153. package/core/Process.js +0 -26
  154. package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
  155. package/docs/server/01-installation/01-quick-install.md +0 -19
  156. package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
  157. package/docs/server/02-get-started/01-core-concepts.md +0 -7
  158. package/docs/server/02-get-started/02-basic-commands.md +0 -57
  159. package/docs/server/02-get-started/03-cli-reference.md +0 -276
  160. package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
  161. package/docs/server/03-service/01-start-a-new-service.md +0 -57
  162. package/docs/server/03-service/02-delete-a-service.md +0 -48
  163. package/docs/server/04-web/01-create-a-website.md +0 -36
  164. package/docs/server/04-web/02-list-websites.md +0 -9
  165. package/docs/server/04-web/03-delete-a-website.md +0 -29
  166. package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
  167. package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
  168. package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
  169. package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
  170. package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
  171. package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
  172. package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
  173. package/docs/server/07-mail/04-change-account-password.md +0 -23
  174. package/framework/src/Candy.js +0 -81
  175. package/framework/src/Route.js +0 -455
  176. package/framework/src/Server.js +0 -15
  177. package/locale/de-DE.json +0 -80
  178. package/locale/en-US.json +0 -79
  179. package/locale/es-ES.json +0 -80
  180. package/locale/fr-FR.json +0 -80
  181. package/locale/pt-BR.json +0 -80
  182. package/locale/ru-RU.json +0 -80
  183. package/locale/tr-TR.json +0 -85
  184. package/locale/zh-CN.json +0 -80
  185. package/server/index.js +0 -5
  186. package/server/src/Api.js +0 -88
  187. package/server/src/DNS.js +0 -940
  188. package/server/src/Hub.js +0 -535
  189. package/server/src/Mail.js +0 -571
  190. package/server/src/SSL.js +0 -180
  191. package/server/src/Server.js +0 -27
  192. package/server/src/Service.js +0 -248
  193. package/server/src/Subdomain.js +0 -64
  194. package/server/src/Web/Firewall.js +0 -170
  195. package/server/src/Web/Proxy.js +0 -134
  196. package/server/src/Web.js +0 -451
  197. package/server/src/mail/imap.js +0 -1091
  198. package/server/src/mail/server.js +0 -32
  199. package/server/src/mail/smtp.js +0 -786
  200. package/test/server/Client.test.js +0 -338
  201. package/test/server/__mocks__/http-proxy.js +0 -105
  202. package/watchdog/index.js +0 -3
  203. package/watchdog/src/Watchdog.js +0 -156
  204. package/web/config.json +0 -5
  205. package/web/view/footer/main.html +0 -11
  206. /package/{framework/src → src}/Env.js +0 -0
  207. /package/{framework/src → src}/Route/Cron.js +0 -0
  208. /package/{framework/src → src}/Token.js +0 -0
@@ -7,12 +7,12 @@ Loops allow you to repeat content for each item in an array or object. This is e
7
7
  The most common way to iterate over arrays and objects:
8
8
 
9
9
  ```html
10
- <candy:for in="users" key="index" value="user">
10
+ <odac:for in="users" key="index" value="user">
11
11
  <div class="user-card">
12
- <h3><candy var="user.name" /></h3>
13
- <p><candy var="user.email" /></p>
12
+ <h3><odac var="user.name" /></h3>
13
+ <p><odac var="user.email" /></p>
14
14
  </div>
15
- </candy:for>
15
+ </odac:for>
16
16
  ```
17
17
 
18
18
  **Parameters:**
@@ -24,7 +24,7 @@ The most common way to iterate over arrays and objects:
24
24
 
25
25
  ```javascript
26
26
  // Controller
27
- Candy.set('products', [
27
+ Odac.set('products', [
28
28
  { name: 'Laptop', price: 999 },
29
29
  { name: 'Mouse', price: 29 },
30
30
  { name: 'Keyboard', price: 79 }
@@ -34,13 +34,13 @@ Candy.set('products', [
34
34
  ```html
35
35
  <!-- View -->
36
36
  <div class="products">
37
- <candy:for in="products" key="index" value="product">
37
+ <odac:for in="products" key="index" value="product">
38
38
  <div class="product">
39
- <span class="number"><candy var="index + 1" />.</span>
40
- <h3><candy var="product.name" /></h3>
41
- <p>$<candy var="product.price" /></p>
39
+ <span class="number"><odac var="index + 1" />.</span>
40
+ <h3><odac var="product.name" /></h3>
41
+ <p>$<odac var="product.price" /></p>
42
42
  </div>
43
- </candy:for>
43
+ </odac:for>
44
44
  </div>
45
45
  ```
46
46
 
@@ -48,7 +48,7 @@ Candy.set('products', [
48
48
 
49
49
  ```javascript
50
50
  // Controller
51
- Candy.set('settings', {
51
+ Odac.set('settings', {
52
52
  theme: 'dark',
53
53
  language: 'en',
54
54
  notifications: true
@@ -58,12 +58,12 @@ Candy.set('settings', {
58
58
  ```html
59
59
  <!-- View -->
60
60
  <table>
61
- <candy:for in="settings" key="settingKey" value="settingValue">
61
+ <odac:for in="settings" key="settingKey" value="settingValue">
62
62
  <tr>
63
- <td><candy var="settingKey" /></td>
64
- <td><candy var="settingValue" /></td>
63
+ <td><odac var="settingKey" /></td>
64
+ <td><odac var="settingValue" /></td>
65
65
  </tr>
66
- </candy:for>
66
+ </odac:for>
67
67
  </table>
68
68
  ```
69
69
 
@@ -72,14 +72,14 @@ Candy.set('settings', {
72
72
  Use while loops for conditional iteration:
73
73
 
74
74
  ```html
75
- <script:candy>
75
+ <script:odac>
76
76
  let counter = 0;
77
- </script:candy>
77
+ </script:odac>
78
78
 
79
- <candy:while condition="counter < 5">
80
- <p>Item <candy var="counter + 1" /></p>
81
- <script:candy>counter++;</script:candy>
82
- </candy:while>
79
+ <odac:while condition="counter < 5">
80
+ <p>Item <odac var="counter + 1" /></p>
81
+ <script:odac>counter++;</script:odac>
82
+ </odac:while>
83
83
  ```
84
84
 
85
85
  **Note:** Be careful with while loops to avoid infinite loops. The condition must eventually become false.
@@ -91,13 +91,13 @@ Use while loops for conditional iteration:
91
91
  Exit the loop early:
92
92
 
93
93
  ```html
94
- <candy:for in="products" value="product">
95
- <candy:if condition="product.stock === 0">
94
+ <odac:for in="products" value="product">
95
+ <odac:if condition="product.stock === 0">
96
96
  <p class="notice">Some products are out of stock</p>
97
- <candy:break />
98
- </candy:if>
99
- <div><candy var="product.name" /></div>
100
- </candy:for>
97
+ <odac:break />
98
+ </odac:if>
99
+ <div><odac var="product.name" /></div>
100
+ </odac:for>
101
101
  ```
102
102
 
103
103
  #### Continue
@@ -105,16 +105,16 @@ Exit the loop early:
105
105
  Skip to the next iteration:
106
106
 
107
107
  ```html
108
- <candy:for in="users" value="user">
109
- <candy:if condition="user.isBlocked">
110
- <candy:continue />
111
- </candy:if>
108
+ <odac:for in="users" value="user">
109
+ <odac:if condition="user.isBlocked">
110
+ <odac:continue />
111
+ </odac:if>
112
112
 
113
113
  <div class="user">
114
- <h3><candy var="user.name" /></h3>
115
- <p><candy var="user.email" /></p>
114
+ <h3><odac var="user.name" /></h3>
115
+ <p><odac var="user.email" /></p>
116
116
  </div>
117
- </candy:for>
117
+ </odac:for>
118
118
  ```
119
119
 
120
120
  ### Practical Examples
@@ -125,18 +125,18 @@ Skip to the next iteration:
125
125
  <div class="product-list">
126
126
  <h2>Our Products</h2>
127
127
 
128
- <candy:for in="products" key="i" value="product">
128
+ <odac:for in="products" key="i" value="product">
129
129
  <div class="product-item">
130
- <span class="number">#<candy var="i + 1" /></span>
131
- <img src="<candy var="product.image" />" alt="<candy var="product.name" />">
132
- <h3><candy var="product.name" /></h3>
133
- <p class="price">$<candy var="product.price" /></p>
130
+ <span class="number">#<odac var="i + 1" /></span>
131
+ <img src="<odac var="product.image" />" alt="<odac var="product.name" />">
132
+ <h3><odac var="product.name" /></h3>
133
+ <p class="price">$<odac var="product.price" /></p>
134
134
 
135
- <candy:if condition="product.discount">
136
- <span class="discount">-<candy var="product.discount" />%</span>
137
- </candy:if>
135
+ <odac:if condition="product.discount">
136
+ <span class="discount">-<odac var="product.discount" />%</span>
137
+ </odac:if>
138
138
  </div>
139
- </candy:for>
139
+ </odac:for>
140
140
  </div>
141
141
  ```
142
142
 
@@ -154,21 +154,21 @@ Skip to the next iteration:
154
154
  </tr>
155
155
  </thead>
156
156
  <tbody>
157
- <candy:for in="users" key="index" value="user">
157
+ <odac:for in="users" key="index" value="user">
158
158
  <tr>
159
- <td><candy var="index + 1" /></td>
160
- <td><candy var="user.name" /></td>
161
- <td><candy var="user.email" /></td>
162
- <td><candy var="user.role" /></td>
159
+ <td><odac var="index + 1" /></td>
160
+ <td><odac var="user.name" /></td>
161
+ <td><odac var="user.email" /></td>
162
+ <td><odac var="user.role" /></td>
163
163
  <td>
164
- <candy:if condition="user.isActive">
164
+ <odac:if condition="user.isActive">
165
165
  <span class="badge success">Active</span>
166
- <candy:else>
166
+ <odac:else>
167
167
  <span class="badge danger">Inactive</span>
168
- </candy:if>
168
+ </odac:if>
169
169
  </td>
170
170
  </tr>
171
- </candy:for>
171
+ </odac:for>
172
172
  </tbody>
173
173
  </table>
174
174
  ```
@@ -177,20 +177,20 @@ Skip to the next iteration:
177
177
 
178
178
  ```html
179
179
  <div class="categories">
180
- <candy:for in="categories" value="category">
180
+ <odac:for in="categories" value="category">
181
181
  <div class="category">
182
- <h2><candy var="category.name" /></h2>
182
+ <h2><odac var="category.name" /></h2>
183
183
 
184
184
  <div class="products">
185
- <candy:for in="category.products" value="product">
185
+ <odac:for in="category.products" value="product">
186
186
  <div class="product">
187
- <h3><candy var="product.name" /></h3>
188
- <p>$<candy var="product.price" /></p>
187
+ <h3><odac var="product.name" /></h3>
188
+ <p>$<odac var="product.price" /></p>
189
189
  </div>
190
- </candy:for>
190
+ </odac:for>
191
191
  </div>
192
192
  </div>
193
- </candy:for>
193
+ </odac:for>
194
194
  </div>
195
195
  ```
196
196
 
@@ -198,18 +198,18 @@ Skip to the next iteration:
198
198
 
199
199
  ```html
200
200
  <div class="grid">
201
- <candy:for in="items" key="i" value="item">
201
+ <odac:for in="items" key="i" value="item">
202
202
  <div class="grid-item">
203
- <img src="<candy var="item.image" />" alt="<candy var="item.title" />">
204
- <h3><candy var="item.title" /></h3>
205
- <p><candy var="item.description" /></p>
203
+ <img src="<odac var="item.image" />" alt="<odac var="item.title" />">
204
+ <h3><odac var="item.title" /></h3>
205
+ <p><odac var="item.description" /></p>
206
206
 
207
207
  <!-- Add row break every 3 items -->
208
- <candy:if condition="(i + 1) % 3 === 0">
208
+ <odac:if condition="(i + 1) % 3 === 0">
209
209
  <div class="row-break"></div>
210
- </candy:if>
210
+ </odac:if>
211
211
  </div>
212
- </candy:for>
212
+ </odac:for>
213
213
  </div>
214
214
  ```
215
215
 
@@ -219,22 +219,22 @@ Skip to the next iteration:
219
219
  <div class="active-users">
220
220
  <h2>Active Users</h2>
221
221
 
222
- <candy:for in="users" value="user">
222
+ <odac:for in="users" value="user">
223
223
  <!-- Skip inactive users -->
224
- <candy:if condition="!user.isActive">
225
- <candy:continue />
226
- </candy:if>
224
+ <odac:if condition="!user.isActive">
225
+ <odac:continue />
226
+ </odac:if>
227
227
 
228
228
  <!-- Skip blocked users -->
229
- <candy:if condition="user.isBlocked">
230
- <candy:continue />
231
- </candy:if>
229
+ <odac:if condition="user.isBlocked">
230
+ <odac:continue />
231
+ </odac:if>
232
232
 
233
233
  <div class="user-card">
234
- <h3><candy var="user.name" /></h3>
235
- <p><candy var="user.email" /></p>
234
+ <h3><odac var="user.name" /></h3>
235
+ <p><odac var="user.email" /></p>
236
236
  </div>
237
- </candy:for>
237
+ </odac:for>
238
238
  </div>
239
239
  ```
240
240
 
@@ -244,21 +244,21 @@ Skip to the next iteration:
244
244
  <div class="products-section">
245
245
  <h2>Products</h2>
246
246
 
247
- <candy:if condition="products && products.length > 0">
247
+ <odac:if condition="products && products.length > 0">
248
248
  <div class="products-grid">
249
- <candy:for in="products" value="product">
249
+ <odac:for in="products" value="product">
250
250
  <div class="product-card">
251
- <h3><candy var="product.name" /></h3>
252
- <p>$<candy var="product.price" /></p>
251
+ <h3><odac var="product.name" /></h3>
252
+ <p>$<odac var="product.price" /></p>
253
253
  </div>
254
- </candy:for>
254
+ </odac:for>
255
255
  </div>
256
- <candy:else>
256
+ <odac:else>
257
257
  <div class="empty-state">
258
258
  <p>No products found.</p>
259
259
  <a href="/products/add">Add your first product</a>
260
260
  </div>
261
- </candy:if>
261
+ </odac:if>
262
262
  </div>
263
263
  ```
264
264
 
@@ -266,12 +266,12 @@ Skip to the next iteration:
266
266
 
267
267
  ```html
268
268
  <table>
269
- <candy:for in="items" key="i" value="item">
270
- <tr class="<candy:if condition="i % 2 === 0">even<candy:else>odd</candy:if>">
271
- <td><candy var="item.name" /></td>
272
- <td><candy var="item.value" /></td>
269
+ <odac:for in="items" key="i" value="item">
270
+ <tr class="<odac:if condition="i % 2 === 0">even<odac:else>odd</odac:if>">
271
+ <td><odac var="item.name" /></td>
272
+ <td><odac var="item.value" /></td>
273
273
  </tr>
274
- </candy:for>
274
+ </odac:for>
275
275
  </table>
276
276
  ```
277
277
 
@@ -281,43 +281,43 @@ Skip to the next iteration:
281
281
  <div class="top-products">
282
282
  <h2>Top 5 Products</h2>
283
283
 
284
- <script:candy>
284
+ <script:odac>
285
285
  let count = 0;
286
- </script:candy>
286
+ </script:odac>
287
287
 
288
- <candy:for in="products" value="product">
289
- <candy:if condition="count >= 5">
290
- <candy:break />
291
- </candy:if>
288
+ <odac:for in="products" value="product">
289
+ <odac:if condition="count >= 5">
290
+ <odac:break />
291
+ </odac:if>
292
292
 
293
293
  <div class="product">
294
- <h3><candy var="product.name" /></h3>
295
- <p>$<candy var="product.price" /></p>
294
+ <h3><odac var="product.name" /></h3>
295
+ <p>$<odac var="product.price" /></p>
296
296
  </div>
297
297
 
298
- <script:candy>count++;</script:candy>
299
- </candy:for>
298
+ <script:odac>count++;</script:odac>
299
+ </odac:for>
300
300
  </div>
301
301
  ```
302
302
 
303
303
  #### Pagination with While
304
304
 
305
305
  ```html
306
- <script:candy>
306
+ <script:odac>
307
307
  const itemsPerPage = 10;
308
- const currentPage = parseInt(Candy.Request.get('page')) || 1;
308
+ const currentPage = parseInt(Odac.Request.get('page')) || 1;
309
309
  const startIndex = (currentPage - 1) * itemsPerPage;
310
310
  const endIndex = startIndex + itemsPerPage;
311
311
  let index = startIndex;
312
- </script:candy>
312
+ </script:odac>
313
313
 
314
314
  <div class="items">
315
- <candy:while condition="index < endIndex && index < items.length">
315
+ <odac:while condition="index < endIndex && index < items.length">
316
316
  <div class="item">
317
- <candy var="items[index].name" />
317
+ <odac var="items[index].name" />
318
318
  </div>
319
- <script:candy>index++;</script:candy>
320
- </candy:while>
319
+ <script:odac>index++;</script:odac>
320
+ </odac:while>
321
321
  </div>
322
322
  ```
323
323
 
@@ -332,22 +332,22 @@ Skip to the next iteration:
332
332
  **Good:**
333
333
  ```javascript
334
334
  // Controller - prepare data
335
- Candy.set('activeUsers', users.filter(u => u.isActive))
335
+ Odac.set('activeUsers', users.filter(u => u.isActive))
336
336
  ```
337
337
 
338
338
  ```html
339
339
  <!-- View - simple loop -->
340
- <candy:for in="activeUsers" value="user">
341
- <div><candy var="user.name" /></div>
342
- </candy:for>
340
+ <odac:for in="activeUsers" value="user">
341
+ <div><odac var="user.name" /></div>
342
+ </odac:for>
343
343
  ```
344
344
 
345
345
  **Avoid:**
346
346
  ```html
347
347
  <!-- Too complex for a view -->
348
- <candy:for in="users" value="user">
349
- <candy:if condition="user.isActive && !user.isBlocked && user.role !== 'guest'">
350
- <div><candy var="user.name" /></div>
351
- </candy:if>
352
- </candy:for>
348
+ <odac:for in="users" value="user">
349
+ <odac:if condition="user.isActive && !user.isBlocked && user.role !== 'guest'">
350
+ <div><odac var="user.name" /></div>
351
+ </odac:if>
352
+ </odac:for>
353
353
  ```