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
@@ -5,13 +5,13 @@ Forms can automatically insert data into your database without writing any contr
5
5
  ## Basic Usage
6
6
 
7
7
  ```html
8
- <candy:form table="waitlist">
9
- <candy:field name="email" type="email" label="Email">
10
- <candy:validate rule="required|email|unique"/>
11
- </candy:field>
8
+ <odac:form table="waitlist">
9
+ <odac:field name="email" type="email" label="Email">
10
+ <odac:validate rule="required|email|unique"/>
11
+ </odac:field>
12
12
 
13
- <candy:submit text="Join"/>
14
- </candy:form>
13
+ <odac:submit text="Join"/>
14
+ </odac:form>
15
15
  ```
16
16
 
17
17
  That's it! The form will automatically:
@@ -44,21 +44,21 @@ CREATE TABLE `waitlist` (
44
44
  <div class="waitlist-page">
45
45
  <h1>Join Our Waitlist</h1>
46
46
 
47
- <candy:form table="waitlist" redirect="/" success="Thank you for joining!">
48
- <candy:field name="email" type="email" label="Email" placeholder="your@email.com">
49
- <candy:validate rule="required|email|unique" message="Please enter a valid email"/>
50
- </candy:field>
47
+ <odac:form table="waitlist" redirect="/" success="Thank you for joining!">
48
+ <odac:field name="email" type="email" label="Email" placeholder="your@email.com">
49
+ <odac:validate rule="required|email|unique" message="Please enter a valid email"/>
50
+ </odac:field>
51
51
 
52
- <candy:field name="name" type="text" label="Name" placeholder="Your name">
53
- <candy:validate rule="required|minlen:2" message="Name is required"/>
54
- </candy:field>
52
+ <odac:field name="name" type="text" label="Name" placeholder="Your name">
53
+ <odac:validate rule="required|minlen:2" message="Name is required"/>
54
+ </odac:field>
55
55
 
56
- <candy:set name="created_at" compute="now"/>
57
- <candy:set name="ip" compute="ip"/>
58
- <candy:set name="user_agent" compute="user_agent"/>
56
+ <odac:set name="created_at" compute="now"/>
57
+ <odac:set name="ip" compute="ip"/>
58
+ <odac:set name="user_agent" compute="user_agent"/>
59
59
 
60
- <candy:submit text="Join Waitlist" loading="Joining..." class="btn btn-primary"/>
61
- </candy:form>
60
+ <odac:submit text="Join Waitlist" loading="Joining..." class="btn btn-primary"/>
61
+ </odac:form>
62
62
  </div>
63
63
  ```
64
64
 
@@ -66,10 +66,10 @@ CREATE TABLE `waitlist` (
66
66
 
67
67
  **controller/waitlist.js**
68
68
  ```javascript
69
- module.exports = Candy => {
70
- Candy.View.skeleton('default')
71
- Candy.View.set({content: 'waitlist'})
72
- Candy.View.print()
69
+ module.exports = Odac => {
70
+ Odac.View.skeleton('default')
71
+ Odac.View.set({content: 'waitlist'})
72
+ Odac.View.print()
73
73
  }
74
74
  ```
75
75
 
@@ -77,7 +77,7 @@ module.exports = Candy => {
77
77
 
78
78
  **route/www.js**
79
79
  ```javascript
80
- Candy.Route.page('/waitlist', 'waitlist')
80
+ Odac.Route.page('/waitlist', 'waitlist')
81
81
  ```
82
82
 
83
83
  Done! No form submission handler needed.
@@ -88,21 +88,21 @@ Done! No form submission handler needed.
88
88
  Database table name where data will be inserted.
89
89
 
90
90
  ```html
91
- <candy:form table="newsletter_subscribers">
91
+ <odac:form table="newsletter_subscribers">
92
92
  ```
93
93
 
94
94
  ### `redirect` (optional)
95
95
  URL to redirect after successful submission.
96
96
 
97
97
  ```html
98
- <candy:form table="waitlist" redirect="/thank-you">
98
+ <odac:form table="waitlist" redirect="/thank-you">
99
99
  ```
100
100
 
101
101
  ### `success` (optional)
102
102
  Custom success message to display.
103
103
 
104
104
  ```html
105
- <candy:form table="waitlist" success="Welcome! We'll notify you soon.">
105
+ <odac:form table="waitlist" success="Welcome! We'll notify you soon.">
106
106
  ```
107
107
 
108
108
  ## Unique Validation
@@ -110,9 +110,9 @@ Custom success message to display.
110
110
  Use `unique` rule to prevent duplicate entries:
111
111
 
112
112
  ```html
113
- <candy:field name="email" type="email">
114
- <candy:validate rule="required|email|unique" message="This email is already registered"/>
115
- </candy:field>
113
+ <odac:field name="email" type="email">
114
+ <odac:validate rule="required|email|unique" message="This email is already registered"/>
115
+ </odac:field>
116
116
  ```
117
117
 
118
118
  The system will:
@@ -122,13 +122,13 @@ The system will:
122
122
 
123
123
  ## Auto-Set Values
124
124
 
125
- Use `<candy:set>` to automatically populate fields:
125
+ Use `<odac:set>` to automatically populate fields:
126
126
 
127
127
  ```html
128
- <candy:set name="created_at" compute="now"/>
129
- <candy:set name="ip" compute="ip"/>
130
- <candy:set name="user_agent" compute="user_agent"/>
131
- <candy:set name="status" value="pending"/>
128
+ <odac:set name="created_at" compute="now"/>
129
+ <odac:set name="ip" compute="ip"/>
130
+ <odac:set name="user_agent" compute="user_agent"/>
131
+ <odac:set name="status" value="pending"/>
132
132
  ```
133
133
 
134
134
  ### Compute Types
@@ -144,9 +144,9 @@ Use `<candy:set>` to automatically populate fields:
144
144
  ### Static Values
145
145
 
146
146
  ```html
147
- <candy:set name="status" value="pending"/>
148
- <candy:set name="source" value="website"/>
149
- <candy:set name="plan" value="free"/>
147
+ <odac:set name="status" value="pending"/>
148
+ <odac:set name="source" value="website"/>
149
+ <odac:set name="plan" value="free"/>
150
150
  ```
151
151
 
152
152
  ### Conditional Set
@@ -154,7 +154,7 @@ Use `<candy:set>` to automatically populate fields:
154
154
  Only set if field is empty:
155
155
 
156
156
  ```html
157
- <candy:set name="country" value="US" if-empty/>
157
+ <odac:set name="country" value="US" if-empty/>
158
158
  ```
159
159
 
160
160
  ## Use Cases
@@ -162,58 +162,58 @@ Only set if field is empty:
162
162
  ### Newsletter Signup
163
163
 
164
164
  ```html
165
- <candy:form table="newsletter" success="Thanks for subscribing!">
166
- <candy:field name="email" type="email">
167
- <candy:validate rule="required|email|unique"/>
168
- </candy:field>
165
+ <odac:form table="newsletter" success="Thanks for subscribing!">
166
+ <odac:field name="email" type="email">
167
+ <odac:validate rule="required|email|unique"/>
168
+ </odac:field>
169
169
 
170
- <candy:set name="subscribed_at" compute="now"/>
171
- <candy:set name="status" value="active"/>
170
+ <odac:set name="subscribed_at" compute="now"/>
171
+ <odac:set name="status" value="active"/>
172
172
 
173
- <candy:submit text="Subscribe"/>
174
- </candy:form>
173
+ <odac:submit text="Subscribe"/>
174
+ </odac:form>
175
175
  ```
176
176
 
177
177
  ### Feedback Form
178
178
 
179
179
  ```html
180
- <candy:form table="feedback" redirect="/" success="Thank you for your feedback!">
181
- <candy:field name="rating" type="number" label="Rating (1-5)">
182
- <candy:validate rule="required|min:1|max:5"/>
183
- </candy:field>
180
+ <odac:form table="feedback" redirect="/" success="Thank you for your feedback!">
181
+ <odac:field name="rating" type="number" label="Rating (1-5)">
182
+ <odac:validate rule="required|min:1|max:5"/>
183
+ </odac:field>
184
184
 
185
- <candy:field name="comment" type="textarea" label="Comment">
186
- <candy:validate rule="required|minlen:10"/>
187
- </candy:field>
185
+ <odac:field name="comment" type="textarea" label="Comment">
186
+ <odac:validate rule="required|minlen:10"/>
187
+ </odac:field>
188
188
 
189
- <candy:set name="created_at" compute="now"/>
190
- <candy:set name="ip" compute="ip"/>
189
+ <odac:set name="created_at" compute="now"/>
190
+ <odac:set name="ip" compute="ip"/>
191
191
 
192
- <candy:submit text="Submit Feedback"/>
193
- </candy:form>
192
+ <odac:submit text="Submit Feedback"/>
193
+ </odac:form>
194
194
  ```
195
195
 
196
196
  ### Beta Access Request
197
197
 
198
198
  ```html
199
- <candy:form table="beta_requests" success="You're on the list!">
200
- <candy:field name="email" type="email">
201
- <candy:validate rule="required|email|unique"/>
202
- </candy:field>
199
+ <odac:form table="beta_requests" success="You're on the list!">
200
+ <odac:field name="email" type="email">
201
+ <odac:validate rule="required|email|unique"/>
202
+ </odac:field>
203
203
 
204
- <candy:field name="company" type="text">
205
- <candy:validate rule="required"/>
206
- </candy:field>
204
+ <odac:field name="company" type="text">
205
+ <odac:validate rule="required"/>
206
+ </odac:field>
207
207
 
208
- <candy:field name="use_case" type="textarea">
209
- <candy:validate rule="required|minlen:20"/>
210
- </candy:field>
208
+ <odac:field name="use_case" type="textarea">
209
+ <odac:validate rule="required|minlen:20"/>
210
+ </odac:field>
211
211
 
212
- <candy:set name="requested_at" compute="now"/>
213
- <candy:set name="status" value="pending"/>
212
+ <odac:set name="requested_at" compute="now"/>
213
+ <odac:set name="status" value="pending"/>
214
214
 
215
- <candy:submit text="Request Access"/>
216
- </candy:form>
215
+ <odac:submit text="Request Access"/>
216
+ </odac:form>
217
217
  ```
218
218
 
219
219
  ## Error Handling
@@ -255,37 +255,37 @@ Automatic DB insert includes all security features:
255
255
 
256
256
  ## Combining with Custom Logic
257
257
 
258
- You can add custom logic by specifying a custom `action` attribute. When you do this, the form data is validated and prepared, but the automatic DB insert is skipped. Instead, your controller receives the validated data via `Candy.formData`:
258
+ You can add custom logic by specifying a custom `action` attribute. When you do this, the form data is validated and prepared, but the automatic DB insert is skipped. Instead, your controller receives the validated data via `Odac.formData`:
259
259
 
260
260
  ```javascript
261
261
  // In your view:
262
- // <candy:form action="/contact/submit" table="contacts">
262
+ // <odac:form action="/contact/submit" table="contacts">
263
263
 
264
264
  // In your controller:
265
- Candy.Route.post('/contact/submit', async Candy => {
266
- // Candy.formData contains validated form data
267
- // Candy.formConfig contains form configuration
265
+ Odac.Route.post('/contact/submit', async Odac => {
266
+ // Odac.formData contains validated form data
267
+ // Odac.formConfig contains form configuration
268
268
 
269
269
  // Perform custom logic (send email, call API, etc.)
270
- await sendEmail(Candy.formData.email, 'Thank you!')
270
+ await sendEmail(Odac.formData.email, 'Thank you!')
271
271
 
272
272
  // Manually insert to database if needed
273
- await Candy.Mysql.query('INSERT INTO contacts SET ?', Candy.formData)
273
+ await Odac.Mysql.query('INSERT INTO contacts SET ?', Odac.formData)
274
274
 
275
- return Candy.return({
275
+ return Odac.return({
276
276
  result: {success: true, message: 'Message sent!'}
277
277
  })
278
278
  })
279
- const data = Candy.formData
279
+ const data = Odac.formData
280
280
 
281
281
  // Send welcome email
282
- Candy.Mail()
282
+ Odac.Mail()
283
283
  .to(data.email)
284
284
  .subject('Welcome!')
285
285
  .send('Thanks for joining!')
286
286
 
287
287
  // Return custom response
288
- return Candy.return({
288
+ return Odac.return({
289
289
  result: {
290
290
  success: true,
291
291
  message: 'Check your email!'
@@ -1,18 +1,18 @@
1
1
  ## 📥 The Request Object
2
2
 
3
- The `Candy.Request` object contains information about the user's incoming request.
3
+ The `Odac.Request` object contains information about the user's incoming request.
4
4
 
5
5
  ### Getting Request Parameters
6
6
 
7
- #### Using Candy.request() (Recommended)
7
+ #### Using Odac.request() (Recommended)
8
8
 
9
- The easiest way to get request parameters is using `Candy.request()`:
9
+ The easiest way to get request parameters is using `Odac.request()`:
10
10
 
11
11
  ```javascript
12
- module.exports = async function (Candy) {
12
+ module.exports = async function (Odac) {
13
13
  // Get parameter from GET or POST automatically
14
- const userName = await Candy.request('name')
15
- const userId = await Candy.request('id')
14
+ const userName = await Odac.request('name')
15
+ const userId = await Odac.request('id')
16
16
 
17
17
  return `Hello ${userName}!`
18
18
  }
@@ -21,12 +21,12 @@ module.exports = async function (Candy) {
21
21
  **Specify Method (Optional):**
22
22
 
23
23
  ```javascript
24
- module.exports = async function (Candy) {
24
+ module.exports = async function (Odac) {
25
25
  // Get from GET parameters only
26
- const searchQuery = await Candy.request('q', 'GET')
26
+ const searchQuery = await Odac.request('q', 'GET')
27
27
 
28
28
  // Get from POST parameters only
29
- const formName = await Candy.request('name', 'POST')
29
+ const formName = await Odac.request('name', 'POST')
30
30
 
31
31
  return `Searching for: ${searchQuery}`
32
32
  }
@@ -37,12 +37,12 @@ module.exports = async function (Candy) {
37
37
  You can also access request data directly:
38
38
 
39
39
  ```javascript
40
- module.exports = function (Candy) {
40
+ module.exports = function (Odac) {
41
41
  // GET parameters (URL query string like ?id=123)
42
- const userId = Candy.Request.get('id')
42
+ const userId = Odac.Request.get('id')
43
43
 
44
44
  // POST parameters (form data)
45
- const userName = Candy.Request.post('name')
45
+ const userName = Odac.Request.post('name')
46
46
 
47
47
  return `User: ${userName}`
48
48
  }
@@ -50,18 +50,18 @@ module.exports = function (Candy) {
50
50
 
51
51
  ### Request Properties
52
52
 
53
- * `Candy.Request.method` - HTTP method ('GET', 'POST', etc.)
54
- * `Candy.Request.url` - Full URL the user visited
55
- * `Candy.Request.host` - Website's hostname
56
- * `Candy.Request.ip` - User's IP address
57
- * `Candy.Request.ssl` - Whether connection is SSL/HTTPS
53
+ * `Odac.Request.method` - HTTP method ('GET', 'POST', etc.)
54
+ * `Odac.Request.url` - Full URL the user visited
55
+ * `Odac.Request.host` - Website's hostname
56
+ * `Odac.Request.ip` - User's IP address
57
+ * `Odac.Request.ssl` - Whether connection is SSL/HTTPS
58
58
 
59
59
  ### Request Headers
60
60
 
61
61
  ```javascript
62
- module.exports = function (Candy) {
63
- const userAgent = Candy.Request.header('user-agent')
64
- const contentType = Candy.Request.header('content-type')
62
+ module.exports = function (Odac) {
63
+ const userAgent = Odac.Request.header('user-agent')
64
+ const contentType = Odac.Request.header('content-type')
65
65
 
66
66
  return `Browser: ${userAgent}`
67
67
  }
@@ -70,25 +70,25 @@ module.exports = function (Candy) {
70
70
  ### Complete Example
71
71
 
72
72
  ```javascript
73
- module.exports = async function (Candy) {
73
+ module.exports = async function (Odac) {
74
74
  // Get request parameters
75
- const productId = await Candy.request('id')
76
- const quantity = await Candy.request('quantity') || 1
75
+ const productId = await Odac.request('id')
76
+ const quantity = await Odac.request('quantity') || 1
77
77
 
78
78
  // Check request method
79
- if (Candy.Request.method === 'POST') {
79
+ if (Odac.Request.method === 'POST') {
80
80
  // Handle form submission
81
81
  const result = await processOrder(productId, quantity)
82
82
  return { success: true, orderId: result.id }
83
83
  }
84
84
 
85
85
  // Show product page
86
- Candy.set({
86
+ Odac.set({
87
87
  productId: productId,
88
88
  quantity: quantity
89
89
  })
90
90
 
91
- Candy.View.set({
91
+ Odac.View.set({
92
92
  skeleton: 'main',
93
93
  content: 'product.detail'
94
94
  })
@@ -4,37 +4,37 @@ Once you've processed the request, it's time to send something back. You've got
4
4
 
5
5
  #### The Simple Way: Just Return It!
6
6
 
7
- For many cases, you can just `return` a value from your controller. CandyPack is smart enough to figure out what to do.
7
+ For many cases, you can just `return` a value from your controller. Odac is smart enough to figure out what to do.
8
8
 
9
9
  ```javascript
10
10
  // Return some HTML
11
- module.exports = function (Candy) {
11
+ module.exports = function (Odac) {
12
12
  return '<h1>Welcome to the site!</h1>';
13
13
  }
14
14
 
15
15
  // Return some JSON for an API
16
- module.exports = function (Candy) {
16
+ module.exports = function (Odac) {
17
17
  return { status: 'success', message: 'Your data was saved!' };
18
18
  }
19
19
  ```
20
20
 
21
21
  #### The Helper Functions: More Control
22
22
 
23
- Need a bit more control? The `Candy` object has your back.
23
+ Need a bit more control? The `Odac` object has your back.
24
24
 
25
- * `Candy.return(data)`: Does the same thing as a direct return, but you can call it from anywhere in your function. It stops everything and sends the response immediately.
26
- * `Candy.direct(url)`: Need to send the user to a different page? This function performs a redirect, telling the user's browser to go to a new URL.
25
+ * `Odac.return(data)`: Does the same thing as a direct return, but you can call it from anywhere in your function. It stops everything and sends the response immediately.
26
+ * `Odac.direct(url)`: Need to send the user to a different page? This function performs a redirect, telling the user's browser to go to a new URL.
27
27
 
28
28
  **Example:**
29
29
  ```javascript
30
- module.exports = function (Candy) {
30
+ module.exports = function (Odac) {
31
31
  // If the user isn't logged in...
32
- if (!Candy.Auth.isLogin()) {
32
+ if (!Odac.Auth.isLogin()) {
33
33
  // ...send them to the login page!
34
- return Candy.direct('/login');
34
+ return Odac.direct('/login');
35
35
  }
36
36
 
37
37
  // Otherwise, give them their data.
38
- Candy.return({ data: 'here is your secret stuff' });
38
+ Odac.return({ data: 'here is your secret stuff' });
39
39
  }
40
40
  ```
@@ -1,6 +1,6 @@
1
1
  ## 📁 View System Overview
2
2
 
3
- CandyPack's view system creates dynamic HTML pages by combining skeleton (layout) and view (content) files. This system provides a modular structure by keeping page layout and content separate.
3
+ Odac's view system creates dynamic HTML pages by combining skeleton (layout) and view (content) files. This system provides a modular structure by keeping page layout and content separate.
4
4
 
5
5
  ### Directory Structure
6
6
 
@@ -1,14 +1,14 @@
1
1
  ## 🎨 Rendering Views
2
2
 
3
- In CandyPack, you use the `Candy.View` object to render views. There are two main approaches:
3
+ In Odac, you use the `Odac.View` object to render views. There are two main approaches:
4
4
 
5
5
  ### 1. Combining Skeleton and View Parts
6
6
 
7
7
  The most common usage is to select a skeleton and place view parts into it.
8
8
 
9
9
  ```javascript
10
- module.exports = function (Candy) {
11
- Candy.View
10
+ module.exports = function (Odac) {
11
+ Odac.View
12
12
  .skeleton('main') // Use skeleton/main.html
13
13
  .set('header', 'main') // Place view/header/main.html into {{ HEADER }}
14
14
  .set('content', 'home') // Place view/content/home.html into {{ CONTENT }}
@@ -21,8 +21,8 @@ module.exports = function (Candy) {
21
21
  You can set all view parts at once:
22
22
 
23
23
  ```javascript
24
- module.exports = function (Candy) {
25
- Candy.View.set({
24
+ module.exports = function (Odac) {
25
+ Odac.View.set({
26
26
  skeleton: 'main',
27
27
  header: 'main',
28
28
  content: 'home',
@@ -36,7 +36,7 @@ module.exports = function (Candy) {
36
36
  View files can be organized in subdirectories. You can access them using dot notation:
37
37
 
38
38
  ```javascript
39
- Candy.View.set({
39
+ Odac.View.set({
40
40
  skeleton: 'dashboard',
41
41
  header: 'dashboard.main', // view/header/dashboard/main.html
42
42
  sidebar: 'dashboard.menu', // view/sidebar/dashboard/menu.html
@@ -50,7 +50,7 @@ You can render views directly from route files without using a controller:
50
50
 
51
51
  ```javascript
52
52
  // route/www.js
53
- Candy.Route.page('/about').view({
53
+ Odac.Route.page('/about').view({
54
54
  skeleton: 'main',
55
55
  header: 'main',
56
56
  content: 'about',
@@ -63,7 +63,7 @@ Candy.Route.page('/about').view({
63
63
  If you're using the same directory structure for all placeholders, you can use the `all()` method:
64
64
 
65
65
  ```javascript
66
- Candy.View
66
+ Odac.View
67
67
  .skeleton('main')
68
68
  .all('home') // view/home/header.html, view/home/content.html, view/home/footer.html
69
69
  ```
@@ -108,27 +108,27 @@ Create a separate view part for the `<head>` section:
108
108
  <head>
109
109
  <meta charset="UTF-8">
110
110
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
111
- <title>{{ Candy.pageTitle }}</title>
112
- <meta name="description" content="{{ Candy.pageDescription }}">
111
+ <title>{{ Odac.pageTitle }}</title>
112
+ <meta name="description" content="{{ Odac.pageDescription }}">
113
113
  <link rel="stylesheet" href="/assets/css/style.css">
114
114
  </head>
115
115
  ```
116
116
 
117
117
  **Controller:**
118
118
  ```javascript
119
- module.exports = async function (Candy) {
120
- const productId = Candy.Request.get('id')
121
- const product = await Candy.Mysql.table('products')
119
+ module.exports = async function (Odac) {
120
+ const productId = Odac.Request.get('id')
121
+ const product = await Odac.Mysql.table('products')
122
122
  .where('id', productId)
123
123
  .first()
124
124
 
125
125
  // Set dynamic title and description
126
- Candy.pageTitle = product ? `${product.name} - My Store` : 'Product Not Found'
127
- Candy.pageDescription = product ? product.short_description : ''
126
+ Odac.pageTitle = product ? `${product.name} - My Store` : 'Product Not Found'
127
+ Odac.pageDescription = product ? product.short_description : ''
128
128
 
129
- Candy.product = product
129
+ Odac.product = product
130
130
 
131
- Candy.View.set({
131
+ Odac.View.set({
132
132
  skeleton: 'main',
133
133
  head: 'main', // Include dynamic head
134
134
  header: 'main',
@@ -159,11 +159,11 @@ Include the title tag in your content view:
159
159
 
160
160
  **Content View (view/content/product.html):**
161
161
  ```html
162
- <title>{{ Candy.product.name }} - My Store</title>
162
+ <title>{{ Odac.product.name }} - My Store</title>
163
163
 
164
164
  <div class="product">
165
- <h1>{{ Candy.product.name }}</h1>
166
- <p>{{ Candy.product.description }}</p>
165
+ <h1>{{ Odac.product.name }}</h1>
166
+ <p>{{ Odac.product.description }}</p>
167
167
  </div>
168
168
  ```
169
169
 
@@ -175,5 +175,5 @@ Include the title tag in your content view:
175
175
  - Skeleton files should be in the `skeleton/` directory, view files in the `view/` directory
176
176
  - Placeholders for view parts are written in uppercase: `{{ HEADER }}`, `{{ CONTENT }}`, etc.
177
177
  - View part names are specified in lowercase: `header`, `content`, etc.
178
- - Variables in skeleton/views are accessed via `Candy` object: `{{ Candy.variableName }}`
179
- - You don't need to use `return` from the controller, `Candy.View.set()` automatically initiates the rendering process
178
+ - Variables in skeleton/views are accessed via `Odac` object: `{{ Odac.variableName }}`
179
+ - You don't need to use `return` from the controller, `Odac.View.set()` automatically initiates the rendering process