100 Commits
Author SHA1 Message Date
David Taylor ba17a5916b DEPS: Bump rubocop, rubocop-rails, rubocop-capybara, and rubocop-rspec (#43305) 2026-09-04 16:55:50 +01:00
David Taylor a4f426a014 DEV: Restore the playwright browser install step in CI (#43288)
PR #40214 dropped this step to avoid re-downloading Chromium on every
system test job, since the discourse_test image already bakes in a
matching browser. That assumption breaks whenever package.json bumps the
playwright version ahead of the image: the pinned npm package then
expects a browser revision the image doesn't have, and every system test
fails with "Executable doesn't exist".

`playwright install` already skips browsers it finds already present for
the current version, so restoring the step costs nothing when the image
is in sync and downloads the right browser when it isn't.
2026-09-04 15:57:34 +01:00
David Taylor 696dfa8151 DEV: Group @warp-drive/* dependabot updates (#43283)
Adds a dependabot group for @warp-drive/* npm packages, following the
same pattern as the existing embroider, codemirror, and uppy groups, so
their version bumps land in a single PR instead of one per package.
2026-09-04 15:11:59 +01:00
David Taylor 5eab0c26c7 DEV: Update pnpm minimumReleaseAge settings (#43286)
- Match pnpm setting to dependabot, so we get the same behavior
regardless of update mechanism
- Add exception for `discourse`, which is the internal alias for
`@discourse/types`

This should get dependabot working again since we bumped
`@discourse/types`
2026-09-04 15:11:52 +01:00
David Taylor c0ef3a1140 DEV: Preserve leading trivia when dts-generator replaces a node (#43282)
processTree() in dts-generator (used to bundle each vendored package's
.d.ts into @discourse/types) replaces certain nodes, like the `declare`
keyword, with an empty string. TypeScript scans a node's `pos` to
include its leading trivia (blank lines, comments), but skip() jumps
straight to `node.end` on replacement, so that trivia got silently
deleted along with the token being replaced.

This surfaced concretely in @floating-ui/dom's type declarations, where
`export { Axis }` was immediately followed by a blank line and `declare
type BivariantCallback = ...`. Removing `declare` also removed the blank
line, merging the two statements onto a single line and producing
invalid TypeScript in the generated
external-types/floating-ui__dom/index.d.ts (confirmed by PR #43280,
which bumped to a build containing this and failed `pnpm lint:types`
with `TS1005: ';' expected`).

The fix emits the node's leading trivia before applying the replacement,
so only the token itself is swallowed.
2026-09-04 12:01:55 +01:00
David Taylor f7761d480f DEV: Wait for @discourse/types release before bumping (#43272)
Followup to 1283213848
2026-09-04 11:29:04 +01:00
David Taylor 1283213848 DEV: Automatically bump @discourse/types when releasing (#43259)
Dependabot doesn't work properly because of the way we alias this
package, and the way that we use the prerelease-format version numbers
2026-09-04 11:16:31 +01:00
David Taylor f0889ee58a DEV: Group codemirror and ember-decorators dependabot updates (#43172) 2026-09-04 11:15:09 +01:00
David Taylor f5a6526dcc FIX: bind declared Data Explorer parameters with their real Postgres type (#43255)
Since parameters bind as native Postgres bind parameters rather than
being spliced into the SQL text, an unresolved-type parameter used
somewhere like a bare `:param IS NULL` makes Postgres fail with "could
not determine data type of parameter $N", because Postgres can't infer a
type for a bind parameter the way it can for a plain literal.

Data Explorer already knows each parameter's declared type from the
query's `-- [params]` block, so this uses it to give `string`,
`string_list`, `date`, and `datetime` parameters an explicit Postgres
type instead of leaving them unresolved. Other declared types are
unaffected.
2026-09-04 10:49:36 +01:00
David Taylor 57b5fbf391 FIX: Bump rails_multisite and update usage (#42684)
`with_connection`, `with_hostname` and `establish_connection` no longer
silently fallback to the default db. When we want that fallback
behavior, we have to specifically opt-in.

For example:
- Most hostname-based lookups in Discourse should fallback to the
default site, so that we match the existing behavior for any sites which
may have misconfigured hostnames

- Loops like CachedCounting, keep_readonly_mode and sidekiq-pausable
should defensively skip attempts to connect to sites which are now
missing, so that they don't get blocked by an exception for one missing
site

Depends on https://github.com/discourse/rails_multisite/pull/40
2026-09-04 09:42:45 +01:00
David Taylor 17780093e3 PERF: Actually cache plugin manifests and asset lookups (#43178)
`Plugin::JsManager.maybe_cache` used `@cache.fetch(key, &blk)`, which
returns the block's value on a miss but never stores it, so the cache
never worked, which led to a large number of filesystem reads.

This commit fixes the cache, and also introduces
`CurrentAttributes`-based caching in development (to match what we do in
`lib/ember_assets.rb`)

`maybe_cache` is now `get_set_cache`, because it always reads through
and writes back.
2026-09-03 17:03:51 +01:00
David Taylor eef25b7c64 DEV: Fixup pnpm-lock and drop unused message-bus-client patch (#43173)
Lockfile issue caused by merge conflict with multiple dependabot PRs.

message-bus-client has now made the same change upstream that we
patched.
2026-09-03 14:12:38 +01:00
David Taylor 4e5abcdeb0 DEV: Correct supportEndDate for 2026.1 (#43167)
This was always supposed to align with the release of 2026.9
2026-09-03 13:37:03 +01:00
David Taylor b0877e98d0 DEV: wait for CSS transition in skip-links test (#43121)
Resolve flaky test
2026-09-02 14:10:24 +01:00
David Taylor 0e2c717ca9 DEV: import the concurrently named export in bin/dev (#43120)
concurrently 10 (bumped in #42829) stopped exporting the run function as
the module's top-level export, so `bin/dev` crashed on startup with
"concurrently is not a function". Use the named export.
2026-09-02 13:44:18 +01:00
David Taylor f56aa58f42 DEV: cleanup PeerManager in peer-manager-test.js (#43119)
Resolves flaky tests for voice plugin
2026-09-02 13:13:00 +01:00
David Taylor 005eb4daf4 DEV: configure conditionNames in rolldown resolver (#43116)
Extracted from the Ember 7 PR (#40407). Vite injects the
`development`/`production` export condition automatically, but our
rolldown config did not.

This is a no-op on `main` today, but becomes relevant since Ember 7
makes use of these flags.
2026-09-02 12:38:45 +01:00
David Taylor e79db287da DEV: refactor sidebar section-link active state (#43117)
Extracted from the Ember 7 PR (#40407). Ember 7's <LinkTo> no longer
considers `@models` when `@current-when` is a string.

Sidebar category/tag links pass a static multi-route `current-when`
string plus `@models` to stay highlighted across filter routes while
narrowing to a single category/tag. Under Ember 7 it causes every link
sharing the route list to light up at once.

This commit implements the `currentWhen` logic we want in JS. On Ember 6
this reproduces what <LinkTo> already does, so behaviour is unchanged.
2026-09-02 12:38:29 +01:00
David Taylor 746d9e266d DEV: drop injectTestHelpers from test setup (#43118)
`Application#injectTestHelpers` sets up Ember's legacy global test
helpers (`find`, `click`, `visit`, `pauseTest`, etc.). We've been
linting against these globals for a long time, and the system will be
finally removed in Ember 7.

We maintain the `pauseTest` global via a custom shim.

Extracted from the Ember 7 PR (#40407).
2026-09-02 12:37:49 +01:00
David Taylor 0af00cdda0 DEV: resolve array deprecation on the AI embeddings edit page (#43115)
The edit route called `.find()` directly on the result of
`store.findAll`, which is a LegacyArrayLikeObject. That triggered the
`discourse.legacy-array-like-object.proxied-array` deprecation and its
admin notice whenever an admin opened an embedding configuration. The
llms and agents edit routes already go through `.content`, so this
brings embeddings in line with them.

Also adds a system spec that edits an existing embedding configuration,
since none covered the edit page before. It fails on the old code
because the deprecation is fatal in system specs.
2026-09-02 11:43:51 +01:00
David Taylor 0aa049e222 DEV: Ensure design-wizard tests do not impact others (#43099) 2026-09-01 17:25:40 +01:00
David Taylor c007df9173 DEV: Fix bin/lint crash on unbundled plugin paths (#43086)
bundled_plugins is a Set, which has no #exclude? without ActiveSupport,
so linting any file under plugins/ that is not bundled raised
NoMethodError.
2026-09-01 15:07:37 +01:00
David Taylor 1cb70b1b36 DEV: Remove both preview stylesheets in color scheme test (#43070)
Selecting a light color scheme also previews it as the dark scheme, so
the test needs to clean up both the cs-preview-light and cs-preview-dark
links it creates. Leaving the dark one behind was leaking a stylesheet
into document.body for the rest of the QUnit run, which sometimes
tripped an unrelated boot-readiness check depending on test order.
2026-09-01 15:03:36 +01:00
David Taylor 7497f38803 SECURITY: bind Data Explorer report parameters instead of inlining them (#43081)
Data Explorer used to splice report parameter values straight into the
saved SQL as escaped literals. When a report placed a parameter inside a
PostgreSQL dollar-quoted literal, a value could close that literal with
its own `$tag$` and append a second statement, because single-quote
escaping means nothing inside a dollar quote. A group member running
such a report through `POST /g/:group_name/reports/:id/run.json` could
use this to read any row the report's database role can see, such as
another user's email.

Values now reach PostgreSQL as bind parameters rather than as text.
`run_query` rewrites each `:name` marker that sits in real code to a
positional `$N` placeholder, collects the values, and passes them to
`async_exec_params`, so a value can never be parsed as SQL no matter
what it contains. This also closes the multi-statement path, since
`exec_params` refuses more than one command.

While the lexer is still regex-based, it is no longer part of the
security paradigm of data-explorer.

- A single lexer, `scan_sql_segments`, walks the SQL once and tells the
rewriter which `:name` markers are real code and which sit inside a
string, comment, or dollar-quoted literal that must be left alone.
- A parameter inside a dollar-quoted literal cannot be a bind, so it is
rejected with a clear error instead of being silently mishandled.
- A list value expands to a run of placeholders, so `IN (:ids)` keeps
working.
- The workflow raw SQL node runs through the same bind path via
`run_query_with_values`, and the old inline `interpolate_params` and its
escaping are gone.
2026-09-01 14:49:22 +01:00
David Taylor 439efc7419 DEV: Introduce system for renaming CSS variables (#42733)
From time-to-time, variables may need to be renamed in core. To avoid
breaking existing themes and plugins, this commit introduces a system to
automatically rewrite old variable names to new ones. A list of renames
is maintained in `stylesheets/variable-renames.json`, and is applied
when CSS is compiled. This list also powers a stylelint rule which will
automatically rewrite old names to new names in source code.

Transformations apply to all core/theme/plugin code. For now, the
stylelint rule/autofix applies to core only, but this will be extracted
to `@discourse/lint-configs` in the near future.

When a transformation is applied, it adds a trailing `/* automatically
renamed --old to --new */` comment so that the behavior is
understandable from the browser developer tools.
2026-09-01 11:34:46 +01:00
David Taylor aa627483b9 DEV: Add discourse/types version to plugin package.json files (#43071)
So that dependabot will keep them up-to-date
2026-09-01 11:29:11 +01:00
David Taylor 529282ca1e DEV: Introduce composer-minimum-post-length valueTransformer (#42686) 2026-08-20 14:26:51 +01:00
David Taylor 016b4a39dd Revert "DEPS: Bump landlock to 0.4.1 (#42766)" (#42770)
This reverts commit d73d6363e5.
2026-08-20 17:00:55 +08:00
David Taylor f9f8b522d5 DEV: Bump pnpm to v10.34.5 (#42721)
In particular, this resolves a bug which caused two copies of libc to be
pulled incorrectly:
https://github.com/pnpm/pnpm/commit/bb8baa7cff48d4bafb0895dc0ec42d0b367ffc7a
2026-08-19 12:58:41 +01:00
David Taylor 03b114b24a FEATURE: type: icon support for theme settings (#42626)
Mirrors site-setting support added in 802fa4c356.

Also updates the sprite-sheet logic so that it includes all site/theme
settings with `type: icon`, in addition to the existing logic which
looked for setting names ending in `_icon`.
2026-08-14 17:11:09 +01:00
David Taylor dbd870bea0 UX: fit review queue images to the content box (#42583)
Images in the review queue could render at their natural size and spill
out of the post content box, which made moderating a post with a large
image awkward. The topic stream caps images with a rule on `.cooked`,
but the review queue renders into `.review-item__post-content`, so
nothing applied there.

This is most visible on posts waiting for approval, since their content
is cooked straight from the raw text and never goes through the image
resizing that a published post gets.

- Cap images in `.review-item__post-content` at the width of the box and
let the height follow.
- Leave avatars and emoji alone so they keep their own sizing.
2026-08-14 09:54:44 +01:00
David Taylor cbdeb06da1 FIX: Reference correct setting name for contains_media (#42581) 2026-08-13 16:23:45 +01:00
David Taylor ab8b989303 DEV: Determine block customization source at build time (#42553)
Previously, the blocks API used the backtrace (via `identifySource()`)
to find the owner of a block. This is relatively slow, and can be broken
by things like browser extensions or other theme/plugin scripts.

This commit updates PluginApi instances so that they accept a `source`,
and sets up the theme/plugin build system to automatically pass that
source. Theme and plugin authors continue importing the plugin-api and
api-initializer as normal, and a virtual module is used to intercept the
import and provide a wrapped version.

Alternative implementation to #41090
2026-08-13 15:27:39 +01:00
David Taylor cbd4986480 DEV: Bump ember-exam and drop patch (#42555)
This fix has now landed upstream
2026-08-12 20:48:27 +01:00
David Taylor a3f1835810 DEV: Remove unused DiscourseURL.controllerFor (#42526)
This isn't called from core or any known theme/plugin
2026-08-12 17:10:34 +01:00
David Taylor 1170faedd7 DEV: Bump mini_racer and update AssetProcessor (#42488)
mini_racer 0.22.0 adds `call_await`, which means we can remove a number
of async-related workarounds in asset-processor.
2026-08-12 15:45:17 +01:00
David Taylor b1b6a555b7 DEV: Refactor exception controller (#42544)
- Remove computed properties
- Move interface to service, so that other code doesn't need to use the
private router or inject the controller
2026-08-12 11:54:01 +01:00
David Taylor 7cf99723c5 DEV: Remove unused custom component hook from category edit panels (#42522)
`EditCategoryPanel` rendered a `customComponent` resolved by name
through the resolver, but nothing has ever passed one since the hook
shipped in 2015. Plugin category tabs use `registerEditCategoryTab` with
component classes instead. `buildCategoryPanel` now extends `Component`
directly and the empty base class is gone.
2026-08-11 17:42:09 +01:00
David Taylor d8c56a057b DEV: Use explicit imports for site-setting components (#42519) 2026-08-11 16:39:05 +01:00
David Taylor a69002956e DEV: Avoid {{component}} helper for plugin-supplied components (#42518)
The bulk-action modal's `setComponent` and sidebar section links'
`contentComponent` were already documented as taking component classes,
but rendering them through the `{{component}}` helper meant a string
would silently resolve through the resolver. Angle-bracket invocation
and `curryComponent` only accept classes, so string-based reliance can't
creep in.
2026-08-11 16:26:57 +01:00
David Taylor f74405cd90 DEV: Deprecate string-based resolution of empty-state-components (#42517) 2026-08-11 15:10:56 +01:00
David Taylor a11cacedb2 DEV: Bump web_hook_events_id_seq to bigint (#42485)
The column is already bigint, but the sequence was still integer, so
would break if any site exceeded max_int.

Migration is intentionally timestamped slightly in the past, so that it
can be cleanly backported to `release/2026.7`. This migration is
completely standalone, so ordering is not a concern.
2026-08-11 14:44:23 +01:00
David Taylor 7f1f91377b DEV: Add registerReviewableComponent plugin API (#42508)
Provides a way for plugins to register reviewable components without
using magic string-based lookups. This will be compatible with future
work on core/plugin/theme JS bundle splitting.
2026-08-11 13:38:52 +01:00
David Taylor 27f4f78a13 DEV: Set tsconfig: false for pretty-text-processor (#42483) 2026-08-10 17:12:22 +01:00
David Taylor cfed6b85b6 DEV: Build server-side PrettyText bundle with Rolldown (#41997)
Previously, lib/pretty_text.rb assembled the mini_racer context by
transpiling and loading ~50 JS modules one-by-one at boot. This commit
replaces that with a single Rolldown-built bundle, precompiled during
assets:precompile and cached on disk under a digest of its inputs. This
uses a new `PrecompiledBundle` class, which is extracted from
`AssetProcessor`.

The whole Ruby -> JS interface now goes through mini_racer's `call`,
which is significantly faster & safer than the old `.eval` strategy.

The plugin interface is maintained by registering modules in
`loader.js`. This is a similar compatibility strategy to the one
currently being used for frontend code.
2026-08-10 16:24:29 +01:00
David Taylor 7933776575 DEV: Tighten image_optim sandbox (#42473)
Create a dedicated tmp directory so that we don't have to grant
read/write access to the system-level tmp directory.
2026-08-10 14:31:37 +01:00
David Taylor f45c125743 DEV: Refactor client_settings_json caching (#42472)
Most site-setting-related data is cached in-process. The exception was
client_settings_json, which was cached in Redis. This could create some
surprising behaviors, especially during deploys while multiple versions
of the app are running against the same redis instance. It was somewhat
mitigated by keying on git_version, but this was not perfect (e.g. if
plugins change, or a patch is applied without committing).

This commit refactors things so that the client_settings and the
JSON-serialized copy are cached in-process along with the rest of the
site-settings data. This should be more robust, and also faster. It also
provides direct access to the client settings hash, before it's
serialized to JSON.
2026-08-10 14:31:12 +01:00
David Taylor 325eb4280d UX: Remove update priority handling in version checks (#42165)
Previously, api.dicourse.org would track whether an update is 'critical'
or not, and then change the color/design of the 'update available'
indicator in the dashboard. These flags have not always been set
reliably, and the extra complexity is not worth maintaining. If an admin
wants to find out what's included in an update, we now have a clear
changelog linked from the dashboard.
2026-08-10 13:48:39 +01:00
David Taylor d7105ba613 DEV: Remove /etc from default SafeExec paths (#42466)
`/etc` can sometimes include sensitive information. Better to list
specific files/directories for each use-case.
2026-08-10 12:49:21 +01:00
David Taylor e4507ffb27 FIX: Deprecation warning banners for boot-time deprecations (#42346)
We were only setting up the listener during the service initialization,
which meant that we missed any deprecations which were thrown before
that (e.g. hbs-extension).

This commit adds a new `registerUniversalDeprecationHandler` API which
supports replaying any deprecations which fired before the handler is
registered. Similar pattern to browser APIs like
`PerformanceObserver.observe(..., {buffered: true})`
2026-08-05 12:30:13 +01:00
David Taylor ff312a7e47 Revert "DEV: Switch letter avatar generation, topic OG image generati… (#42265)
…on and dominant color detection to use libvips (#42150)"

This reverts commit 8c315e3c39.

Internal t/188655
2026-08-03 13:50:43 +01:00
David Taylor b88e77d405 DEV: Bump development branch to v2026.8.0-latest.1 2026-07-31 22:01:37 +01:00
David Taylor 1a47bbf0af FIX: Clear disabled/deleted ProblemChecks automatically (#42243) 2026-07-31 21:18:28 +01:00
David Taylor ed7994da56 DEV: Restore landlock problem-check (#42172)
Reverts #42059, which dropped the `ProblemCheck::Landlock` check. This
restores the check, its spec, and re-registers it in the problem-check
list. The `landlock` locale string was left in place by the drop, so no
locale change is needed.
2026-07-30 15:13:37 +01:00
David Taylor 69f214374e DEV: Improve OIDC and OAuth2 plugin timeout handling (#42136)
- Make timeout configurable for OAuth2, to match OIDC

- Correctly log timeout errors

- Show nicer auth-failure screen to users, instead of the generic
'something went wrong' page
2026-07-29 18:22:40 +01:00
David TaylorandLoïc Guitaut 088af28a78 DEV: Use precise dates in versions.json (#42129)
Compute releaseDate and supportEndDate as the last Tuesday of the
relevant month (a fully-specified YYYY-MM-DD) instead of an approximate
YYYY-MM month, and convert the remaining vague values in versions.json
to their precise last-Tuesday equivalents.

---------

Co-authored-by: Loïc Guitaut <loic@discourse.org>
2026-07-29 15:21:42 +01:00
David Taylor 37b64504c9 FEATURE: Support markdown in tag descriptions (#41996)
We previously supported a subset of HTML in tag descriptions, but the
escaping/unescaping of characters wasn't perfectly consistent, so
results could be surprising.

This commit runs tag descriptions through our standard markdown
pipeline, which supports the same subset of HTML, plus real markdown. It
also adds the standard DEditor in tag editing forms. This has parity
with group/user bios, and with category descriptions.

Now the character support is clearly defined, and perfectly matches
other parts of Discourse.

---

<img width="527" height="545" alt="SCR-20260723-rdpm"
src="https://github.com/user-attachments/assets/812a9a3a-ece7-4594-8d9b-65e7e30649c8"
/>

---

<img width="564" height="213" alt="SCR-20260723-rduy"
src="https://github.com/user-attachments/assets/4ea4a6ff-81d3-4489-95b3-bf5f9b1e5fa0"
/>
---
2026-07-29 14:43:47 +01:00
David Taylor 2306592f89 DEV: Raise on missing GHSA during release (#42102) 2026-07-29 13:01:49 +01:00
David Taylor 8010956fe2 DEV: Resolve preload-store-test flake (#42084)
There is already a `#data-preloaded` on the page, which was interacting
badly with the test. Add before/after logic to temporarily remove the
real preload element while these tests run, then restore it afterwards.
2026-07-28 10:44:43 +01:00
David Taylor a071880169 DEV: Sandbox all image processing via Landlock (#42048)
- Update all imagemagick calls to go through a new `::Imagemagick`
wrapper, which wraps the command in `Discourse::SafeExec`
- Patch image_optim to force its calls through `SafeExec`

This provides robust defense-in-depth against vulnerabilities in image
processing binaries. Landlock is supported on Linux Kernel 5.13 and
above.
2026-07-27 18:27:34 +01:00
David Taylor 8b552f97d2 DEV: Drop landlock problem-check (#42059)
We're not quite using this for image-processing yet, so let's remove the
problem-check for now.
2026-07-27 16:54:51 +01:00
David Taylor 7c3e615934 DEV: Remove deprecated array .clear() call (#42051)
This was triggered when restoring a backup at `/admin/backups/logs`
2026-07-27 16:50:20 +01:00
David Taylor 226adb08ea DEV: Bump landlock, refactor, and add problem check (#42049)
- Bump landlock to 0.3
- Refactor `SafeExec` now that Landlock gem is always present (it's no
longer conditional in the Gemfile)
- Strip ENV even when landlock is unavailable (for more consistent
developer experience on macOS)
- Add problem check which alerts admins if a production instance is
running without landlock support
2026-07-27 13:51:16 +01:00
David Taylor 4a6959f6a2 DEV: Move upcoming-changes CSS to dedicated files, loaded last (#41987)
Ensures that UC CSS always wins over core CSS, even if they have the
same specificity
2026-07-24 16:57:22 +01:00
David Taylor 973af7b6bd DEV: Simplify topics/bulk deduplication test (#42006)
No need for 1M items to test this logic
2026-07-24 07:52:43 +08:00
David Taylor eb4759b28e SECURITY: DoS vis uncapped Bulk Topic Actions (#42001)
## Summary

Limit and deduplicate topic_ids for bulk actions.

## Source

- Patch Triage: https://patch.discourse.org/patch-triage/1477

Co-authored-by: discourse-patch-triage
<272280883+discourse-patch-triage[bot]@users.noreply.github.com>
2026-07-23 23:06:50 +01:00
David Taylor d2dc8d4f22 DEV: Drop empty core mobile/desktop stylesheets (#41988)
b1399d6a6f removed the last mobile/desktop-specific CSS from Discourse.
Everything is now handled by media queries in common scss.

This commit drops the mobile/desktop stylesheet infrastructure for core.
It remains in place for themes & plugins.

Much of the diff is updating specs to avoid mobile/desktop as fixtures,
and to remove argument defaults which no longer make sense.
2026-07-23 20:30:13 +01:00
David Taylor df011c5ba7 DEV: Move pnpm config from package.json to pnpm-workspace.yaml (#41991)
This is the more modern pattern. Having the config in `package.json` is
deprecated in pnpm 11.
2026-07-23 17:54:14 +01:00
David Taylor 9981e29915 DEV: Document bin/qunit regex filters (#41916) 2026-07-22 15:50:36 +01:00
David Taylor ce04edc1ae DEV: Enforce :where() for .uc-* upcoming-change classes via stylelint (#41917)
Upcoming changes with `body_class: true` add a `uc-*` class to `<body>`.
This class is temporary, so we do not want core/theme/plugin CSS to
become dependent on it. Therefore we must not allow it to contribute
specificity to selectors.

This commit adds a `discourse/uc-classes-in-where` which reports any
misuse of `.uc-*` classes, fixes up some existing cases, and documents
the pattern in the upcoming-changes skill.
2026-07-22 15:26:59 +01:00
David Taylor 0ba2b5a76b DEV: Ensure multiple rolldown devservers cannot run concurrently (#41913) 2026-07-22 14:19:13 +01:00
David Taylor 864f5200d9 DEV: Fix ai_image_caption_agent site setting leaking between specs (#41806)
Previously, `image_caption_enabled_validator_spec` saved the
`ai_image_caption_agent` override with a string key via
`SiteSetting.provider.save`, so the symbol-keyed `remove_override!`
cleanup never cleared it and a rolled-back agent id leaked into later
specs in the same worker, making `generate_post_image_captions_spec`
fail with `agent_missing` whenever the two ran together.

This change saves the override with a symbol key so it round-trips with
the standard cleanup, keeping the setting isolated per example.
2026-07-17 11:12:21 +01:00
David Taylor 858581dce9 UX: Do not log error for empty .discourse-compatibility file (#41804) 2026-07-17 10:55:00 +01:00
David Taylor 92bb4d422e DEV: Switch to hotlinked version of Zoom SDK (#41778)
Adding the Zoom SDK, and its react-related peerdeps, had a noticable
impact on Discourse core's build time. It created the largest JS chunk,
which took more than 10s to brotli-compress on our build machine.

Instead, we can load the built versions of the dependencies from Zoom's
CDN. Normally we try to avoid this because of the extra runtime
dependency. However, given that showing a Zoom meeting is already
dependent on Zoom's servers, that isn't a concern in this case.

Upstream docs for CDN-based SDK loading can be found
[here](https://developers.zoom.us/docs/meeting-sdk/web/get-started/).
2026-07-17 09:22:34 +01:00
David Taylor 4cee62dbd5 PERF: Only recompile stylesheets when required (#41735)
When precompiling stylesheets, we were forcibly recompiling, even if we
already had the correct stylesheet in the cache. This commit updates the
precompile job so that it tries to pull an already-compiled copy from
the database and cache it on disk, rather than doing a full recompile.
2026-07-16 12:14:28 +01:00
David Taylor 10087b16b7 DEV: Allow browser to cache stylesheets in development (#41736)
Stylesheets are all served with digests in their URL, so there's no need
for browsers to re-request identical files every time
2026-07-16 12:14:23 +01:00
David Taylor 6dfcbb6282 FEATURE: Support 'Happy Eyeballs' in FinalDestination::HTTP (#41680)
Ruby 3.4 shipped support for happy eyeballs in `Socket.tcp` and
`TCPSocket`. However, our `FinalDestination::HTTP` wrapper was
performing a DNS lookup and passing IP addresses one at a time when
opening the socket. That meant that we didn't benefit from the new Ruby
feature in most Discourse features.

This commit factors the strategy. Now, `FinalDestination::HTTP` encodes
the DNS result and passes it to the underlying implementation as a fake
hostname string. A patch to `Addrinfo` detects this fake hostname and
returns the given IPs instead of performing its own lookup.

For this Addrinfo patch to work, we also had to patch `TCPSocket` so
that it uses the ruby-based `Socket.tcp` rather than its native C
socket-opening code.

The result is that we now get the benefit of the native Ruby 'Happy
Eyeballs' support for concurrent ipv4 and ipv6 connections.

All this patching of low-level ruby classes is not ideal, but there is
no native way to control name resolution in `Net::HTTP` or its
dependencies.
2026-07-15 11:31:23 +01:00
David Taylor eeb3b3ff00 DEV: Add comments/typescript guidance to AI-AGENTS.md (#41666) 2026-07-15 09:36:42 +01:00
David Taylor 216dc56395 DEV: Add admin warning banner for es6-extension (#41702)
Followup to fd98c6d576
2026-07-14 15:52:41 +01:00
David Taylor fd98c6d576 DEV: Enable admin warning for all pending deprecations (#41697)
Support for these things will be removed soon after the next ESR
release.
2026-07-14 13:29:25 +01:00
David Taylor fdeb9ebc06 DEV: Bump ember-curry-component to 0.5.0 (#41658)
It now includes proper type definitions, so we need a couple tweaks to
our signatures
2026-07-13 15:26:56 +01:00
David Taylor 59588b5d2a DEV: Remove unused d-hover class reference (#41656)
This was used in the old widget system, but none of our templates use
this class name any more.
2026-07-13 11:12:29 +01:00
David Taylor 57c6c9d9ad DEV: Drop jquery from textarea-text-manipulation (#41628) 2026-07-13 10:32:44 +01:00
David Taylor 1fa84c250f DEV: Remove jQuery from composer-editor (#41520)
Port the editor/preview scroll sync to native DOM, and delete the unused
scroll-map logic. That code has been unreachable since 60851037
2026-07-08 16:47:24 +01:00
David Taylor de793bc6ed DEV: add typescript support for core, themes and plugins (#41478)
We've been using basic type-checking via JSDoc for some time. This
commit allows us to author proper `.ts`/`.gts` files, and use the full
typescript syntax. Initially, only d-button and a single chat file are
migrated, as proof of functionality.

In future, we may migrate more files, and consider making our tsconfig
more strict.
2026-07-08 12:57:18 +01:00
David Taylor 991cbda452 DEV: Modernize TopicNavigation component (#41513)
- Convert from a classic to glimmer

- Refactor `_checkSize` observer to be a declarative `renderTimeline`
getter, leaning on `TrackedMediaQuery`

- Drop jQuery

- Refactor drag handling to `modifierFn`

- Replace `canRender` + `didUpdateAttrs` re-render hack with the
`{{#each` pattern

- Replace the two-way `expanded` binding into `topic-progress` with an
`@onExpandToggle` callback

- Fix a pre-existing bug: `onSwipeEnd`/`onSwipeCancel` called
`shouldCloseMenu`/`getMaxAnimationTimeMs` as instance methods, but they
are module-level exports, so swipe-to-dismiss was throwing an error
2026-07-08 10:39:20 +01:00
David Taylor 3fbbcba19f FIX: Do not load tsconfig during core assets build (#41518)
Similar to 2d34d84d: we don't need this, and loading it can cause
problems if people mess with core plugins
2026-07-07 17:40:17 +01:00
David Taylor 2b9d19ab48 DEV: Drop JQuery from discourse-topic and modernize click-track (#41468)
click-track was relying on `e.currentTarget`, which may not be the
actual link in a vanilla-js event. It worked in JQuery because listeners
could be set with filters like `"a"`, and `currentTarget` would be set
accordingly. But in vanilla JS, `currentTarget` is the wrapper element
with the event-listener attached.

Instead, we can use `event.target.closest("a")` to find the actual link
element.
2026-07-07 16:59:29 +01:00
David Taylor b93d4420eb DEV: Bump glint to 1.8 and drop JSDoc import() extension workarounds (#41493)
Upgrades @glint/ember-tsc from 1.5 to 1.8.11 (along with @glint/template
1.7.8 and @glint/tsserver-plugin 2.5.17), which fixes extensionless
resolution of `.gjs`/`.gts` module imports under ember-tsc's `-b`
(solution build) mode used by `lint:types`. Previously extensionless
resolution only worked in single-project mode; the solution builder
bypassed Volar's resolution hook, so imports of `.gjs`/`.gts` modules
without an explicit extension failed with TS2307.

Upstream fixes:
https://github.com/typed-ember/glint/commit/f1b13305e5d49c44b1dc651d75f6d69ab3a69a03
and
https://github.com/typed-ember/glint/commit/b519399e0ef6aeab6ad65da97bdf16138f0f490e

With extensionless resolution now working, the `/** @type
{import("….gjs").default} */` hints placed above component imports to
force type resolution are redundant, so they are removed.

Also broadens d-otp's `onInput` parameter type from `InputEvent` to
`Event`, which glint 1.8 correctly requires for the `{{on "input" …}}`
binding: the handler must accept the generic event the modifier
provides.
2026-07-06 22:06:35 +01:00
David Taylor 2ef5ce2cf1 DEV: Bump prettier-plugin-ember-template-tag and reformat (#41489)
As of 2.1.7 the plugin correctly enforces the `templateExportDefault:
true` option.
2026-07-06 19:18:44 +01:00
David Taylor f3b72660ac DEV: Drop (almost)-unused TopicEntrance component (#41424)
We stopped using this UI in most topic lists as part of the raw-hbs ->
glimmer conversion, since it was seldom-used, and simple links are a
better UX.

However, the implementation remained, and it was still accessible in
some very specific places (e.g. user-activity/topics on mobile devices).

This commit strips out the implementation, so we have consistent
behavior across all topic lists.
2026-07-03 17:18:35 +01:00
David Taylor c57265f88a DEV: Drop unused decorateCooked from discourse-details (#41426)
This has been a no-op since 8f2f9e6afa in 2020, when we removed the JS
polyfill of `<details>`
2026-07-03 17:18:20 +01:00
David Taylor 1599e156d2 DEV: Convert caret-position from JQuery to vanilla JS (#41428)
This was verified by a/b testing a large number of scenarios against old
and new implementations, and confirming that they returned precisely
identical coordinates.
2026-07-03 17:14:19 +01:00
David Taylor d43833cf68 DEV: Convert reactions animations from JQuery to native (#41427) 2026-07-03 17:14:10 +01:00
David Taylor c1879db224 DEV: Drop jquery in patreon plugin (#41425)
This was doing direct manipulation of ember-rendered DOM, which is
risky. This commit changes it to be a simple non-animated closure, which
is safer, and more in line with other Discourse UX.
2026-07-03 17:13:54 +01:00
David Taylor 325ed5c1a9 DEV: Remove jquery usage from lib/url (#41422) 2026-07-03 17:13:46 +01:00
David Taylor 26810e97c0 DEV: Remove jquery from select-kit-helper and category-badge-test (#41421)
- The 'selectAll' path in the select-kit-helper is completely unused, so
we can just drop it

- Update HTML parsing in category-badge-test
2026-07-03 17:13:44 +01:00
David Taylor 62a5798b78 FIX: Prevent error when a reviewable claim is broadcast for a topicless reviewable (#41418)
Previously, claiming a topic in the review queue threw `Cannot read
properties of null (reading 'id')` in every `ReviewableItem` whose
reviewable had no associated topic (e.g. `ReviewableUser` or a queued
new topic), because `_updateClaimedBy` dereferenced
`this.reviewable.topic.id` on the `/reviewable_claimed` broadcast.

This change compares against the existing `topicId` getter, which safely
resolves the topic id and lets topicless reviewables ignore the
broadcast instead of erroring.
2026-07-03 13:10:23 +01:00
David Taylor 868ca5e0aa DEV: Use sinon to stub capabilities.touch (#41419)
Using `Object.defineProperty` means that it persists and affects other
tests in the suite

Followup to 64d03062de
2026-07-03 13:10:07 +01:00
David Taylor 97e102c6c5 FIX: Stop asset-processor build from loading tsconfig (#41415)
Our tsconfig is designed for development use only, and is not needed for
a successful asset-processor build.

In most cases, it didn't cause a problem. However, if someone does `rm
-rf` on a core plugin, then it causes core's tscconfig to become
invalid, which then breaks the asset-processor build.
2026-07-03 10:30:13 +01:00