- we don't need to load this if we haven't configured Node profiling to occur
- this might help fix random segfaults we've been seeing in CI, which
only started occurring after this dependency was added
refs ARCH-29
- Added Sentry Profiling to collect more detailed performance data on
the backend.
- This feature is opt-in behind a config. To enable profiling, first
enable tracing with `sentry.tracing.enabled: true`, then set
`sentry.profiling.enabled: true` and `sentry.profiling.sampleRate` to a
decimal number between 0 and 1.
refs TryGhost/Product#4125
This PR adds two new integration tests to ensure all our Koenig cards
are rendered properly after going through the EmailRenderer. Although we
have thorough tests for the cards themselves in the Koenig repo, the
EmailRenderer does post-processing on the rendered HTML, such as
inlining CSS, which can adversely impact the rendered output of our
cards in email clients (usually Outlook).
Since email newsletters are a core feature of Ghost, these bugs are
typically fairly urgent, and since it is email, they are also quite
difficult to troubleshoot and fix. These two tests are intended to
prevent bugs of this sort, which in the past have been created by
seemingly harmless changes like bumping dependencies that are used in
the EmailRenderer.
The idea is to create a 'Golden Post' which has at least 1 of every card
from Koenig, run that post through the EmailRenderer, and take a
snapshot of the rendered HTML. In the future, if we make any changes to
the EmailRenderer or the Koenig cards themselves, this will trigger us
to carefully consider the changes, and it provides an 'expected' output
to compare our changes against.
Additionally, the second test simply checks that all cards from
`kg-default-nodes` are included in the 'Golden Post'. This protects
against any new cards that we will add in the future — as soon as we add
them to Koenig and bump `kg-default-nodes` in Ghost, this test will
fail, prompting us to add the new card to the Golden Post and update the
snapshots.
We should also run the 'Golden Post' through a test in Litmus, which
allows us to visually inspect the rendered email across many different
email clients. Ideally we would create a process to review the output of
the 'Golden Post' in Litmus whenever we update the snapshot as well.
refs ARCH-21
- We currently have NewRelic setup for a few of our largest customers
for monitoring performance, but it is too expensive to enable across all
sites
- Sentry has similar (but simpler) performance monitoring tools to keep
track of response times that are available to us for free, but we just
haven't configured them
- This PR sets up Sentry Performance monitoring for API requests so we
can have one place for monitoring errors + performance so we can stay on
top of response times more easily.
- Tracing is disabled by default, so there is no additional overhead
unless `sentry.tracing.enabled` is set to `true` in the site's config.
Additionally, `sentry.tracing.sampleRate` should be set to a decimal
value between 0 and 1. This value defaults to 0 to avoid accidentally
blowing through quota, and requires a value to explicitly be set in
order to send the traces to Sentry.
refs https://github.com/TryGhost/Product/issues/4209
- bumped Koenig packages
- `koenig-lexical` added nested editor TK support
- all packages dropped Node 16 support
- switched to using `isTKEnabled` prop and `<TKCountPlugin>`
Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
fixes PROD-61
This adds a new default plan setting. It defaults to yearly, which is
the current default selected interval in Portal.
Behind the new portal improvements feature flag, the default plan can be
changed. It will also change automatically if the available intervals
are changed.
This PR also wires up passing the new setting to the Portal preview.
fixes https://github.com/TryGhost/Product/issues/4216
When generating page/post metadata, we generate a "context object" from
several meta helpers. In the event there is no context from the resource
type, we generate a fallback object.
However... we generate this fallback object no matter what.
Now, the fallback object is just 3x settingsCache.get, which should be
fast, but it's not. I've opened a separate issue for that: https://github.com/TryGhost/Product/issues/4217
In the mean time, we can switch this logic around to only do these calls
when we have no other context.
From testing, this allows for 10% more throughput on a post 🤯
fixes GRO-72
- added "default_email_address" and "support_email_address" to the
public settings
- when available, use these addresses in Portal. Otherwise, fallback to
current logic
refs https://github.com/TryGhost/Product/issues/4196
The offers API basically returns the data you pass to it, rather than
the created database record. It looks like this is how it was intended
to work in the first place; the `setMilliseconds` is because the test
helper expects `.000Z`, which I assume is because MySQL will strip off
the milliseconds when it's saved.
fixes GRO-71
- Current flow: unchanged
- New managed flow: verification required
- New managed flow with custom sending domain: only verification
required for different domains
- Self hosters (feature flag): no verification required
closes https://github.com/TryGhost/Product/issues/4191
Without this patch, themes can read arbitrary files from your system and
expose them to the internet via the layout feature of express-hbs.
For example `{{!< ../../../../config.production.json}}` would spit out config,
which can contain secrets.
As theme upload is restricted to users with the Admin role, this mostly effects
hosting providers which use their own secret keys for e.g. mail or database config
refs https://github.com/TryGhost/Product/issues/4181
We were seeing slow queries when joining on this table, and the index
speeds them up. The down migration is tricky because when we add the
index MySQL can optimise away some `KEY` indexes on the `newsletter_id`
column. When we then go to remove the newly created index, there is no
index for the FK!
We also remove the use of `force index` as 1. the index we're forcing is
optimised away and 2. we don't need it anymore!
Co-authored-by: Daniel Lockyer <hi@daniellockyer.com>
refs GRO-80
- added a new meta field "email_verified" to the /verification endpoint
for newsletters. This meta field contains which email has been verified,
"sender_email" or "sender_reply_to"
- updated copy in newsletter settings, based on which email has been
verified
fixes GRO-73
We need to avoid duplicating the complex logic for determining the
default email address and the support email address. So these are now
exposed as calculated settings.
ref GRO-54
fixes GRO-63
fixes GRO-62
fixes GRO-69
When the config `hostSettings:managedEmail:enabled` is enabled, or the
new flag (`newEmailAddresses`) is enabled for self-hosters, we'll start
to check the from addresses of all outgoing emails more strictly.
- Current flow: nothing changes if the managedEmail config is not set or
the `newEmailAddresses` feature flag is not set
- When managedEmail is enabled: never allow to send an email from any
chosen email. We always use `mail.from` for all outgoing emails. Custom
addresses should be set as replyTo instead. Changing the newsletter
sender_email is not allowed anymore (and ignored if it is set).
- When managedEmail is enabled with a custom sending domain: if a from
address doesn't match the sending domain, we'll default to mail.from and
use the original as a replyTo if appropriate and only when no other
replyTo was set. A newsletter sender email addresss can only be set to
an email address on this domain.
- When `newEmailAddresses` is enabled: self hosters are free to set all
email addresses to whatever they want, without verification. In addition
to that, we stop making up our own email addresses and send from
`mail.from` by default instead of generating a `noreply`+ `@` +
`sitedomain.com` address
A more in depth example of all cases can be seen in
`ghost/core/test/integration/services/email-addresses.test.js`
Includes lots of new E2E tests for most new situations. Apart from that,
all email snapshots are changed because the from and replyTo addresses
are now included in snapshots (so we can see unexpected changes in the
future).
Dropped test coverage requirement, because tests were failing coverage
locally, but not in CI
Fixed settings test that set the site title to an array - bug tracked in
GRO-68
refs TryGhost/Product#4175
- Added error handling to Sentry's beforeSend function in both Admin and
Core, so if there is any error in beforeSend, we will still send the
unmodified event to Sentry
- This is in response to an incident yesterday wherein the beforeSend
function threw an error due to an unexpected missing value in the
exception. The event sent to Sentry was the error in the beforeSend
function, and the original error never reached Sentry.
- If the original event had reached Sentry, even if unmodified by the
logic in beforeSend, we could have been alerted to the issue sooner and
more easily identified all affected sites.
- Also added defensive logic to protect for certain values in the
exception passed to beforeSend not existing and added unit tests for the
beforeSend function in admin and core
refs https://github.com/TryGhost/Product/issues/4181
- we've seen MySQL change its query planner to use a different index
than the ideal one, resulting in drastically slower query performance
when fetching newsletters with the member count
- this forces the use of the ideal index on MySQL
- this kept many of the Ghost team up overnight, so I hope MySQL is
happy
fixes GRO-34
fixes GRO-33
This is a revision of a previous commit, that broke the browser tests
because changes in the data generator (requiring bookshelf had side
effects).
This adds a new way to run all tests with enforced numeric ObjectIDs.
These numeric ids cause issues if they are used withing NQL filters. So
they surface tiny bugs in our codebase.
You can run tests using this option via:
NUMERIC_IDS=1 yarn test:e2e
Removed some defensive logic that could be explained by this discovered
issue.
refs https://github.com/TryGhost/Arch/issues/101
Refined the cache invalidation logic so that when updating a user, we
only invalidate the cache when an attribute of the user that is used on
the frontend changes.
refs https://github.com/TryGhost/Product/issues/4152
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖[[deprecated]](https://githubnext.com/copilot-for-prs-sunset)
Generated by Copilot at a28462f</samp>
This pull request adds a new admin-x app called `admin-x-demo`, which
demonstrates how to use the shared packages `admin-x-framework` and
`admin-x-design-system` to create a simple app that renders a button and
a modal. It also improves the development workflow, the vite
integration, the dependency management, and the type checking for the
admin-x apps and packages. It modifies some files in the
`admin-x-framework` and `admin-x-design-system` packages to make the
modals prop optional, to introduce a new type for the props from the
Ember app, to fix the z-index of the modal backdrop, and to use
consistent file extensions and module syntax.
fixes GRO-34
fixes GRO-33
This also adds a new way to run all tests with enforced numeric ObjectIDs.
These numeric ids cause issues if they are used withing NQL filters. So they
surface tiny bugs in our codebase.
You can run tests using this option via:
NUMERIC_IDS=1 yarn test:e2e
Also removed some defensive logic that could be explained by unquoted ids.
refs https://github.com/TryGhost/Product/issues/4140
- added `social-image` image size to our `internalImagesSizes` list with a max-width of 1200
- extracted image utils from `{{img_url}}` helper to a utils file for re-use
- updated `getImageDimensions` method that reads image dimensions and modifies the finalised `metaData` object before use to adjust dimensions and associated URLs to match max width of 1200px
refs https://github.com/TryGhost/Product/issues/4159
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖[[deprecated]](https://githubnext.com/copilot-for-prs-sunset)
Generated by Copilot at 9e68f4d</samp>
This pull request refactors several components in the `admin-x-settings`
app to use common hooks from the `@tryghost/admin-x-framework` package,
which reduces code duplication and improves consistency. It also updates
the `package.json` file and adds unit tests for the `admin-x-framework`
package, which improves the formatting, testing, and dependency
management. Additionally, it makes some minor changes to the `hooks.ts`,
`FrameworkProvider.tsx`, and `.eslintrc.cjs` files in the
`admin-x-framework` package, which enhance the public API and the
linting configuration.
refs https://github.com/TryGhost/Product/issues/4051
- added a "List-Unsubscribe" header to emails, in compliance with the
RFC 8058 requirements
- Gmail, Apple Mail, Yahoo Mail, and other popular email clients offer
an option to unsubscribe in one-click, based on the "List-Unsubscribe"
header. Some require an HTTPS endpoint, some a mailto address; both
options are provided in the "List-Unsubscribe" header
Co-authored-by: Simon Backx <simon@ghost.org>
Co-authored-by: Djordje Vlaisavljevic <dzvlais@gmail.com>
refs https://github.com/TryGhost/DevOps/issues/3
refs b6d8e0192a
- see referenced commit for full context but this should improve the
theme check time for themes with a large number of files and partials
- locally, checking a particularly heavy theme goes from 5s to 1.7s with this
commit, and the improvement is larger on slower machines
ref https://ghost.slack.com/archives/C02G9E68C/p1700129928489809
- When the GET /api/session endpoint is called, the session is deleted
if it is invalid
- We don't have a body parser for this GET endoint, and the request
object was passed to the deleteSession handler. This caused a type error
(cannot read properties of undefined)
- We had dangling promise because deleteSession is async and wasn't
awaited, causing random errors in tests
- Added a test that would have caught this earlier
refs https://github.com/TryGhost/Product/issues/4153
- We need use the `created_at` timestamp in the new AdminX offers. The
API doesn't return that value.
- With this change the API returns the created_at property so that we
can consume it.
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖[[deprecated]](https://githubnext.com/copilot-for-prs-sunset)
Generated by Copilot at dc282af</samp>
This pull request adds a `createdAt` property to the offer domain model,
data transfer object, and repository. This allows tracking and auditing
the creation and modification of offers and offer codes in
`ghost/offers`.
fixes GRO-25
Updated @tryghost/nql to 0.12.0 and other packages that depend on it
1. SQLite: when a filter string contains /.
When we use a NQL contain/starts/endsWith filter that contains a slash,
underlyingly the whole filter will get converted to a MongoDB query, in
which we just use a regexp to represent the filter. In here we will
escape the slash: \/ as expected in a regexp. Later when we convert this
MongoDB query back to knex/SQL, we use a SQL LIKE query. Currently we
don't remove the escaping here for a normal slash. MySQL seems to ignore
this (kinda incorrect). SQLite doesn't like it, and this breaks queries
on SQLite that use slashes. The solution here is simple: remove the
backslash escaping when converting the regexp to LIKE, just like we do
with other special regexp characters.
2. We don't escape % and _, which have a special meaning in LIKE queries
Usage of % and _ is now as expected and doesn't have the special SQL
meaning anymore.
fixes https://github.com/TryGhost/Product/issues/3738https://www.notion.so/ghost/Member-Session-Invalidation-13254316f2244c34bcbc65c101eb5cc4
- Adds the transient_id column to the members table. This defaults to
email, to keep it backwards compatible (not logging out all existing
sessions)
- Instead of using the email in the cookies, we now use the transient_id
- Updating the transient_id means invalidating all sessions of a member
- Adds an endpoint to the admin api to log out a member from all devices
- Added the `all` body property to the DELETE session endpoint in the
members API. Setting it to true will sign a member out from all devices.
- Adds a UI button in Admin to sign a member out from all devices
- Portal 'sign out of all devices' will not be added for now
Related changes (added because these areas were affected by the code
changes):
- Adds a serializer to member events / activity feed endpoints - all
member fields were returned here, so the transient_id would also be
returned - which is not needed and bloats the API response size
(`transient_id` is not a secret because the cookies are signed)
- Removed `loadMemberSession` from public settings browse (not used
anymore + bad pattern)
Performance tests on site with 50.000 members (on Macbook M1 Pro):
- Migrate: 6s (adding column 4s, setting to email is 1s, dropping
nullable: 1s)
- Rollback: 2s
closes https://github.com/TryGhost/Product/issues/4133
- we were creating a new JSDOM instance every time we rendered a card which lowered performance because JSDOM instantiation is heavy
- updated Koenig packages to remove the need for passing in an external `createDocument` option method as they now re-use the renderer's internal single instance of JSDOM
refs https://github.com/TryGhost/DevOps/issues/105
- this will run a small benchmark on the boot time for Ghost, and push
the stats to another repository which has GitHub Pages enabled, so we
can visualise the change over time
- will only run on pushes to `main` so we don't pollute the stats with
commits from PRs
- just a test for now to see if we get stable numbers
closesTryGhost/Product#4136
- the `/p/` route is only intended for drafts, not published content
(e.g. sent newsletters)
- email-only posts (newsletters) do not get assigned a slug, and could
still be viewed at `/p/:uuid`, which didn't hide paid/member content
fixes https://github.com/TryGhost/Product/issues/4108
- Updates filters behind a new alpha feature flag so you can also filter
on members who have email disabled (because the email had a permanent
bounce, they reported spam or the email address is invalid)
- When returning members, we now also use the email_disabled flag to set
email_suppression.suppressed correctly (in case they are out of sync,
which should normally never happen).
closes https://github.com/TryGhost/Product/issues/4075
- when a member clicks on "Unsubscribe from that list" from Apple Mail,
the member's email is put into Mailgun's Unsubscribe suppression list.
Ghost listens for "Unsubscribe" events from Mailgun, and unsubscribes
the member from all the newsletters
- now, the member is only unsubscribed from the newsletter they
unsubscribe to (not all of them)
- now, the email is also deleted from Mailgun's suppression list, so
that it doesn't affect any other membership
fixes https://github.com/TryGhost/DevOps/issues/99
- this inlines the `monobundle` script into the monorepo from an
external repo in order to avoid some caching issues we've seen
- it also makes it easier to maintain because you can change the script
alongside changes in the monorepo
refs https://github.com/TryGhost/Product/issues/4095
- Removes `min-height` of the card in order to make the template more
flexible half-empty states look better (missing description, short
description, featured image...)
- Fixes wrong variables used in Outlook-specific template
fixes https://github.com/TryGhost/Product/issues/4118
The newsletter uuids were not passed when fetching all the members current newsletters. Therefore, Portals logic broke to remove all newsletters that matched the uuid that was passed to the unsubscribe link. No newsletters were removed, still the notification toast said that the member was unsubscribed from the newsletter.
refs https://github.com/TryGhost/Product/issues/4086
- we're seeing random test timeouts on CI but not locally, these logs should help pinpoint if it's the require that's taking a long time, the conversion itself, or something else entirely
refs https://github.com/TryGhost/Product/issues/4098
- added basic metadata (title, description, image, url) on the password
wall for private sites
- when a private site recommends me, I can now see the usual metadata
ref https://github.com/TryGhost/Product/issues/4110
Made this change to increase clarity in data export
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 6c0508d</samp>
Renamed a column in posts export data and updated the corresponding test
case. This change makes the export data more consistent and clear for
users who have different member features enabled.
no issue
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 474a274</samp>
This pull request fixes a timezone display bug in the admin and post
settings. It also updates the `publishing.spec.js` file to test the
timezone functionality with a consistent option.
refs https://github.com/TryGhost/Product/issues/4055
---
<!-- Leave the line below if you'd like GitHub Copilot to generate a
summary from your commit -->
<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 3b24693</samp>
Removed unused components related to announcement settings, custom theme
settings, and file upload. These components were part of a deprecated
feature or a legacy UI.
no issue
When a custom welcome page is set for a tier, the recommendations modal
didn't show. If recommendations were disabled, there was also no toast
to confirm the sign up.
To fix this, we'll need to set the success and action query parameters
on the welcome page, but only if it is not an external site.
fixes https://github.com/TryGhost/Product/issues/4102
E.g. you recommend myghostsite.com, while that site redirects all
traffic to [www.myghostsite.com](#):
The redirect causes CORS issues, which means we cannot detect
one-click-subscribe support.
- This is fixed by moving the whole detection to the backend, which has
the additional benefit that we can update it in the background without
the frontend, and update it on every recommendation change.
- This change also fixes existing recommendations by doing a check on
boot (we can move this to a background job in the future).
closes https://github.com/TryGhost/Product/issues/4046
- when editing the member's email in Admin, the email_disabled field was
not recalculated, making it inconsistent with the suppression list
- now, if the new email is part of the suppression list, we set
email_disabled to true. Otherwise set it to false
closes https://github.com/TryGhost/Product/issues/4098
- when a site is private, the metadata title is "My Site — Private Site
Access". When fetching the metadata via oembed, we get "Private Site
Access" as publisher, and "My Site — Private Site Access" as title
- this fix removes "- Private Site Access" from the metadata title when
a Ghost site is private
no refs
Fixed error caused by uploading empty redirects YAML file:
```
Cannot read properties of undefined (reading '302')
```
This error was occurring due to `yaml.load` returning `undefined` when
the provided yaml file was empty. I've made the check on the return
value of `yaml.load` stricter (i.e we only want an `object`) to prevent
this error from occurring.
closes https://github.com/TryGhost/Koenig/pull/1038
- updated `<KoenigLexicalEditorInput>` to load `<EmojiPickerPlugin>` and compose it into the editor unless used with `<KoenigLexicalEditorInput @emojiPicker={{false}} />`
- bumped Koenig packages so `EmojiPickerPlugin` is available to import from `koenig-lexical`
refs TryGhost/Product#4083
- In the vast majority of cases, we shouldn't have SQL errors in our
code. Due to some limitations with validating e.g. nql filters passed to
the API, sometimes we don't catch these errors and they bubble up to the
user.
- In these rare cases, Ghost was returning the raw SQL error from mysql
which is not very user friendly and also exposes information about the
database, which generally is not a good practice.
- To make things worse, Sentry was treating every instance of these
errors as a unique issue, even when it was exactly the same query
failing over and over.
- This change improves the error message returned from the API, and also
makes sure that Sentry will group all these errors together, so we can
easily see how many times they are happening and where.
- It also adds more specific context to the event that is sent to
Sentry, including the mysql error number, code, and the SQL query
itself.
refs https://github.com/TryGhost/Product/issues/4088
The Content API should not expose the lexical/mobiledoc source content because it's not membership-gated and although not used at the present time may in future contain additional internal metadata. We were handling this for the more-typical `?formats` param but it was still possible to access this data using the `?fields` param.
- updated post mapper used in our API output serializers to strip the `mobiledoc` and `lexical` fields ready for API output
- credits to Prathap Puthran for reporting
fixes https://github.com/TryGhost/Product/issues/4085
Increases the performance for the post analytics export by adding new
indexes. These indexes are used when counting the amount of (paid)
subscribers that were attributed to a given post. With the indexes, the
time required to export 700 posts with 300k members decreases from 40s
to 0.6s.
Tests show that adding these indexes should be very fast (< 1 s) if the
tables contain up to 300k rows.
closes https://github.com/TryGhost/Product/issues/4084
---
### <samp>🤖 Generated by Copilot at 9380e1f</samp>
This pull request adds a new UI for creating and managing offers for
members in the admin settings, which is controlled by an alpha feature
flag. It introduces new modal components for the offers UI, a new
sidebar item, new routes, and a new setting group. It also updates the
`labs.js` file to include the `adminXOffers` flag.
- resolves `DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead` in tests
refs https://github.com/TryGhost/Product/issues/4053
This adds the feature flag. If enabled, the list-unsubscribe header
should be set. The value currently is only for testing purposes and
probably won't work yet.
no issue
- flag is no longer used in Admin so we can clean it up in Core too
- updated Post model to set blank document to `lexical` field rather than `mobiledoc` as a default value
- switched over to returning `mobiledoc,lexical` as default formats in Admin API
no issue
- updates `@tryghost/koenig-lexical` with indent improvements
- prevents indents on paragraphs/headings etc which are not supported when rendering for front-end display
- improves indent behaviour for lists so <kbd>Tab</kbd> can be pressed anywhere in a list item to indent rather than only at the beginning of the list
closes https://github.com/TryGhost/Product/issues/4037
- bumps `@tryghost/kg-html-to-lexical` that includes better node normalization to handle `<br>` in top-level text nodes and after a nested block-level element
- also includes fix for button hrefs having `about:blank` prefixed to hash URLs
refs https://github.com/TryGhost/Product/issues/3831
---
### <samp>🤖 Generated by Copilot at 539c2d3</samp>
This pull request updates and adds some test cases for the date picker
and newsletter features in the Ghost admin panel. It introduces a test
helper function for the date picker in `editor-test.js`, and removes a
redundant test case from `publish-flow-test.js`. It also adds two new
test cases in `publishing.spec.js` using the Playwright framework to
verify the timezone and recipient settings for publishing posts.
closes https://github.com/TryGhost/Ghost/issues/18448
- improved slash menu positioning when opening at the bottom of a post
- fixed backspace sometimes deleting a preceding card (e.g. backspace at end of link inside a paragraph preceded by a card)
- fixed `?source=html` issues
- images not rendering in front-end output after import
- images wrapped in links losing their link after import
- fixed inline styles in HTML card content not displaying in the editor
- fixed broken help link in the email card
no issue
- Casper and Source theme files were out of date — this commit updates the theme fixtures, and fixes up a few tests to pass with the updated themes
closesTryGhost/Product#4032
- the api flag ?convert_to_lexical converts a mobiledoc string to
lexical
- if run on a post/page with lexical content, would null it out
- this optimizes the number of `get` calls we need to do to the adapter
for settings cache
- for example, this prevents ~187 calls to the adapter during boot
- right now we use the in-memory adapter for settings, so there's probably
not much benefit, but if we ever switch to the Redis adapter, this will
help prevent a lot of extra Redis calls
no issue
Some flaky tests found, and it seems as though they're being caused by an invalid Stripe account id.
It's possible that by re-using the worker after a test which calls `setupStripe` could cause some Stripe functionality to not work.