nibula 1.6.0 → 1.6.1

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 (99) hide show
  1. package/.eleventy.js +81 -81
  2. package/CHANGELOG.md +384 -377
  3. package/LICENSE +169 -169
  4. package/NOTICE +4 -4
  5. package/README.md +110 -110
  6. package/bin/create.js +505 -505
  7. package/bin/delegate.js +57 -57
  8. package/bin/nibula.js +302 -302
  9. package/docs/Assistant CLI.md +65 -65
  10. package/docs/Backend.md +201 -201
  11. package/docs/Components.md +140 -140
  12. package/docs/Creating pages.md +69 -69
  13. package/docs/Deploy.md +210 -210
  14. package/docs/Head and SEO.md +139 -139
  15. package/docs/Javascript.md +126 -126
  16. package/docs/Styling with SCSS.md +139 -139
  17. package/nginx.conf +113 -113
  18. package/package.json +69 -69
  19. package/src/backend/.htaccess +6 -6
  20. package/src/backend/_core/composer.json +5 -5
  21. package/src/backend/_core/composer.lock +492 -492
  22. package/src/backend/_core/index.js +267 -267
  23. package/src/backend/_core/index.php +160 -160
  24. package/src/backend/_core/init.js +52 -52
  25. package/src/backend/_core/init.php +33 -33
  26. package/src/backend/_core/modules/RateLimiter.js +58 -58
  27. package/src/backend/_core/modules/RateLimiter.php +30 -30
  28. package/src/backend/_core/modules/Response.js +59 -59
  29. package/src/backend/_core/modules/Response.php +48 -48
  30. package/src/backend/api/protected/example-protected.js +23 -23
  31. package/src/backend/api/protected/example-protected.php +16 -16
  32. package/src/backend/api/public/example-public.js +24 -24
  33. package/src/backend/api/public/example-public.php +16 -16
  34. package/src/backend/database/Database.js +46 -46
  35. package/src/backend/database/Database.php +23 -23
  36. package/src/backend/example.config.js +37 -37
  37. package/src/backend/example.config.php +37 -37
  38. package/src/backend/package.json +17 -17
  39. package/src/backend/web.config +43 -43
  40. package/src/frontend/.htaccess +51 -51
  41. package/src/frontend/404.njk +17 -17
  42. package/src/frontend/assets/brand/favicon.svg +54 -54
  43. package/src/frontend/assets/brand/logo.svg +54 -54
  44. package/src/frontend/components/global/footer.njk +25 -25
  45. package/src/frontend/components/global/header.njk +6 -6
  46. package/src/frontend/components/welcome.njk +115 -115
  47. package/src/frontend/index.njk +8 -8
  48. package/src/frontend/js/global.js +10 -10
  49. package/src/frontend/js/modules/exampleModule.js +2 -2
  50. package/src/frontend/js/pages/404.js +8 -8
  51. package/src/frontend/js/pages/homepage.js +8 -8
  52. package/src/frontend/layouts/base.njk +136 -136
  53. package/src/frontend/layouts/page-components.njk +13 -13
  54. package/src/frontend/llms.njk +17 -17
  55. package/src/frontend/robots.njk +7 -7
  56. package/src/frontend/scss/_global.scss +46 -46
  57. package/src/frontend/scss/_root.scss +13 -13
  58. package/src/frontend/scss/modules/_animations.scss +24 -24
  59. package/src/frontend/scss/modules/_footer.scss +28 -28
  60. package/src/frontend/scss/modules/_header.scss +26 -26
  61. package/src/frontend/scss/modules/_mobile.scss +29 -29
  62. package/src/frontend/scss/modules/_typography.scss +18 -18
  63. package/src/frontend/scss/modules/frameworks/_bootstrap.scss +109 -109
  64. package/src/frontend/scss/modules/frameworks/_bulma.scss +108 -108
  65. package/src/frontend/scss/modules/frameworks/_foundation.scss +137 -137
  66. package/src/frontend/scss/modules/frameworks/_uikit.scss +109 -109
  67. package/src/frontend/scss/pages/404.scss +27 -27
  68. package/src/frontend/scss/pages/homepage.scss +22 -22
  69. package/src/frontend/sitemap.njk +17 -17
  70. package/src/frontend/ts/global.ts +11 -11
  71. package/src/frontend/ts/modules/exampleModule.ts +2 -2
  72. package/src/frontend/ts/pages/404.ts +8 -8
  73. package/src/frontend/ts/pages/homepage.ts +8 -8
  74. package/src/frontend/web.config +51 -51
  75. package/tools/assistant.js +122 -122
  76. package/tools/buildJs.js +39 -39
  77. package/tools/cleanOutput.js +23 -23
  78. package/tools/cli/prompt.js +40 -40
  79. package/tools/cli/ui.js +87 -87
  80. package/tools/config/messages.json +80 -80
  81. package/tools/config/settings.json +130 -130
  82. package/tools/lib/colors.js +17 -17
  83. package/tools/lib/files.js +75 -75
  84. package/tools/lib/logger.js +22 -22
  85. package/tools/lib/outputPath.js +141 -141
  86. package/tools/lib/pageActions.js +146 -146
  87. package/tools/lib/pageArtifacts.js +46 -46
  88. package/tools/lib/pageComponents.js +88 -88
  89. package/tools/lib/pagesData.js +87 -87
  90. package/tools/lib/paths.js +63 -63
  91. package/tools/lib/project.js +54 -54
  92. package/tools/lib/text.js +47 -47
  93. package/tools/lib/validation.js +40 -40
  94. package/tools/res/templates/template.js +7 -7
  95. package/tools/res/templates/template.njk +8 -8
  96. package/tools/res/templates/template.scss +22 -22
  97. package/tools/res/templates/template.ts +8 -8
  98. package/tsconfig.json +24 -24
  99. package/src/frontend/scss/pages/prova.scss +0 -23
package/CHANGELOG.md CHANGED
@@ -1,377 +1,384 @@
1
- # Changelog
2
-
3
- All notable changes to Nibula are documented here.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [2.0.0] - 2026-08-06
9
-
10
- ### Breaking
11
- - Per-page settings must move out of `site.json`. Take the block under the `pages`
12
- key and make it the root object of a new `src/frontend/data/pages.json`, then
13
- update `base.njk`, `sitemap.njk` and `llms.njk` to read `pages[title]` instead of
14
- `site.pages[title]`. Without `pages.json` the assistant reports the missing file
15
- and stops.
16
- - SCSS and JS import paths change with the `_root`, `_global` and `global` moves.
17
- Update the `@use` and `@import` lines in your page entry points accordingly.
18
- - Existing projects keep working until you run `npm install nibula@latest` inside
19
- them: commands now delegate to the project's own copy, so an old project keeps
20
- running the version it was built with.
21
-
22
- ### Changed
23
- - **Per-page settings moved from `site.json` to a new `pages.json`.** They were nested under a `pages` key in the same file the CLI writes on every page operation; splitting them means a syntax error in one page's record no longer makes the whole site configuration unreadable. Access changes from `{{ site.pages[title] }}` to `{{ pages[title] }}`, and the CLI now reads and writes `pages.json` only.
24
- - Commands run inside a project now execute the project's own Nibula, taken from its `node_modules`, instead of the globally installed one. `nib cli` typed in a terminal used to run the global copy against local files, so a project scaffolded with an older version could be operated on by a newer CLI expecting a different structure. When the two versions differ, the one being used is reported before the command runs, and the assistant's title shows it as well.
25
- - `_root.scss` and `_global.scss` moved out of `scss/modules/`. They are not modules — every page imports them and nothing else does — so they now sit at the root of `scss/`.
26
- - `global.js` and `global.ts` moved out of their `modules/` folders, for the same reason.
27
- - Import paths updated across existing modules, pages and scaffold templates to match both moves.
28
- - `base.njk` applies the `url` filter to per-page CSS and JS, to the favicons and to the framework scripts. Without it these paths ignore `pathPrefix`, so every asset 404s on a site published under a subpath — GitHub Pages being the common case.
29
- - Documentation updated throughout for the new structure and the `site.json` / `pages.json` split.
30
-
31
- ### Fixed
32
- - TypeScript page entry points imported modules with a `.js` extension.
33
- - `logo` was nested inside `legal` in `site.json`, so `{{ site.logo }}` resolved to nothing in the header, the footer, the Open Graph image and the JSON-LD publisher block. It now sits at the root, where the templates already looked for it.
34
-
35
- ### Removed
36
- - `legal.cookieControls` from `site.json`.
37
- - Preconnect hint to `cdn.jsdelivr.net` in `base.njk`. The project loads its framework from `node_modules` through passthrough copy, so the hint opened a TCP and TLS connection to a host that was never used.
38
-
39
- ## [1.5.3] - 2026-08-05
40
-
41
- ### Fixed
42
- - `web.config` no longer breaks on Windows shared hosting. `ApiToNode` was the
43
- first rule, so every `/api` request returned a 500: rewriting to an absolute
44
- URL needs the ARR module, and the `<serverVariables>` block needs an entry in
45
- `applicationHost.config` — neither is available on a shared plan. `ApiToPhp`
46
- is now the default and `ApiToNode` ships commented out, with the requirements
47
- spelled out above it. `<serverVariables>` is gone; on a server with ARR the
48
- forwarded-protocol header is set server-side.
49
- - The PHP front controller looked for `404.html` only under
50
- `$_SERVER['DOCUMENT_ROOT']`, which doesn't resolve to the site root on shared
51
- hosting, so an unknown `/api` route returned an empty page. It now falls back
52
- to the path relative to `_core`, matching how `index.js` already resolved it.
53
- - `Content-Type: text/html` was only sent when `404.html` existed; the plain
54
- fallback went out undeclared.
55
- - Requesting a protected endpoint in a browser opened a credentials prompt
56
- instead of showing the error. IIS attaches `WWW-Authenticate: Basic` to 401
57
- responses, which the browser answers with a login dialog. It is now removed in
58
- `web.config`, so the JSON envelope reaches the client as intended.
59
- - `httpErrors` under `backend/` is set to `PassThrough`. The site root keeps
60
- `Replace` so unknown pages get `404.html`, but under `backend/` every response
61
- is the API's own JSON envelope and IIS must not substitute its HTML for it.
62
- - `nib rename` overwrote the page's SEO title in `site.json` with one derived
63
- from the new name, discarding whatever you had written. It now moves the
64
- record under the new key and changes nothing else. This also fixes the rename
65
- failing outright when the record's `seo` field was malformed, since the field
66
- is no longer read.
67
- - `nib rename` rewrote `title` in the route's front matter for the same reason.
68
- Only `permalink` is updated now.
69
-
70
- ### Changed
71
- - `docs/Deploy.md` documents the new IIS default, and warns that a Node project
72
- published to Windows shared hosting should leave the `backend` folder out —
73
- the requests would be rewritten onto a PHP front controller the project
74
- doesn't contain.
75
-
76
- ## [1.5.2] - 2026-08-05
77
-
78
- ### Fixed
79
- - `nib new` no longer creates an empty `src/frontend/routes` folder. 1.5.1
80
- removed it from `CREATE_DIRS` but left it in `MANDATORY_COPY`, so it still
81
- arrived from the template. It is now created on demand when the first page is
82
- added, and removed again when the last one is deleted.
83
-
84
- ## [1.5.1] - 2026-08-05
85
-
86
- ### Fixed
87
- - `nib new` no longer creates an empty `routes` folder. Page source folders are
88
- created on demand when a page is added, and removed again when the last page
89
- in them is deleted — `routes`, `scss/pages` and the JS/TS pages folder alike.
90
- - Removing a page that doesn't exist reported the skip and then went on to strip
91
- its entry from `site.json` and `page-components.njk` anyway. It now stops.
92
- - `example.config.php` was missing the `APP_ENV` key, so PHP projects had no way
93
- to discover the debug switch from the template. Behaviour was unaffected —
94
- the code already fell back to `production` — but the key is now visible and
95
- documented, and the two templates are identical again.
96
- - The backend's `dev` script set `APP_ENV` as an environment variable, which
97
- neither backend reads. It ran in production mode and produced no debug output.
98
- The script is gone; error verbosity is set in `config.js` / `config.php`.
99
- - `bin/create.js` repeated the `mysql2` version already declared in
100
- `src/backend/package.json`. It now reads that file, so the two cannot drift.
101
- - `docs/Deploy.md` pointed at `backend/backend-node.service.example`, removed in
102
- 1.5.0. The systemd unit is written out in full instead.
103
- - `docs/Deploy.md` gave the backend path as `/var/www/backend/SITE_FOLDER`,
104
- inverted with respect to the rest of the document.
105
-
106
- ### Changed
107
- - Nginx setup steps moved from the `nginx.conf` header into `docs/Deploy.md`,
108
- under "Your own server". The header keeps only the three placeholders that
109
- appear in the file and a pointer to the docs, so a config copied into
110
- `/etc/nginx/sites-available/` no longer carries 60 lines of install
111
- instructions that were already followed.
112
- - `docs/Deploy.md` troubleshooting is now a table, with a row for a 502 on
113
- `/api` caused by the Node process not running.
114
- - `.eleventyignore` reduced to `src/frontend/assets/**`. The `scss`, `js` and
115
- `src/backend` entries excluded nothing: the first two are not Eleventy
116
- template formats and the third is outside the input directory. The last one
117
- was also misleading, since `.eleventy.js` deliberately copies `src/backend`
118
- into the build.
119
- - `docs/Backend.md` documents `APP_ENV` in its own section, including the
120
- `display_errors` behaviour specific to PHP, and states explicitly that it is
121
- a config key rather than an environment variable.
122
-
123
- ### Notes
124
- - Existing projects are unaffected: the scaffolding and template changes apply
125
- only to newly created ones.
126
-
127
- ## [1.5.0] - 2026-08-04
128
-
129
- ### Added
130
- - `nginx.conf` now covers **both backends** with no manual edits. `/api` is
131
- proxied to Node on `127.0.0.1:3000`; if Node is unreachable, the request is
132
- retried through the PHP front controller via the internal `@php_backend`
133
- location. The same file works for a Node deployment and a PHP one.
134
- - `nginx.conf` header now documents the PHP-FPM requirement, the version-agnostic
135
- socket, and the errors specific to a PHP deployment.
136
-
137
- ### Changed
138
- - PHP is invoked through `SCRIPT_FILENAME` instead of by URL, so `.php` requests
139
- keep returning 404 even on a PHP deployment and no source file is ever
140
- reachable by name.
141
- - `fastcgi_pass` targets the version-agnostic socket `unix:/run/php/php-fpm.sock`
142
- instead of a versioned path, so the config survives PHP upgrades.
143
- - `web.config` is now blocked anywhere in the tree, not only at the document root.
144
- - `docs/Backend.md` is limited to writing endpoints: routing, `public` vs
145
- `protected`, the `Response` helper and configuration. Examples are Node-only,
146
- with a note that PHP behaves identically. Hosting and server requirements
147
- moved to `docs/Deploy.md`.
148
- - `docs/Deploy.md` rewritten around where a site can be published and what each
149
- target requires, including why shared hosting cannot run the Node backend.
150
-
151
- ### Removed
152
- - `docs/Nginx.md` — the setup steps live in the `nginx.conf` header, where they
153
- are read at the moment they are needed.
154
- - `src/backend/backend-node.service.example` — the systemd unit is documented
155
- in `docs/Deploy.md` instead of shipped as a file.
156
-
157
- ## [1.4.0] - 2026-08-03
158
-
159
- ### Changed
160
- - `nginx.conf` is now a complete, ready-to-use site file instead of a set of
161
- directives to paste into your own `server` block. Replace three placeholders
162
- (`YOUR_DOMAIN`, `SITE_FOLDER`, `YOUR_CERTIFICATE`), symlink it into
163
- `sites-enabled/`, reload.
164
- - Nginx documentation moved from `docs/Deploy.md` to `docs/Nginx.md`;
165
- `Deploy.md` now covers only where to publish, one section per server.
166
-
167
- ### Added
168
- - HTTP → HTTPS redirect on port 80, with an optional ACME webroot block.
169
- - TLS setup via Let's Encrypt, with placeholders for the certificate path.
170
- - Security headers: `X-Content-Type-Options`, `X-Frame-Options`,
171
- `Referrer-Policy`, `Strict-Transport-Security` (`max-age=300` by default).
172
- - `.php` requests return 404, preventing source-code leaks when php-fpm is
173
- not configured.
174
-
175
- ### Removed
176
- - **Breaking:** the automatic Node → PHP fallback on Nginx. `/api` is now
177
- proxied to Node only; if the process is down, Nginx returns 502. For a PHP
178
- deployment, edit the `.php` block and `try_files` as described in
179
- `docs/Nginx.md`.
180
-
181
- ### Migration
182
- Existing Nginx deployments: replace your `server` block with the new
183
- `nginx.conf` and fill in the three placeholders. If you relied on the PHP
184
- fallback, follow *Using the PHP backend* in `docs/Nginx.md`.
185
-
186
- ## [1.3.0] - 2026-08-01
187
-
188
- ### Added
189
- - A `global.js` module in `src/frontend/js/modules/`, for code that has to run
190
- on every page — a header menu, a theme toggle, a cookie banner. Page entry
191
- points import it once and it takes care of running the shared modules, so
192
- there's no longer a line to remember in every single page.
193
- - `docs/Javascript.md` now covers the global module, with the header burger
194
- menu as a worked example and a note on when a behaviour belongs in
195
- `global.js` rather than in a page.
196
-
197
- ### Changed
198
- - Page entry points, and the template new pages are created from, now start
199
- with `import '../modules/global.js';`.
200
-
201
- ### Notes
202
- - Existing projects keep working as they are. To adopt the global module, add
203
- `src/frontend/js/modules/global.js` and the import line at the top of each
204
- page entry point.
205
-
206
- ## [1.2.6] - 2026-08-01
207
-
208
- ### Fixed
209
- - The scaffolder created the routes folder as `src/frontend/_routes` instead of
210
- `src/frontend/routes`. The CLI writes and looks for page templates in
211
- `routes`, so on a freshly created project every page ended up outside the
212
- folder Eleventy and the assistant expect.
213
-
214
- ### Notes
215
- - Projects created with 1.2.5 have an empty `src/frontend/_routes` folder that
216
- can be deleted. Pages created before this fix should be moved to
217
- `src/frontend/routes`.
218
-
219
- ## [1.2.5] - 2026-08-01
220
-
221
- ### Added
222
- - `nib new` now refuses to run from inside an existing Nibula project. Creating
223
- a project inside another one produced a broken setup, since the outer build
224
- would pick up the inner project's files. The error message reports the path of
225
- the project that was detected, so it's clear which one triggered the check.
226
- - A GitHub Actions workflow that publishes the package to npm whenever a release
227
- is created, using npm's trusted publishing. The workflow verifies that the git
228
- tag matches the version in `package.json` before publishing, and attaches a
229
- provenance attestation to the published package.
230
-
231
- ### Changed
232
- - Rewrote the README: added a section on when Nibula is *not* the right tool,
233
- clarified that Composer is only needed with the PHP backend, and moved the
234
- editor extensions from the required to the recommended prerequisites.
235
-
236
- ## [1.2.4] - 2026-07-31
237
-
238
- ### Changed
239
- - Internal refactor of `tools/`: the logic is now split across `lib/`, `cli/`
240
- and `config/`, with values and messages extracted into `settings.json` and
241
- `messages.json`. No behaviour changes — pages, `site.json` and
242
- `page-components.njk` are written exactly as before.
243
- - The CLI now uses a uniform palette: colour is limited to the title box, and
244
- the menu numbers are dimmed instead of each carrying its own colour.
245
-
246
- ### Fixed
247
- - The last line of the menu never closed the `dim` colour code, which stayed
248
- active on the following line.
249
-
250
- ## [1.2.3] - 2026-07-29
251
-
252
- ### Fixed
253
- - `updateOutputPath` no longer strips custom flags from `build:css` and `serve:css`: the output path is now replaced in place instead of regenerating the whole script
254
- - Missing `--load-path=node_modules` in the regenerated Sass scripts, which broke Bootstrap SCSS imports
255
- - Malformed `outDir` in `tsconfig.json` when the output path is absolute (`./c:/...`)
256
-
257
- ## [1.2.2] - 2026-07-23
258
-
259
- ### Added
260
- - **Full favicon set**: `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png`
261
- (180×180, opaque) in `assets/brand/`. iOS home-screen icons no longer fall back
262
- to a screenshot of the page.
263
-
264
- ### Changed
265
- - **`data_bs_theme` renamed to `theme`** in `site.json`. It still drives
266
- `data-bs-theme` on the `<html>` tag; the shorter name keeps the config readable
267
- and independent from the framework naming.
268
- - **`theme_color` is now a single value** instead of a `light`/`dark` pair. The
269
- theme is fixed per build, so two per-scheme colors could contradict the
270
- rendered page.
271
- - **Favicon paths are hardcoded in `base.njk`.** The `favicon` key was removed
272
- from `site.json`: it only ever covered one of the three tags, which was more
273
- confusing than helpful. Replace the files in `assets/brand/` instead.
274
- - `_routes/` renamed to `routes/` — it holds entry points, not internals.
275
-
276
- ### Removed
277
- - **`mdFile` shortcode** and the `markdown-it` dependency.
278
- - **`github-markdown-css`** and its two passthrough copies.
279
-
280
- ### Migration
281
- - In `site.json`: rename `data_bs_theme` to `theme`, flatten `theme_color` to a
282
- single string, drop `favicon`.
283
- - Place `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png` in
284
- `src/frontend/assets/brand/`.
285
- - If you used `{% mdFile %}`, render the Markdown ahead of time or add
286
- `markdown-it` back to your own project.
287
-
288
- ## [1.1.3] - 2026-07-22
289
-
290
- ### Changed
291
- - **The update check no longer runs on every command.** Previously every
292
- invocation of `nib` (and the `nbl` / `nibula` aliases) contacted the npm
293
- registry before doing anything, adding up to 2.5s of latency to `nib run`,
294
- `nib build`, `nib cli` and `nib clean`. The check now runs only for `nib new`
295
- and `nib update`; all other commands work entirely offline.
296
- - **`nib new` now completes the update automatically.** When a newer version is
297
- available and you accept the prompt, Nibula installs it and immediately
298
- re-runs the scaffolding with the new version, instead of asking you to type
299
- `nib new <project-name>` a second time.
300
- - **New projects are scaffolded at version `0.0.0`** instead of `1.0.0`, so a
301
- freshly created site no longer claims a stable public release. Bump it
302
- yourself as the project grows, and reach `1.0.0` when you go to production.
303
- - **Framework SCSS imports are now short and readable.** The framework modules
304
- in `src/frontend/scss/modules/frameworks/` used a five-level relative path
305
- back to `node_modules`; they now import directly by package name, e.g.
306
- `@import "bootstrap/scss/card";`. This matches what the styling docs already
307
- showed, and makes commenting modules out far less error-prone.
308
- - `nib help` no longer appends an "a newer version is available" line, since it
309
- no longer performs the check.
310
-
311
- ### Added
312
- - Internal `--skip-update-check` flag on `nib new`, set automatically when the
313
- command is re-run after a self-update. It prevents a loop if the registry is
314
- slow to propagate the new version.
315
- - `--load-path=node_modules` on the repository's own `build:css` and `serve:css`
316
- scripts, so the short framework imports resolve. Generated projects already
317
- carried this flag.
318
-
319
- ### Fixed
320
- - Repaired the ASCII header boxes and the commented-out example import inside
321
- `_bootstrap.scss`, `_bulma.scss` and `_foundation.scss`, where an earlier
322
- find-and-replace had injected the `node_modules` path into comment text and
323
- broken the alignment.
324
- - `src/frontend/data` is no longer copied to the output folder. It holds the
325
- Eleventy global data file, which is consumed at build time to render meta
326
- tags and page config — publishing it produced a dead file in `out/` and
327
- exposed the full page map, including `noindex` entries. It remains a watch
328
- target, so edits still trigger a rebuild.
329
-
330
- ### Notes
331
- - If the updated installation can't be located after `npm install -g` (an
332
- unusual `npm root -g` setup, for example), Nibula reports the problem and
333
- asks you to re-run the command, rather than scaffolding silently with the
334
- old templates.
335
- - Existing projects are unaffected by the version change: it applies only to
336
- newly created ones.
337
- - Short SCSS imports rely on Sass's `--load-path`, which is passed by the npm
338
- scripts. Compiling the stylesheets with a different tool (a VS Code Sass
339
- extension, for instance) will need the same load path configured.
340
-
341
- ## [1.1.0] - 2026-07-21
342
-
343
- ### Added
344
- - **Node.js backend** as an alternative to PHP, living side by side in
345
- `src/backend/`: `_core/index.js` front controller (which is also the HTTP
346
- server), `Response` and `RateLimiter` modules, a `mysql2` pool singleton
347
- `Database.js`, `example.config.js`, and a `package.json` for the backend's
348
- own dependencies. Same REST API as PHP: routing, `X-Api-Key` auth, CORS and
349
- file-based rate limiting are identical.
350
- - **Backend choice at scaffold time**: `nib new` now asks whether to use Node.js
351
- or PHP, in addition to language and CSS framework.
352
- - `backend/backend-node.service.example` — a ready-to-adapt **systemd** unit for
353
- keeping the Node backend running on a server.
354
- - `config.js` is generated from `example.config.js` at scaffold time (mirroring
355
- the existing `config.php` generation).
356
- - Deployment docs now cover running the Node backend with **`screen`** (quick /
357
- small setups) and **systemd** (production), plus environment variables.
358
-
359
- ### Changed
360
- - **Composer is now required only when the PHP backend is chosen.** If you pick
361
- Node, `composer install` is skipped entirely and the backend's npm
362
- dependencies (`mysql2`) are installed instead.
363
- - `.htaccess`, `web.config` and `nginx.conf` now cover **both** backends. On
364
- nginx, `/api` goes to Node and automatically falls back to the PHP front
365
- controller when Node is unreachable. On Apache/IIS the active backend is
366
- selected by configuration (documented), since per-directory configs can't
367
- health-check an upstream.
368
- - `.gitignore` now also ignores `src/backend/config.js`,
369
- `src/backend/node_modules/` and `src/backend/cache/`.
370
- - Documentation (`README.md`, `docs/Backend.md`, `docs/Deploy.md`) updated:
371
- backend examples now use JavaScript/Node as the reference, with the equivalent
372
- PHP shown alongside and a note that PHP behaves identically.
373
-
374
- ### Notes
375
- - Both backends are always scaffolded, so you can switch later without
376
- re-creating the project. The PHP front controller only serves `.php` endpoint
377
- files and the Node one only `.js`, so they coexist without conflict.
1
+ # Changelog
2
+
3
+ All notable changes to Nibula are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.6.1] - 2026-08-06
9
+
10
+ ### Fixed
11
+ - `src/frontend/scss/pages/prova.scss` was left in the template and shipped with 1.6.0, so every new project started with a stylesheet for a page that doesn't exist — no route, no script, no entry in `pages.json`.
12
+ - Open Graph and Twitter Card tags read `seo.title` and `seo.description` directly, with none of the fallbacks the `<title>` and meta description already had. A page that left those fields empty in `pages.json` published an empty social preview — exactly the case the fallbacks exist for. They now follow the same chain.
13
+ - `data-theme` was missing from the `<html>` tag. It is documented as the hook to target in SCSS for theme variables, so a selector written against it never matched.
14
+
15
+ ## [1.6.0] - 2026-08-06
16
+
17
+ ### Breaking
18
+ - Per-page settings must move out of `site.json`. Take the block under the `pages`
19
+ key and make it the root object of a new `src/frontend/data/pages.json`, then
20
+ update `base.njk`, `sitemap.njk` and `llms.njk` to read `pages[title]` instead of
21
+ `site.pages[title]`. Without `pages.json` the assistant reports the missing file
22
+ and stops.
23
+ - SCSS and JS import paths change with the `_root`, `_global` and `global` moves.
24
+ Update the `@use` and `@import` lines in your page entry points accordingly.
25
+ - Existing projects keep working until you run `npm install nibula@latest` inside
26
+ them: commands now delegate to the project's own copy, so an old project keeps
27
+ running the version it was built with.
28
+
29
+ ### Changed
30
+ - **Per-page settings moved from `site.json` to a new `pages.json`.** They were nested under a `pages` key in the same file the CLI writes on every page operation; splitting them means a syntax error in one page's record no longer makes the whole site configuration unreadable. Access changes from `{{ site.pages[title] }}` to `{{ pages[title] }}`, and the CLI now reads and writes `pages.json` only.
31
+ - Commands run inside a project now execute the project's own Nibula, taken from its `node_modules`, instead of the globally installed one. `nib cli` typed in a terminal used to run the global copy against local files, so a project scaffolded with an older version could be operated on by a newer CLI expecting a different structure. When the two versions differ, the one being used is reported before the command runs, and the assistant's title shows it as well.
32
+ - `_root.scss` and `_global.scss` moved out of `scss/modules/`. They are not modules — every page imports them and nothing else does — so they now sit at the root of `scss/`.
33
+ - `global.js` and `global.ts` moved out of their `modules/` folders, for the same reason.
34
+ - Import paths updated across existing modules, pages and scaffold templates to match both moves.
35
+ - `base.njk` applies the `url` filter to per-page CSS and JS, to the favicons and to the framework scripts. Without it these paths ignore `pathPrefix`, so every asset 404s on a site published under a subpath — GitHub Pages being the common case.
36
+ - Documentation updated throughout for the new structure and the `site.json` / `pages.json` split.
37
+
38
+ ### Fixed
39
+ - TypeScript page entry points imported modules with a `.js` extension.
40
+ - `logo` was nested inside `legal` in `site.json`, so `{{ site.logo }}` resolved to nothing in the header, the footer, the Open Graph image and the JSON-LD publisher block. It now sits at the root, where the templates already looked for it.
41
+
42
+ ### Removed
43
+ - `legal.cookieControls` from `site.json`.
44
+ - Preconnect hint to `cdn.jsdelivr.net` in `base.njk`. The project loads its framework from `node_modules` through passthrough copy, so the hint opened a TCP and TLS connection to a host that was never used.
45
+
46
+ ## [1.5.3] - 2026-08-05
47
+
48
+ ### Fixed
49
+ - `web.config` no longer breaks on Windows shared hosting. `ApiToNode` was the
50
+ first rule, so every `/api` request returned a 500: rewriting to an absolute
51
+ URL needs the ARR module, and the `<serverVariables>` block needs an entry in
52
+ `applicationHost.config` — neither is available on a shared plan. `ApiToPhp`
53
+ is now the default and `ApiToNode` ships commented out, with the requirements
54
+ spelled out above it. `<serverVariables>` is gone; on a server with ARR the
55
+ forwarded-protocol header is set server-side.
56
+ - The PHP front controller looked for `404.html` only under
57
+ `$_SERVER['DOCUMENT_ROOT']`, which doesn't resolve to the site root on shared
58
+ hosting, so an unknown `/api` route returned an empty page. It now falls back
59
+ to the path relative to `_core`, matching how `index.js` already resolved it.
60
+ - `Content-Type: text/html` was only sent when `404.html` existed; the plain
61
+ fallback went out undeclared.
62
+ - Requesting a protected endpoint in a browser opened a credentials prompt
63
+ instead of showing the error. IIS attaches `WWW-Authenticate: Basic` to 401
64
+ responses, which the browser answers with a login dialog. It is now removed in
65
+ `web.config`, so the JSON envelope reaches the client as intended.
66
+ - `httpErrors` under `backend/` is set to `PassThrough`. The site root keeps
67
+ `Replace` so unknown pages get `404.html`, but under `backend/` every response
68
+ is the API's own JSON envelope and IIS must not substitute its HTML for it.
69
+ - `nib rename` overwrote the page's SEO title in `site.json` with one derived
70
+ from the new name, discarding whatever you had written. It now moves the
71
+ record under the new key and changes nothing else. This also fixes the rename
72
+ failing outright when the record's `seo` field was malformed, since the field
73
+ is no longer read.
74
+ - `nib rename` rewrote `title` in the route's front matter for the same reason.
75
+ Only `permalink` is updated now.
76
+
77
+ ### Changed
78
+ - `docs/Deploy.md` documents the new IIS default, and warns that a Node project
79
+ published to Windows shared hosting should leave the `backend` folder out —
80
+ the requests would be rewritten onto a PHP front controller the project
81
+ doesn't contain.
82
+
83
+ ## [1.5.2] - 2026-08-05
84
+
85
+ ### Fixed
86
+ - `nib new` no longer creates an empty `src/frontend/routes` folder. 1.5.1
87
+ removed it from `CREATE_DIRS` but left it in `MANDATORY_COPY`, so it still
88
+ arrived from the template. It is now created on demand when the first page is
89
+ added, and removed again when the last one is deleted.
90
+
91
+ ## [1.5.1] - 2026-08-05
92
+
93
+ ### Fixed
94
+ - `nib new` no longer creates an empty `routes` folder. Page source folders are
95
+ created on demand when a page is added, and removed again when the last page
96
+ in them is deleted — `routes`, `scss/pages` and the JS/TS pages folder alike.
97
+ - Removing a page that doesn't exist reported the skip and then went on to strip
98
+ its entry from `site.json` and `page-components.njk` anyway. It now stops.
99
+ - `example.config.php` was missing the `APP_ENV` key, so PHP projects had no way
100
+ to discover the debug switch from the template. Behaviour was unaffected —
101
+ the code already fell back to `production` — but the key is now visible and
102
+ documented, and the two templates are identical again.
103
+ - The backend's `dev` script set `APP_ENV` as an environment variable, which
104
+ neither backend reads. It ran in production mode and produced no debug output.
105
+ The script is gone; error verbosity is set in `config.js` / `config.php`.
106
+ - `bin/create.js` repeated the `mysql2` version already declared in
107
+ `src/backend/package.json`. It now reads that file, so the two cannot drift.
108
+ - `docs/Deploy.md` pointed at `backend/backend-node.service.example`, removed in
109
+ 1.5.0. The systemd unit is written out in full instead.
110
+ - `docs/Deploy.md` gave the backend path as `/var/www/backend/SITE_FOLDER`,
111
+ inverted with respect to the rest of the document.
112
+
113
+ ### Changed
114
+ - Nginx setup steps moved from the `nginx.conf` header into `docs/Deploy.md`,
115
+ under "Your own server". The header keeps only the three placeholders that
116
+ appear in the file and a pointer to the docs, so a config copied into
117
+ `/etc/nginx/sites-available/` no longer carries 60 lines of install
118
+ instructions that were already followed.
119
+ - `docs/Deploy.md` troubleshooting is now a table, with a row for a 502 on
120
+ `/api` caused by the Node process not running.
121
+ - `.eleventyignore` reduced to `src/frontend/assets/**`. The `scss`, `js` and
122
+ `src/backend` entries excluded nothing: the first two are not Eleventy
123
+ template formats and the third is outside the input directory. The last one
124
+ was also misleading, since `.eleventy.js` deliberately copies `src/backend`
125
+ into the build.
126
+ - `docs/Backend.md` documents `APP_ENV` in its own section, including the
127
+ `display_errors` behaviour specific to PHP, and states explicitly that it is
128
+ a config key rather than an environment variable.
129
+
130
+ ### Notes
131
+ - Existing projects are unaffected: the scaffolding and template changes apply
132
+ only to newly created ones.
133
+
134
+ ## [1.5.0] - 2026-08-04
135
+
136
+ ### Added
137
+ - `nginx.conf` now covers **both backends** with no manual edits. `/api` is
138
+ proxied to Node on `127.0.0.1:3000`; if Node is unreachable, the request is
139
+ retried through the PHP front controller via the internal `@php_backend`
140
+ location. The same file works for a Node deployment and a PHP one.
141
+ - `nginx.conf` header now documents the PHP-FPM requirement, the version-agnostic
142
+ socket, and the errors specific to a PHP deployment.
143
+
144
+ ### Changed
145
+ - PHP is invoked through `SCRIPT_FILENAME` instead of by URL, so `.php` requests
146
+ keep returning 404 even on a PHP deployment and no source file is ever
147
+ reachable by name.
148
+ - `fastcgi_pass` targets the version-agnostic socket `unix:/run/php/php-fpm.sock`
149
+ instead of a versioned path, so the config survives PHP upgrades.
150
+ - `web.config` is now blocked anywhere in the tree, not only at the document root.
151
+ - `docs/Backend.md` is limited to writing endpoints: routing, `public` vs
152
+ `protected`, the `Response` helper and configuration. Examples are Node-only,
153
+ with a note that PHP behaves identically. Hosting and server requirements
154
+ moved to `docs/Deploy.md`.
155
+ - `docs/Deploy.md` rewritten around where a site can be published and what each
156
+ target requires, including why shared hosting cannot run the Node backend.
157
+
158
+ ### Removed
159
+ - `docs/Nginx.md` — the setup steps live in the `nginx.conf` header, where they
160
+ are read at the moment they are needed.
161
+ - `src/backend/backend-node.service.example` — the systemd unit is documented
162
+ in `docs/Deploy.md` instead of shipped as a file.
163
+
164
+ ## [1.4.0] - 2026-08-03
165
+
166
+ ### Changed
167
+ - `nginx.conf` is now a complete, ready-to-use site file instead of a set of
168
+ directives to paste into your own `server` block. Replace three placeholders
169
+ (`YOUR_DOMAIN`, `SITE_FOLDER`, `YOUR_CERTIFICATE`), symlink it into
170
+ `sites-enabled/`, reload.
171
+ - Nginx documentation moved from `docs/Deploy.md` to `docs/Nginx.md`;
172
+ `Deploy.md` now covers only where to publish, one section per server.
173
+
174
+ ### Added
175
+ - HTTP → HTTPS redirect on port 80, with an optional ACME webroot block.
176
+ - TLS setup via Let's Encrypt, with placeholders for the certificate path.
177
+ - Security headers: `X-Content-Type-Options`, `X-Frame-Options`,
178
+ `Referrer-Policy`, `Strict-Transport-Security` (`max-age=300` by default).
179
+ - `.php` requests return 404, preventing source-code leaks when php-fpm is
180
+ not configured.
181
+
182
+ ### Removed
183
+ - **Breaking:** the automatic Node → PHP fallback on Nginx. `/api` is now
184
+ proxied to Node only; if the process is down, Nginx returns 502. For a PHP
185
+ deployment, edit the `.php` block and `try_files` as described in
186
+ `docs/Nginx.md`.
187
+
188
+ ### Migration
189
+ Existing Nginx deployments: replace your `server` block with the new
190
+ `nginx.conf` and fill in the three placeholders. If you relied on the PHP
191
+ fallback, follow *Using the PHP backend* in `docs/Nginx.md`.
192
+
193
+ ## [1.3.0] - 2026-08-01
194
+
195
+ ### Added
196
+ - A `global.js` module in `src/frontend/js/modules/`, for code that has to run
197
+ on every page — a header menu, a theme toggle, a cookie banner. Page entry
198
+ points import it once and it takes care of running the shared modules, so
199
+ there's no longer a line to remember in every single page.
200
+ - `docs/Javascript.md` now covers the global module, with the header burger
201
+ menu as a worked example and a note on when a behaviour belongs in
202
+ `global.js` rather than in a page.
203
+
204
+ ### Changed
205
+ - Page entry points, and the template new pages are created from, now start
206
+ with `import '../modules/global.js';`.
207
+
208
+ ### Notes
209
+ - Existing projects keep working as they are. To adopt the global module, add
210
+ `src/frontend/js/modules/global.js` and the import line at the top of each
211
+ page entry point.
212
+
213
+ ## [1.2.6] - 2026-08-01
214
+
215
+ ### Fixed
216
+ - The scaffolder created the routes folder as `src/frontend/_routes` instead of
217
+ `src/frontend/routes`. The CLI writes and looks for page templates in
218
+ `routes`, so on a freshly created project every page ended up outside the
219
+ folder Eleventy and the assistant expect.
220
+
221
+ ### Notes
222
+ - Projects created with 1.2.5 have an empty `src/frontend/_routes` folder that
223
+ can be deleted. Pages created before this fix should be moved to
224
+ `src/frontend/routes`.
225
+
226
+ ## [1.2.5] - 2026-08-01
227
+
228
+ ### Added
229
+ - `nib new` now refuses to run from inside an existing Nibula project. Creating
230
+ a project inside another one produced a broken setup, since the outer build
231
+ would pick up the inner project's files. The error message reports the path of
232
+ the project that was detected, so it's clear which one triggered the check.
233
+ - A GitHub Actions workflow that publishes the package to npm whenever a release
234
+ is created, using npm's trusted publishing. The workflow verifies that the git
235
+ tag matches the version in `package.json` before publishing, and attaches a
236
+ provenance attestation to the published package.
237
+
238
+ ### Changed
239
+ - Rewrote the README: added a section on when Nibula is *not* the right tool,
240
+ clarified that Composer is only needed with the PHP backend, and moved the
241
+ editor extensions from the required to the recommended prerequisites.
242
+
243
+ ## [1.2.4] - 2026-07-31
244
+
245
+ ### Changed
246
+ - Internal refactor of `tools/`: the logic is now split across `lib/`, `cli/`
247
+ and `config/`, with values and messages extracted into `settings.json` and
248
+ `messages.json`. No behaviour changes — pages, `site.json` and
249
+ `page-components.njk` are written exactly as before.
250
+ - The CLI now uses a uniform palette: colour is limited to the title box, and
251
+ the menu numbers are dimmed instead of each carrying its own colour.
252
+
253
+ ### Fixed
254
+ - The last line of the menu never closed the `dim` colour code, which stayed
255
+ active on the following line.
256
+
257
+ ## [1.2.3] - 2026-07-29
258
+
259
+ ### Fixed
260
+ - `updateOutputPath` no longer strips custom flags from `build:css` and `serve:css`: the output path is now replaced in place instead of regenerating the whole script
261
+ - Missing `--load-path=node_modules` in the regenerated Sass scripts, which broke Bootstrap SCSS imports
262
+ - Malformed `outDir` in `tsconfig.json` when the output path is absolute (`./c:/...`)
263
+
264
+ ## [1.2.2] - 2026-07-23
265
+
266
+ ### Added
267
+ - **Full favicon set**: `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png`
268
+ (180×180, opaque) in `assets/brand/`. iOS home-screen icons no longer fall back
269
+ to a screenshot of the page.
270
+
271
+ ### Changed
272
+ - **`data_bs_theme` renamed to `theme`** in `site.json`. It still drives
273
+ `data-bs-theme` on the `<html>` tag; the shorter name keeps the config readable
274
+ and independent from the framework naming.
275
+ - **`theme_color` is now a single value** instead of a `light`/`dark` pair. The
276
+ theme is fixed per build, so two per-scheme colors could contradict the
277
+ rendered page.
278
+ - **Favicon paths are hardcoded in `base.njk`.** The `favicon` key was removed
279
+ from `site.json`: it only ever covered one of the three tags, which was more
280
+ confusing than helpful. Replace the files in `assets/brand/` instead.
281
+ - `_routes/` renamed to `routes/` — it holds entry points, not internals.
282
+
283
+ ### Removed
284
+ - **`mdFile` shortcode** and the `markdown-it` dependency.
285
+ - **`github-markdown-css`** and its two passthrough copies.
286
+
287
+ ### Migration
288
+ - In `site.json`: rename `data_bs_theme` to `theme`, flatten `theme_color` to a
289
+ single string, drop `favicon`.
290
+ - Place `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png` in
291
+ `src/frontend/assets/brand/`.
292
+ - If you used `{% mdFile %}`, render the Markdown ahead of time or add
293
+ `markdown-it` back to your own project.
294
+
295
+ ## [1.1.3] - 2026-07-22
296
+
297
+ ### Changed
298
+ - **The update check no longer runs on every command.** Previously every
299
+ invocation of `nib` (and the `nbl` / `nibula` aliases) contacted the npm
300
+ registry before doing anything, adding up to 2.5s of latency to `nib run`,
301
+ `nib build`, `nib cli` and `nib clean`. The check now runs only for `nib new`
302
+ and `nib update`; all other commands work entirely offline.
303
+ - **`nib new` now completes the update automatically.** When a newer version is
304
+ available and you accept the prompt, Nibula installs it and immediately
305
+ re-runs the scaffolding with the new version, instead of asking you to type
306
+ `nib new <project-name>` a second time.
307
+ - **New projects are scaffolded at version `0.0.0`** instead of `1.0.0`, so a
308
+ freshly created site no longer claims a stable public release. Bump it
309
+ yourself as the project grows, and reach `1.0.0` when you go to production.
310
+ - **Framework SCSS imports are now short and readable.** The framework modules
311
+ in `src/frontend/scss/modules/frameworks/` used a five-level relative path
312
+ back to `node_modules`; they now import directly by package name, e.g.
313
+ `@import "bootstrap/scss/card";`. This matches what the styling docs already
314
+ showed, and makes commenting modules out far less error-prone.
315
+ - `nib help` no longer appends an "a newer version is available" line, since it
316
+ no longer performs the check.
317
+
318
+ ### Added
319
+ - Internal `--skip-update-check` flag on `nib new`, set automatically when the
320
+ command is re-run after a self-update. It prevents a loop if the registry is
321
+ slow to propagate the new version.
322
+ - `--load-path=node_modules` on the repository's own `build:css` and `serve:css`
323
+ scripts, so the short framework imports resolve. Generated projects already
324
+ carried this flag.
325
+
326
+ ### Fixed
327
+ - Repaired the ASCII header boxes and the commented-out example import inside
328
+ `_bootstrap.scss`, `_bulma.scss` and `_foundation.scss`, where an earlier
329
+ find-and-replace had injected the `node_modules` path into comment text and
330
+ broken the alignment.
331
+ - `src/frontend/data` is no longer copied to the output folder. It holds the
332
+ Eleventy global data file, which is consumed at build time to render meta
333
+ tags and page config — publishing it produced a dead file in `out/` and
334
+ exposed the full page map, including `noindex` entries. It remains a watch
335
+ target, so edits still trigger a rebuild.
336
+
337
+ ### Notes
338
+ - If the updated installation can't be located after `npm install -g` (an
339
+ unusual `npm root -g` setup, for example), Nibula reports the problem and
340
+ asks you to re-run the command, rather than scaffolding silently with the
341
+ old templates.
342
+ - Existing projects are unaffected by the version change: it applies only to
343
+ newly created ones.
344
+ - Short SCSS imports rely on Sass's `--load-path`, which is passed by the npm
345
+ scripts. Compiling the stylesheets with a different tool (a VS Code Sass
346
+ extension, for instance) will need the same load path configured.
347
+
348
+ ## [1.1.0] - 2026-07-21
349
+
350
+ ### Added
351
+ - **Node.js backend** as an alternative to PHP, living side by side in
352
+ `src/backend/`: `_core/index.js` front controller (which is also the HTTP
353
+ server), `Response` and `RateLimiter` modules, a `mysql2` pool singleton
354
+ `Database.js`, `example.config.js`, and a `package.json` for the backend's
355
+ own dependencies. Same REST API as PHP: routing, `X-Api-Key` auth, CORS and
356
+ file-based rate limiting are identical.
357
+ - **Backend choice at scaffold time**: `nib new` now asks whether to use Node.js
358
+ or PHP, in addition to language and CSS framework.
359
+ - `backend/backend-node.service.example` — a ready-to-adapt **systemd** unit for
360
+ keeping the Node backend running on a server.
361
+ - `config.js` is generated from `example.config.js` at scaffold time (mirroring
362
+ the existing `config.php` generation).
363
+ - Deployment docs now cover running the Node backend with **`screen`** (quick /
364
+ small setups) and **systemd** (production), plus environment variables.
365
+
366
+ ### Changed
367
+ - **Composer is now required only when the PHP backend is chosen.** If you pick
368
+ Node, `composer install` is skipped entirely and the backend's npm
369
+ dependencies (`mysql2`) are installed instead.
370
+ - `.htaccess`, `web.config` and `nginx.conf` now cover **both** backends. On
371
+ nginx, `/api` goes to Node and automatically falls back to the PHP front
372
+ controller when Node is unreachable. On Apache/IIS the active backend is
373
+ selected by configuration (documented), since per-directory configs can't
374
+ health-check an upstream.
375
+ - `.gitignore` now also ignores `src/backend/config.js`,
376
+ `src/backend/node_modules/` and `src/backend/cache/`.
377
+ - Documentation (`README.md`, `docs/Backend.md`, `docs/Deploy.md`) updated:
378
+ backend examples now use JavaScript/Node as the reference, with the equivalent
379
+ PHP shown alongside and a note that PHP behaves identically.
380
+
381
+ ### Notes
382
+ - Both backends are always scaffolded, so you can switch later without
383
+ re-creating the project. The PHP front controller only serves `.php` endpoint
384
+ files and the Node one only `.js`, so they coexist without conflict.