Repository navigation
Critical Notes 1.3.0
The prep and play release. The DM gets a history of every page with compare and restore, can reveal secrets and
handouts to the players while they are reading, and gets more help at the combat table. A player's save no longer
destroys the DM's hidden links. This release changes the database and the change cannot be undone: back up first
(see Upgrade notes below).
Added
- Page history (game master only).
- Every change to a page is saved as a version: edits in the web editor, a player's edits to their character,
edits by an AI assistant, restores, templates, imports and edition changes. Open a page and choose History in
the toolbar (it is hidden for players and in "Preview as player"). - Saves by the same person within 2 minutes become one version, so typing does not create hundreds of entries.
Change this withHISTORY_COALESCE_MINUTES(0 keeps every save). - Each entry shows who made the change and when. Changes made through an AI token are marked via AI assistant
with the token's name. - Compare a version with the current page, or two versions with each other. Changes are shown as added and
removed text, marked with+and-, underline and strike-through, and with spoken words for screen readers.
Changes to the title, type, details and properties are listed under "Other changes". - Restore brings an earlier version back as a new version, so you can Undo restore. A restore brings back
content only: title, type, text, details and properties. It does not change who can see the page, its parent, tags,
icon or who owns a player character. - Old versions are thinned so history does not grow without end: every version is kept for 30 days, then one per
day, then one per month after a year, and a page or campaign over its limit is thinned early (oldest first, never
the last 30 days). The settings areHISTORY_KEEP_ALL_DAYS,HISTORY_COALESCE_MINUTES,
HISTORY_MONTHLY_AFTER_DAYS,HISTORY_MAX_PER_PAGEandHISTORY_MAX_MB_PER_CAMPAIGN; the defaults are in the
README. Thinning stops history from growing; it does not make the database file smaller. - Players never see history, and a campaign export does not include it.
- AI assistants with a game master's token get two new tools:
get_page_history(list the versions of a page, or read
one in full) andrestore_page_version(needs a read and write token).
- Every change to a page is saved as a version: edits in the web editor, a player's edits to their character,
- Reveal to players.
- Reveal now in a block's options menu (
Ctrl+.) reveals a DM secret or a DM-only block at once, with a 15
second Undo. Share now (and Share with chosen players) does the same for a handout page. - Players see it while they play, without reloading: a short message ("New: ...", "New details on this page"), a
New label in the page tree and on the page, and a highlight on the revealed block. A player who is typing on
that page is offered Reload instead of having their text replaced. - The message only tells the player's browser to look again. It never carries a title or text; the browser then
asks for the page like any other request, so the usual rules about what a player may see still apply. - If the live connection fails for a long time, the browser falls back to checking now and then. Live updates need one
server process, which is what the shippeddocker-compose.ymlruns. The limits areEVENTS_MAX_CONNECTIONSand
EVENTS_MAX_PER_CAMPAIGN.
- Reveal now in a block's options menu (
- Combat tracker.
- Death saves for player characters: success and failure marks, a d20 field and Roll for me, Natural 20
(back up at 1 HP) and Natural 1 (two failures), Stable and Dead, and extra failures for damage at 0 HP
(two for a critical hit). Damage that brings a character past 0 HP by at least their maximum HP kills at once.
Damage that temporary HP absorbs adds no failure; this is a table convention, and the help text in the tracker
says so. Players see these marks for characters only. - Legendary actions (spend and undo; they refill when the creature's turn starts) and Legendary Resistance
(use and give back; a new round never resets it), read from the statblock when you add the creature. Players never
see either. - Recharge abilities: mark one as used, and at the start of the creature's turn the tracker rolls the d6 and
shows the roll to you only. - Lair actions: a hidden row on initiative 20 that loses ties, and a toggle for creatures that are in their lair.
While a hidden row acts, players see no highlighted turn. - Ready (with a trigger; players see it for player characters only) and Move after, which moves a combatant
to just after another one. Move after is the tracker's way to handle Delay, a table convention rather than a rule
printed in the core books. When the active creature moves, the turn passes on at once and its conditions do not
tick. - A More section on each row, two toolbar groups, and one-key shortcuts on a row (press
?for the list).
- Death saves for player characters: success and failure marks, a d20 field and Roll for me, Natural 20
- Query block views. A query block can show its pages as a table or as cards as well as a list. A column
picker chooses and orders the columns (type, tags, dates, details and properties). Anyone who views a table can sort
it by clicking a header; that sorting is not saved. Players see only the rows and columns they may see.
Changed
- Empty values in a query now sort last in both directions.
- A backup may now compress its database up to 200 to 1 instead of 50 to 1 when it is checked, because a database with
a lot of history compresses very well. Backups and restores work as before.
Fixed
- A player saving a page no longer destroys the game master's content on it.
- Links to pages the player cannot see survive when the player edits another paragraph or the text around them, also
when the link's label is bold or italic or appears more than once in the paragraph. The link comes back without
bold or italic. - A callout or other container saved without its contents keeps its DM-only blocks. Repeated or reused block ids can
no longer duplicate DM-only blocks or take over their ids. - A link or embed that a player adds to a page they cannot see is dropped from their save (a link becomes plain text),
so a save cannot be used to find out which pages exist. - A player cannot mark a block as revealed.
- Players still never receive the hidden pages' ids or DM-only text. To keep this safe, a player's save has limits: a
paragraph can hold at most 100,000 characters (text plus link labels) and a page at most 2 MB. See Known issues.
- Links to pages the player cannot see survive when the player edits another paragraph or the text around them, also
- The live combat view closes when someone loses access while it is open (removed from the campaign, disabled, signed
out, password changed, or no longer a co-DM for the DM view). It used to check only when it opened. The check runs
at least every 25 seconds.
Upgrade notes
- Back up first, with the version that is running now, and copy the backup off the machine:
- Docker:
docker compose exec app node admin.mjs backup - Without Docker:
node apps/server/dist/admin.mjs backup
- Docker:
- Update.
- Docker: set
CN_VERSIONto the new version in.env(or followlatest), then
docker compose pull && docker compose up -d. - Without Docker: check out the new tag, run
pnpm install && pnpm build, and restart the server.
- Docker: set
- Migration 0007 adds the page history table. It runs when the server starts and cannot be undone.
- History starts empty. The first time a page is edited after the upgrade, its earlier state is stored as a
"before history was recorded" version, so you can get back to what the page was before that edit. - Sessions and logins keep working. Nobody is signed out.
- The new settings are optional and their defaults suit most tables:
HISTORY_KEEP_ALL_DAYS(30),
HISTORY_COALESCE_MINUTES(2),HISTORY_MONTHLY_AFTER_DAYS(365),HISTORY_MAX_PER_PAGE(200),
HISTORY_MAX_MB_PER_CAMPAIGN(500),EVENTS_MAX_CONNECTIONS(500) andEVENTS_MAX_PER_CAMPAIGN(100). See the
README. With Docker, the new settings reach the container only through the new
docker-compose.yml: if you changed your copy of that file, copy the new lines (HISTORY_*,EVENTS_*) into it,
or the values you put in.envhave no effect. - There is no downgrade. To go back, stop the app, set
CN_VERSIONback to your old version and restore the
backup you made before updating:
docker compose run --rm app node admin.mjs restore /data/app/backups/<file> --yes. This discards everything
written since that backup, signs everyone out, and revokes API tokens and invite links.
Starting an older version on an upgraded database is not refused, but it is not supported. - Backups made by 1.3 are refused by 1.2.x (exit code 66, "update first"). Backups from 1.2.x restore into 1.3 and are
migrated on the way.
Known issues
- If a player rewrites the label of a link to a page they cannot see, the link is lost when they save. When a link is
kept on a bold or italic label, it comes back without bold or italic. - A player cannot make a paragraph longer than 100,000 characters (text plus link labels). If the DM wrote a longer one, the player can still save the page as long as that paragraph is left unchanged or made shorter, but cannot edit it while it stays that long.
- Players can save pages only up to 2 MB.
- The check on page-link properties can confirm to a player who already knows a hidden page's id that the page exists.
Planned for 1.3.1. - When a player moves a paragraph into a container, such as a callout, it may lose the DM's hidden link. Planned
for 1.3.1. - Tracker streams (the live combat view) are not counted in the per-user stream limit, so one player can open many of
them. Planned for 1.3.1. - A player who was offline when something was revealed is not told about reveals on pages they did not have open. They
see the change when they open the page. - History folds saves by the same author within 2 minutes into one version, so a paste you regret can overwrite up to 2
minutes of earlier state. LowerHISTORY_COALESCE_MINUTESfor finer versions.