ghost 6.0.10 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/components/tryghost-i18n-6.1.0.tgz +0 -0
  2. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +1 -1
  3. package/core/built/admin/assets/admin-x-activitypub/{index-wBqnq7A5.mjs → index-DmCoswaX.mjs} +2 -2
  4. package/core/built/admin/assets/admin-x-activitypub/{index-XhNX0QuF.mjs → index-lT95Q15h.mjs} +8212 -8183
  5. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-BDBDWpWl.mjs → CodeEditorView-Bu9qXr9c.mjs} +2 -2
  6. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  7. package/core/built/admin/assets/admin-x-settings/{index-BB7hgOf0.mjs → index-BEpRBH9g.mjs} +2 -2
  8. package/core/built/admin/assets/admin-x-settings/{index-DsbJfrQ7.mjs → index-qEdfz2hd.mjs} +94 -94
  9. package/core/built/admin/assets/admin-x-settings/{modals-CCpr5VWU.mjs → modals-BtQORnS4.mjs} +6 -6
  10. package/core/built/admin/assets/{chunk.524.695215c994f8cbf547d3.js → chunk.524.2aa0847042f20c9a2a00.js} +7 -7
  11. package/core/built/admin/assets/{chunk.582.a949b80543caba37906c.js → chunk.582.9182c19afab95991771e.js} +8 -8
  12. package/core/built/admin/assets/ghost-791574a9e2efe65c88412947d2e80170.css +1 -0
  13. package/core/built/admin/assets/{ghost-9c608430440a10746540adb7d2cd0f31.js → ghost-9c47d152972b304cab0fb982dc3fccc1.js} +38 -34
  14. package/core/built/admin/assets/ghost-dark-1a7d101d525c0fdcf406ac0abd98540f.css +1 -0
  15. package/core/built/admin/assets/posts/posts.js +27345 -27315
  16. package/core/built/admin/assets/stats/stats.js +28699 -28672
  17. package/core/built/admin/index.html +4 -4
  18. package/core/frontend/public/member-attribution.min.js +1 -1
  19. package/core/server/api/endpoints/search-index.js +2 -2
  20. package/core/server/api/endpoints/stats.js +10 -4
  21. package/core/server/data/migrations/versions/6.1/2025-09-11-00-38-13-add-uuid-column-to-tokens.js +8 -0
  22. package/core/server/data/migrations/versions/6.1/2025-09-11-00-39-08-backfill-tokens-uuid.js +19 -0
  23. package/core/server/data/migrations/versions/6.1/2025-09-11-00-39-36-tokens-drop-nullable-uuid.js +4 -0
  24. package/core/server/data/schema/schema.js +1 -0
  25. package/core/server/data/tinybird/datasources/_mv_hits.datasource +7 -4
  26. package/core/server/data/tinybird/endpoints/api_top_utm_campaigns.pipe +2 -8
  27. package/core/server/data/tinybird/endpoints/api_top_utm_contents.pipe +2 -8
  28. package/core/server/data/tinybird/endpoints/api_top_utm_mediums.pipe +2 -8
  29. package/core/server/data/tinybird/endpoints/api_top_utm_sources.pipe +2 -8
  30. package/core/server/data/tinybird/endpoints/api_top_utm_terms.pipe +2 -8
  31. package/core/server/data/tinybird/fixtures/analytics_events.ndjson +11 -11
  32. package/core/server/data/tinybird/pipes/mv_hits.pipe +12 -2
  33. package/core/server/data/tinybird/pipes/mv_session_data.pipe +16 -6
  34. package/core/server/data/tinybird/tests/api_top_utm_campaigns.yaml +35 -34
  35. package/core/server/data/tinybird/tests/api_top_utm_contents.yaml +57 -48
  36. package/core/server/data/tinybird/tests/api_top_utm_mediums.yaml +40 -38
  37. package/core/server/data/tinybird/tests/api_top_utm_sources.yaml +59 -39
  38. package/core/server/data/tinybird/tests/api_top_utm_terms.yaml +55 -48
  39. package/core/server/models/single-use-token.js +1 -0
  40. package/core/server/services/email-service/EmailRenderer.js +1 -0
  41. package/core/server/services/email-service/email-templates/template.hbs +6 -0
  42. package/core/server/services/members/emails/signin.js +4 -4
  43. package/core/server/services/stats/MrrStatsService.js +10 -5
  44. package/core/server/services/stats/StatsService.js +2 -2
  45. package/package.json +6 -6
  46. package/tsconfig.tsbuildinfo +1 -1
  47. package/yarn.lock +1002 -419
  48. package/components/tryghost-i18n-6.0.10.tgz +0 -0
  49. package/core/built/admin/assets/ghost-a7a53bf80dc45c37ae9c174a0d02a882.css +0 -1
  50. package/core/built/admin/assets/ghost-dark-6e0062029f988d8676e87f22d8e7f4a3.css +0 -1
@@ -3,106 +3,113 @@
3
3
  description: All fixture data
4
4
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC
5
5
  expected_result: |
6
- {"utm_term":"ghost cms","visits":6}
7
- {"utm_term":"blog software","visits":3}
8
- {"utm_term":"content management","visits":3}
9
- {"utm_term":"newsletter platform","visits":3}
10
- {"utm_term":"membership site","visits":1}
6
+ {"utm_term":"discount","visits":1}
7
+ {"utm_term":"ghost_blog","visits":1}
8
+ {"utm_term":"subscribers","visits":1}
9
+ {"utm_term":"loyal_customers","visits":1}
10
+ {"utm_term":"black_friday","visits":1}
11
+ {"utm_term":"new_feature","visits":1}
12
+ {"utm_term":"announcement","visits":1}
11
13
 
12
14
  - name: Filtered by browser - Chrome
13
15
  description: Filtered by browser - Chrome
14
16
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&browser=chrome
15
17
  expected_result: |
16
- {"utm_term":"ghost cms","visits":4}
17
- {"utm_term":"blog software","visits":1}
18
- {"utm_term":"content management","visits":1}
19
- {"utm_term":"newsletter platform","visits":1}
18
+ {"utm_term":"discount","visits":1}
19
+ {"utm_term":"ghost_blog","visits":1}
20
+ {"utm_term":"loyal_customers","visits":1}
20
21
 
21
22
  - name: Filtered by device - desktop
22
23
  description: Filtered by device - desktop
23
24
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop
24
25
  expected_result: |
25
- {"utm_term":"ghost cms","visits":6}
26
- {"utm_term":"blog software","visits":3}
27
- {"utm_term":"content management","visits":3}
28
- {"utm_term":"newsletter platform","visits":2}
29
- {"utm_term":"membership site","visits":1}
26
+ {"utm_term":"discount","visits":1}
27
+ {"utm_term":"ghost_blog","visits":1}
28
+ {"utm_term":"subscribers","visits":1}
29
+ {"utm_term":"loyal_customers","visits":1}
30
+ {"utm_term":"black_friday","visits":1}
31
+ {"utm_term":"new_feature","visits":1}
32
+ {"utm_term":"announcement","visits":1}
30
33
 
31
34
  - name: Filtered by location - UK
32
35
  description: Filtered by location - UK
33
36
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&location=GB
34
37
  expected_result: |
35
- {"utm_term":"ghost cms","visits":3}
36
- {"utm_term":"blog software","visits":2}
37
- {"utm_term":"newsletter platform","visits":2}
38
- {"utm_term":"content management","visits":1}
38
+ {"utm_term":"discount","visits":1}
39
+ {"utm_term":"ghost_blog","visits":1}
40
+ {"utm_term":"subscribers","visits":1}
41
+ {"utm_term":"new_feature","visits":1}
39
42
 
40
43
  - name: Filtered by OS - Windows
41
44
  description: Filtered by OS - Windows
42
45
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&os=windows
43
46
  expected_result: |
44
- {"utm_term":"ghost cms","visits":5}
45
- {"utm_term":"blog software","visits":3}
46
- {"utm_term":"content management","visits":3}
47
- {"utm_term":"newsletter platform","visits":2}
48
- {"utm_term":"membership site","visits":1}
47
+ {"utm_term":"discount","visits":1}
48
+ {"utm_term":"ghost_blog","visits":1}
49
+ {"utm_term":"subscribers","visits":1}
50
+ {"utm_term":"loyal_customers","visits":1}
51
+ {"utm_term":"black_friday","visits":1}
52
+ {"utm_term":"new_feature","visits":1}
53
+ {"utm_term":"announcement","visits":1}
49
54
 
50
55
  - name: Filtered by pathname - /about/
51
56
  description: Filtered by pathname - /about/
52
57
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&pathname=%2Fabout%2F
53
58
  expected_result: |
54
- {"utm_term":"ghost cms","visits":4}
55
- {"utm_term":"content management","visits":2}
56
- {"utm_term":"blog software","visits":1}
57
- {"utm_term":"newsletter platform","visits":1}
59
+ {"utm_term":"discount","visits":1}
60
+ {"utm_term":"subscribers","visits":1}
61
+ {"utm_term":"loyal_customers","visits":1}
62
+ {"utm_term":"new_feature","visits":1}
63
+ {"utm_term":"announcement","visits":1}
58
64
 
59
65
  - name: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
60
66
  description: Filtered by post_uuid - 06b1b0c9-fb53-4a15-a060-3db3fde7b1fc (/about/)
61
67
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&post_uuid=06b1b0c9-fb53-4a15-a060-3db3fde7b1fc
62
68
  expected_result: |
63
- {"utm_term":"ghost cms","visits":4}
64
- {"utm_term":"content management","visits":2}
65
- {"utm_term":"blog software","visits":1}
66
- {"utm_term":"newsletter platform","visits":1}
69
+ {"utm_term":"discount","visits":1}
70
+ {"utm_term":"subscribers","visits":1}
71
+ {"utm_term":"loyal_customers","visits":1}
72
+ {"utm_term":"new_feature","visits":1}
73
+ {"utm_term":"announcement","visits":1}
67
74
 
68
75
  - name: Filtered by source - bing.com
69
76
  description: Filtered by source - bing.com
70
77
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&source=bing.com
71
78
  expected_result: |
72
- {"utm_term":"content management","visits":2}
79
+ {"utm_term":"subscribers","visits":1}
80
+ {"utm_term":"loyal_customers","visits":1}
73
81
 
74
82
  - name: Filtered by member status - paid
75
83
  description: Filtered by member status - paid
76
84
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=paid
77
85
  expected_result: |
78
- {"utm_term":"blog software","visits":2}
79
- {"utm_term":"ghost cms","visits":2}
80
- {"utm_term":"content management","visits":1}
86
+ {"utm_term":"ghost_blog","visits":1}
87
+ {"utm_term":"loyal_customers","visits":1}
88
+ {"utm_term":"new_feature","visits":1}
81
89
 
82
90
  - name: Filtered by member status - undefined
83
91
  description: Filtered by member status - undefined
84
92
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&member_status=undefined
85
93
  expected_result: |
86
- {"utm_term":"newsletter platform","visits":3}
87
- {"utm_term":"blog software","visits":1}
88
- {"utm_term":"membership site","visits":1}
89
- {"utm_term":"ghost cms","visits":1}
94
+ {"utm_term":"discount","visits":1}
95
+ {"utm_term":"black_friday","visits":1}
96
+ {"utm_term":"announcement","visits":1}
90
97
 
91
98
  - name: Filtered by timezone - America/Los_Angeles
92
99
  description: Filtered by timezone - America/Los_Angeles
93
100
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=America/Los_Angeles
94
101
  expected_result: |
95
- {"utm_term":"ghost cms","visits":5}
96
- {"utm_term":"blog software","visits":3}
97
- {"utm_term":"content management","visits":2}
98
- {"utm_term":"newsletter platform","visits":2}
99
- {"utm_term":"membership site","visits":1}
102
+ {"utm_term":"discount","visits":1}
103
+ {"utm_term":"ghost_blog","visits":1}
104
+ {"utm_term":"loyal_customers","visits":1}
105
+ {"utm_term":"black_friday","visits":1}
106
+ {"utm_term":"new_feature","visits":1}
107
+ {"utm_term":"announcement","visits":1}
100
108
 
101
109
  - name: Test with multiple filters combined
102
110
  description: Test with multiple filters combined
103
111
  parameters: site_uuid=mock_site_uuid&date_from=2100-01-01&date_to=2100-01-07&timezone=Etc/UTC&device=desktop&browser=firefox
104
112
  expected_result: |
105
- {"utm_term":"blog software","visits":2}
106
- {"utm_term":"membership site","visits":1}
107
- {"utm_term":"content management","visits":1}
108
- {"utm_term":"newsletter platform","visits":1}
113
+ {"utm_term":"black_friday","visits":1}
114
+ {"utm_term":"new_feature","visits":1}
115
+ {"utm_term":"announcement","visits":1}
@@ -7,6 +7,7 @@ const SingleUseToken = ghostBookshelf.Model.extend({
7
7
  defaults() {
8
8
  return {
9
9
  used_count: 0,
10
+ uuid: crypto.randomUUID(),
10
11
  token: crypto
11
12
  .randomBytes(192 / 8)
12
13
  .toString('base64')
@@ -1241,6 +1241,7 @@ class EmailRenderer {
1241
1241
  }, true) : null
1242
1242
  },
1243
1243
  preheader: this.#getEmailPreheader(post, segment, html),
1244
+ preheaderSpacing: '‌ '.repeat(75),
1244
1245
  html,
1245
1246
 
1246
1247
  post: {
@@ -9,6 +9,12 @@
9
9
  </head>
10
10
  <body>
11
11
  <span class="preheader">{{preheader}}</span>
12
+ {{#hasFeature 'emailCustomization'}}
13
+ <!-- SPACING TO AVOID BODY TEXT BEING DUPLICATED IN PREVIEW TEXT -->
14
+ <div style="display:none; max-height:0; overflow:hidden; mso-hide: all;" aria-hidden="true" role="presentation">
15
+ {{{preheaderSpacing}}}
16
+ </div>
17
+ {{/hasFeature}}
12
18
 
13
19
  <!-- HEADER WITH FULL-WIDTH BACKGROUND -->
14
20
  {{#if hasHeaderContent}}
@@ -126,8 +126,8 @@ module.exports = ({t, siteTitle, email, url, otc, accentColor = '#15212A', siteD
126
126
  <td style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; vertical-align: top;">
127
127
  <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 20px; color: #15212A; font-weight: bold; line-height: 24px; margin: 0; margin-bottom: 15px;">${t('Hey there,')}</p>
128
128
  ${otc ?
129
- `<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 24px; margin-bottom: 24px;">${t(`Welcome back! Here's your code to sign in to {siteTitle}. For your security, it's only valid for 24 hours`, {siteTitle, interpolation: {escapeValue: false}})}:</p>
130
- <table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box; margin-bottom: 32px;">
129
+ `<p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 24px; margin-bottom: 24px;">${t(`Welcome back! Here's your code to sign in to {siteTitle}`, {siteTitle, interpolation: {escapeValue: false}})}:</p>
130
+ <table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; min-width: 100%; width: 100%; box-sizing: border-box; margin-bottom: 32px;">
131
131
  <tbody>
132
132
  <tr>
133
133
  <td style="padding: 16px; background-color: #F4F5F6; border-radius: 8px; text-align: center; vertical-align: middle;" valign="middle">
@@ -137,11 +137,11 @@ module.exports = ({t, siteTitle, email, url, otc, accentColor = '#15212A', siteD
137
137
  </tbody>
138
138
  </table>
139
139
  <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; color: #3A464C; font-weight: normal; margin: 0; line-height: 24px; margin-bottom: 24px;">${t('Or, skip the code and sign in directly')}:</p>
140
- <table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
140
+ <table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; min-width: 100%; box-sizing: border-box;">
141
141
  <tbody>
142
142
  <tr>
143
143
  <td align="center" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; padding-bottom: 35px;">
144
- <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
144
+ <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; min-width: 100%;">
145
145
  <tbody>
146
146
  <tr>
147
147
  <td align="center" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; vertical-align: top; background-color: ${accentColor}; border-radius: 5px; text-align: center;"> <a href="${url}" target="_blank" style="display: inline-block; color: #ffffff; background-color: ${accentColor}; border: solid 1px ${accentColor}; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; font-size: 16px; font-weight: normal; margin: 0; padding: 9px 22px 10px; border-color: ${accentColor};">${t('Sign in now')}</a> </td>
@@ -34,18 +34,21 @@ class MrrStatsService {
34
34
 
35
35
  /**
36
36
  * Get the MRR deltas for all days (from old to new), grouped by currency (ascending alphabetically)
37
+ * @param {string} [dateFrom] - Start date to fetch deltas from
37
38
  * @returns {Promise<MrrDelta[]>} The deltas sorted from new to old
38
39
  */
39
- async fetchAllDeltas() {
40
+ async fetchAllDeltas(dateFrom) {
40
41
  const knex = this.knex;
41
- const ninetyDaysAgo = moment.utc().subtract(90, 'days').startOf('day').utc().format('YYYY-MM-DD HH:mm:ss');
42
+ const startDate = dateFrom
43
+ ? moment.utc(dateFrom).startOf('day').utc().format('YYYY-MM-DD HH:mm:ss')
44
+ : moment.utc().subtract(90, 'days').startOf('day').utc().format('YYYY-MM-DD HH:mm:ss');
42
45
  const rows = await knex('members_paid_subscription_events')
43
46
  .select('currency')
44
47
  // In SQLite, DATE(created_at) would map to a string value, while DATE(created_at) would map to a JSDate object in MySQL
45
48
  // That is why we need the cast here (to have some consistency)
46
49
  .select(knex.raw('CAST(DATE(created_at) as CHAR) as date'))
47
50
  .select(knex.raw(`SUM(mrr_delta) as delta`))
48
- .where('created_at', '>=', ninetyDaysAgo)
51
+ .where('created_at', '>=', startDate)
49
52
  .groupByRaw('CAST(DATE(created_at) as CHAR), currency');
50
53
  return rows;
51
54
  }
@@ -53,13 +56,15 @@ class MrrStatsService {
53
56
  /**
54
57
  * Returns a list of the MRR history for each day and currency, including the current MRR per currency as meta data.
55
58
  * The respons is in ascending date order, and currencies for the same date are always in ascending order.
59
+ * @param {Object} [options]
60
+ * @param {string} [options.dateFrom] - Start date to fetch history from
56
61
  * @returns {Promise<MrrHistory>}
57
62
  */
58
- async getHistory() {
63
+ async getHistory(options = {}) {
59
64
  // Fetch current total amounts and start counting from there
60
65
  const totals = await this.getCurrentMrr();
61
66
 
62
- const rows = await this.fetchAllDeltas();
67
+ const rows = await this.fetchAllDeltas(options.dateFrom);
63
68
 
64
69
  rows.sort((rowA, rowB) => {
65
70
  const dateA = new Date(rowA.date);
@@ -23,8 +23,8 @@ class StatsService {
23
23
  this.content = deps.content;
24
24
  }
25
25
 
26
- async getMRRHistory() {
27
- return this.mrr.getHistory();
26
+ async getMRRHistory(options = {}) {
27
+ return this.mrr.getHistory(options);
28
28
  }
29
29
 
30
30
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghost",
3
- "version": "6.0.10",
3
+ "version": "6.1.0",
4
4
  "description": "The professional publishing platform",
5
5
  "author": "Ghost Foundation",
6
6
  "homepage": "https://ghost.org",
@@ -86,7 +86,7 @@
86
86
  "@tryghost/helpers": "1.1.97",
87
87
  "@tryghost/html-to-plaintext": "1.0.4",
88
88
  "@tryghost/http-cache-utils": "0.1.20",
89
- "@tryghost/i18n": "file:components/tryghost-i18n-6.0.10.tgz",
89
+ "@tryghost/i18n": "file:components/tryghost-i18n-6.1.0.tgz",
90
90
  "@tryghost/image-transform": "1.4.6",
91
91
  "@tryghost/job-manager": "1.0.3",
92
92
  "@tryghost/kg-card-factory": "5.1.2",
@@ -196,7 +196,7 @@
196
196
  "moment": "2.24.0",
197
197
  "moment-timezone": "0.5.45",
198
198
  "multer": "2.0.2",
199
- "mysql2": "3.15.0",
199
+ "mysql2": "3.15.1",
200
200
  "nconf": "0.13.0",
201
201
  "node-fetch": "2.7.0",
202
202
  "node-jose": "2.2.0",
@@ -225,7 +225,7 @@
225
225
  },
226
226
  "devDependencies": {
227
227
  "@actions/core": "1.11.1",
228
- "@playwright/test": "1.55.0",
228
+ "@playwright/test": "1.55.1",
229
229
  "@prettier/sync": "0.6.1",
230
230
  "@tryghost/express-test": "0.15.0",
231
231
  "@tryghost/webhook-mock-receiver": "0.2.17",
@@ -264,7 +264,7 @@
264
264
  "supertest": "6.3.4",
265
265
  "tmp": "0.2.5",
266
266
  "toml": "3.0.0",
267
- "tsx": "4.20.5",
267
+ "tsx": "4.20.6",
268
268
  "typescript": "5.8.3"
269
269
  },
270
270
  "resolutions": {
@@ -273,7 +273,7 @@
273
273
  "jackspeak": "2.3.6",
274
274
  "moment": "2.24.0",
275
275
  "moment-timezone": "0.5.45",
276
- "@tryghost/i18n": "file:components/tryghost-i18n-6.0.10.tgz"
276
+ "@tryghost/i18n": "file:components/tryghost-i18n-6.1.0.tgz"
277
277
  },
278
278
  "nx": {
279
279
  "targets": {