Show pictures from inside Chronicle page text in Foundry journals - #138
Merged
Merged
Conversation
Chronicle serves media only through signed links that expire in about 15 minutes, so a picture link saved into a journal breaks. Journal sync now copies each shared picture into the world's files once and points the journal at the copy. GM-only pictures are never copied; they go inside Foundry's own secret block, and the GM's screen shows them from a fresh signed link. On push every picture goes back as the plain /media/<id> path, and every Chronicle picture inside a secret block goes back GM-only, so a Foundry edit can't make it visible to players. Fixes #127 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MfPNYnQNHxBmUgRgU4VyHh
…-5q4j0i # Conflicts: # .ai.md # bench/journals.bench.mjs # styles/chronicle-sync.css
6 of 8 tasks
…-5q4j0i # Conflicts: # CLAUDE.md # scripts/journal-sync.mjs
6 of 8 tasks
…-5q4j0i # Conflicts: # CLAUDE.md
…-5q4j0i # Conflicts: # .ai.md # CLAUDE.md # scripts/journal-sync.mjs # tools/test-gm-secrets.mjs
keyxmakerx
marked this pull request as ready for review
October 4, 2026 01:02
This was referenced Oct 4, 2026
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.
Requested by Key Maker · project thread
Fixes #127
Security implication: GM-only pictures must never reach players. They are never copied. On pull they go into a secret block that the GM-only text fix (#147) then stores as a placeholder, so the picture is not in the saved journal at all; the GM's screen fills it in. Any Chronicle picture inside a secret block is pushed back GM-only whatever shape the editor leaves it in. Copies are fetched only from the
apiUrlhost, raster types only, with no redirects.Consumer-verified: Chronicle
internal/plugins/syncapi/media_api_handler.gotoAPIResponse(signedurl,mime_type,file_size;SignedURLTTL= 15 min ininternal/plugins/media/signed_url.go). The figure shape and thece-img--gmstrip come from Chronicle#1014, now merged (static/js/widgets/editor_image.js,internal/sanitize/sanitize.gogmPictureRe).Foundry compatibility: FilePicker is resolved for v12 (global) and v13/v14 (
foundry.applications.apps.FilePicker.implementation). Not checked in a live Foundry world yet; see the test plan.Mockup: Sign-offs card
foundry-pictures-127(before/after), signed "Yes, as shown".Merge order: after #147 (merged). Test-merged with #153 and #159: no conflicts.
What this changes
Before: Chronicle pages can now hold pictures inside their text (Chronicle#1014). Journal sync copied each picture's
/media/<id>path into Foundry unchanged. That path resolves against Foundry's own address, so every picture showed broken.After:
worlds/<world>/chronicle-media/<id>.<ext>, and the journal points at the copy. It keeps Chronicle's size, side and caption./media/<id>paths back, with GM-only intact.Why
#127 planned to resolve each
/media/<id>to a link the way map sync does. That can't work for journals. Chronicle's signed links expire after 15 minutes, so a saved link would break for players soon after every pull. The module keeps its own copy instead.#127 also said GM-only pictures never arrive because Chronicle strips them. That is true only for keys below Scribe. The module uses the owner's key, so they do arrive, and the module now handles them itself. The same gap for GM secret text is tracked privately.
How
scripts/_inline-pictures.mjs(pure) translates the HTML both ways.toFoundryPicturesswaps shared srcs for local copies and wraps GM-only figures in<section class="secret chronicle-gm-picture">. It leaves an existing secret block alone.toChroniclePicturesrestores/media/<uuid>, including from full or signed Chronicle links. Inside any secret block it marks every Chronicle picturece-img--gm: a figure without the class, a bare picture, or a picture alone in a paragraph. It removes only the block sync itself added.scripts/picture-store.mjsmakes the copies.GET /media/:id, fetches cookieless on theapiUrlhost with no redirects, and uploads withFilePicker.upload.browse.watchGMPicturesputs a fresh signed link into GM-only pictures on the GM's screen. It skips editors, so the link is never saved.scripts/journal-sync.mjs:_pullHtmlruns_withPicturesbeforehideSecrets, so GM-only pictures are hidden with the GM-only text._loadSecretPiecesbuilds the same blocks (without copying), so placeholder ids match._forPushrunstoChroniclePicturesafterrestoreSecretsand beforetoChronicleSecrets, so a GM-only picture in restored content or in a block the GM typed leaves GM-only.watchGMPicturessigns pictures asgm-secret-view.mjsfills placeholders on the GM's screen.styles/chronicle-sync.cssmirrors Chronicle's.ce-imgwidth, side and caption rules.game.worldand an in-memory FilePicker.Honest deviations:
.ai.mdand on the card.Test plan
node --test tools/test-*.mjs: 1359 pass, 0 fail, 1 skipped (needsCHRONICLE_DIR), after merging main with Security fix: keep GM-only page content out of saved Foundry journals #147. This includes the newtools/test-inline-pictures.mjs, with 19 tests, one of them the placeholder round trip.CHRONICLE_DIR=../Chronicle bench/run.shagainst Chronicle main passes 27 of 27, pictures scenario included.node tools/check-package-descriptor.mjs: OK, 0 warnings.node tools/check-error-catalog.mjs: matches.Tenet self-check
apiUrlhost, GM-only pictures are never copied, and a Foundry edit can't drop the GM-only mark.ai.mdfile index and trust table,API-CONTRACT.mdGET /media/:mediaId,CLAUDE.mdfile listGenerated by Claude Code