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
@@ -1,22 +1,22 @@
1
1
  # Custom Forms
2
2
 
3
- CandyPack provides an automatic form system with built-in validation, CSRF protection, and seamless client-side integration. The `<candy:form>` tag allows you to create forms with minimal code while maintaining full control.
3
+ Odac provides an automatic form system with built-in validation, CSRF protection, and seamless client-side integration. The `<odac:form>` tag allows you to create forms with minimal code while maintaining full control.
4
4
 
5
5
  ## Basic Usage
6
6
 
7
7
  ```html
8
- <candy:form action="/contact/submit" method="POST">
9
- <candy:field name="email" type="email" label="Email">
10
- <candy:validate rule="required|email" message="Valid email required"/>
11
- </candy:field>
8
+ <odac:form action="/contact/submit" method="POST">
9
+ <odac:field name="email" type="email" label="Email">
10
+ <odac:validate rule="required|email" message="Valid email required"/>
11
+ </odac:field>
12
12
 
13
- <candy:submit text="Send" loading="Sending..."/>
14
- </candy:form>
13
+ <odac:submit text="Send" loading="Sending..."/>
14
+ </odac:form>
15
15
  ```
16
16
 
17
17
  ## Form Attributes
18
18
 
19
- ### `<candy:form>`
19
+ ### `<odac:form>`
20
20
 
21
21
  - `action` - Form submission URL (optional if using `table`)
22
22
  - `method` - HTTP method (default: POST)
@@ -28,81 +28,81 @@ CandyPack provides an automatic form system with built-in validation, CSRF prote
28
28
 
29
29
  ```html
30
30
  <!-- With custom controller -->
31
- <candy:form action="/api/save" method="POST" class="my-form" id="contact-form">
31
+ <odac:form action="/api/save" method="POST" class="my-form" id="contact-form">
32
32
  <!-- fields here -->
33
- </candy:form>
33
+ </odac:form>
34
34
 
35
35
  <!-- With automatic DB insert -->
36
- <candy:form table="waitlist" redirect="/" success="Thank you for joining!">
36
+ <odac:form table="waitlist" redirect="/" success="Thank you for joining!">
37
37
  <!-- fields here -->
38
- </candy:form>
38
+ </odac:form>
39
39
  ```
40
40
 
41
41
  ## Field Types
42
42
 
43
- ### `<candy:field>`
43
+ ### `<odac:field>`
44
44
 
45
45
  Supports all standard HTML input types:
46
46
 
47
47
  ```html
48
48
  <!-- Text input with multiple validations -->
49
- <candy:field name="username" type="text" label="Username" placeholder="Enter username">
50
- <candy:validate rule="required" message="Username is required"/>
51
- <candy:validate rule="minlen:3" message="Username must be at least 3 characters"/>
52
- <candy:validate rule="maxlen:20" message="Username cannot exceed 20 characters"/>
53
- <candy:validate rule="alphanumeric" message="Username can only contain letters and numbers"/>
54
- </candy:field>
49
+ <odac:field name="username" type="text" label="Username" placeholder="Enter username">
50
+ <odac:validate rule="required" message="Username is required"/>
51
+ <odac:validate rule="minlen:3" message="Username must be at least 3 characters"/>
52
+ <odac:validate rule="maxlen:20" message="Username cannot exceed 20 characters"/>
53
+ <odac:validate rule="alphanumeric" message="Username can only contain letters and numbers"/>
54
+ </odac:field>
55
55
 
56
56
  <!-- Email input -->
57
- <candy:field name="email" type="email" label="Email Address" placeholder="your@email.com">
58
- <candy:validate rule="required" message="Email address is required"/>
59
- <candy:validate rule="email" message="Please enter a valid email address"/>
60
- <candy:validate rule="maxlen:100" message="Email is too long"/>
61
- </candy:field>
57
+ <odac:field name="email" type="email" label="Email Address" placeholder="your@email.com">
58
+ <odac:validate rule="required" message="Email address is required"/>
59
+ <odac:validate rule="email" message="Please enter a valid email address"/>
60
+ <odac:validate rule="maxlen:100" message="Email is too long"/>
61
+ </odac:field>
62
62
 
63
63
  <!-- Password input with strong validation -->
64
- <candy:field name="password" type="password" label="Password">
65
- <candy:validate rule="required" message="Password is required"/>
66
- <candy:validate rule="minlen:8" message="Password must be at least 8 characters long"/>
67
- <candy:validate rule="maxlen:50" message="Password is too long"/>
68
- </candy:field>
64
+ <odac:field name="password" type="password" label="Password">
65
+ <odac:validate rule="required" message="Password is required"/>
66
+ <odac:validate rule="minlen:8" message="Password must be at least 8 characters long"/>
67
+ <odac:validate rule="maxlen:50" message="Password is too long"/>
68
+ </odac:field>
69
69
 
70
70
  <!-- Textarea with character limits -->
71
- <candy:field name="message" type="textarea" label="Your Message" placeholder="Tell us what you think...">
72
- <candy:validate rule="required" message="Please enter your message"/>
73
- <candy:validate rule="minlen:10" message="Message must be at least 10 characters"/>
74
- <candy:validate rule="maxlen:500" message="Message cannot exceed 500 characters"/>
75
- </candy:field>
71
+ <odac:field name="message" type="textarea" label="Your Message" placeholder="Tell us what you think...">
72
+ <odac:validate rule="required" message="Please enter your message"/>
73
+ <odac:validate rule="minlen:10" message="Message must be at least 10 characters"/>
74
+ <odac:validate rule="maxlen:500" message="Message cannot exceed 500 characters"/>
75
+ </odac:field>
76
76
 
77
77
  <!-- Checkbox for terms acceptance -->
78
- <candy:field name="agree" type="checkbox" label="I agree to the Terms of Service and Privacy Policy">
79
- <candy:validate rule="accepted" message="You must accept the terms to continue"/>
80
- </candy:field>
78
+ <odac:field name="agree" type="checkbox" label="I agree to the Terms of Service and Privacy Policy">
79
+ <odac:validate rule="accepted" message="You must accept the terms to continue"/>
80
+ </odac:field>
81
81
 
82
82
  <!-- Number input with range -->
83
- <candy:field name="age" type="number" label="Your Age">
84
- <candy:validate rule="required" message="Age is required"/>
85
- <candy:validate rule="min:18" message="You must be at least 18 years old"/>
86
- <candy:validate rule="max:120" message="Please enter a valid age"/>
87
- </candy:field>
83
+ <odac:field name="age" type="number" label="Your Age">
84
+ <odac:validate rule="required" message="Age is required"/>
85
+ <odac:validate rule="min:18" message="You must be at least 18 years old"/>
86
+ <odac:validate rule="max:120" message="Please enter a valid age"/>
87
+ </odac:field>
88
88
 
89
89
  <!-- Phone number -->
90
- <candy:field name="phone" type="text" label="Phone Number" placeholder="+1 (555) 123-4567">
91
- <candy:validate rule="required" message="Phone number is required"/>
92
- <candy:validate rule="minlen:10" message="Phone number must be at least 10 digits"/>
93
- </candy:field>
90
+ <odac:field name="phone" type="text" label="Phone Number" placeholder="+1 (555) 123-4567">
91
+ <odac:validate rule="required" message="Phone number is required"/>
92
+ <odac:validate rule="minlen:10" message="Phone number must be at least 10 digits"/>
93
+ </odac:field>
94
94
 
95
95
  <!-- URL input -->
96
- <candy:field name="website" type="url" label="Website" placeholder="https://example.com">
97
- <candy:validate rule="url" message="Please enter a valid URL"/>
98
- </candy:field>
96
+ <odac:field name="website" type="url" label="Website" placeholder="https://example.com">
97
+ <odac:validate rule="url" message="Please enter a valid URL"/>
98
+ </odac:field>
99
99
 
100
100
  <!-- Name with alpha validation -->
101
- <candy:field name="full_name" type="text" label="Full Name" placeholder="John Doe">
102
- <candy:validate rule="required" message="Full name is required"/>
103
- <candy:validate rule="minlen:2" message="Name must be at least 2 characters"/>
104
- <candy:validate rule="maxlen:50" message="Name is too long"/>
105
- </candy:field>
101
+ <odac:field name="full_name" type="text" label="Full Name" placeholder="John Doe">
102
+ <odac:validate rule="required" message="Full name is required"/>
103
+ <odac:validate rule="minlen:2" message="Name must be at least 2 characters"/>
104
+ <odac:validate rule="maxlen:50" message="Name is too long"/>
105
+ </odac:field>
106
106
  ```
107
107
 
108
108
  ### Field Attributes
@@ -116,14 +116,14 @@ Supports all standard HTML input types:
116
116
 
117
117
  ## Validation Rules
118
118
 
119
- ### `<candy:validate>`
119
+ ### `<odac:validate>`
120
120
 
121
121
  Add validation rules to fields:
122
122
 
123
123
  ```html
124
- <candy:field name="username" type="text">
125
- <candy:validate rule="required|minlen:3|maxlen:20" message="Username must be 3-20 characters"/>
126
- </candy:field>
124
+ <odac:field name="username" type="text">
125
+ <odac:validate rule="required|minlen:3|maxlen:20" message="Username must be 3-20 characters"/>
126
+ </odac:field>
127
127
  ```
128
128
 
129
129
  ### Available Rules
@@ -145,7 +145,7 @@ Add validation rules to fields:
145
145
  Combine rules with `|`:
146
146
 
147
147
  ```html
148
- <candy:validate rule="required|email|maxlen:100" message="Invalid email"/>
148
+ <odac:validate rule="required|email|maxlen:100" message="Invalid email"/>
149
149
  ```
150
150
 
151
151
  ### Unique Validation
@@ -153,20 +153,20 @@ Combine rules with `|`:
153
153
  For automatic DB insert, use `unique` to check if value already exists:
154
154
 
155
155
  ```html
156
- <candy:validate rule="required|email|unique" message="This email is already registered"/>
156
+ <odac:validate rule="required|email|unique" message="This email is already registered"/>
157
157
  ```
158
158
 
159
159
  ## Auto-Set Values
160
160
 
161
- ### `<candy:set>`
161
+ ### `<odac:set>`
162
162
 
163
163
  Automatically set field values without user input:
164
164
 
165
165
  ```html
166
- <candy:set name="created_at" compute="now"/>
167
- <candy:set name="ip" compute="ip"/>
168
- <candy:set name="user_agent" compute="user_agent"/>
169
- <candy:set name="status" value="pending"/>
166
+ <odac:set name="created_at" compute="now"/>
167
+ <odac:set name="ip" compute="ip"/>
168
+ <odac:set name="user_agent" compute="user_agent"/>
169
+ <odac:set name="status" value="pending"/>
170
170
  ```
171
171
 
172
172
  ### Available Compute Types
@@ -189,17 +189,17 @@ Automatically set field values without user input:
189
189
 
190
190
  ## Submit Button
191
191
 
192
- ### `<candy:submit>`
192
+ ### `<odac:submit>`
193
193
 
194
194
  ```html
195
195
  <!-- Simple -->
196
- <candy:submit text="Submit"/>
196
+ <odac:submit text="Submit"/>
197
197
 
198
198
  <!-- With loading state -->
199
- <candy:submit text="Send Message" loading="Sending..."/>
199
+ <odac:submit text="Send Message" loading="Sending..."/>
200
200
 
201
201
  <!-- With styling -->
202
- <candy:submit text="Save" loading="Saving..." class="btn btn-primary" id="save-btn"/>
202
+ <odac:submit text="Save" loading="Saving..." class="btn btn-primary" id="save-btn"/>
203
203
  ```
204
204
 
205
205
  ## Controller Handler
@@ -208,9 +208,9 @@ Handle form submission in your controller:
208
208
 
209
209
  ```javascript
210
210
  module.exports = {
211
- submit: Candy => {
211
+ submit: Odac => {
212
212
  // Access validated form data
213
- const data = Candy.formData
213
+ const data = Odac.formData
214
214
 
215
215
  // data contains all field values
216
216
  console.log(data.email, data.message)
@@ -218,7 +218,7 @@ module.exports = {
218
218
  // Process the data (save to database, send email, etc.)
219
219
 
220
220
  // Return success response
221
- return Candy.return({
221
+ return Odac.return({
222
222
  result: {
223
223
  success: true,
224
224
  message: 'Form submitted successfully!',
@@ -235,12 +235,12 @@ Return validation errors:
235
235
 
236
236
  ```javascript
237
237
  module.exports = {
238
- submit: Candy => {
239
- const data = Candy.formData
238
+ submit: Odac => {
239
+ const data = Odac.formData
240
240
 
241
241
  // Custom validation
242
242
  if (data.email.includes('spam')) {
243
- return Candy.return({
243
+ return Odac.return({
244
244
  result: {success: false},
245
245
  errors: {
246
246
  email: 'This email is not allowed'
@@ -248,7 +248,7 @@ module.exports = {
248
248
  })
249
249
  }
250
250
 
251
- return Candy.return({
251
+ return Odac.return({
252
252
  result: {success: true, message: 'Success!'}
253
253
  })
254
254
  }
@@ -262,20 +262,20 @@ Forms can automatically insert data into database without writing a controller:
262
262
  ### View (view/content/waitlist.html)
263
263
 
264
264
  ```html
265
- <candy:form table="waitlist" redirect="/" success="Thank you for joining!">
266
- <candy:field name="email" type="email" label="Email">
267
- <candy:validate rule="required|email|unique" message="Valid email required"/>
268
- </candy:field>
265
+ <odac:form table="waitlist" redirect="/" success="Thank you for joining!">
266
+ <odac:field name="email" type="email" label="Email">
267
+ <odac:validate rule="required|email|unique" message="Valid email required"/>
268
+ </odac:field>
269
269
 
270
- <candy:field name="name" type="text" label="Name">
271
- <candy:validate rule="required|minlen:2" message="Name required"/>
272
- </candy:field>
270
+ <odac:field name="name" type="text" label="Name">
271
+ <odac:validate rule="required|minlen:2" message="Name required"/>
272
+ </odac:field>
273
273
 
274
- <candy:set name="created_at" compute="now"/>
275
- <candy:set name="ip" compute="ip"/>
274
+ <odac:set name="created_at" compute="now"/>
275
+ <odac:set name="ip" compute="ip"/>
276
276
 
277
- <candy:submit text="Join Waitlist" loading="Joining..."/>
278
- </candy:form>
277
+ <odac:submit text="Join Waitlist" loading="Joining..."/>
278
+ </odac:form>
279
279
  ```
280
280
 
281
281
  ### Database Table
@@ -294,7 +294,7 @@ CREATE TABLE `waitlist` (
294
294
  ### Route (route/www.js)
295
295
 
296
296
  ```javascript
297
- Candy.Route.page('/waitlist', 'waitlist')
297
+ Odac.Route.page('/waitlist', 'waitlist')
298
298
  ```
299
299
 
300
300
  That's it! No controller needed. The form will:
@@ -312,25 +312,25 @@ That's it! No controller needed. The form will:
312
312
  <div class="contact-page">
313
313
  <h1>Contact Us</h1>
314
314
 
315
- <candy:form action="/contact/submit" method="POST" class="contact-form">
316
- <candy:field name="name" type="text" label="Your Name" placeholder="Enter your name">
317
- <candy:validate rule="required|minlen:3" message="Name must be at least 3 characters"/>
318
- </candy:field>
315
+ <odac:form action="/contact/submit" method="POST" class="contact-form">
316
+ <odac:field name="name" type="text" label="Your Name" placeholder="Enter your name">
317
+ <odac:validate rule="required|minlen:3" message="Name must be at least 3 characters"/>
318
+ </odac:field>
319
319
 
320
- <candy:field name="email" type="email" label="Email" placeholder="your@email.com">
321
- <candy:validate rule="required|email" message="Please enter a valid email"/>
322
- </candy:field>
320
+ <odac:field name="email" type="email" label="Email" placeholder="your@email.com">
321
+ <odac:validate rule="required|email" message="Please enter a valid email"/>
322
+ </odac:field>
323
323
 
324
- <candy:field name="subject" type="text" label="Subject" placeholder="What is this about?">
325
- <candy:validate rule="required|minlen:5" message="Subject must be at least 5 characters"/>
326
- </candy:field>
324
+ <odac:field name="subject" type="text" label="Subject" placeholder="What is this about?">
325
+ <odac:validate rule="required|minlen:5" message="Subject must be at least 5 characters"/>
326
+ </odac:field>
327
327
 
328
- <candy:field name="message" type="textarea" label="Message" placeholder="Your message...">
329
- <candy:validate rule="required|minlen:10" message="Message must be at least 10 characters"/>
330
- </candy:field>
328
+ <odac:field name="message" type="textarea" label="Message" placeholder="Your message...">
329
+ <odac:validate rule="required|minlen:10" message="Message must be at least 10 characters"/>
330
+ </odac:field>
331
331
 
332
- <candy:submit text="Send Message" loading="Sending..." class="btn btn-primary"/>
333
- </candy:form>
332
+ <odac:submit text="Send Message" loading="Sending..." class="btn btn-primary"/>
333
+ </odac:form>
334
334
  </div>
335
335
  ```
336
336
 
@@ -338,22 +338,22 @@ That's it! No controller needed. The form will:
338
338
 
339
339
  ```javascript
340
340
  module.exports = {
341
- index: Candy => {
342
- Candy.View.skeleton('default')
343
- Candy.View.set({content: 'contact'})
344
- Candy.View.print()
341
+ index: Odac => {
342
+ Odac.View.skeleton('default')
343
+ Odac.View.set({content: 'contact'})
344
+ Odac.View.print()
345
345
  },
346
346
 
347
- submit: Candy => {
348
- const data = Candy.formData
347
+ submit: Odac => {
348
+ const data = Odac.formData
349
349
 
350
350
  // Save to database
351
- // await Candy.Mysql.query('INSERT INTO contacts SET ?', data)
351
+ // await Odac.Mysql.query('INSERT INTO contacts SET ?', data)
352
352
 
353
353
  // Send email notification
354
- // await Candy.Mail().to('admin@example.com').subject('New Contact').send(data.message)
354
+ // await Odac.Mail().to('admin@example.com').subject('New Contact').send(data.message)
355
355
 
356
- return Candy.return({
356
+ return Odac.return({
357
357
  result: {
358
358
  success: true,
359
359
  message: 'Thank you! We will get back to you soon.',
@@ -367,8 +367,8 @@ module.exports = {
367
367
  ### Route (route/www.js)
368
368
 
369
369
  ```javascript
370
- Candy.Route.page('/contact', 'contact')
371
- Candy.Route.post('/contact/submit', 'contact.submit')
370
+ Odac.Route.page('/contact', 'contact')
371
+ Odac.Route.post('/contact/submit', 'contact.submit')
372
372
  ```
373
373
 
374
374
  ## Features