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,420 @@
1
+ # Form Handling with candy.js
2
+
3
+ Learn how to handle forms with automatic AJAX submission, CSRF protection, and validation in CandyPack.
4
+
5
+ ## Quick Start
6
+
7
+ ### Basic Form
8
+
9
+ ```html
10
+ <form id="contact-form" action="/api/contact" method="POST">
11
+ <input name="email" type="email" required>
12
+ <button type="submit">Submit</button>
13
+ </form>
14
+ ```
15
+
16
+ ```javascript
17
+ Candy.form('#contact-form', function(data) {
18
+ if (data.result.success) {
19
+ alert('Form submitted successfully!')
20
+ }
21
+ })
22
+ ```
23
+
24
+ That's it! candy.js handles:
25
+ - ✅ AJAX submission
26
+ - ✅ CSRF token (automatic)
27
+ - ✅ Validation errors (auto-generated)
28
+ - ✅ Success messages (auto-generated)
29
+ - ✅ Loading states
30
+
31
+ **Note:** Error and success message elements are automatically created if not present in your HTML. You can optionally add them for custom styling or positioning.
32
+
33
+ ## Form Configuration
34
+
35
+ ### Basic Usage
36
+
37
+ ```javascript
38
+ Candy.form('#my-form', function(data) {
39
+ console.log('Response:', data)
40
+ })
41
+ ```
42
+
43
+ ### With Options
44
+
45
+ ```javascript
46
+ Candy.form({
47
+ form: '#my-form',
48
+ messages: true, // Show error/success messages
49
+ loading: function(percent) {
50
+ console.log('Upload progress:', percent + '%')
51
+ }
52
+ }, function(data) {
53
+ if (data.result.success) {
54
+ console.log('Success!')
55
+ }
56
+ })
57
+ ```
58
+
59
+ ### Redirect After Submit
60
+
61
+ ```javascript
62
+ Candy.form('#my-form', '/success-page')
63
+ // Redirects to /success-page on success
64
+ ```
65
+
66
+ ## Error Handling
67
+
68
+ ### Automatic Error Display
69
+
70
+ By default, errors are automatically displayed next to the input fields when validation fails. The system creates error elements automatically.
71
+
72
+ ### Custom Error Placement (Optional)
73
+
74
+ If you want to control where errors appear, add error elements manually:
75
+
76
+ ```html
77
+ <input name="email" type="email">
78
+ <span candy-form-error="email"></span>
79
+ ```
80
+
81
+ **If not present:** The system automatically creates `<span candy-form-error="email">` after the input field.
82
+
83
+ **If present:** The system uses your existing element and updates its content.
84
+
85
+ ### Custom Error Display
86
+
87
+ ```javascript
88
+ Candy.form('#my-form', function(data) {
89
+ if (!data.result.success) {
90
+ // Custom error handling
91
+ Object.entries(data.errors).forEach(([field, message]) => {
92
+ console.log(`${field}: ${message}`)
93
+ })
94
+ }
95
+ })
96
+ ```
97
+
98
+ ### Styling Errors
99
+
100
+ ```css
101
+ /* Error message */
102
+ [candy-form-error] {
103
+ color: #ef4444;
104
+ font-size: 0.875rem;
105
+ margin-top: 0.25rem;
106
+ display: none;
107
+ }
108
+
109
+ /* Invalid input */
110
+ input._candy_error {
111
+ border-color: #ef4444;
112
+ }
113
+ ```
114
+
115
+ ## Success Messages
116
+
117
+ ### Automatic Success Display
118
+
119
+ Success messages are automatically displayed at the end of the form when submission succeeds.
120
+
121
+ ### Custom Success Placement (Optional)
122
+
123
+ If you want to control where success messages appear, add a success element manually:
124
+
125
+ ```html
126
+ <form id="my-form" action="/api/submit" method="POST">
127
+ <!-- form fields -->
128
+ <button type="submit">Submit</button>
129
+ <div candy-form-success></div>
130
+ </form>
131
+ ```
132
+
133
+ **If not present:** The system automatically creates `<span candy-form-success>` at the end of the form.
134
+
135
+ **If present:** The system uses your existing element and updates its content.
136
+
137
+ ### Custom Success Message
138
+
139
+ ```javascript
140
+ Candy.form('#my-form', function(data) {
141
+ if (data.result.success) {
142
+ document.querySelector('#custom-message').innerHTML =
143
+ 'Thank you! Your form has been submitted.'
144
+ }
145
+ })
146
+ ```
147
+
148
+ ## File Uploads
149
+
150
+ ### Basic File Upload
151
+
152
+ ```html
153
+ <form id="upload-form" action="/api/upload" method="POST">
154
+ <input name="file" type="file" required>
155
+ <button type="submit">Upload</button>
156
+ </form>
157
+ ```
158
+
159
+ ```javascript
160
+ Candy.form('#upload-form', function(data) {
161
+ if (data.result.success) {
162
+ console.log('File uploaded:', data.result.filename)
163
+ }
164
+ })
165
+ ```
166
+
167
+ ### Upload Progress
168
+
169
+ ```javascript
170
+ Candy.form({
171
+ form: '#upload-form',
172
+ loading: function(percent) {
173
+ document.querySelector('#progress').style.width = percent + '%'
174
+ document.querySelector('#progress-text').textContent = percent + '%'
175
+ }
176
+ }, function(data) {
177
+ console.log('Upload complete!')
178
+ })
179
+ ```
180
+
181
+ ### Multiple Files
182
+
183
+ ```html
184
+ <input name="files[]" type="file" multiple>
185
+ ```
186
+
187
+ ## Advanced Features
188
+
189
+ ### Disable Messages
190
+
191
+ ```javascript
192
+ Candy.form({
193
+ form: '#my-form',
194
+ messages: false // Don't show automatic messages
195
+ }, function(data) {
196
+ // Handle messages manually
197
+ })
198
+ ```
199
+
200
+ ### Disable Specific Messages
201
+
202
+ ```javascript
203
+ Candy.form({
204
+ form: '#my-form',
205
+ messages: ['error'] // Only show errors, not success
206
+ }, function(data) {
207
+ // Custom success handling
208
+ })
209
+ ```
210
+
211
+ ### Form Reset
212
+
213
+ ```javascript
214
+ Candy.form('#my-form', function(data) {
215
+ if (data.result.success) {
216
+ // Reset the form
217
+ document.querySelector('#my-form').reset()
218
+ }
219
+ })
220
+ ```
221
+
222
+ ### Conditional Submission
223
+
224
+ ```javascript
225
+ document.querySelector('#my-form').addEventListener('submit', function(e) {
226
+ if (!confirm('Are you sure?')) {
227
+ e.preventDefault()
228
+ e.stopPropagation()
229
+ }
230
+ })
231
+
232
+ Candy.form('#my-form', function(data) {
233
+ console.log('Submitted!')
234
+ })
235
+ ```
236
+
237
+ ## Server-Side Setup
238
+
239
+ ### Controller Example
240
+
241
+ ```javascript
242
+ // controller/post/contact.js
243
+ module.exports = async function(Candy) {
244
+ const email = await Candy.Request.request('email')
245
+ const message = await Candy.Request.request('message')
246
+
247
+ // Validation
248
+ const errors = {}
249
+ if (!email) errors.email = 'Email is required'
250
+ if (!message) errors.message = 'Message is required'
251
+
252
+ if (Object.keys(errors).length > 0) {
253
+ return {
254
+ result: {success: false},
255
+ errors: errors
256
+ }
257
+ }
258
+
259
+ // Process form
260
+ // ... send email, save to database, etc.
261
+
262
+ return {
263
+ result: {
264
+ success: true,
265
+ message: 'Thank you for your message!'
266
+ }
267
+ }
268
+ }
269
+ ```
270
+
271
+ ### Route Setup
272
+
273
+ ```javascript
274
+ // route/www.js
275
+ Candy.Route.post('/api/contact', 'contact')
276
+ ```
277
+
278
+ ## Validation
279
+
280
+ ### Client-Side Validation
281
+
282
+ Use HTML5 validation:
283
+
284
+ ```html
285
+ <input name="email" type="email" required>
286
+ <input name="age" type="number" min="18" max="100">
287
+ <input name="website" type="url">
288
+ ```
289
+
290
+ ### Server-Side Validation
291
+
292
+ Always validate on the server:
293
+
294
+ ```javascript
295
+ module.exports = async function(Candy) {
296
+ const email = await Candy.Request.request('email')
297
+
298
+ const errors = {}
299
+
300
+ // Required field
301
+ if (!email) {
302
+ errors.email = 'Email is required'
303
+ }
304
+
305
+ // Email format
306
+ else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
307
+ errors.email = 'Invalid email format'
308
+ }
309
+
310
+ // Check if exists
311
+ else if (await emailExists(email)) {
312
+ errors.email = 'Email already registered'
313
+ }
314
+
315
+ if (Object.keys(errors).length > 0) {
316
+ return {result: {success: false}, errors}
317
+ }
318
+
319
+ // Process...
320
+ }
321
+ ```
322
+
323
+ ## Common Patterns
324
+
325
+ ### Contact Form
326
+
327
+ ```html
328
+ <form id="contact-form" action="/api/contact" method="POST">
329
+ <input name="name" type="text" required>
330
+ <input name="email" type="email" required>
331
+ <textarea name="message" required></textarea>
332
+ <button type="submit">Send Message</button>
333
+ </form>
334
+ ```
335
+
336
+ **Note:** Error and success elements are auto-generated. Add them manually only if you need custom positioning or styling.
337
+
338
+ ```javascript
339
+ Candy.form('#contact-form', function(data) {
340
+ if (data.result.success) {
341
+ document.querySelector('#contact-form').reset()
342
+ }
343
+ })
344
+ ```
345
+
346
+ ### Login Form
347
+
348
+ ```html
349
+ <form id="login-form" action="/api/login" method="POST">
350
+ <input name="email" type="email" required>
351
+ <input name="password" type="password" required>
352
+ <button type="submit">Login</button>
353
+ </form>
354
+ ```
355
+
356
+ ```javascript
357
+ Candy.form('#login-form', function(data) {
358
+ if (data.result.success) {
359
+ // Redirect to dashboard
360
+ window.location.href = '/dashboard'
361
+ }
362
+ })
363
+ ```
364
+
365
+ ### Registration Form
366
+
367
+ ```html
368
+ <form id="register-form" action="/api/register" method="POST">
369
+ <input name="name" type="text" required>
370
+ <input name="email" type="email" required>
371
+ <input name="password" type="password" required minlength="8">
372
+ <input name="password_confirm" type="password" required>
373
+ <button type="submit">Register</button>
374
+ </form>
375
+ ```
376
+
377
+ **Tip:** For better UX, you can add custom error elements for specific positioning:
378
+
379
+ ```html
380
+ <div class="form-group">
381
+ <input name="email" type="email" required>
382
+ <span candy-form-error="email" class="error-message"></span>
383
+ </div>
384
+ ```
385
+
386
+ ## Best Practices
387
+
388
+ 1. **Always Validate Server-Side**: Never trust client-side validation alone
389
+ 2. **Show Clear Errors**: Display errors next to the relevant fields
390
+ 3. **Provide Feedback**: Show loading states during submission
391
+ 4. **Reset on Success**: Clear the form after successful submission
392
+ 5. **Handle Errors Gracefully**: Provide helpful error messages
393
+ 6. **Use HTTPS**: Always use HTTPS for forms with sensitive data
394
+
395
+ ## Troubleshooting
396
+
397
+ ### Form Not Submitting
398
+
399
+ - Check that `Candy.form()` is called after DOM is ready
400
+ - Verify the form selector is correct
401
+ - Check browser console for errors
402
+
403
+ ### Errors Not Displaying
404
+
405
+ - Errors are automatically created - no manual elements needed
406
+ - Check that server returns errors in correct format: `{result: {success: false}, errors: {fieldName: 'message'}}`
407
+ - Verify `messages` option is not set to `false`
408
+ - If using custom error elements, ensure `candy-form-error` attributes match field names exactly
409
+
410
+ ### CSRF Token Errors
411
+
412
+ - CSRF tokens are handled automatically
413
+ - If you get token errors, check server configuration
414
+ - Ensure cookies are enabled
415
+
416
+ ## Next Steps
417
+
418
+ - Learn about [Validation](02-validation.md)
419
+ - Explore [File Uploads](03-file-uploads.md)
420
+ - Check [API Requests](../04-api-requests/01-get-post.md)