Repository navigation
chore(release): 3.1.1 - #40
Merged
Merged
Conversation
Resources described in JavaScript files, a REST API and an admin app to edit them, records kept in a JSON file store that replicates between nodes, a JWT login with its login page, a documentation page for the fields, and unit tests for the API, the queries and replication. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com> Co-authored-by: Kong Yim <kongyim@gmail.com>
…r login The MongoDB store connects with X.509 client certificates over TLS, and its protocol can be overridden. The login page and its error messages are reworked, and the API routes tidied. request-promise and underscore are gone, along with other unused libraries. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com> Co-authored-by: Kong Yim <kongyim@gmail.com>
- A system log page: colours from the terminal, search, autoscroll that stops when you scroll up, a count of warnings and errors, examples until it is set up, and a virtual log on Linux when a path is given. - Records can be selected together, with Shift+click and Ctrl+A. - A JWT session ends when the user's password changes; Basic authentication fixes. - lodash instead of underscore, the logger instead of log4js, and localisation fixes. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com> Co-authored-by: Kong Yim <kongyim@gmail.com>
Authentication is dispatched between the login methods, explains itself in the debug log, and is documented. The login screen waits for the translations. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com>
A session key option, an async bootstrap, record updates over WebSockets, and Arabic among the locales. Fixes for the anonymous user, the MongoDB connection options, sessions and replicated attachments; Ctrl+A selects text in a field again when multiple selection is off. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com> Co-authored-by: Kong Yim <kongyim@gmail.com>
The xlsx import and the CMS import are fixed, the MongoDB store updated, and the dependencies brought up to date, without the ones nothing used. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com> Co-authored-by: Kong Yim <kongyim@gmail.com>
Queries sent to the MongoDB store are sanitised; settings and dependencies updated. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com>
The admin is rebuilt on Vue 3 and Vuetify 3, served and built by Vite: - a new omnibar, a virtual-scrolled record list, a table view, a theme switch, and reworked fields and paragraphs; - localised values stored field first ([field].[locale]), a _updatedBy field on every record; - images processed with sharp instead of imagemin, resized copies cached and removed with their attachment; - system information and the log page over server-sent events, socket.io removed; - plugins loaded at run time, Node 22, a documentation page per field type, the cms.json options and resource examples, and the unit tests rewritten. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com> Co-authored-by: Kong Yim <kongyim@gmail.com>
Smart cropping of images, Material Design icons as SVG, and fixes to image uploads, text field validation, disabled fields and the paragraph menu; dependency updates. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com>
Every field can show a hint, records sort by their update time, and notifications show the error. Email and form validation fixes, databases close cleanly, smart cropping's TensorFlow dependency removed, and sub-paragraph headers placed right. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com>
…itch The log and system pages reconnect on their own, the remote import can use its cache (--use-cache), image and file fields check their size limit and required state and show the size right, group permissions fixes, and a disableDarkMode option. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com>
Code and rich text fields format code properly with highlight.js, paragraphs show their outline in the form, the remote import script is refactored, rich text validation and textarea scrolling fixed, and login and error handling fixes. The unit tests are reworked. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com>
… start Image fields can store their files on OSS and keep the image metadata, paragraphs with bad data no longer break the editor, the attachments API is fixed, a PostgreSQL store is started, and dependencies are updated. Co-authored-by: Xiaodoudou <edouard.durand@gmail.com> Co-authored-by: Zegfault <zegfault42@gmail.com>
…kend - Backend unit and security tests (mocha), frontend tests (vitest), coverage, and a GitHub Actions workflow that runs them with the lint and the build. - Dependencies updated; the private logger dependency and the unused packages removed; the project stands on its own, without its former owner's services. - The admin redesigned: a design system with tokens in both themes, a collapsible navigation rail, a record editor with unsaved-state tracking, dialogs, toasts and an uploads panel, the table view, consistent field states, the field catalogue (one resource per family of field types) and one documentation page per field type. - The backend audited and hardened: security settings with a legacy and a hardened profile, stronger authentication and sessions, HTTP headers, CSRF and body limits, authenticated and validated replication, query safety and performance work, and MongoDB and PostgreSQL drivers that pass one contract suite.
…uration, update CI actions Admin polish, the recommended production configuration, CI on current actions - The log page reworked, settings menu icons, Ctrl+K on resources and plugins, compact toasts and list rows, breadcrumb, dropdowns, JSON editors and rich text in the field style, the open record in the address. - A record is saved before its files; saving is refused while a required field is empty; uploads without an extension keep their type; switches are saved as false. - The recommended production configuration is documented and tested; the whole repository passes lint and knip. - CI on Node 24 actions (checkout and setup-node v7) and a pinned runner; the legacy suite cleans up after a transient error.
Real components mounted with Vuetify: the record list, select fields, pillbox, colour picker, record editor, the app (routing, address, unsaved-edits guard, breadcrumb), blocks, the JSON editor and the navigation. Fixed along the way: a new record opens a blank editor again, a refused request is not logged as a server error, record names and labels after the mustache 4 update, a record whose id overlaps the machine id can be changed and removed, and remove and update throw instead of failing silently.
…inst the code Documentation refactor: one source of truth per topic, checked against the code A README that goes from nothing to a running CMS, a map of the docs, architecture, concepts and contributing pages, one configuration reference, the API, the plugins and every field page rewritten against the code, diagrams in Mermaid, and the bugs found on the way recorded.
…nent Every bug from the documentation review fixed, and every component tested - The 39 bugs found while the docs were checked, each with a regression test: among them, the login page and the admin agree on the theme, one JSON body limit with a clear 413, the cms command is a plain CMS in a project, installs from git come with the admin built, ?locale= stores values field first, and syncing one record checks it. - Smart cropping uses sharp's attention strategy: no AI model, and every TensorFlow trace removed. - Component tests for every remaining component, and the bugs they found; FormService and SchemaService tested. - The remaining lint warnings fixed.
Green timestamps, levels coloured by severity and highlighted values on a terminal, plain text in files and pipes (stdout and stderr checked separately), NO_COLOR and FORCE_COLOR. The log page shows the colours and reads the level of a coloured line.
… README Every protection is on by default and the legacy profile is gone. The bug and audit notes leave the docs now that they are covered. The README gets a centred header with badges, a screenshot of the default resources, and says the default store is a key-value store saved to a file.
A delete goes to the replication peers right away again, cms-import prints no empty progress bars into logs, the xlsx import answers 400 without a file, express-session defaults stated, quiet test runs, eslint 10, and canvas and rollup-plugin-node-polyfills dropped.
…ngoDB and PostgreSQL Record stores: LevelDB and SQLite beside the JSON file, MongoDB and PostgreSQL dbEngine.type can be sqlite or leveldb; LevelDB is the default for new content, and a resource that still has a db.json keeps it until it is migrated with the tool that moves content between the local engines. A storage engines page with measurements and a crash test, and the benchmark for all five engines.
The version becomes 3.0.0 and the license GPL-3.0-only. Versions up to 2.6.1 were MIT: the license file keeps their notice, with its copyright line, as the MIT license requires, so the brand test leaves that one file out.
…l alias Text fields: autocomplete "nope", so Brave stops offering an email alias on emails and links The shared mixin set autocomplete back to "off" after Vuetify rendered the field, and browsers ignore "off" for what they take for an email or a sign-up form. Text fields now get an invalid token, passwords keep "new-password". The email field is a plain text box.
Icon buttons everywhere: move, delete, fold, add, Edit JSON and Object Properties. Selects are a button and a list like the other dropdowns of the admin, and booleans a checkbox. Nesting is an indentation with a thin rule, not boxes inside boxes: a container is a header line (fold chevron, name, ghost icon buttons) over its body, and the root object has no box. List items are rows (position, field, move and delete icons); items that are objects or lists have their own header line; "Add item" is one dashed button under the rows, and "Delete All" an icon on the header, moved there by a small hook (the library builds it under the rows). A type chip on mixed items and added properties; the name field of Object properties is emptied after each add. Tables keep their bordered look with ghost row actions. Works in the dark theme and on a phone; tokens only. The boolean of the catalogue's Settings field is declared as a checkbox (format: 'checkbox'). The object field page describes this editor (header lines, icons, Object Properties, lists, added properties) and its five screenshots show it.
Remove the Cms Config page and its routes, and list Syslog in the CMS menu The page rewrote cms.json from the browser and restarted the server: it let an admin change the secrets and ports, and a mistake could leave the CMS unable to start. /admin/cms-config is gone, with the helpers only it used. Syslog moves from the System menu to the CMS group, next to Users, Groups and Settings. The names of the plugin pages (Syslog, Replicator, Import, Sync) are translation keys now, in the menus, the breadcrumb, the tab and the quick switcher (Syslog reads 系统日志 in Chinese). Their display name does not change: it is what the `plugins` right of a group names.
…a stalled page Syslog: a very long log no longer fills the disk, the memory or a stalled page syslog.maxLineLength cuts a line on the page (10000 characters, the file keeps it whole), syslog.maxFileSize copies a log file past 10 MB to <path>.1 and empties it, syslog.maxClientBuffer drops a page that stopped reading (8 MB). Each is off at 0.
Login page: a softer, more finished look, still following the system theme An accent glow behind the card, a gradient strip along its top edge, a larger logo, a deeper shadow and a short fade-up when it appears.
…al since boot node-os-utils has no bandwidth on Windows, so the server keeps the previous byte counters and works out bytes per second between two reports. The card shows the rate (the total is its tooltip, and what shows until a second report gives a rate).
npm audit reported 6 high severity vulnerabilities, all one chain: braces (a stack exhaustion with deeply nested patterns, advisory GHSA-vfj7-8cjw-p6xm, for every version up to the latest 3.0.3, with no patched release) reached through micromatch, fast-glob, globby, del and del-cli. Only dev tools were affected: npm audit --omit=dev found nothing. del-cli was used by one script, dev, to remove src/plugins. That is one line of Node (fs.rmSync with force, which does not mind a missing folder), so the dependency and its 27 packages are gone, and npm audit finds 0 vulnerabilities, shipped and dev alike. The lockfile loses those 28 packages and changes no version.
The dev script carried the whole call to fs.rmSync, with its quotes escaped, inside package.json. It is now scripts/clean-plugins.js, and the dev script reads: node scripts/clean-plugins.js && cross-env ... vite. The behaviour is the one of the one-liner: a folder is emptied, a missing folder is no error, and a symlink (src/plugins can point to the plugins of the project) is removed without touching what it points to.
…stream-to-array Both places collected the chunks of a stream with stream-to-array and joined them with Buffer.concat. Node's stream/consumers does the same in one call (buffer(stream)), so the dependency goes.
cms-import and cms-import-remote use prompt for one thing: a yes or no before they write. prompt is a general library that was last released in 2022 and brings an abandoned stack for it: winston 2 (end of life since 2018), colors, eyes, cycle, revalidator and two versions of async, 12 packages in all, in the tools that hold the credentials of a CMS. lib/util/confirm.js asks the question with Node's readline. Anything but a whole yes or no asks again, and an input that closes (a pipe that ended, Ctrl+D) answers no, so nothing is written when nobody answered. The two commands answer no and exit 1 as before.
… enter In production the sessions are files in <data>/.sessions.json, and a session holds the login token of the person in clear text. The folder was made with the permissions of the umask (usually 0755) and its files were 0644 on a normal system: any other account of the machine, or a container that shares the volume, could read a token and use it until it expires, 24 hours. ensurePrivateFolder sets the folder to 0700 at every start, also when an earlier version made it. The permissions of the folder decide who can reach the files in it, so the files need no change. Turning on the encryption that session-file-store offers was tried and left out: a clear-text session file that is read once the encryption is on throws inside the store's callback and stops the process.
The folder of the sessions holds the login tokens of the people who are signed in. A backup has no use for them, and a token in a backup that is copied off the machine is a login that can be taken, for as long as it lasts. cms-backup files now skips <data>/.sessions.json and says so; the rest of the data folder, hidden files included, is copied as before. Everyone signs in again after a restore.
build(deps): replace del-cli with a script, clearing 6 high audit warnings
# Conflicts: # package-lock.json
build(deps): replace prompt and stream-to-array with Node built-ins
fix(security): keep the session files in a folder only the server can enter
Moves the Unreleased entries of the changelog under 3.0.7, adds its compare link and bumps the version of package.json.
Knip 6 finds ten default exports in src/utils that nothing imports, as every caller uses the named exports, so the default objects go. playwright-core is loaded on demand by the screenshot scripts, so it is listed as an ignored dependency. Three entries in the ignore list are no longer needed and knip still exits 0 without them.
chore(knip): clean up what knip 6 reports
The proxy rewrote Host to the backend port while the browser kept its own Origin, so the CSRF check refused every cookie-authenticated write and the updates websocket in development.
The buttons are pushed to the right end of the bar, so the title no longer floats in the middle when the block has no summary text.
A resource's group can be a list of names, ['Content', 'Blog'], to file it in a group inside a group. The sidebar shows the tree, the collapsed rail shows the top group with the groups inside it in its pop-up, and the breadcrumb, the quick switcher and the title dropdown follow. Every group can get an icon in Settings, a group inside another as 'Content / Blog'. The sidebar is also cheaper to resize: while the pointer moves only a CSS variable changes, and the app re-renders when it is let go. The width stops at what the longest visible name needs.
Lists every key of a file in resources/ with its type, default and what it does, explains nested menu groups, and documents displayItem and extraSources, which were not described anywhere.
feat(admin): nest menu groups to any depth
engines was ^22.12.0, which npm reads as Node 22 only, so Node 24 got an engine warning. It now allows ^22.12.0 || ^24.0.0, and a node-24 job runs the unit, frontend, integration and build steps next to the Node 22 ones. It is a separate job because the rules of main ask for checks named test and drivers.
The Docker example builds and runs on node:24-bookworm-slim. The commit check, the drivers job and the npm publish run on Node 24. The test job stays on Node 22, the oldest supported line, beside the node-24 job.
After a wrong answer, confirm asked the question again with rl.prompt(). When the input ended in the same chunk (printf 'what\n' | cms-import), the interface was already closed, and Node 24 throws ERR_USE_AFTER_CLOSE there where Node 22 let it pass. The question is now asked again only while the input is open, so a closed input still counts as no.
engines is now ^24.0.0, every CI job runs on Node 24, and the separate node-24 job is gone because test is the Node 24 job now. The README, CONTRIBUTING, the create-site skill and the changelog say Node 24.
build: require Node 24 and drop Node 22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changed
engineswas^22.12.0. It is now^24.0.0, so installing on Node 22 prints an engine warning. CI runs every job on Node 24, and the Docker example runs onnode:24-bookworm-slim.Fixed
cms-importandcms-import-remotecrashed on Node 24 when their input ended right after a wrong answer. Asked again after the wrong answer, the question was put to a closed input, which Node 24 refuses withERR_USE_AFTER_CLOSE. It now answers no, as it does when the input closes before any answer.