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.
- package/.editorconfig +21 -0
- package/.github/workflows/auto-pr-description.yml +49 -0
- package/.github/workflows/release.yml +32 -0
- package/.github/workflows/test-coverage.yml +58 -0
- package/.husky/pre-commit +2 -0
- package/.kiro/steering/code-style.md +56 -0
- package/.kiro/steering/product.md +20 -0
- package/.kiro/steering/structure.md +77 -0
- package/.kiro/steering/tech.md +87 -0
- package/.prettierrc +10 -0
- package/.releaserc.js +134 -0
- package/AGENTS.md +84 -0
- package/CHANGELOG.md +181 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +661 -0
- package/README.md +57 -0
- package/SECURITY.md +26 -0
- package/bin/candy +10 -0
- package/bin/candypack +10 -0
- package/cli/index.js +3 -0
- package/cli/src/Cli.js +348 -0
- package/cli/src/Connector.js +93 -0
- package/cli/src/Monitor.js +416 -0
- package/core/Candy.js +87 -0
- package/core/Commands.js +239 -0
- package/core/Config.js +1094 -0
- package/core/Lang.js +52 -0
- package/core/Log.js +43 -0
- package/core/Process.js +26 -0
- package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
- package/docs/backend/01-overview/03-development-server.md +79 -0
- package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
- package/docs/backend/03-config/00-configuration-overview.md +214 -0
- package/docs/backend/03-config/01-database-connection.md +60 -0
- package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
- package/docs/backend/03-config/03-request-timeout.md +11 -0
- package/docs/backend/03-config/04-environment-variables.md +227 -0
- package/docs/backend/03-config/05-early-hints.md +352 -0
- package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
- package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
- package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
- package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
- package/docs/backend/04-routing/05-advanced-routing.md +14 -0
- package/docs/backend/04-routing/06-error-pages.md +101 -0
- package/docs/backend/04-routing/07-cron-jobs.md +149 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
- package/docs/backend/05-controllers/03-controller-classes.md +93 -0
- package/docs/backend/05-forms/01-custom-forms.md +395 -0
- package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
- package/docs/backend/07-views/01-the-view-directory.md +73 -0
- package/docs/backend/07-views/02-rendering-a-view.md +179 -0
- package/docs/backend/07-views/03-template-syntax.md +181 -0
- package/docs/backend/07-views/03-variables.md +328 -0
- package/docs/backend/07-views/04-request-data.md +231 -0
- package/docs/backend/07-views/05-conditionals.md +290 -0
- package/docs/backend/07-views/06-loops.md +353 -0
- package/docs/backend/07-views/07-translations.md +358 -0
- package/docs/backend/07-views/08-backend-javascript.md +398 -0
- package/docs/backend/07-views/09-comments.md +297 -0
- package/docs/backend/08-database/01-database-connection.md +99 -0
- package/docs/backend/08-database/02-using-mysql.md +322 -0
- package/docs/backend/09-validation/01-the-validator-service.md +424 -0
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
- package/docs/backend/10-authentication/03-register.md +134 -0
- package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
- package/docs/backend/10-authentication/05-session-management.md +159 -0
- package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
- package/docs/backend/11-mail/01-the-mail-service.md +42 -0
- package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
- package/docs/backend/13-utilities/01-candy-var.md +504 -0
- package/docs/frontend/01-overview/01-introduction.md +146 -0
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
- package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
- package/docs/frontend/03-forms/01-form-handling.md +420 -0
- package/docs/frontend/04-api-requests/01-get-post.md +443 -0
- package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
- package/docs/index.json +452 -0
- package/docs/server/01-installation/01-quick-install.md +19 -0
- package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
- package/docs/server/02-get-started/01-core-concepts.md +7 -0
- package/docs/server/02-get-started/02-basic-commands.md +57 -0
- package/docs/server/02-get-started/03-cli-reference.md +276 -0
- package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
- package/docs/server/03-service/01-start-a-new-service.md +57 -0
- package/docs/server/03-service/02-delete-a-service.md +48 -0
- package/docs/server/04-web/01-create-a-website.md +36 -0
- package/docs/server/04-web/02-list-websites.md +9 -0
- package/docs/server/04-web/03-delete-a-website.md +29 -0
- package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
- package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
- package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
- package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
- package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
- package/docs/server/07-mail/04-change-account-password.md +23 -0
- package/eslint.config.mjs +120 -0
- package/framework/index.js +4 -0
- package/framework/src/Auth.js +309 -0
- package/framework/src/Candy.js +81 -0
- package/framework/src/Config.js +79 -0
- package/framework/src/Env.js +60 -0
- package/framework/src/Lang.js +57 -0
- package/framework/src/Mail.js +83 -0
- package/framework/src/Mysql.js +575 -0
- package/framework/src/Request.js +301 -0
- package/framework/src/Route/Cron.js +128 -0
- package/framework/src/Route/Internal.js +439 -0
- package/framework/src/Route.js +455 -0
- package/framework/src/Server.js +15 -0
- package/framework/src/Stream.js +163 -0
- package/framework/src/Token.js +37 -0
- package/framework/src/Validator.js +271 -0
- package/framework/src/Var.js +211 -0
- package/framework/src/View/EarlyHints.js +190 -0
- package/framework/src/View/Form.js +600 -0
- package/framework/src/View.js +513 -0
- package/framework/web/candy.js +838 -0
- package/jest.config.js +22 -0
- package/locale/de-DE.json +80 -0
- package/locale/en-US.json +79 -0
- package/locale/es-ES.json +80 -0
- package/locale/fr-FR.json +80 -0
- package/locale/pt-BR.json +80 -0
- package/locale/ru-RU.json +80 -0
- package/locale/tr-TR.json +85 -0
- package/locale/zh-CN.json +80 -0
- package/package.json +86 -0
- package/server/index.js +5 -0
- package/server/src/Api.js +88 -0
- package/server/src/DNS.js +940 -0
- package/server/src/Hub.js +535 -0
- package/server/src/Mail.js +571 -0
- package/server/src/SSL.js +180 -0
- package/server/src/Server.js +27 -0
- package/server/src/Service.js +248 -0
- package/server/src/Subdomain.js +64 -0
- package/server/src/Web/Firewall.js +170 -0
- package/server/src/Web/Proxy.js +134 -0
- package/server/src/Web.js +451 -0
- package/server/src/mail/imap.js +1091 -0
- package/server/src/mail/server.js +32 -0
- package/server/src/mail/smtp.js +786 -0
- package/test/cli/Cli.test.js +36 -0
- package/test/core/Candy.test.js +234 -0
- package/test/core/Commands.test.js +538 -0
- package/test/core/Config.test.js +1435 -0
- package/test/core/Lang.test.js +250 -0
- package/test/core/Process.test.js +156 -0
- package/test/framework/Route.test.js +239 -0
- package/test/framework/View/EarlyHints.test.js +282 -0
- package/test/scripts/check-coverage.js +132 -0
- package/test/server/Api.test.js +647 -0
- package/test/server/Client.test.js +338 -0
- package/test/server/DNS.test.js +2050 -0
- package/test/server/DNS.test.js.bak +2084 -0
- package/test/server/Log.test.js +73 -0
- package/test/server/Mail.account.test_.js +460 -0
- package/test/server/Mail.init.test_.js +411 -0
- package/test/server/Mail.test_.js +1340 -0
- package/test/server/SSL.test_.js +1491 -0
- package/test/server/Server.test.js +765 -0
- package/test/server/Service.test_.js +1127 -0
- package/test/server/Subdomain.test.js +440 -0
- package/test/server/Web/Firewall.test.js +175 -0
- package/test/server/Web.test_.js +1562 -0
- package/test/server/__mocks__/acme-client.js +17 -0
- package/test/server/__mocks__/bcrypt.js +50 -0
- package/test/server/__mocks__/child_process.js +389 -0
- package/test/server/__mocks__/crypto.js +432 -0
- package/test/server/__mocks__/fs.js +450 -0
- package/test/server/__mocks__/globalCandy.js +227 -0
- package/test/server/__mocks__/http-proxy.js +105 -0
- package/test/server/__mocks__/http.js +575 -0
- package/test/server/__mocks__/https.js +272 -0
- package/test/server/__mocks__/index.js +249 -0
- package/test/server/__mocks__/mail/server.js +100 -0
- package/test/server/__mocks__/mail/smtp.js +31 -0
- package/test/server/__mocks__/mailparser.js +81 -0
- package/test/server/__mocks__/net.js +369 -0
- package/test/server/__mocks__/node-forge.js +328 -0
- package/test/server/__mocks__/os.js +320 -0
- package/test/server/__mocks__/path.js +291 -0
- package/test/server/__mocks__/selfsigned.js +8 -0
- package/test/server/__mocks__/server/src/mail/server.js +100 -0
- package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
- package/test/server/__mocks__/smtp-server.js +106 -0
- package/test/server/__mocks__/sqlite3.js +394 -0
- package/test/server/__mocks__/testFactories.js +299 -0
- package/test/server/__mocks__/testHelpers.js +363 -0
- package/test/server/__mocks__/tls.js +229 -0
- package/watchdog/index.js +3 -0
- package/watchdog/src/Watchdog.js +156 -0
- package/web/config.json +5 -0
- package/web/controller/page/about.js +27 -0
- package/web/controller/page/index.js +34 -0
- package/web/package.json +18 -0
- package/web/public/assets/css/style.css +1835 -0
- package/web/public/assets/js/app.js +96 -0
- package/web/route/www.js +19 -0
- package/web/skeleton/main.html +22 -0
- package/web/view/content/about.html +65 -0
- package/web/view/content/home.html +205 -0
- package/web/view/footer/main.html +11 -0
- package/web/view/head/main.html +5 -0
- package/web/view/header/main.html +14 -0
package/core/Lang.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
|
|
3
|
+
class Lang {
|
|
4
|
+
#locale = Intl.DateTimeFormat().resolvedOptions().locale
|
|
5
|
+
#file = __dirname + '/../locale/' + this.#locale + '.json'
|
|
6
|
+
#strings = {}
|
|
7
|
+
#loaded = false
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
this.#load()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
#save() {
|
|
14
|
+
try {
|
|
15
|
+
fs.promises.writeFile(this.#file, JSON.stringify(this.#strings, null, 4), 'utf8')
|
|
16
|
+
} catch (err) {
|
|
17
|
+
console.error('Error saving language file:', err)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#load() {
|
|
22
|
+
try {
|
|
23
|
+
const data = fs.readFileSync(this.#file, 'utf8')
|
|
24
|
+
this.#loaded = true
|
|
25
|
+
this.#strings = JSON.parse(data)
|
|
26
|
+
} catch {
|
|
27
|
+
this.#strings = {}
|
|
28
|
+
this.#save()
|
|
29
|
+
}
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get(key, ...args) {
|
|
34
|
+
if (!this.#loaded) this.#load()
|
|
35
|
+
if (key === 'CandyPack') return 'CandyPack'
|
|
36
|
+
let text = this.#strings[key]
|
|
37
|
+
if (text === undefined) {
|
|
38
|
+
text = key
|
|
39
|
+
this.#strings[key] = text
|
|
40
|
+
this.#save()
|
|
41
|
+
}
|
|
42
|
+
if (args.length > 0) {
|
|
43
|
+
args.forEach((arg, i) => {
|
|
44
|
+
if (text.includes(`%s${i + 1}`)) text = text.replace(`%s${i + 1}`, arg)
|
|
45
|
+
else text = text.replace('%s', arg)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
return text
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = Lang
|
package/core/Log.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class Log {
|
|
2
|
+
#cliMode = false
|
|
3
|
+
|
|
4
|
+
constructor() {
|
|
5
|
+
// Detect if we're running in CLI mode
|
|
6
|
+
// CLI mode is when the main module is in cli/ or bin/ directory
|
|
7
|
+
if (require.main && require.main.filename) {
|
|
8
|
+
const mainFile = require.main.filename
|
|
9
|
+
this.#cliMode = mainFile.includes('/cli/') || mainFile.includes('/bin/')
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init(...arg) {
|
|
14
|
+
this.module = '[' + arg.join('][') + '] '
|
|
15
|
+
return {
|
|
16
|
+
error: this.error.bind(this),
|
|
17
|
+
log: this.log.bind(this)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
error(...arg) {
|
|
22
|
+
// Always show errors, even in CLI mode
|
|
23
|
+
console.error(this.module, ...arg)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
log(...arg) {
|
|
27
|
+
// Suppress logs in CLI mode to avoid breaking the interface
|
|
28
|
+
if (this.#cliMode) return
|
|
29
|
+
|
|
30
|
+
if (!arg.length) return this
|
|
31
|
+
if (typeof arg[0] === 'string' && arg[0].includes('%s')) {
|
|
32
|
+
let message = arg.shift()
|
|
33
|
+
while (message.includes('%s') && arg.length > 0) {
|
|
34
|
+
message = message.replace('%s', arg.shift())
|
|
35
|
+
}
|
|
36
|
+
message = message.replace(/%s/g, '')
|
|
37
|
+
arg.unshift(message)
|
|
38
|
+
}
|
|
39
|
+
console.log(this.module, ...arg)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = Log
|
package/core/Process.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const findProcess = require('find-process').default
|
|
2
|
+
|
|
3
|
+
class Process {
|
|
4
|
+
stop(pid) {
|
|
5
|
+
return new Promise(resolve => {
|
|
6
|
+
findProcess('pid', pid)
|
|
7
|
+
.then(list => {
|
|
8
|
+
for (const proc of list) if (proc.name == 'node') process.kill(proc.pid, 'SIGTERM')
|
|
9
|
+
})
|
|
10
|
+
.catch(() => {})
|
|
11
|
+
.finally(() => {
|
|
12
|
+
resolve()
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async stopAll() {
|
|
18
|
+
if (Candy.core('Config').config.server?.watchdog) await this.stop(Candy.core('Config').config.server.watchdog)
|
|
19
|
+
if (Candy.core('Config').config.server?.pid) await this.stop(Candy.core('Config').config.server.pid)
|
|
20
|
+
for (const domain of Object.keys(Candy.core('Config').config?.websites ?? {}))
|
|
21
|
+
if (Candy.core('Config').config.websites[domain].pid) await this.stop(Candy.core('Config').config.websites[domain].pid)
|
|
22
|
+
for (const service of Candy.core('Config').config.services ?? []) if (service.pid) await this.stop(service.pid)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = Process
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## 🧰 What's in the `Candy` box?
|
|
2
|
+
|
|
3
|
+
Your `Candy` assistant comes with a bunch of handy services:
|
|
4
|
+
|
|
5
|
+
* `Request`: All the details about the user's incoming request.
|
|
6
|
+
* `View`: A tool to render your beautiful HTML pages.
|
|
7
|
+
* `Auth`: Your friendly security guard for managing the current user's login.
|
|
8
|
+
* `Token`: Helps protect the user's forms from nasty CSRF attacks.
|
|
9
|
+
* `Lang`: A helper for translating your app into the user's language.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## ✨ Super-Handy Helper Functions
|
|
2
|
+
|
|
3
|
+
On top of that, `Candy` has some quick-and-easy helper functions:
|
|
4
|
+
|
|
5
|
+
* `return(data)`: Quickly send a response back to the user and you're done.
|
|
6
|
+
* `direct(url)`: Need to send the user to another page? This is your tool.
|
|
7
|
+
* `cookie(key, value)`: Leave a little cookie in the user's browser.
|
|
8
|
+
* `env(key, defaultValue)`: Access environment variables with an optional default value.
|
|
9
|
+
* `validator()`: A powerful tool to check the user's submitted data.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
## 🚀 Development Server
|
|
2
|
+
|
|
3
|
+
CandyPack provides a built-in development server that allows you to test your website locally without running the full CandyPack server infrastructure.
|
|
4
|
+
|
|
5
|
+
### Quick Start
|
|
6
|
+
|
|
7
|
+
Navigate to your website directory and run one of these commands:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Using npm script
|
|
11
|
+
npm start
|
|
12
|
+
|
|
13
|
+
# Using CandyPack directly
|
|
14
|
+
candypack framework run
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Both commands will start a local development server on port `1071` by default, and your website will be accessible at `http://127.0.0.1:1071`.
|
|
18
|
+
|
|
19
|
+
### Custom Port
|
|
20
|
+
|
|
21
|
+
You can specify a custom port by adding it as an argument:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Using npm script with custom port
|
|
25
|
+
npm start 8080
|
|
26
|
+
|
|
27
|
+
# Using CandyPack directly with custom port
|
|
28
|
+
candypack framework run 8080
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will start the server on your specified port (e.g., `http://127.0.0.1:8080`).
|
|
32
|
+
|
|
33
|
+
### Development vs Production
|
|
34
|
+
|
|
35
|
+
The development server (`npm start`) is designed for:
|
|
36
|
+
|
|
37
|
+
- **Local testing** and development only
|
|
38
|
+
- **Quick iteration** without server setup
|
|
39
|
+
- **Debugging** your application logic
|
|
40
|
+
- **Testing on localhost** (127.0.0.1)
|
|
41
|
+
|
|
42
|
+
**Important**: The development server does NOT provide DNS, SSL, or other production services.
|
|
43
|
+
|
|
44
|
+
For production deployment with full CandyPack server features, create your website using:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
candy web create
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This registers your website with the CandyPack server and provides:
|
|
51
|
+
|
|
52
|
+
- **Automatic SSL** certificate management
|
|
53
|
+
- **DNS handling** for your domain
|
|
54
|
+
- **Multi-domain hosting** capabilities
|
|
55
|
+
- **Process monitoring** and auto-restart
|
|
56
|
+
- **Production optimizations** and security
|
|
57
|
+
|
|
58
|
+
### Package.json Scripts
|
|
59
|
+
|
|
60
|
+
When you create a new website, CandyPack automatically generates a `package.json` with these useful scripts:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"scripts": {
|
|
65
|
+
"start": "candy framework run",
|
|
66
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- `npm start` - Starts the development server for local testing
|
|
72
|
+
- `npm test` - Placeholder for your test suite
|
|
73
|
+
|
|
74
|
+
### Tips
|
|
75
|
+
|
|
76
|
+
- The development server automatically detects changes in your code
|
|
77
|
+
- Use `Ctrl+C` to stop the development server
|
|
78
|
+
- The server will show helpful error messages in the console
|
|
79
|
+
- All CandyPack framework features are available in development mode
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## 📂 Typical Project Layout
|
|
2
|
+
|
|
3
|
+
Let's take a look at a typical project layout:
|
|
4
|
+
|
|
5
|
+
- `project_root/`
|
|
6
|
+
- `config.json`: This is where you'll keep your app's secrets and settings, like database passwords or API keys.
|
|
7
|
+
- `index.js`: The starting pistol for your web application! This file kicks off the CandyPack framework.
|
|
8
|
+
- `package.json`: Contains project metadata and npm scripts for development. Automatically generated when creating a new website.
|
|
9
|
+
- `public/`: All files placed in this folder are directly accessible from the outside. This is the perfect place for your images, stylesheets, and client-side JavaScript.
|
|
10
|
+
- `route/`: This folder holds all your route definitions. The filename of the route file corresponds to the subdomain it serves.
|
|
11
|
+
- `www.js`: Used for routes on your main domain (e.g., `www.example.com` or `example.com`).
|
|
12
|
+
- `api.js`: Used for routes on a subdomain (e.g., `api.example.com`). When a request comes in for `api.example.com`, this is the route file that gets used. You can create files for any subdomain!
|
|
13
|
+
- `controller/`: This is where the magic happens! Controllers contain the main logic for your application.
|
|
14
|
+
- `page/`: We suggest putting controllers that show HTML pages in here.
|
|
15
|
+
- `api/`: If you're building an API, it's a great idea to keep those controllers separate in their own folder.
|
|
16
|
+
- `view/`: For all your HTML template files. This is what your users will see.
|
|
17
|
+
|
|
18
|
+
### Development Commands
|
|
19
|
+
|
|
20
|
+
Your `package.json` includes helpful npm scripts for development:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Start development server (default port 1071)
|
|
24
|
+
npm start
|
|
25
|
+
|
|
26
|
+
# Start development server on custom port
|
|
27
|
+
npm start 8080
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
You can also use CandyPack commands directly:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Development server (local testing only)
|
|
34
|
+
candypack framework run [port]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Note**: For production websites with DNS and SSL, use `candy web create` to register with CandyPack server.
|
|
38
|
+
|
|
39
|
+
Following this structure helps keep your code's responsibilities separate. Your routing logic lives in one place, your app logic in another, and your presentation files in a third. It's a recipe for success!
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
## ⚙️ Configuration Overview
|
|
2
|
+
|
|
3
|
+
CandyPack uses a simple and flexible configuration system based on `config.json` and optional `.env` files. You can choose the approach that best fits your needs.
|
|
4
|
+
|
|
5
|
+
### Configuration Files
|
|
6
|
+
|
|
7
|
+
#### config.json (Required)
|
|
8
|
+
The main configuration file located in your website's root directory. This file contains all your application settings in JSON format.
|
|
9
|
+
|
|
10
|
+
```json
|
|
11
|
+
{
|
|
12
|
+
"request": {
|
|
13
|
+
"timeout": 30000
|
|
14
|
+
},
|
|
15
|
+
"mysql": {
|
|
16
|
+
"host": "localhost",
|
|
17
|
+
"user": "root",
|
|
18
|
+
"password": "secret123",
|
|
19
|
+
"database": "myapp"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### .env (Optional)
|
|
25
|
+
An optional environment variables file for storing sensitive information like passwords and API keys. This file should be added to `.gitignore` to keep secrets out of version control.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# .env
|
|
29
|
+
MYSQL_PASSWORD=super_secret_123
|
|
30
|
+
API_KEY=your_api_key_here
|
|
31
|
+
NODE_ENV=production
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Three Ways to Configure
|
|
35
|
+
|
|
36
|
+
#### 1. Direct Values (Simple)
|
|
37
|
+
Perfect for development or non-sensitive settings:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mysql": {
|
|
42
|
+
"host": "localhost",
|
|
43
|
+
"password": "dev123"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### 2. Environment Variables (Secure)
|
|
49
|
+
Use `${VARIABLE}` syntax in `config.json` to reference `.env` values:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mysql": {
|
|
54
|
+
"host": "${MYSQL_HOST}",
|
|
55
|
+
"password": "${MYSQL_PASSWORD}"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# .env
|
|
62
|
+
MYSQL_HOST=production.db.com
|
|
63
|
+
MYSQL_PASSWORD=super_secret_123
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### 3. Mixed Approach (Flexible)
|
|
67
|
+
Combine both methods - use direct values for non-sensitive data and environment variables for secrets:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mysql": {
|
|
72
|
+
"host": "localhost",
|
|
73
|
+
"user": "root",
|
|
74
|
+
"password": "${MYSQL_PASSWORD}",
|
|
75
|
+
"database": "myapp"
|
|
76
|
+
},
|
|
77
|
+
"api": {
|
|
78
|
+
"endpoint": "https://api.example.com",
|
|
79
|
+
"key": "${API_KEY}"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Accessing Configuration
|
|
85
|
+
|
|
86
|
+
#### In Controllers
|
|
87
|
+
You can access configuration values in three ways:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
// 1. From Candy.Config (recommended for structured config)
|
|
91
|
+
const dbHost = Candy.Config.mysql.host
|
|
92
|
+
|
|
93
|
+
// 2. Using Candy.env() helper
|
|
94
|
+
const apiKey = Candy.env('API_KEY')
|
|
95
|
+
const debug = Candy.env('DEBUG', 'false')
|
|
96
|
+
|
|
97
|
+
// 3. Direct process.env access
|
|
98
|
+
const nodeEnv = process.env.NODE_ENV
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Best Practices
|
|
102
|
+
|
|
103
|
+
**Development:**
|
|
104
|
+
- Use direct values in `config.json` for quick setup
|
|
105
|
+
- Keep development credentials simple
|
|
106
|
+
|
|
107
|
+
**Production:**
|
|
108
|
+
- Store sensitive data in `.env` file
|
|
109
|
+
- Add `.env` to `.gitignore`
|
|
110
|
+
- Use environment variables for passwords, API keys, and tokens
|
|
111
|
+
- Copy `.env.example` to `.env` and fill in production values
|
|
112
|
+
|
|
113
|
+
**Version Control:**
|
|
114
|
+
- Commit `config.json` with `${VARIABLE}` placeholders
|
|
115
|
+
- Commit `.env.example` with dummy values
|
|
116
|
+
- Never commit `.env` with real credentials
|
|
117
|
+
|
|
118
|
+
### Common Configuration Options
|
|
119
|
+
|
|
120
|
+
**Request timeout:**
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"request": {
|
|
124
|
+
"timeout": 30000
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Database connection:**
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"database": {
|
|
133
|
+
"host": "localhost",
|
|
134
|
+
"user": "root",
|
|
135
|
+
"password": "${MYSQL_PASSWORD}",
|
|
136
|
+
"database": "myapp"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Authentication sessions:**
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"auth": {
|
|
145
|
+
"table": "users",
|
|
146
|
+
"token": "user_tokens",
|
|
147
|
+
"maxAge": 2592000000,
|
|
148
|
+
"updateAge": 86400000
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Early Hints (HTTP 103):**
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"earlyHints": {
|
|
157
|
+
"enabled": true,
|
|
158
|
+
"auto": true,
|
|
159
|
+
"maxResources": 5
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Early Hints is a performance optimization feature that works automatically without any configuration. The server sends preliminary HTTP headers to the browser before the final response, allowing browsers to start preloading critical resources (CSS, JavaScript, fonts) earlier. This is completely zero-config - it detects resources from your HTML automatically and sends hints on subsequent requests.
|
|
165
|
+
|
|
166
|
+
See individual documentation sections for detailed configuration options.
|
|
167
|
+
|
|
168
|
+
### Example Setup
|
|
169
|
+
|
|
170
|
+
**config.json** (committed to git):
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"request": {
|
|
174
|
+
"timeout": 30000
|
|
175
|
+
},
|
|
176
|
+
"mysql": {
|
|
177
|
+
"host": "${MYSQL_HOST}",
|
|
178
|
+
"user": "${MYSQL_USER}",
|
|
179
|
+
"password": "${MYSQL_PASSWORD}",
|
|
180
|
+
"database": "myapp"
|
|
181
|
+
},
|
|
182
|
+
"auth": {
|
|
183
|
+
"maxAge": 2592000000,
|
|
184
|
+
"updateAge": 86400000
|
|
185
|
+
},
|
|
186
|
+
"mail": {
|
|
187
|
+
"from": "${MAIL_FROM}"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**.env.example** (committed to git):
|
|
193
|
+
```bash
|
|
194
|
+
# Database
|
|
195
|
+
MYSQL_HOST=localhost
|
|
196
|
+
MYSQL_USER=root
|
|
197
|
+
MYSQL_PASSWORD=your_password_here
|
|
198
|
+
|
|
199
|
+
# Mail
|
|
200
|
+
MAIL_FROM=noreply@example.com
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**.env** (gitignored, not committed):
|
|
204
|
+
```bash
|
|
205
|
+
# Database
|
|
206
|
+
MYSQL_HOST=production.db.com
|
|
207
|
+
MYSQL_USER=prod_user
|
|
208
|
+
MYSQL_PASSWORD=super_secret_production_password
|
|
209
|
+
|
|
210
|
+
# Mail
|
|
211
|
+
MAIL_FROM=noreply@myapp.com
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
This approach keeps your code secure while maintaining flexibility across different environments.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
## 🔌 Database Connection
|
|
2
|
+
|
|
3
|
+
When you add a `mysql` object to your `config.json`, the system will automatically connect to your MySQL database. No separate connection setup is needed in your code.
|
|
4
|
+
|
|
5
|
+
### Basic Configuration
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"mysql": {
|
|
10
|
+
"host": "localhost",
|
|
11
|
+
"user": "your_user",
|
|
12
|
+
"password": "your_password",
|
|
13
|
+
"database": "your_database"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Once this is configured, you can directly use `Candy.Mysql` commands to run queries.
|
|
19
|
+
|
|
20
|
+
### Using Environment Variables
|
|
21
|
+
|
|
22
|
+
For better security, especially in production, you can use environment variables for sensitive information:
|
|
23
|
+
|
|
24
|
+
**config.json:**
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mysql": {
|
|
28
|
+
"host": "${MYSQL_HOST}",
|
|
29
|
+
"user": "${MYSQL_USER}",
|
|
30
|
+
"password": "${MYSQL_PASSWORD}",
|
|
31
|
+
"database": "myapp"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**.env:**
|
|
37
|
+
```bash
|
|
38
|
+
MYSQL_HOST=localhost
|
|
39
|
+
MYSQL_USER=root
|
|
40
|
+
MYSQL_PASSWORD=super_secret_123
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The `.env` file should be added to `.gitignore` to keep your credentials secure.
|
|
44
|
+
|
|
45
|
+
### Mixed Approach
|
|
46
|
+
|
|
47
|
+
You can also mix direct values with environment variables:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"mysql": {
|
|
52
|
+
"host": "localhost",
|
|
53
|
+
"user": "root",
|
|
54
|
+
"password": "${MYSQL_PASSWORD}",
|
|
55
|
+
"database": "myapp"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This way, non-sensitive values are directly in the config while passwords remain in the `.env` file.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## 🗺️ Static Route Mapping (Optional)
|
|
2
|
+
|
|
3
|
+
Normally, all publicly served files should be in your `public` folder. However, if you need to expose a specific file from somewhere else on your server, you can use the optional `route` object in your `config.json`. This creates a direct mapping from a URL path to that file.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
"route": {
|
|
7
|
+
"/assets/js/candy.js": "${candy}/framework/web/candy.js",
|
|
8
|
+
"/css/main.css": "/path/to/your/project/assets/css/main.css"
|
|
9
|
+
}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
When a user visits a URL that matches a key in the `route` object, CandyPack will serve the corresponding file from your filesystem.
|
|
13
|
+
|
|
14
|
+
#### Using the `${candy}` Variable
|
|
15
|
+
|
|
16
|
+
The special variable `${candy}` is a shortcut that points to the root directory where CandyPack is installed. This is helpful for linking to files that are part of the framework itself.
|
|
17
|
+
|
|
18
|
+
#### Absolute Paths
|
|
19
|
+
|
|
20
|
+
For your own project files, you should provide a full, absolute path to the file on your server.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## ⏱️ Request Timeout
|
|
2
|
+
|
|
3
|
+
You can configure the global timeout for incoming requests by adding a `request` object to your `config.json`.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
"request": {
|
|
7
|
+
"timeout": 10000
|
|
8
|
+
}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The `timeout` value is in milliseconds. In this example, any request that takes longer than 10,000 milliseconds (10 seconds) to process will be timed out.
|