[pull] main from TryGhost:main - #1457
Merged
Merged
Conversation
no ref The gifts jobs module uses the legacy jobs service for the reminders job and the class-based jobs service for cleanup. The legacy binding held the jobsService name, forcing the class-based parameter into the awkward classBasedJobs name. jobManager matches the legacy service's own vocabulary (addJob) and frees jobsService for the new service.
no ref classBasedJobs described the service relative to the legacy one it replaces, which only means something during the migration. Now that the legacy binding is jobManager the injected class-based jobs service can take the plain jobsService name.
…eter no ref The token and expired-comped scheduling functions reached into the jobs service module with getInstance(), while the gift and update-check equivalents already receive the service from boot. Injecting it makes boot the single composition root for job scheduling and lets the tests pass a plain stub instead of initialising the real service and stubbing its backend adapter.
no ref The handler read the gift service off the gifts module at execution time with an uninitialised guard, unlike the media inliner which boot resolves and injects at registration. Handler registration already runs after initServices, and no job executes before jobsService.start(), so boot can assert the service exists and inject the instance - the same pattern it already uses for the gift delivery service. A boot-order regression now fails at wire-up instead of at the first job delivery.
no ref register-job-handlers assembled the db, models, events, logging and sentry dependencies for the two member cleanup tasks, which made the wiring file a second composition root. The members jobs module now owns that composition behind an init() called from boot, the same shape content-import uses, so every handler in the wiring file is a single delegating line and the dependency interface shrinks to the jobs service plus the service instances.
ref https://linear.app/ghost/issue/HKG-1977 Preparation for moving processWebmention onto the class-based jobs service: the work the background job does is now a named controller method, so the job body no longer has to be a closure over the request frame. The destructure of frame.data moves from execution time to enqueue time. That is behaviour-preserving because frame.data is not mutated in between, and it leaves the method taking exactly the fields a serialized job payload will carry. URL parsing stays inside the method: a malformed URL must keep failing inside the job, after the request has already been answered with a 202.
… queue ref https://linear.app/ghost/issue/HKG-1977 These tests waited for the mentions job manager to go idle, which ties them to the queue that happens to run the work today. Ahead of moving processWebmention to the jobs service, they now wait for the mentions API to report the webmention processed, which is true of either transport, and the assertions are unchanged. The signal is the API's own '[Webmention] Created/Updated/Deleted/Restored' log line rather than the mention row appearing: three tests re-post the same source to assert a new verification result, and polling the row would find the previous test's row already in the asserted state and pass without the job ever running.
ref https://linear.app/ghost/issue/HKG-1977 The mentions controller is about to dispatch through the jobs service, and it receives its dependencies during initServices, which ran before the jobs service existed. Boot is the composition root, so it builds the instance first and can then inject it rather than have services reach for a module singleton. Handler registration and start() deliberately stay where they were: handlers need the initialised services, and the backend queue is created paused, so a dispatch that lands between construction and start() is buffered.
ref https://linear.app/ghost/issue/HKG-1977 Receiving a webmention queued a closure over the request frame on the mentions job manager. It now dispatches a serializable ProcessWebmentionJob, and central handler registration routes it back to the controller method that does the work, so dispatch and execution are no longer tied together by a closure. The mentions job manager stays for sendWebmentions, which is a separate migration. Two things worth knowing. The dispatched payload keeps source and target as strings and parses them in the executor, because a malformed URL has to keep failing inside the job rather than turning the request's 202 into a 400. And the executor still swallows every processing error: the job never fails from the transport's point of view, exactly as it did before, so this change does not start reporting webmention failures to Sentry.
no ref Promotes the `tagDetailsReact` Labs flag to generally available, so every site serves `/tags/:slug` and `/tags/new` from the React tag detail screen.
no ref Used the shared Shade timestamp formatter so older entries follow the common date format. <img width="1191" height="272" alt="Screenshot 2026-08-31 at 9 41 59 AM" src="https://github.com/user-attachments/assets/fa8c71b0-2fd6-4dba-9d72-c2d3c92f6ef4" />
- only pass docker build secret to benchmark script on main push - remove unused "member in org" check in setup - removed release workflow branch input - add npm-release env to other npm publishing steps
no ref Keep generated outcome metadata together at the start of errors.csv so publishers can immediately see why each row failed before reviewing or correcting the original source values. Preserve collision-safe names and original source order so the file remains safe to edit and re-upload.
no ref Publishers should not have to infer where row-level failures are explained. Point the failed count at errors.csv only when that actionable attachment exists, preserving honest copy for fatal runs and outcomes without source data.
no ref Frontmatter is not part of the supported CSV migration contract and exposing it in the mapping UI implied support publishers should not rely on. Remove it at both Admin and Core boundaries while leaving legacy JSON imports and normal post APIs unchanged.
no ref A post's coverImage, ogImage, and twitterImage frequently resolve to the same feature_image URL, and getImageDimensions() looks all three up concurrently via Promise.all. Since ImageSize.getImageSizeFromUrl() had no in-flight deduplication, a single cold pageview could fire off multiple simultaneous origin requests (HTTP probe or storage read) for the exact same image. This coalesces concurrent lookups for the same URL into one underlying request, regardless of which cache adapter (or none) is configured, since the dedup lives below the caching layer.
no ref Follow-up to #30349, which removed the SQLite acceptance and legacy jobs from CI.
…ides (#30381) no ref In the admin acceptance harness, the `labs` render option compiled into full canned `browseSettings`/`browseConfig` boot overrides, and `boot` was spread after it — so any test passing a `boot` override for either of those entries silently lost its labs flags. Tests that needed both had to hand-mutate the boot response object (build a `configResponse({labs})`, tweak it, pass it as the override) instead of just naming the flags.
no ref
The admin acceptance harness's `labs` render option used to be silently
ignored whenever a `boot` override supplied the config or settings
response, so any spec that needed both had to bake the flag into a
hand-built `configResponse({labs})`/`settingsResponse({labs})` as well
as (or instead of) the `labs` option. The harness now composes `labs`
flags into boot-provided responses, so each spec can state a flag
exactly once.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )