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/.editorconfig
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# EditorConfig is awesome: https://EditorConfig.org
|
|
2
|
+
|
|
3
|
+
# top-most EditorConfig file
|
|
4
|
+
root = true
|
|
5
|
+
|
|
6
|
+
[*]
|
|
7
|
+
indent_style = space
|
|
8
|
+
indent_size = 2
|
|
9
|
+
end_of_line = lf
|
|
10
|
+
charset = utf-8
|
|
11
|
+
trim_trailing_whitespace = true
|
|
12
|
+
insert_final_newline = true
|
|
13
|
+
|
|
14
|
+
[*.js]
|
|
15
|
+
quote_type = single
|
|
16
|
+
|
|
17
|
+
[*.json]
|
|
18
|
+
indent_size = 2
|
|
19
|
+
|
|
20
|
+
[*.md]
|
|
21
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Auto-generate PR Description
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened]
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
update-pr-description:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
# Only run for PRs from `dev` to `main`
|
|
13
|
+
if: github.head_ref == 'dev' && github.base_ref == 'main'
|
|
14
|
+
permissions:
|
|
15
|
+
pull-requests: write
|
|
16
|
+
contents: read
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
# Fetch all history for all branches and tags to get the commit messages
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
|
|
24
|
+
- name: Generate PR Body
|
|
25
|
+
id: generate_body
|
|
26
|
+
run: |
|
|
27
|
+
# Get commit messages from the PR's commits
|
|
28
|
+
COMMITS=$(git log origin/${{ github.base_ref }}..origin/${{ github.head_ref }} --pretty=format:"* %s")
|
|
29
|
+
# Set the multiline output for the next step
|
|
30
|
+
{
|
|
31
|
+
echo 'body<<EOF'
|
|
32
|
+
echo "This PR includes the following changes:"
|
|
33
|
+
echo ""
|
|
34
|
+
echo "$COMMITS"
|
|
35
|
+
echo 'EOF'
|
|
36
|
+
} >> "$GITHUB_OUTPUT"
|
|
37
|
+
|
|
38
|
+
- name: Update PR Title and Body
|
|
39
|
+
uses: actions/github-script@v7
|
|
40
|
+
with:
|
|
41
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
42
|
+
script: |
|
|
43
|
+
github.rest.pulls.update({
|
|
44
|
+
owner: context.repo.owner,
|
|
45
|
+
repo: context.repo.repo,
|
|
46
|
+
pull_number: context.issue.number,
|
|
47
|
+
title: 'Sync `dev` to `main`',
|
|
48
|
+
body: `${{ steps.generate_body.outputs.body }}`
|
|
49
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths-ignore:
|
|
8
|
+
- 'CHANGELOG.md'
|
|
9
|
+
- 'package.json'
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release:
|
|
14
|
+
name: Release
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
if: "!contains(github.event.head_commit.message, 'CandyPack v') || github.event_name == 'workflow_dispatch'"
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v3
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- name: Setup Node.js
|
|
23
|
+
uses: actions/setup-node@v3
|
|
24
|
+
with:
|
|
25
|
+
node-version: '20'
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: npm install
|
|
28
|
+
- name: Release
|
|
29
|
+
env:
|
|
30
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
31
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
32
|
+
run: npx semantic-release
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Test Coverage
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, dev]
|
|
6
|
+
paths:
|
|
7
|
+
- '**/*.js'
|
|
8
|
+
- 'package.json'
|
|
9
|
+
- 'jest.config.js'
|
|
10
|
+
pull_request:
|
|
11
|
+
branches: [main, dev]
|
|
12
|
+
paths:
|
|
13
|
+
- '**/*.js'
|
|
14
|
+
- 'package.json'
|
|
15
|
+
- 'jest.config.js'
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
strategy:
|
|
22
|
+
matrix:
|
|
23
|
+
node-version: [18.x, 22.x]
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout code
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: ${{ matrix.node-version }}
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: npm install
|
|
36
|
+
|
|
37
|
+
- name: Run linter
|
|
38
|
+
run: npm run lint
|
|
39
|
+
|
|
40
|
+
- name: Run tests with coverage
|
|
41
|
+
run: npm test
|
|
42
|
+
|
|
43
|
+
- name: Upload coverage reports
|
|
44
|
+
if: matrix.node-version == '18.x'
|
|
45
|
+
uses: codecov/codecov-action@v3
|
|
46
|
+
with:
|
|
47
|
+
files: ./coverage/lcov.info
|
|
48
|
+
flags: unittests
|
|
49
|
+
name: codecov-umbrella
|
|
50
|
+
fail_ci_if_error: false
|
|
51
|
+
|
|
52
|
+
- name: Comment PR with coverage
|
|
53
|
+
if: github.event_name == 'pull_request' && matrix.node-version == '18.x'
|
|
54
|
+
uses: romeovs/lcov-reporter-action@v0.3.1
|
|
55
|
+
with:
|
|
56
|
+
lcov-file: ./coverage/lcov.info
|
|
57
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
58
|
+
delete-old-comments: true
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
inclusion: always
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Code Style Guidelines
|
|
6
|
+
|
|
7
|
+
## Comments
|
|
8
|
+
|
|
9
|
+
- **Language**: All code comments MUST be written in English
|
|
10
|
+
- **Minimalism**: Avoid unnecessary comments - write self-documenting code instead
|
|
11
|
+
- **When to comment**: Only add comments when the code's intent is not immediately clear from the code itself
|
|
12
|
+
- **What not to comment**:
|
|
13
|
+
- Obvious operations (e.g., `// Set variable` before `x = 5`)
|
|
14
|
+
- Code that explains itself through clear naming
|
|
15
|
+
- Redundant descriptions of what the code does
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
### Bad (unnecessary comments):
|
|
20
|
+
```javascript
|
|
21
|
+
// Get user email
|
|
22
|
+
const email = user.email
|
|
23
|
+
|
|
24
|
+
// Loop through items
|
|
25
|
+
for (const item of items) {
|
|
26
|
+
// Process item
|
|
27
|
+
processItem(item)
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Good (self-documenting):
|
|
32
|
+
```javascript
|
|
33
|
+
const email = user.email
|
|
34
|
+
|
|
35
|
+
for (const item of items) {
|
|
36
|
+
processItem(item)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Good (necessary comment):
|
|
41
|
+
```javascript
|
|
42
|
+
// ACME protocol requires 30-second delay between retries
|
|
43
|
+
await sleep(30000)
|
|
44
|
+
|
|
45
|
+
// Workaround for MySQL connection pool bug in v2.3.0
|
|
46
|
+
if (connection.threadId === null) {
|
|
47
|
+
connection = await reconnect()
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## General Principles
|
|
52
|
+
|
|
53
|
+
- Let the code speak for itself through clear variable and function names
|
|
54
|
+
- Use comments sparingly to explain "why" not "what"
|
|
55
|
+
- Keep comments concise and to the point
|
|
56
|
+
- Update or remove comments when code changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# CandyPack Product Overview
|
|
2
|
+
|
|
3
|
+
CandyPack is a next-generation server and framework toolkit that combines hosting infrastructure with a web development framework. It's designed as a lightweight, zero-config solution for building and deploying modern web applications.
|
|
4
|
+
|
|
5
|
+
## Core Components
|
|
6
|
+
|
|
7
|
+
- **Server**: Full-featured hosting platform with DNS, SSL, mail server (IMAP/SMTP), and multi-domain support
|
|
8
|
+
- **Backend**: Web application framework with routing, authentication, CSRF protection, and internationalization
|
|
9
|
+
- **Frontend**: Client-side framework (candy.js) with AJAX navigation, form handling, and API requests
|
|
10
|
+
- **CLI**: Command-line interface for server management and deployment
|
|
11
|
+
- **Watchdog**: Process monitoring and management system
|
|
12
|
+
|
|
13
|
+
## Key Philosophy
|
|
14
|
+
|
|
15
|
+
- **Developer-first**: Zero-config approach, focus on code rather than infrastructure
|
|
16
|
+
- **Performance-oriented**: Lightweight and optimized for speed
|
|
17
|
+
- **Security-focused**: Built-in CSRF protection, SSL automation, secure defaults
|
|
18
|
+
- **Global-ready**: Multi-language support and internationalization built-in
|
|
19
|
+
|
|
20
|
+
The project follows AGPL-3.0 licensing and targets Node.js 18+ environments.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Project Structure & Architecture
|
|
2
|
+
|
|
3
|
+
## Directory Organization
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
├── bin/ # Executable binaries (candy, candypack)
|
|
7
|
+
├── cli/ # Command-line interface
|
|
8
|
+
│ └── src/ # CLI implementation (Cli.js, Connector.js, Monitor.js)
|
|
9
|
+
├── core/ # Core dependency injection system
|
|
10
|
+
├── framework/ # Web framework implementation
|
|
11
|
+
│ ├── src/ # Framework modules (Auth, Route, Server, etc.)
|
|
12
|
+
│ └── web/ # Client-side JavaScript (candy.js)
|
|
13
|
+
├── server/ # Server infrastructure
|
|
14
|
+
│ └── src/ # Server modules (DNS, SSL, Mail, Web, etc.)
|
|
15
|
+
├── watchdog/ # Process monitoring system
|
|
16
|
+
├── web/ # Template website (copied when creating new sites)
|
|
17
|
+
│ ├── controller/ # Template controllers
|
|
18
|
+
│ ├── package.json # Template package.json with {{domain}} placeholders
|
|
19
|
+
│ └── config.json # Template configuration
|
|
20
|
+
├── docs/ # Documentation (backend, frontend & server)
|
|
21
|
+
│ ├── index.json # Documentation navigation structure
|
|
22
|
+
│ ├── backend/ # Backend documentation files
|
|
23
|
+
│ ├── frontend/ # Frontend documentation files
|
|
24
|
+
│ └── server/ # Server documentation files
|
|
25
|
+
├── locale/ # Internationalization files
|
|
26
|
+
└── test/ # Jest test files
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Architecture Patterns
|
|
30
|
+
|
|
31
|
+
### Dependency Injection (Core)
|
|
32
|
+
|
|
33
|
+
- **Global Candy**: Singleton registry pattern via `global.Candy`
|
|
34
|
+
- **Module Loading**: Dynamic require with `core()`, `cli()`, `server()`, `watchdog()` methods
|
|
35
|
+
- **Singleton Management**: Automatic instantiation and caching
|
|
36
|
+
|
|
37
|
+
### Framework Pattern
|
|
38
|
+
|
|
39
|
+
- **Request Lifecycle**: Each request gets a fresh Candy instance with req/res context
|
|
40
|
+
- **Controller Pattern**: Simple function exports in `controller/` directories
|
|
41
|
+
- **Helper Functions**: Global shortcuts (`__()`, `abort()`, `return()`, etc.)
|
|
42
|
+
|
|
43
|
+
### File Naming Conventions
|
|
44
|
+
|
|
45
|
+
- **PascalCase**: Class files and main modules (e.g., `Candy.js`, `Server.js`)
|
|
46
|
+
- **camelCase**: Utility functions and instances
|
|
47
|
+
- **lowercase**: Entry points (`index.js`)
|
|
48
|
+
|
|
49
|
+
### Module Structure
|
|
50
|
+
|
|
51
|
+
- Each module can have an optional `init()` method for setup
|
|
52
|
+
- Framework modules receive Candy instance for request context
|
|
53
|
+
- Server modules are typically singletons for infrastructure
|
|
54
|
+
|
|
55
|
+
### Web Template System
|
|
56
|
+
|
|
57
|
+
- **Template Directory**: `web/` serves as the template for new websites
|
|
58
|
+
- **Automatic Copying**: When creating a new site, entire `web/` directory is copied
|
|
59
|
+
- **Template Variables**: Files can contain placeholders like `{{domain}}` and `{{domain_original}}`
|
|
60
|
+
- **Post-Processing**: After copying, template variables are replaced with actual values
|
|
61
|
+
- **Template Files**:
|
|
62
|
+
- `package.json` - Contains domain placeholders for name and description
|
|
63
|
+
- `config.json` - Basic routing configuration
|
|
64
|
+
- `controller/` - Example controller implementations
|
|
65
|
+
|
|
66
|
+
### Documentation System
|
|
67
|
+
|
|
68
|
+
- **Index File**: `docs/index.json` contains the navigation structure for all documentation
|
|
69
|
+
- **Adding New Docs**: When creating new documentation files, they MUST be added to `docs/index.json`
|
|
70
|
+
- **Language**: All documentation content must be written in English
|
|
71
|
+
- **Structure**: Documentation is organized into THREE sections only:
|
|
72
|
+
- `docs/server/` - Server infrastructure documentation (CLI, DNS, SSL, Mail)
|
|
73
|
+
- `docs/backend/` - Backend framework documentation (Controllers, Routing, Auth, Database)
|
|
74
|
+
- `docs/frontend/` - Frontend documentation (candy.js, AJAX navigation, Forms)
|
|
75
|
+
- **IMPORTANT**: There is NO `docs/framework/` directory - backend docs go in `docs/backend/`
|
|
76
|
+
- **File Organization**: Each section has folders with numbered prefixes (01-overview, 02-structure, etc.)
|
|
77
|
+
- **Navigation**: The index.json file defines the title and hierarchy shown in documentation site
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Technology Stack & Build System
|
|
2
|
+
|
|
3
|
+
## Tech Stack
|
|
4
|
+
|
|
5
|
+
- **Runtime**: Node.js 18+ (required)
|
|
6
|
+
- **Language**: JavaScript (ES6+, CommonJS modules)
|
|
7
|
+
- **Database**: MySQL2, SQLite3 support
|
|
8
|
+
- **Security**: bcrypt, node-forge, ACME client for SSL
|
|
9
|
+
- **Mail**: Built-in SMTP/IMAP server with DKIM signing
|
|
10
|
+
- **Proxy**: HTTP proxy for multi-domain hosting
|
|
11
|
+
- **DNS**: Native DNS server implementation
|
|
12
|
+
|
|
13
|
+
## Code Quality Tools
|
|
14
|
+
|
|
15
|
+
- **Linting**: ESLint with Prettier integration
|
|
16
|
+
- **Testing**: Jest with coverage reporting (no threshold enforcement)
|
|
17
|
+
- **Git Hooks**: Husky with pre-commit linting and test execution
|
|
18
|
+
- **Release**: Semantic Release with conventional commits
|
|
19
|
+
- **Test Check**: Automatic test execution on commit for changed files (pass/fail only)
|
|
20
|
+
|
|
21
|
+
## Common Commands
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Development
|
|
25
|
+
npm run lint # Run ESLint
|
|
26
|
+
npm run lint:fix # Fix linting issues automatically
|
|
27
|
+
npm test # Run Jest tests with coverage
|
|
28
|
+
npm run test:watch # Run tests in watch mode
|
|
29
|
+
|
|
30
|
+
# Release
|
|
31
|
+
npm run release # Semantic release (automated)
|
|
32
|
+
|
|
33
|
+
# Installation
|
|
34
|
+
curl -sL https://candypack.dev/install | bash # Quick install
|
|
35
|
+
npm install -g candypack # Manual install
|
|
36
|
+
|
|
37
|
+
# Git Hooks & CI/CD
|
|
38
|
+
# Pre-commit automatically runs:
|
|
39
|
+
# 1. lint-staged (ESLint + Prettier on staged files)
|
|
40
|
+
# 2. Test execution for changed core/ and server/ files (test/scripts/check-coverage.js)
|
|
41
|
+
# Note: Coverage is tracked but doesn't block commits - focus is on test pass/fail
|
|
42
|
+
|
|
43
|
+
# GitHub Actions (on PR to main/dev):
|
|
44
|
+
# 1. Runs all tests with coverage
|
|
45
|
+
# 2. Runs linter
|
|
46
|
+
# 3. Tests on Node.js 18.x and 22.x
|
|
47
|
+
# 4. Uploads coverage to Codecov
|
|
48
|
+
# 5. Comments PR with coverage report
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Code Style
|
|
52
|
+
|
|
53
|
+
- **Prettier Config**: No semicolons, single quotes, 140 char width, 2-space tabs
|
|
54
|
+
- **ESLint**: Separate configs for server/framework/web/browser contexts
|
|
55
|
+
- **Globals**: `Candy` and `__` are global variables across the codebase
|
|
56
|
+
- **Module System**: CommonJS (`require`/`module.exports`) for server-side code
|
|
57
|
+
|
|
58
|
+
## Logging Standards
|
|
59
|
+
|
|
60
|
+
### Server & Core Modules
|
|
61
|
+
- **Log Class**: Use `Candy.core('Log', false).init('ModuleName')` for all logging in `server/` and `core/` directories
|
|
62
|
+
- **Usage Pattern**:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const {log, error} = Candy.core('Log', false).init('ModuleName')
|
|
66
|
+
|
|
67
|
+
log('Info message')
|
|
68
|
+
log('Message with %s placeholder', 'value')
|
|
69
|
+
error('Error message', errorObject)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- **CLI Mode**: Logs are automatically suppressed in CLI mode to avoid breaking the interface
|
|
73
|
+
- **Location**: Log class is in `core/Log.js` (also available via `server/src/Log.js` for backward compatibility)
|
|
74
|
+
|
|
75
|
+
### Framework Modules
|
|
76
|
+
- **Console Logging**: Use `console.log()` and `console.error()` directly in `framework/` directory
|
|
77
|
+
- **Reason**: Framework runs in user's application context where Log class may not be available
|
|
78
|
+
- **Usage Pattern**:
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
console.log('[ModuleName] Info message')
|
|
82
|
+
console.error('[ModuleName] Error:', error.message)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### General Rule
|
|
86
|
+
- **Server/Core**: Always use Log class (never `console.log`)
|
|
87
|
+
- **Framework**: Always use `console.log` (Log class not guaranteed to be available)
|
package/.prettierrc
ADDED
package/.releaserc.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
branches: ['main'],
|
|
3
|
+
plugins: [
|
|
4
|
+
[
|
|
5
|
+
'@semantic-release/commit-analyzer',
|
|
6
|
+
{
|
|
7
|
+
preset: 'conventionalcommits'
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
[
|
|
11
|
+
'@semantic-release/release-notes-generator',
|
|
12
|
+
{
|
|
13
|
+
preset: 'conventionalcommits',
|
|
14
|
+
writerOpts: {
|
|
15
|
+
transform: (c, context) => {
|
|
16
|
+
const commit = JSON.parse(JSON.stringify(c))
|
|
17
|
+
|
|
18
|
+
const map = {
|
|
19
|
+
feat: "✨ What's New",
|
|
20
|
+
fix: '🛠️ Fixes & Improvements',
|
|
21
|
+
perf: '⚡️ Performance Upgrades',
|
|
22
|
+
refactor: '⚙️ Engine Tuning',
|
|
23
|
+
docs: '📚 Documentation',
|
|
24
|
+
style: '🎨 Style',
|
|
25
|
+
test: '✅ Tests',
|
|
26
|
+
chore: '🔧 Maintenance & Cleanup',
|
|
27
|
+
build: '🏗️ Build',
|
|
28
|
+
ci: '🤖 CI'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
commit.type = map[commit.type] || commit.type
|
|
32
|
+
|
|
33
|
+
const hide = ['🎨 Style', '🔧 Maintenance & Cleanup', '🏗️ Build', '🤖 CI', '✅ Tests']
|
|
34
|
+
if (!commit.type || hide.includes(commit.type)) return false
|
|
35
|
+
|
|
36
|
+
if (commit.scope === '*' || commit.scope === 'root') commit.scope = ''
|
|
37
|
+
|
|
38
|
+
if (commit.notes) {
|
|
39
|
+
commit.notes.forEach(n => {
|
|
40
|
+
n.title = '💥 BREAKING CHANGES'
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (commit.subject) {
|
|
45
|
+
// Find and extract PR number from the subject, e.g., "feat: new thing (#123)"
|
|
46
|
+
const prRegex = /\s\(#(\d+)\)$/
|
|
47
|
+
const prMatch = commit.subject.match(prRegex)
|
|
48
|
+
const prNumber = prMatch ? prMatch[1] : null
|
|
49
|
+
|
|
50
|
+
// If a PR number is found, remove it from the subject to avoid it appearing twice
|
|
51
|
+
if (prNumber) {
|
|
52
|
+
commit.subject = commit.subject.replace(prRegex, '')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let prLink = ''
|
|
56
|
+
|
|
57
|
+
// Get author name - prefer GitHub login if available
|
|
58
|
+
const email = commit.committer.email || commit.authorEmail || ''
|
|
59
|
+
const ghUserMatch = email.match(/^(?:\d+\+)?([a-zA-Z0-9-]+)@users\.noreply\.github\.com$/)
|
|
60
|
+
const ghUser = ghUserMatch ? ghUserMatch[1] : null
|
|
61
|
+
|
|
62
|
+
let attribution = ''
|
|
63
|
+
if (ghUser) attribution = `by @${ghUser}`
|
|
64
|
+
|
|
65
|
+
// Get PR link if a number was found
|
|
66
|
+
if (prNumber && context.host && context.owner && context.repository) {
|
|
67
|
+
const prUrl = `https://${context.host}/${context.owner}/${context.repository}/pull/${prNumber}`
|
|
68
|
+
const prLink = `[#${prNumber}](${prUrl})`
|
|
69
|
+
attribution = attribution ? `${attribution} in ${prLink}` : prLink
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Append the attribution string to the subject if we created one
|
|
73
|
+
// if (attribution && prLink) {
|
|
74
|
+
// commit.subject = `${commit.subject} ${attribution} in ${prLink}`;
|
|
75
|
+
// } else if (prLink) {
|
|
76
|
+
// commit.subject = `${commit.subject} ${prLink}`;
|
|
77
|
+
// } else if (attribution) {
|
|
78
|
+
// commit.subject = `${commit.subject} ${attribution}`;
|
|
79
|
+
// }
|
|
80
|
+
}
|
|
81
|
+
return commit
|
|
82
|
+
},
|
|
83
|
+
groupBy: 'type',
|
|
84
|
+
commitGroupsSort: (a, b) => (a.title > b.title ? 1 : -1),
|
|
85
|
+
commitsSort: ['scope', 'subject'],
|
|
86
|
+
headerPartial: '',
|
|
87
|
+
commitPartial: '- {{#if scope}}**{{scope}}:** {{/if}}{{subject}}\n',
|
|
88
|
+
mainTemplate: `
|
|
89
|
+
{{#if commitGroups}}
|
|
90
|
+
{{#each commitGroups}}
|
|
91
|
+
### {{title}}
|
|
92
|
+
|
|
93
|
+
{{#each commits}}
|
|
94
|
+
{{> commit root=@root}}
|
|
95
|
+
{{/each}}
|
|
96
|
+
|
|
97
|
+
{{/each}}
|
|
98
|
+
{{/if}}
|
|
99
|
+
|
|
100
|
+
{{#if noteGroups}}
|
|
101
|
+
{{#each noteGroups}}
|
|
102
|
+
### {{title}}
|
|
103
|
+
|
|
104
|
+
{{#each notes}}
|
|
105
|
+
- {{text}}
|
|
106
|
+
{{/each}}
|
|
107
|
+
|
|
108
|
+
{{/each}}
|
|
109
|
+
{{/if}}
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
Powered by [🍭 CandyPack](https://candypack.dev)
|
|
114
|
+
`
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
[
|
|
119
|
+
'@semantic-release/changelog',
|
|
120
|
+
{
|
|
121
|
+
changelogFile: 'CHANGELOG.md'
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
'@semantic-release/npm',
|
|
125
|
+
[
|
|
126
|
+
'@semantic-release/git',
|
|
127
|
+
{
|
|
128
|
+
assets: ['package.json', 'CHANGELOG.md'],
|
|
129
|
+
message: '🍭 CandyPack v${nextRelease.version} Released'
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
'@semantic-release/github'
|
|
133
|
+
]
|
|
134
|
+
}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# AGENTS Guidelines for This Repository
|
|
2
|
+
|
|
3
|
+
This document provides a comprehensive guide for developers working on the CandyPack source code. It covers the project's architecture, class system, directory structure, and usage patterns.
|
|
4
|
+
|
|
5
|
+
## 1. Project Overview
|
|
6
|
+
|
|
7
|
+
CandyPack is a toolkit for building and deploying web applications, consisting of two main parts:
|
|
8
|
+
1. **A Core System**: A background service that manages servers (web, mail, etc.), process monitoring, and provides a command-line interface (CLI).
|
|
9
|
+
2. **A Web Framework**: A lightweight framework for building the actual web applications that are served by the core system.
|
|
10
|
+
|
|
11
|
+
## 2. Core Architecture (`core/Candy.js`)
|
|
12
|
+
|
|
13
|
+
The heart of the core system is a service container implemented in `core/Candy.js`. This module creates a global singleton object named `Candy`.
|
|
14
|
+
|
|
15
|
+
### Service Container
|
|
16
|
+
|
|
17
|
+
The `Candy` object acts as a service locator and dependency injection container. It can dynamically load and cache modules (services) from different parts of the application.
|
|
18
|
+
|
|
19
|
+
- **Registration and Resolution**: Modules are registered with a key and can be resolved (retrieved) using that key. The container handles the instantiation of classes and can cache them as singletons.
|
|
20
|
+
- **Module Loaders**: It has dedicated methods for loading modules from specific directories:
|
|
21
|
+
- `Candy.core(name)`: Loads a module from the `core/` directory.
|
|
22
|
+
- `Candy.cli(name)`: Loads a module from the `cli/src/` directory.
|
|
23
|
+
- `Candy.server(name)`: Loads a module from the `server/src/` directory.
|
|
24
|
+
- `Candy.watchdog(name)`: Loads a module from the `watchdog/src` directory.
|
|
25
|
+
|
|
26
|
+
**Example Usage:**
|
|
27
|
+
To access the application's configuration manager (defined in `core/Config.js`), you would use:
|
|
28
|
+
```javascript
|
|
29
|
+
const config = Candy.core('Config');
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 3. Web Framework Architecture (`framework/src/Candy.js`)
|
|
33
|
+
|
|
34
|
+
The web framework provides the tools to build a website or API. Its main entry point is `framework/src/Candy.js`. Unlike the core `Candy` object, the framework creates a **request-specific instance** for every incoming HTTP request.
|
|
35
|
+
|
|
36
|
+
### Request-Specific Context
|
|
37
|
+
|
|
38
|
+
When a web request hits the server, the framework's `instance()` method is called to create a `_candy` object. This object is a "context" that holds all the necessary components for handling that specific request.
|
|
39
|
+
|
|
40
|
+
This context object includes:
|
|
41
|
+
- `Request`: An object representing the incoming HTTP request.
|
|
42
|
+
- `View`: A view renderer for HTML pages.
|
|
43
|
+
- `Auth`: An authentication manager.
|
|
44
|
+
- `Token`: A CSRF token handler.
|
|
45
|
+
- `Lang`: An internationalization (i18n) helper.
|
|
46
|
+
- `Mysql`: A database connection handler.
|
|
47
|
+
|
|
48
|
+
It also attaches numerous helper functions to the context object for convenience within a controller, such as:
|
|
49
|
+
- `return(data)`: Ends the request and sends data back to the client.
|
|
50
|
+
- `direct(url)`: Redirects the client to a new URL.
|
|
51
|
+
- `cookie(key, value)`: Sets a cookie.
|
|
52
|
+
- `validator()`: Creates a new input validator.
|
|
53
|
+
|
|
54
|
+
This context object is passed to the controller function that handles the route.
|
|
55
|
+
|
|
56
|
+
## 4. Directory Structure Guide
|
|
57
|
+
|
|
58
|
+
- `bin/`: Executable scripts for the CLI (`candy`, `candypack`).
|
|
59
|
+
- `cli/`: Source code for the CLI. The main logic is in `cli/src/Cli.js`.
|
|
60
|
+
- `core/`: Core application logic and shared modules (e.g., `Config.js`, `Commands.js`).
|
|
61
|
+
- `framework/`: The source code for the web framework.
|
|
62
|
+
- `server/`: Low-level server implementations (HTTP, Mail, DNS, SSL).
|
|
63
|
+
- `web/`: **This is a template for a user's website.** When a new site is created with CandyPack, this directory is copied to serve as the starting point.
|
|
64
|
+
- `web/index.js`: The entry point for a web application. It initializes the framework.
|
|
65
|
+
- `web/route/`: Contains route definition files.
|
|
66
|
+
- `web/controller/`: Contains controller files.
|
|
67
|
+
- `web/view/`: (Assumed) Would contain HTML templates for the `View` engine.
|
|
68
|
+
- `web/config.json`: Application-specific configuration.
|
|
69
|
+
- `test/`: Project test files.
|
|
70
|
+
- `watchdog/`: A process monitor that ensures the main CandyPack server stays running.
|
|
71
|
+
|
|
72
|
+
## 5. Using the CLI (`bin/candy`)
|
|
73
|
+
|
|
74
|
+
The `candy` command is the main tool for managing the CandyPack server.
|
|
75
|
+
|
|
76
|
+
- `candy`: Shows the server status (online/offline, uptime, etc.) and lists available commands.
|
|
77
|
+
- `candy start`: (Inferred) Starts the CandyPack server daemon.
|
|
78
|
+
- `candy stop`: (Inferred) Stops the server.
|
|
79
|
+
- `candy restart`: (Inferred) Restarts the server.
|
|
80
|
+
- `candy monitor`: Opens an interactive terminal UI to monitor the status of all hosted websites and services.
|
|
81
|
+
- `candy debug`: Opens an interactive UI to view live logs from different core modules.
|
|
82
|
+
- `candy help <command>`: Shows detailed help for a specific command.
|
|
83
|
+
|
|
84
|
+
The commands are defined in `core/Commands.js` and implemented in various modules, primarily `cli/src/Cli.js`.
|