nibula 1.1.2 → 1.2.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 (49) hide show
  1. package/.eleventy.js +1 -9
  2. package/CHANGELOG.md +31 -0
  3. package/README.md +6 -2
  4. package/bin/create.js +2 -3
  5. package/bin/nibula.js +4 -4
  6. package/docs/Assistant CLI.md +1 -1
  7. package/docs/Components.md +3 -14
  8. package/docs/Creating pages.md +5 -5
  9. package/docs/Head and SEO.md +36 -14
  10. package/docs/Javascript.md +1 -3
  11. package/docs/Styling with SCSS.md +9 -3
  12. package/nginx.conf +75 -75
  13. package/package.json +3 -3
  14. package/src/backend/_core/index.js +267 -267
  15. package/src/backend/_core/init.js +52 -52
  16. package/src/backend/_core/modules/RateLimiter.js +58 -58
  17. package/src/backend/_core/modules/Response.js +59 -59
  18. package/src/backend/api/protected/example-protected.js +23 -23
  19. package/src/backend/api/public/example-public.js +24 -24
  20. package/src/backend/backend-node.service.example +30 -30
  21. package/src/backend/database/Database.js +46 -46
  22. package/src/backend/example.config.js +37 -37
  23. package/src/backend/package.json +18 -18
  24. package/src/frontend/.htaccess +51 -51
  25. package/src/frontend/assets/brand/apple-touch-icon.png +0 -0
  26. package/src/frontend/assets/brand/favicon-32.png +0 -0
  27. package/src/frontend/assets/brand/favicon-48.png +0 -0
  28. package/src/frontend/assets/brand/favicon.svg +54 -54
  29. package/src/frontend/assets/brand/logo.svg +54 -54
  30. package/src/frontend/components/global/header.njk +1 -1
  31. package/src/frontend/components/welcome.njk +0 -1
  32. package/src/frontend/data/site.json +48 -54
  33. package/src/frontend/layouts/base.njk +6 -15
  34. package/src/frontend/scss/modules/_global.scss +4 -0
  35. package/src/frontend/web.config +55 -55
  36. package/{_tools → tools}/modules/constants.js +2 -2
  37. /package/{_tools → tools}/assistant.js +0 -0
  38. /package/{_tools → tools}/buildJs.js +0 -0
  39. /package/{_tools → tools}/cleanOutput.js +0 -0
  40. /package/{_tools → tools}/modules/pageComponents.js +0 -0
  41. /package/{_tools → tools}/modules/updateData.js +0 -0
  42. /package/{_tools → tools}/modules/updateOutputPath.js +0 -0
  43. /package/{_tools → tools}/modules/updatePage.js +0 -0
  44. /package/{_tools → tools}/modules/utils.js +0 -0
  45. /package/{_tools → tools}/modules/validation.js +0 -0
  46. /package/{_tools → tools}/res/templates/template.js +0 -0
  47. /package/{_tools → tools}/res/templates/template.njk +0 -0
  48. /package/{_tools → tools}/res/templates/template.scss +0 -0
  49. /package/{_tools → tools}/res/templates/template.ts +0 -0
package/.eleventy.js CHANGED
@@ -1,7 +1,6 @@
1
1
  const esbuild = require("esbuild");
2
2
  const glob = require("glob");
3
3
  const Image = require("@11ty/eleventy-img");
4
- const markdownIt = require('markdown-it');
5
4
  const fs = require("fs");
6
5
  const path = require("path");
7
6
 
@@ -24,18 +23,11 @@ module.exports = function (eleventyConfig) {
24
23
  }
25
24
  }
26
25
 
27
- const md = markdownIt({ html: true });
28
-
29
26
  eleventyConfig.addShortcode('mdFile', function(filePath) {
30
27
  const content = fs.readFileSync(filePath, 'utf8');
31
28
  return md.render(content);
32
29
  });
33
30
 
34
- eleventyConfig.addPassthroughCopy({
35
- "node_modules/github-markdown-css/github-markdown-dark.css": "css/github-markdown-dark.css",
36
- "node_modules/github-markdown-css/github-markdown-light.css": "css/github-markdown-light.css",
37
- });
38
-
39
31
  eleventyConfig.on("eleventy.before", () => {
40
32
  copyRecursiveSync("src/backend", `${OUTPUT_DIR}/backend`);
41
33
  });
@@ -77,7 +69,7 @@ module.exports = function (eleventyConfig) {
77
69
  });
78
70
 
79
71
  eleventyConfig.addWatchTarget("./src/frontend/scss");
80
- eleventyConfig.addWatchTarget("./src/frontend/_routes");
72
+ eleventyConfig.addWatchTarget("./src/frontend/routes");
81
73
  eleventyConfig.addWatchTarget("./src/frontend/data");
82
74
 
83
75
  eleventyConfig.setServerOptions({
package/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ All notable changes to Nibula are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0] - 2026-07-23
9
+
10
+ ### Added
11
+ - **Full favicon set**: `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png`
12
+ (180×180, opaque) in `assets/brand/`. iOS home-screen icons no longer fall back
13
+ to a screenshot of the page.
14
+
15
+ ### Changed
16
+ - **`data_bs_theme` renamed to `theme`** in `site.json`. It still drives
17
+ `data-bs-theme` on the `<html>` tag; the shorter name keeps the config readable
18
+ and independent from the framework naming.
19
+ - **`theme_color` is now a single value** instead of a `light`/`dark` pair. The
20
+ theme is fixed per build, so two per-scheme colors could contradict the
21
+ rendered page.
22
+ - **Favicon paths are hardcoded in `base.njk`.** The `favicon` key was removed
23
+ from `site.json`: it only ever covered one of the three tags, which was more
24
+ confusing than helpful. Replace the files in `assets/brand/` instead.
25
+ - `_routes/` renamed to `routes/` — it holds entry points, not internals.
26
+
27
+ ### Removed
28
+ - **`mdFile` shortcode** and the `markdown-it` dependency.
29
+ - **`github-markdown-css`** and its two passthrough copies.
30
+
31
+ ### Migration
32
+ - In `site.json`: rename `data_bs_theme` to `theme`, flatten `theme_color` to a
33
+ single string, drop `favicon`.
34
+ - Place `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png` in
35
+ `src/frontend/assets/brand/`.
36
+ - If you used `{% mdFile %}`, render the Markdown ahead of time or add
37
+ `markdown-it` back to your own project.
38
+
8
39
  ## [1.1.0] - 2026-07-21
9
40
 
10
41
  ### Added
package/README.md CHANGED
@@ -21,7 +21,7 @@ Building a website from scratch involves a lot of moving parts: templating, buil
21
21
  - 🪶 **Lightweight by default** — SCSS frameworks can be filtered so you ship only what you actually use
22
22
  - 🌍 **Open source** — free to use, free to modify, free to share
23
23
 
24
- ![Version](https://img.shields.io/badge/version-1.1.2-blue)
24
+ ![Version](https://img.shields.io/badge/version-1.2.0-blue)
25
25
  ![License](https://img.shields.io/badge/license-Apache--2.0-blue)
26
26
  ![Eleventy](https://img.shields.io/badge/11ty-v3.1.2-black)
27
27
 
@@ -44,9 +44,13 @@ Nibula ships with a clean, opinionated layout so beginners are never lost. But i
44
44
 
45
45
  ## Prerequisites
46
46
 
47
+ ### Required
48
+
47
49
  * **Node.js**: v18.0.0 or higher — **always required** (the Nibula CLI, the build, and the optional Node backend all run on Node)
48
50
  * **Composer**: **only required if you choose the PHP backend**, to install its PHP dependencies. If you pick the **Node** backend, Composer is never used — you can skip installing it entirely.
49
- * *Optional:* the **Better Nunjucks** VS Code extension by Ed Heltzel
51
+ ### Recomended
52
+ * *Suggested:* **Better Nunjucks** VS Code extension by Ed Heltzel
53
+ * *Suggester:* **Material Icon Theme** VS Code extension by Philipp Kief
50
54
 
51
55
  ## Installation
52
56
 
package/bin/create.js CHANGED
@@ -5,7 +5,7 @@ const path = require('path');
5
5
  const readline = require('readline');
6
6
  const { writeSync } = require('fs');
7
7
  const { spawnSync } = require('child_process');
8
- const { color } = require('../_tools/modules/constants');
8
+ const { color } = require('../tools/modules/constants');
9
9
 
10
10
  // ── PATHS ────────────────────────────────────────────────────────────────────
11
11
 
@@ -75,7 +75,7 @@ const FRONTEND_EXCLUDE = {
75
75
  };
76
76
 
77
77
  const CREATE_DIRS = [
78
- 'src/frontend/_routes',
78
+ 'src/frontend/routes',
79
79
  ];
80
80
 
81
81
  // Backend files that belong to exactly one backend, matched by basename.
@@ -170,7 +170,6 @@ const PROJECT_PACKAGE = {
170
170
  'bootstrap-icons': '^1.13.1',
171
171
  'bulma': '^1.0.4',
172
172
  'foundation-sites': '^6.9.0',
173
- 'github-markdown-css': '^5.9.0',
174
173
  'glob': '^13.0.6',
175
174
  'uikit': '^3.25.13',
176
175
  },
package/bin/nibula.js CHANGED
@@ -5,16 +5,16 @@ const path = require('path');
5
5
  const https = require('https');
6
6
  const readline = require('readline');
7
7
  const { spawnSync } = require('child_process');
8
- const { findProjectRoot, color, NOT_INSIDE_PROJECT_MESSAGE } = require('../_tools/modules/constants');
8
+ const { findProjectRoot, color, NOT_INSIDE_PROJECT_MESSAGE } = require('../tools/modules/constants');
9
9
 
10
10
  const pkg = require('../package.json');
11
11
 
12
12
  const [, , cmd, ...rest] = process.argv;
13
13
 
14
14
  const CREATE = path.join(__dirname, 'create.js');
15
- const ASSISTANT = path.join(__dirname, '..', '_tools', 'assistant.js');
16
- const BUILDJS = path.join(__dirname, '..', '_tools', 'buildJs.js');
17
- const CLEAN = path.join(__dirname, '..', '_tools', 'cleanOutput.js');
15
+ const ASSISTANT = path.join(__dirname, '..', 'tools', 'assistant.js');
16
+ const BUILDJS = path.join(__dirname, '..', 'tools', 'buildJs.js');
17
+ const CLEAN = path.join(__dirname, '..', 'tools', 'cleanOutput.js');
18
18
 
19
19
  const REGISTRY = 'https://registry.npmjs.org/nibula/latest';
20
20
  const CHECK_TIMEOUT = 2500;
@@ -31,7 +31,7 @@ For a page named `my-page`, the following files are created:
31
31
  |---|---|
32
32
  | `src/frontend/scss/pages/myPage.scss` | SCSS entry point |
33
33
  | `src/frontend/js/pages/myPage.js` | JS entry point |
34
- | `src/frontend/_routes/my-page.njk` | Nunjucks template |
34
+ | `src/frontend/routes/my-page.njk` | Nunjucks template |
35
35
 
36
36
  It also adds an `elif` block in `page-components.njk` and a stub entry in `site.json`:
37
37
 
@@ -43,18 +43,6 @@ Add a new `{% elif %}` block for each page, listing its components in order. If
43
43
 
44
44
  > ⚠️ If you move or delete a component, always update `page-components.njk` or the site will break
45
45
 
46
- ### Using Markdown files in components
47
-
48
- You can also render a `.md` file directly inside any `.njk` component using the `mdFile` shortcode:
49
-
50
- ```njk
51
- {% mdFile "docs/your-file.md" %}
52
- ```
53
-
54
- The path is relative to the project root (where `.eleventy.js` lives).
55
-
56
- > ⚠️ The file is read at build time — changes to the `.md` file trigger a rebuild in watch mode.
57
-
58
46
  ## Nest components
59
47
 
60
48
  A component can include other components. This is useful for breaking complex sections into smaller, reusable pieces.
@@ -77,11 +65,12 @@ Header and footer live in `src/frontend/components/global/` and are automaticall
77
65
 
78
66
  All values defined in `src/frontend/data/site.json` are globally available in every component via `{{ site.* }}`
79
67
 
80
- ### site.json <small>(`src/data/`)</small>
68
+ ### site.json <small>(`src/frontend/data/`)</small>
81
69
  ```json
82
70
  {
83
71
  "title": "My Site",
84
- "logo": "/img/logo.png",
72
+ "theme": "dark",
73
+ "logo": "/assets/brand/logo.svg",
85
74
  "legal": {
86
75
  "privacy": "/privacy"
87
76
  }
@@ -9,7 +9,7 @@ For a page named `my-page`:
9
9
 
10
10
  | File | Purpose |
11
11
  |---|---|
12
- | `src/frontend/_routes_/my-page.njk` | Template with front matter |
12
+ | `src/frontend/routes/my-page.njk` | Template with front matter |
13
13
  | `src/frontend/scss/pages/myPage.scss` | Imports framework + modules |
14
14
  | `src/frontend/js/pages/myPage.js` | Imports JS modules |
15
15
 
@@ -31,7 +31,7 @@ The URL is the kebab-case name (`/my-page/`). The `title` in the front matter is
31
31
 
32
32
  ## Subpages (nested URLs)
33
33
 
34
- To create a URL like `domain.it/about/team`, edit the `permalink` in `src/frontend/_routes/team.njk` and add the parent segment before the final slash:
34
+ To create a URL like `domain.it/about/team`, edit the `permalink` in `src/frontend/routes/team.njk` and add the parent segment before the final slash:
35
35
 
36
36
  ```njk
37
37
  ---
@@ -45,9 +45,9 @@ The parent path (`about`) does **not** need to exist as a real page — it's jus
45
45
 
46
46
  | Goal URL | permalink value | File |
47
47
  |---|---|---|
48
- | `/team/` | `/team/` | `_routes/team.njk` |
49
- | `/about/team/` | `/about/team/` | `_routes/team.njk` |
50
- | `/company/about/team/` | `/company/about/team/` | `_routes/team.njk` |
48
+ | `/team/` | `/team/` | `routes/team.njk` |
49
+ | `/about/team/` | `/about/team/` | `routes/team.njk` |
50
+ | `/company/about/team/` | `/company/about/team/` | `routes/team.njk` |
51
51
 
52
52
  ## SEO
53
53
 
@@ -14,12 +14,7 @@ Global settings live in `src/frontend/data/site.json` and are available everywhe
14
14
  "url": "https://yoursite.com",
15
15
  "lang": "en",
16
16
  "author": "Name and surname",
17
- "data_bs_theme": "dark",
18
- "theme_color": {
19
- "light": "#ffffff",
20
- "dark": "#0d1117"
21
- },
22
- "favicon": "/assets/brand/favicon.svg",
17
+ "theme": "dark",
23
18
  "logo": "/assets/brand/logo.svg",
24
19
  "legal": {
25
20
  "privacy": "",
@@ -43,9 +38,8 @@ Global settings live in `src/frontend/data/site.json` and are available everywhe
43
38
  | `domain` / `url` | Canonical URLs, `og:url`, JSON-LD |
44
39
  | `lang` | HTML `lang` attribute |
45
40
  | `author` | Meta author and JSON-LD author |
46
- | `data_bs_theme` | Bootstrap color scheme (`light` / `dark`) |
47
- | `theme_color` | Browser UI / PWA color, per scheme (`light` / `dark`) |
48
- | `favicon` | Path to the favicon |
41
+ | `theme` | Site color scheme (`light` / `dark`) — sets `data-theme`, `data-bs-theme` and `color-scheme` |
42
+ | `theme_color` | Browser UI / PWA bar color should match the chosen `theme` |
49
43
  | `logo` | Path to the logo, also used as social image |
50
44
  | `legal.privacy` / `cookie` / `cookieControls` / `terms` | Legal page URLs |
51
45
  | `legal.copyright.year` / `text` | Footer copyright |
@@ -93,16 +87,44 @@ Global values are defaults, not duplicates. A page value is used when present; o
93
87
 
94
88
  `noindex` and `canonical` have no global default: `noindex` defaults to indexable behavior, `canonical` is computed from the URL. They exist per-page only.
95
89
 
96
- ## theme_color
90
+ ## Theme
97
91
 
98
- Two tags are emitted so the browser bar follows the user's system scheme:
92
+ `theme` is a single fixed value that drives the whole site:
99
93
 
100
94
  ```njk
101
- <meta name="theme-color" content="{{ site.theme_color.light }}" media="(prefers-color-scheme: light)">
102
- <meta name="theme-color" content="{{ site.theme_color.dark }}" media="(prefers-color-scheme: dark)">
95
+ <html data-theme="{{ site.theme }}" data-bs-theme="{{ site.theme }}">
96
+ <meta name="color-scheme" content="{{ site.theme }}">
97
+ <meta name="theme-color" content="{{ site.theme_color }}">
103
98
  ```
104
99
 
105
- This is independent from `data_bs_theme`, which controls the Bootstrap theme, not the browser UI.
100
+ | Attribute | Purpose |
101
+ |---|---|
102
+ | `data-theme` | Your own hook — target it in SCSS to define theme variables |
103
+ | `data-bs-theme` | Bootstrap's color mode. Ignored (harmless) if you use another framework |
104
+ | `color-scheme` | Standard CSS — makes scrollbars, form controls and autofill follow the theme |
105
+ | `theme-color` | Color of the browser UI bar on mobile |
106
+
107
+ Keep `theme` and `theme_color` consistent: a `dark` theme with a white `theme_color` gives a white browser bar over a dark page.
108
+
109
+ See the SCSS docs for how to hook your variables to `data-theme`.
110
+
111
+ ## Favicon
112
+
113
+ The three favicon tags are hardcoded in `base.njk`. To change the icons, replace the files in `src/frontend/assets/brand/` keeping the same names:
114
+
115
+ ```html
116
+ <link rel="icon" type="image/svg+xml" href="/assets/brand/favicon.svg">
117
+ <link rel="icon" type="image/png" sizes="32x32" href="/assets/brand/favicon-32.png">
118
+ <link rel="apple-touch-icon" sizes="180x180" href="/assets/brand/apple-touch-icon.png">
119
+ ```
120
+
121
+ | File | Purpose |
122
+ |---|---|
123
+ | `favicon.svg` | Modern browsers, scales to any size |
124
+ | `favicon-32.png` | Fallback for older browsers and some crawlers |
125
+ | `apple-touch-icon.png` | iOS home screen icon — 180×180, must be opaque (iOS renders transparency as black) |
126
+
127
+ > ⚠️ Without `apple-touch-icon.png`, iOS uses a screenshot of the page as the home screen icon.
106
128
 
107
129
  ## AI & SEO bots
108
130
 
@@ -48,6 +48,4 @@ In TypeScript, omit the extension:
48
48
 
49
49
  ```ts
50
50
  import { exampleModule } from '../modules/exampleModule';
51
- ```
52
-
53
- > ⚠️ Files inside `_tools/` run directly in Node.js without a bundler — use CommonJS (`require` / `module.exports`) there, not ESM.
51
+ ```
@@ -7,6 +7,7 @@ Each page has its own SCSS entry point in `src/frontend/scss/pages/`
7
7
  It must contain `_root.scss` + other modules like `_global.scss` or any other one that you need and its own specific css rules
8
8
 
9
9
  `_root.scss` uses `@use` to enable namespaced access (`root.$var`); other modules use `@import` as they don't expose variables.
10
+
10
11
  ### examplePage.scss <small>(`src/frontend/scss/pages/`)</small>
11
12
  ```scss
12
13
  //==========================
@@ -39,7 +40,9 @@ header {
39
40
  height: root.$header-height;
40
41
  }
41
42
  ```
43
+
42
44
  ## Scss modules
45
+
43
46
  You can create your custom css modules by creating a new `.scss` file in `src/frontend/scss/modules/` (the name of the file must start with `_`)
44
47
 
45
48
  You can create subfolders if you want to refactor the structure, but be sure to update the relative paths in the pages that import them
@@ -70,7 +73,7 @@ body {
70
73
  |---|---|
71
74
  | `_root.scss` | Global variables (colors, spacing) |
72
75
  | `_global.scss` | Site-wide base rules and frameworks |
73
- | `_typography.scss` | Font rules
76
+ | `_typography.scss` | Font rules |
74
77
  | `_header.scss` | Header styles |
75
78
  | `_footer.scss` | Footer styles |
76
79
  | `_mobile.scss` | Media query rules |
@@ -84,7 +87,6 @@ You can choose one or none of them (more than 1 works, but you may get in variou
84
87
 
85
88
  To enable/disable them you have to modify 3 files around the project by just commenting them
86
89
 
87
-
88
90
  ### 1. _global.scss <small>(`src/frontend/scss/modules/`)</small>
89
91
  ```scss
90
92
  @import "../modules/frameworks/bootstrap";
@@ -109,7 +111,7 @@ To enable/disable them you have to modify 3 files around the project by just com
109
111
  {# Bulma — no JS needed #}
110
112
  ```
111
113
 
112
- ### 3. .eleventy.js
114
+ ### 3. eleventy.config.js
113
115
 
114
116
  ```javascript
115
117
  eleventyConfig.addPassthroughCopy({
@@ -128,8 +130,12 @@ eleventyConfig.addPassthroughCopy({
128
130
  });
129
131
  ```
130
132
 
133
+ > ⚠️ Changes to `eleventy.config.js` are not picked up while the dev server is running — restart it.
134
+
131
135
  ### Reducing bundle size
136
+
132
137
  To reduce the bundle size, open the corresponding framework file (`src/frontend/scss/modules/frameworks/`) and comment out any modules you don't need
138
+
133
139
  ```scss
134
140
  @import "bootstrap/scss/card"; // Cards
135
141
  @import "bootstrap/scss/carousel"; // Carousel
package/nginx.conf CHANGED
@@ -1,75 +1,75 @@
1
- # Example nginx directives for a Nibula site — covers BOTH backends.
2
- #
3
- # /api is served by Node (index.js) if it is running on 127.0.0.1:3000; if Node
4
- # is unreachable, nginx falls back to the PHP front controller automatically.
5
- # So the same config works whether you deployed the Node backend or the PHP one:
6
- # - Node backend running -> Node answers /api
7
- # - only PHP deployed -> Node is down -> falls back to PHP-FPM
8
- #
9
- # This is NOT a ready-to-use file: paste these directives inside your own
10
- # server { } block (the one with server_name, listen and SSL) and set `root`
11
- # to your `out` folder.
12
-
13
- # Hide the nginx version from response headers
14
- server_tokens off;
15
-
16
- # Force HTTPS on future requests (applies site-wide, including /api)
17
- add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
18
-
19
- root /var/www/your-site/out;
20
- index index.html;
21
-
22
- # Disable directory listing
23
- autoindex off;
24
-
25
- error_page 403 404 /404.html;
26
- location = /404.html {
27
- internal;
28
- }
29
-
30
- # Never expose the backend source directory over HTTP.
31
- location ^~ /backend/ {
32
- return 404;
33
- }
34
-
35
- # Block server config files anywhere in the tree (.htaccess, web.config).
36
- location ~* (^|/)(\.htaccess|web\.config)$ {
37
- return 404;
38
- }
39
-
40
- # --- /api: Node primary, PHP fallback ---------------------------------------
41
- # Try the Node backend first. If it is down (502/504), retry through the PHP
42
- # front controller. Security headers for API responses are set by the backend.
43
- location ^~ /api/ {
44
- proxy_pass http://127.0.0.1:3000;
45
- proxy_http_version 1.1;
46
- proxy_set_header Host $host;
47
- proxy_set_header X-Real-IP $remote_addr;
48
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
49
- proxy_set_header X-Forwarded-Proto $scheme;
50
-
51
- proxy_intercept_errors on;
52
- error_page 502 504 = @php_backend;
53
- }
54
-
55
- location @php_backend {
56
- include fastcgi_params;
57
- fastcgi_param SCRIPT_FILENAME $document_root/backend/_core/index.php;
58
-
59
- # Adjust the PHP-FPM socket to your distro:
60
- # Debian / Ubuntu : unix:/run/php/php8.3-fpm.sock
61
- # RHEL / Fedora : unix:/run/php-fpm/php-fpm.sock
62
- # TCP fallback : 127.0.0.1:9000
63
- fastcgi_pass unix:/run/php/php8.3-fpm.sock;
64
- }
65
-
66
- # Serve static files, fall back to the 404 page.
67
- # A location with add_header does not inherit server-level headers,
68
- # so Strict-Transport-Security is repeated here.
69
- location / {
70
- add_header X-Content-Type-Options "nosniff" always;
71
- add_header X-Frame-Options "SAMEORIGIN" always;
72
- add_header Referrer-Policy "strict-origin-when-cross-origin" always;
73
- add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
74
- try_files $uri $uri/ /404.html;
75
- }
1
+ # Example nginx directives for a Nibula site — covers BOTH backends.
2
+ #
3
+ # /api is served by Node (index.js) if it is running on 127.0.0.1:3000; if Node
4
+ # is unreachable, nginx falls back to the PHP front controller automatically.
5
+ # So the same config works whether you deployed the Node backend or the PHP one:
6
+ # - Node backend running -> Node answers /api
7
+ # - only PHP deployed -> Node is down -> falls back to PHP-FPM
8
+ #
9
+ # This is NOT a ready-to-use file: paste these directives inside your own
10
+ # server { } block (the one with server_name, listen and SSL) and set `root`
11
+ # to your `out` folder.
12
+
13
+ # Hide the nginx version from response headers
14
+ server_tokens off;
15
+
16
+ # Force HTTPS on future requests (applies site-wide, including /api)
17
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
18
+
19
+ root /var/www/your-site/out;
20
+ index index.html;
21
+
22
+ # Disable directory listing
23
+ autoindex off;
24
+
25
+ error_page 403 404 /404.html;
26
+ location = /404.html {
27
+ internal;
28
+ }
29
+
30
+ # Never expose the backend source directory over HTTP.
31
+ location ^~ /backend/ {
32
+ return 404;
33
+ }
34
+
35
+ # Block server config files anywhere in the tree (.htaccess, web.config).
36
+ location ~* (^|/)(\.htaccess|web\.config)$ {
37
+ return 404;
38
+ }
39
+
40
+ # --- /api: Node primary, PHP fallback ---------------------------------------
41
+ # Try the Node backend first. If it is down (502/504), retry through the PHP
42
+ # front controller. Security headers for API responses are set by the backend.
43
+ location ^~ /api/ {
44
+ proxy_pass http://127.0.0.1:3000;
45
+ proxy_http_version 1.1;
46
+ proxy_set_header Host $host;
47
+ proxy_set_header X-Real-IP $remote_addr;
48
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
49
+ proxy_set_header X-Forwarded-Proto $scheme;
50
+
51
+ proxy_intercept_errors on;
52
+ error_page 502 504 = @php_backend;
53
+ }
54
+
55
+ location @php_backend {
56
+ include fastcgi_params;
57
+ fastcgi_param SCRIPT_FILENAME $document_root/backend/_core/index.php;
58
+
59
+ # Adjust the PHP-FPM socket to your distro:
60
+ # Debian / Ubuntu : unix:/run/php/php8.3-fpm.sock
61
+ # RHEL / Fedora : unix:/run/php-fpm/php-fpm.sock
62
+ # TCP fallback : 127.0.0.1:9000
63
+ fastcgi_pass unix:/run/php/php8.3-fpm.sock;
64
+ }
65
+
66
+ # Serve static files, fall back to the 404 page.
67
+ # A location with add_header does not inherit server-level headers,
68
+ # so Strict-Transport-Security is repeated here.
69
+ location / {
70
+ add_header X-Content-Type-Options "nosniff" always;
71
+ add_header X-Frame-Options "SAMEORIGIN" always;
72
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
73
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
74
+ try_files $uri $uri/ /404.html;
75
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nibula",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "A beginner-friendly static site generator built on Eleventy that stays close to vanilla HTML, CSS and JS — with a page-management CLI, an optional PHP backend, and SEO files generated for you.",
5
5
  "keywords": [
6
6
  "static-site-generator",
@@ -54,9 +54,9 @@
54
54
  "serve:css": "sass --watch src/frontend/scss:out/css --no-source-map --quiet",
55
55
  "serve:js": "esbuild \"src/frontend/ts/pages/*.ts\" --bundle --outdir=out/js/pages --watch",
56
56
  "serve:11ty": "eleventy --serve --quiet",
57
- "clean": "node _tools/cleanOutput.js",
57
+ "clean": "node tools/cleanOutput.js",
58
58
  "serve": "npm run clean && concurrently \"npm run serve:11ty\" \"npm run serve:css\" \"npm run serve:js\"",
59
- "assistant": "node _tools/assistant.js"
59
+ "assistant": "node tools/assistant.js"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@11ty/eleventy": "^3.1.2",