ghost 4.25.0 → 4.27.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 (37) hide show
  1. package/content/themes/casper/assets/built/screen.css +1 -1
  2. package/content/themes/casper/assets/built/screen.css.map +1 -1
  3. package/content/themes/casper/assets/css/screen.css +54 -10
  4. package/content/themes/casper/package.json +1 -1
  5. package/core/app.js +8 -4
  6. package/core/boot.js +50 -23
  7. package/core/built/assets/{chunk.3.8f95b516d88ff4eec64c.js → chunk.3.e54be01b5124e4e27958.js} +7 -7
  8. package/core/built/assets/ghost-dark-ae67fe157509b6e82c607ba560fc52e9.css +1 -0
  9. package/core/built/assets/{ghost.min-bc72f685c1c9adc9885925c1412435a5.js → ghost.min-2d534cce15c43c646814b26f4beefb78.js} +134 -131
  10. package/core/built/assets/ghost.min-b1e58e098721e467388682a85a7c187d.css +1 -0
  11. package/core/built/assets/{vendor.min-d1234c632a54502777c34e50752fa3fc.js → vendor.min-e433aa7d5620e7837f30e170cd43f84e.js} +597 -563
  12. package/core/frontend/apps/amp/lib/views/amp.hbs +67 -0
  13. package/core/frontend/helpers/url.js +18 -1
  14. package/core/frontend/src/cards/css/audio.css +258 -0
  15. package/core/frontend/src/cards/css/blockquote.css +23 -0
  16. package/core/frontend/src/cards/css/callout.css +13 -4
  17. package/core/frontend/src/cards/css/product.css +101 -0
  18. package/core/frontend/src/cards/css/toggle.css +42 -20
  19. package/core/frontend/src/cards/js/audio.js +147 -0
  20. package/core/frontend/web/site.js +1 -1
  21. package/core/server/notify.js +1 -2
  22. package/core/server/services/mega/template.js +31 -5
  23. package/core/server/services/members/api.js +2 -2
  24. package/core/server/services/members/emails/signup-paid.js +4 -4
  25. package/core/server/services/nft-oembed.js +1 -1
  26. package/core/server/services/oembed.js +9 -1
  27. package/core/server/services/twitter-embed.js +3 -1
  28. package/core/server/web/admin/views/default-prod.html +4 -4
  29. package/core/server/web/admin/views/default.html +4 -4
  30. package/core/server/web/parent/app.js +2 -22
  31. package/core/server/web/parent/backend.js +2 -0
  32. package/core/shared/express.js +1 -1
  33. package/core/shared/labs.js +6 -4
  34. package/package.json +36 -36
  35. package/yarn.lock +362 -447
  36. package/core/built/assets/ghost-dark-d690e732e17ffc794e2e59c1467ca282.css +0 -1
  37. package/core/built/assets/ghost.min-043bb7480a0810109b130f13b2a4235e.css +0 -1
@@ -0,0 +1,147 @@
1
+ const handleAudioPlayer = function (audioElementContainer) {
2
+ const audioPlayerContainer = audioElementContainer.querySelector('.kg-player-container');
3
+ const playIconContainer = audioElementContainer.querySelector('.kg-audio-play-icon');
4
+ const pauseIconContainer = audioElementContainer.querySelector('.kg-audio-pause-icon');
5
+ const seekSlider = audioElementContainer.querySelector('.kg-audio-seek-slider');
6
+ const playbackRateContainer = audioElementContainer.querySelector('.kg-audio-playback-rate');
7
+ const muteIconContainer = audioElementContainer.querySelector('.kg-audio-mute-icon');
8
+ const unmuteIconContainer = audioElementContainer.querySelector('.kg-audio-unmute-icon');
9
+ const volumeSlider = audioElementContainer.querySelector('.kg-audio-volume-slider');
10
+ const audio = audioElementContainer.querySelector('audio');
11
+ const durationContainer = audioElementContainer.querySelector('.kg-audio-duration');
12
+ const currentTimeContainer = audioElementContainer.querySelector('.kg-audio-current-time');
13
+ let playbackRates = [{
14
+ rate: 0.75,
15
+ label: '0.7×'
16
+ }, {
17
+ rate: 1.0,
18
+ label: '1×'
19
+ }, {
20
+ rate: 1.25,
21
+ label: '1.2×'
22
+ }, {
23
+ rate: 1.75,
24
+ label: '1.7×'
25
+ }, {
26
+ rate: 2.0,
27
+ label: '2×'
28
+ }];
29
+
30
+ let raf = null;
31
+ let currentPlaybackRateIdx = 1;
32
+
33
+ audio.src = audioElementContainer.getAttribute('data-kg-audio-src');
34
+
35
+ const whilePlaying = () => {
36
+ seekSlider.value = Math.floor(audio.currentTime);
37
+ currentTimeContainer.textContent = calculateTime(seekSlider.value);
38
+ audioPlayerContainer.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`);
39
+ raf = requestAnimationFrame(whilePlaying);
40
+ }
41
+
42
+ const showRangeProgress = (rangeInput) => {
43
+ if (rangeInput === seekSlider) {
44
+ audioPlayerContainer.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%');
45
+ }
46
+ else {
47
+ audioPlayerContainer.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%');
48
+ }
49
+ }
50
+
51
+ const calculateTime = (secs) => {
52
+ const minutes = Math.floor(secs / 60);
53
+ const seconds = Math.floor(secs % 60);
54
+ const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
55
+ return `${minutes}:${returnedSeconds}`;
56
+ }
57
+
58
+ const displayDuration = () => {
59
+ durationContainer.textContent = calculateTime(audio.duration);
60
+ }
61
+
62
+ const setSliderMax = () => {
63
+ seekSlider.max = Math.floor(audio.duration);
64
+ }
65
+
66
+ const displayBufferedAmount = () => {
67
+ if (audio.buffered.length > 0) {
68
+ const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1));
69
+ audioPlayerContainer.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`);
70
+ }
71
+ }
72
+
73
+ if (audio.readyState > 0) {
74
+ displayDuration();
75
+ setSliderMax();
76
+ displayBufferedAmount();
77
+ } else {
78
+ audio.addEventListener('loadedmetadata', () => {
79
+ displayDuration();
80
+ setSliderMax();
81
+ displayBufferedAmount();
82
+ });
83
+ }
84
+
85
+ playIconContainer.addEventListener('click', () => {
86
+ playIconContainer.classList.add("kg-audio-hide");
87
+ pauseIconContainer.classList.remove("kg-audio-hide");
88
+ audio.play();
89
+ requestAnimationFrame(whilePlaying);
90
+ });
91
+
92
+ pauseIconContainer.addEventListener('click', () => {
93
+ pauseIconContainer.classList.add("kg-audio-hide");
94
+ playIconContainer.classList.remove("kg-audio-hide");
95
+ audio.pause();
96
+ cancelAnimationFrame(raf);
97
+ });
98
+
99
+ muteIconContainer.addEventListener('click', () => {
100
+ muteIconContainer.classList.add("kg-audio-hide");
101
+ unmuteIconContainer.classList.remove("kg-audio-hide");
102
+ audio.muted = false;
103
+ });
104
+
105
+ unmuteIconContainer.addEventListener('click', () => {
106
+ unmuteIconContainer.classList.add("kg-audio-hide");
107
+ muteIconContainer.classList.remove("kg-audio-hide");
108
+ audio.muted = true;
109
+ });
110
+
111
+ playbackRateContainer.addEventListener('click', () => {
112
+ let nextPlaybackRate = playbackRates[(currentPlaybackRateIdx + 1) % 5];
113
+ currentPlaybackRateIdx = currentPlaybackRateIdx + 1;
114
+ audio.playbackRate = nextPlaybackRate.rate;
115
+ playbackRateContainer.textContent = nextPlaybackRate.label;
116
+ });
117
+
118
+ audio.addEventListener('progress', displayBufferedAmount);
119
+
120
+ seekSlider.addEventListener('input', (e) => {
121
+ showRangeProgress(e.target);
122
+ currentTimeContainer.textContent = calculateTime(seekSlider.value);
123
+ if (!audio.paused) {
124
+ cancelAnimationFrame(raf);
125
+ }
126
+ });
127
+
128
+ seekSlider.addEventListener('change', () => {
129
+ audio.currentTime = seekSlider.value;
130
+ if (!audio.paused) {
131
+ requestAnimationFrame(whilePlaying);
132
+ }
133
+ });
134
+
135
+ volumeSlider.addEventListener('input', (e) => {
136
+ const value = e.target.value;
137
+ showRangeProgress(e.target);
138
+ audio.volume = value / 100;
139
+ });
140
+ }
141
+
142
+ const audioCardElements = document.querySelectorAll('.kg-audio-card');
143
+
144
+ for (let i = 0; i < audioCardElements.length; i++) {
145
+ handleAudioPlayer(audioCardElements[i]);
146
+ }
147
+
@@ -112,7 +112,7 @@ module.exports = function setupSiteApp(options = {}) {
112
112
 
113
113
  // Card assets
114
114
  siteApp.use(mw.servePublicFile('built', 'public/cards.min.css', 'text/css', constants.ONE_YEAR_S));
115
- siteApp.use(mw.servePublicFile('built', 'public/cards.min.js', 'text/js', constants.ONE_YEAR_S));
115
+ siteApp.use(mw.servePublicFile('built', 'public/cards.min.js', 'application/javascript', constants.ONE_YEAR_S));
116
116
 
117
117
  // Serve blog images using the storage adapter
118
118
  siteApp.use(STATIC_IMAGE_URL_PREFIX, mw.handleImageSizes, storage.getStorage('images').serve());
@@ -8,7 +8,6 @@
8
8
 
9
9
  // Required Ghost internals
10
10
  const config = require('../shared/config');
11
- const logging = require('@tryghost/logging');
12
11
 
13
12
  let notified = {
14
13
  started: false,
@@ -53,7 +52,7 @@ async function notify(type, error = null) {
53
52
  let socketAddress = config.get('bootstrap-socket');
54
53
  if (socketAddress) {
55
54
  const bootstrapSocket = require('@tryghost/bootstrap-socket');
56
- return bootstrapSocket.connectAndSend(socketAddress, logging, message);
55
+ return bootstrapSocket.connectAndSend(socketAddress, message);
57
56
  }
58
57
 
59
58
  return Promise.resolve();
@@ -148,7 +148,7 @@ dd {
148
148
  }
149
149
 
150
150
  blockquote {
151
- margin: 2em 0;
151
+ margin: 2em 0 2em 0;
152
152
  padding: 0 25px 0 25px;
153
153
  border-left: ${templateSettings.accentColor || '#15212A'} 2px solid;
154
154
  font-size: 17px;
@@ -157,6 +157,15 @@ blockquote {
157
157
  letter-spacing: -0.2px;
158
158
  }
159
159
 
160
+ blockquote.kg-blockquote-alt {
161
+ border-left: 0 none;
162
+ padding: 0 50px 0 50px;
163
+ text-align: center;
164
+ font-size: 1.2em;
165
+ font-style: italic;
166
+ color: #999999;
167
+ }
168
+
160
169
  blockquote p {
161
170
  margin: 0.8em 0;
162
171
  font-size: 1em;
@@ -557,6 +566,16 @@ figure blockquote p {
557
566
  padding-bottom: 4px;
558
567
  }
559
568
 
569
+ .kg-twitter-link {
570
+ display: block;
571
+ text-decoration: none !important;
572
+ color: #15212A !important;
573
+ font-family: inherit !important;
574
+ font-size: 15px;
575
+ padding: 8px;
576
+ line-height: 1.3em;
577
+ }
578
+
560
579
  .kg-callout-card {
561
580
  display: flex;
562
581
  margin: 0 0 1.5em 0;
@@ -888,10 +907,17 @@ figure blockquote p {
888
907
  }
889
908
 
890
909
  table.body blockquote {
891
- font-size: 17px !important;
892
- line-height: 1.6em !important;
893
- margin-bottom: 0 !important;
894
- padding-left: 15px !important;
910
+ font-size: 17px;
911
+ line-height: 1.6em;
912
+ margin-bottom: 0;
913
+ padding-left: 15px;
914
+ }
915
+
916
+ table.body blockquote.kg-blockquote-alt {
917
+ border-left: 0 none !important;
918
+ margin: 0 0 2.5em 0 !important;
919
+ padding: 0 50px 0 50px !important;
920
+ font-size: 1.2em;
895
921
  }
896
922
 
897
923
  table.body blockquote + * {
@@ -98,9 +98,9 @@ function createApiInstance(config) {
98
98
  `;
99
99
  case 'signup-paid':
100
100
  return `
101
- Thank you for subscribing to ${siteTitle}!
101
+ Hey there!
102
102
 
103
- Tap the link below to be automatically signed in:
103
+ Thank you for subscribing to ${siteTitle}. Tap the link below to be automatically signed in:
104
104
 
105
105
  ${url}
106
106
 
@@ -107,7 +107,7 @@ module.exports = ({siteTitle, email, url, accentColor = '#15212A', siteDomain, s
107
107
  <div class="content" style="box-sizing: border-box; display: block; margin: 0 auto; max-width: 600px; padding: 30px 20px;">
108
108
 
109
109
  <!-- START CENTERED WHITE CONTAINER -->
110
- <span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Complete signup for ${siteTitle}!</span>
110
+ <span class="preheader" style="color: transparent; display: none; height: 0; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; mso-hide: all; visibility: hidden; width: 0;">Thank you for subscribing to ${siteTitle}.</span>
111
111
  <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
112
112
 
113
113
  <!-- START MAIN CONTENT AREA -->
@@ -116,8 +116,8 @@ module.exports = ({siteTitle, email, url, accentColor = '#15212A', siteDomain, s
116
116
  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
117
117
  <tr>
118
118
  <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;">
119
- <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: 25px; margin: 0; margin-bottom: 15px;">Thank you for subscribing to ${siteTitle}</p>
120
- <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; line-height: 25px; margin: 0; margin-bottom: 32px;">Tap the link below to be automatically signed in:</p>
119
+ <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: 25px; margin: 0; margin-bottom: 15px;">Hey there!</p>
120
+ <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; line-height: 25px; margin: 0; margin-bottom: 32px;">Thank you for subscribing to ${siteTitle}. Tap the link below to be automatically signed in:</p>
121
121
  <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;">
122
122
  <tbody>
123
123
  <tr>
@@ -125,7 +125,7 @@ module.exports = ({siteTitle, email, url, accentColor = '#15212A', siteDomain, s
125
125
  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: auto;">
126
126
  <tbody>
127
127
  <tr>
128
- <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: 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};">Confirm signup</a> </td>
128
+ <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: 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};">Sign in</a> </td>
129
129
  </tr>
130
130
  </tbody>
131
131
  </table>
@@ -46,7 +46,7 @@ class NFTOEmbedProvider {
46
46
  return {
47
47
  version: '1.0',
48
48
  type: 'nft',
49
- title: result.body.name,
49
+ title: result.body.name ? result.body.name : `#${result.body.token_id}`,
50
50
  author_name: result.body.creator.user.username,
51
51
  author_url: `https://opensea.io/${result.body.creator.user.username}`,
52
52
  provider_name: 'OpenSea',
@@ -1,6 +1,7 @@
1
1
  const errors = require('@tryghost/errors');
2
2
  const tpl = require('@tryghost/tpl');
3
3
  const logging = require('@tryghost/logging');
4
+ const sentry = require('../../shared/sentry');
4
5
  const {extract, hasProvider} = require('oembed-parser');
5
6
  const cheerio = require('cheerio');
6
7
  const _ = require('lodash');
@@ -128,7 +129,14 @@ class OEmbed {
128
129
  const response = await this.externalRequest(url, {cookieJar});
129
130
 
130
131
  const html = response.body;
131
- scraperResponse = await metascraper({html, url});
132
+ try {
133
+ scraperResponse = await metascraper({html, url});
134
+ } catch (err) {
135
+ // Log to avoid being blind to errors happenning in metascraper
136
+ sentry.captureException(err);
137
+ logging.error(err);
138
+ return this.unknownProvider(url);
139
+ }
132
140
 
133
141
  const metadata = Object.assign({}, scraperResponse, {
134
142
  thumbnail: scraperResponse.image,
@@ -1,4 +1,5 @@
1
1
  const {extract} = require('oembed-parser');
2
+ const labs = require('../../shared/labs');
2
3
 
3
4
  /**
4
5
  * @typedef {import('./oembed').ICustomProvider} ICustomProvider
@@ -41,7 +42,7 @@ class TwitterOEmbedProvider {
41
42
  /** @type {object} */
42
43
  const oembedData = await extract(url.href);
43
44
 
44
- if (this.dependencies.config.bearerToken) {
45
+ if (this.dependencies.config.bearerToken && labs.isSet('richTwitterNewsletters')) {
45
46
  const query = {
46
47
  expansions: ['attachments.poll_ids', 'attachments.media_keys', 'author_id', 'entities.mentions.username', 'geo.place_id', 'in_reply_to_user_id', 'referenced_tweets.id', 'referenced_tweets.id.author_id'],
47
48
  'media.fields': ['duration_ms', 'height', 'media_key', 'preview_image_url', 'type', 'url', 'width', 'public_metrics', 'alt_text'],
@@ -66,6 +67,7 @@ class TwitterOEmbedProvider {
66
67
  const body = JSON.parse(result.body);
67
68
 
68
69
  oembedData.tweet_data = body.data;
70
+ oembedData.tweet_data.includes = body.includes;
69
71
  } catch (err) {
70
72
  this.dependencies.logging.error(err);
71
73
  }
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.25%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.27%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -41,7 +41,7 @@
41
41
 
42
42
 
43
43
  <link rel="stylesheet" href="assets/vendor.min-987af30228885bce50f05c4723fe6f53.css">
44
- <link rel="stylesheet" href="assets/ghost.min-043bb7480a0810109b130f13b2a4235e.css" title="light">
44
+ <link rel="stylesheet" href="assets/ghost.min-b1e58e098721e467388682a85a7c187d.css" title="light">
45
45
 
46
46
 
47
47
 
@@ -59,8 +59,8 @@
59
59
  <div id="ember-basic-dropdown-wormhole"></div>
60
60
 
61
61
 
62
- <script src="assets/vendor.min-d1234c632a54502777c34e50752fa3fc.js"></script>
63
- <script src="assets/ghost.min-bc72f685c1c9adc9885925c1412435a5.js"></script>
62
+ <script src="assets/vendor.min-e433aa7d5620e7837f30e170cd43f84e.js"></script>
63
+ <script src="assets/ghost.min-2d534cce15c43c646814b26f4beefb78.js"></script>
64
64
 
65
65
  </body>
66
66
  </html>
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.25%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.27%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -41,7 +41,7 @@
41
41
 
42
42
 
43
43
  <link rel="stylesheet" href="assets/vendor.min-987af30228885bce50f05c4723fe6f53.css">
44
- <link rel="stylesheet" href="assets/ghost.min-043bb7480a0810109b130f13b2a4235e.css" title="light">
44
+ <link rel="stylesheet" href="assets/ghost.min-b1e58e098721e467388682a85a7c187d.css" title="light">
45
45
 
46
46
 
47
47
 
@@ -59,8 +59,8 @@
59
59
  <div id="ember-basic-dropdown-wormhole"></div>
60
60
 
61
61
 
62
- <script src="assets/vendor.min-d1234c632a54502777c34e50752fa3fc.js"></script>
63
- <script src="assets/ghost.min-bc72f685c1c9adc9885925c1412435a5.js"></script>
62
+ <script src="assets/vendor.min-e433aa7d5620e7837f30e170cd43f84e.js"></script>
63
+ <script src="assets/ghost.min-2d534cce15c43c646814b26f4beefb78.js"></script>
64
64
 
65
65
  </body>
66
66
  </html>
@@ -3,22 +3,15 @@ const config = require('../../../shared/config');
3
3
  const express = require('../../../shared/express');
4
4
  const compress = require('compression');
5
5
  const mw = require('./middleware');
6
- const vhost = require('@tryghost/vhost-middleware');
7
6
 
8
- /**
9
- * @param {Object} options
10
- * @param {Boolean} [options.start]
11
- * @param {Boolean} [options.backend]
12
- * @param {Boolean} [options.frontend]
13
- */
14
- module.exports = function setupParentApp({start, frontend = true, backend = true}) {
7
+ module.exports = function setupParentApp() {
15
8
  debug('ParentApp setup start');
16
9
  const parentApp = express('parent');
17
10
 
18
11
  parentApp.use(mw.requestId);
19
12
  parentApp.use(mw.logRequest);
20
13
 
21
- // Register event emmiter on req/res to trigger cache invalidation webhook event
14
+ // Register event emitter on req/res to trigger cache invalidation webhook event
22
15
  parentApp.use(mw.emitEvents);
23
16
 
24
17
  // enabled gzip compression by default
@@ -30,19 +23,6 @@ module.exports = function setupParentApp({start, frontend = true, backend = true
30
23
  // @TODO: figure out if this is really needed everywhere? Is it not frontend only...
31
24
  parentApp.use(mw.ghostLocals);
32
25
 
33
- // Mount the express apps on the parentApp
34
-
35
- if (backend) {
36
- debug('Mounting bakcend: ADMIN + API');
37
- const backendApp = require('./backend')();
38
- parentApp.use(vhost(config.getBackendMountPath(), backendApp));
39
- }
40
-
41
- if (frontend) {
42
- debug('Mounting frontend: SITE + MEMBERS');
43
- const frontendApp = require('./frontend')({start});
44
- parentApp.use(vhost(config.getFrontendMountPath(), frontendApp));
45
- }
46
26
  debug('ParentApp setup end');
47
27
 
48
28
  return parentApp;
@@ -10,9 +10,11 @@ module.exports = () => {
10
10
  // BACKEND
11
11
  // Wrap the admin and API apps into a single express app for use with vhost
12
12
  const backendApp = express('backend');
13
+
13
14
  backendApp.lazyUse('/ghost/api', require('../api'));
14
15
  backendApp.lazyUse('/ghost/oauth', require('../oauth'));
15
16
  backendApp.lazyUse('/ghost/.well-known', require('../well-known'));
17
+
16
18
  backendApp.use('/ghost', require('../../services/auth/session').createSessionFromToken, require('../admin')());
17
19
 
18
20
  return backendApp;
@@ -29,7 +29,7 @@ module.exports = (name) => {
29
29
  };
30
30
 
31
31
  // Wrap the main express router call
32
- // This is mostly an experiement, and can likely be removed soon
32
+ // This is mostly an experiment, and can likely be removed soon
33
33
  module.exports.Router = (name, options) => {
34
34
  debug('new Router start', name);
35
35
  const router = express.Router(options);
@@ -16,7 +16,10 @@ const messages = {
16
16
  // flags in this list always return `true`, allows quick global enable prior to full flag removal
17
17
  const GA_FEATURES = [
18
18
  'customThemeSettings',
19
- 'nftCard'
19
+ 'nftCard',
20
+ 'calloutCard',
21
+ 'accordionCard',
22
+ 'richTwitterNewsletters'
20
23
  ];
21
24
 
22
25
  // NOTE: this allowlist is meant to be used to filter out any unexpected
@@ -34,13 +37,12 @@ const ALPHA_FEATURES = [
34
37
  'mediaAPI',
35
38
  'filesAPI',
36
39
  'membersAutoLogin',
37
- 'calloutCard',
38
- 'accordionCard',
39
40
  'fileCard',
40
41
  'audioCard',
41
42
  'videoCard',
42
43
  'productCard',
43
- 'quoteStyles'
44
+ 'beforeAfterCard',
45
+ 'tweetGridCard'
44
46
  ];
45
47
 
46
48
  module.exports.GA_KEYS = [...GA_FEATURES];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghost",
3
- "version": "4.25.0",
3
+ "version": "4.27.0",
4
4
  "description": "The professional publishing platform",
5
5
  "author": "Ghost Foundation",
6
6
  "homepage": "https://ghost.org",
@@ -54,53 +54,53 @@
54
54
  },
55
55
  "dependencies": {
56
56
  "@nexes/nql": "0.6.0",
57
- "@sentry/node": "6.15.0",
58
- "@tryghost/adapter-manager": "0.2.18",
57
+ "@sentry/node": "6.16.0",
58
+ "@tryghost/adapter-manager": "0.2.24",
59
59
  "@tryghost/admin-api-schema": "2.6.1",
60
- "@tryghost/bookshelf-plugins": "0.3.4",
61
- "@tryghost/bootstrap-socket": "0.2.13",
60
+ "@tryghost/bookshelf-plugins": "0.3.5",
61
+ "@tryghost/bootstrap-socket": "0.2.14",
62
62
  "@tryghost/color-utils": "0.1.5",
63
63
  "@tryghost/config-url-helpers": "0.1.3",
64
64
  "@tryghost/constants": "1.0.0",
65
65
  "@tryghost/custom-theme-settings-service": "0.3.1",
66
66
  "@tryghost/debug": "0.1.9",
67
- "@tryghost/email-analytics-provider-mailgun": "1.0.5",
68
- "@tryghost/email-analytics-service": "1.0.4",
67
+ "@tryghost/email-analytics-provider-mailgun": "1.0.6",
68
+ "@tryghost/email-analytics-service": "1.0.5",
69
69
  "@tryghost/errors": "1.0.4",
70
70
  "@tryghost/express-dynamic-redirects": "0.2.2",
71
71
  "@tryghost/helpers": "1.1.54",
72
- "@tryghost/image-transform": "1.0.18",
73
- "@tryghost/job-manager": "0.8.13",
72
+ "@tryghost/image-transform": "1.0.24",
73
+ "@tryghost/job-manager": "0.8.16",
74
74
  "@tryghost/kg-card-factory": "3.1.0",
75
75
  "@tryghost/kg-default-atoms": "3.1.0",
76
- "@tryghost/kg-default-cards": "5.9.0",
76
+ "@tryghost/kg-default-cards": "5.11.5",
77
77
  "@tryghost/kg-markdown-html-renderer": "5.1.0",
78
- "@tryghost/kg-mobiledoc-html-renderer": "5.3.0",
79
- "@tryghost/limit-service": "1.0.0",
80
- "@tryghost/logging": "1.0.1",
78
+ "@tryghost/kg-mobiledoc-html-renderer": "5.3.1",
79
+ "@tryghost/limit-service": "1.0.6",
80
+ "@tryghost/logging": "1.0.2",
81
81
  "@tryghost/magic-link": "1.0.14",
82
- "@tryghost/members-api": "2.8.2",
83
- "@tryghost/members-csv": "1.1.8",
84
- "@tryghost/members-importer": "0.3.4",
82
+ "@tryghost/members-api": "2.8.4",
83
+ "@tryghost/members-csv": "1.2.0",
84
+ "@tryghost/members-importer": "0.3.5",
85
85
  "@tryghost/members-offers": "0.10.3",
86
- "@tryghost/members-ssr": "1.0.15",
86
+ "@tryghost/members-ssr": "1.0.16",
87
87
  "@tryghost/metrics": "1.0.1",
88
- "@tryghost/minifier": "0.1.1",
88
+ "@tryghost/minifier": "0.1.7",
89
89
  "@tryghost/mw-session-from-token": "0.1.26",
90
- "@tryghost/nodemailer": "0.3.7",
91
- "@tryghost/package-json": "1.0.6",
90
+ "@tryghost/nodemailer": "0.3.8",
91
+ "@tryghost/package-json": "1.0.12",
92
92
  "@tryghost/promise": "0.1.13",
93
- "@tryghost/request": "0.1.9",
93
+ "@tryghost/request": "0.1.10",
94
94
  "@tryghost/root-utils": "0.3.7",
95
95
  "@tryghost/security": "0.2.13",
96
- "@tryghost/session-service": "0.1.28",
96
+ "@tryghost/session-service": "0.1.34",
97
97
  "@tryghost/settings-path-manager": "0.1.2",
98
98
  "@tryghost/social-urls": "0.1.27",
99
99
  "@tryghost/string": "0.1.21",
100
100
  "@tryghost/tpl": "0.1.8",
101
101
  "@tryghost/update-check-service": "0.2.5",
102
102
  "@tryghost/url-utils": "2.0.4",
103
- "@tryghost/validator": "0.1.8",
103
+ "@tryghost/validator": "0.1.9",
104
104
  "@tryghost/version": "0.1.7",
105
105
  "@tryghost/vhost-middleware": "1.0.19",
106
106
  "@tryghost/zip": "1.1.18",
@@ -130,7 +130,7 @@
130
130
  "ghost-storage-base": "1.0.0",
131
131
  "glob": "7.2.0",
132
132
  "got": "9.6.0",
133
- "gscan": "4.15.0",
133
+ "gscan": "4.16.0",
134
134
  "html-to-text": "5.1.1",
135
135
  "image-size": "1.0.0",
136
136
  "intl": "1.2.5",
@@ -145,18 +145,18 @@
145
145
  "lodash": "4.17.21",
146
146
  "luxon": "2.1.1",
147
147
  "mailgun-js": "0.22.0",
148
- "metascraper": "5.25.2",
149
- "metascraper-author": "5.25.2",
150
- "metascraper-description": "5.25.2",
151
- "metascraper-image": "5.25.2",
152
- "metascraper-logo": "5.25.2",
153
- "metascraper-logo-favicon": "5.25.2",
154
- "metascraper-publisher": "5.25.2",
155
- "metascraper-title": "5.25.2",
156
- "metascraper-url": "5.25.2",
148
+ "metascraper": "5.25.5",
149
+ "metascraper-author": "5.25.5",
150
+ "metascraper-description": "5.25.5",
151
+ "metascraper-image": "5.25.5",
152
+ "metascraper-logo": "5.25.5",
153
+ "metascraper-logo-favicon": "5.25.5",
154
+ "metascraper-publisher": "5.25.5",
155
+ "metascraper-title": "5.25.5",
156
+ "metascraper-url": "5.25.5",
157
157
  "moment": "2.24.0",
158
158
  "moment-timezone": "0.5.23",
159
- "multer": "1.4.3",
159
+ "multer": "1.4.4",
160
160
  "mysql": "2.18.1",
161
161
  "nconf": "0.11.3",
162
162
  "node-jose": "2.0.0",
@@ -174,7 +174,7 @@
174
174
  "xml": "1.0.1"
175
175
  },
176
176
  "optionalDependencies": {
177
- "@tryghost/html-to-mobiledoc": "1.4.0",
177
+ "@tryghost/html-to-mobiledoc": "1.5.0",
178
178
  "sqlite3": "5.0.2"
179
179
  },
180
180
  "devDependencies": {
@@ -183,7 +183,7 @@
183
183
  "coffeescript": "2.6.1",
184
184
  "cssnano": "5.0.12",
185
185
  "eslint": "7.32.0",
186
- "eslint-plugin-ghost": "2.10.0",
186
+ "eslint-plugin-ghost": "2.11.0",
187
187
  "grunt": "1.4.1",
188
188
  "grunt-bg-shell": "2.3.3",
189
189
  "grunt-contrib-clean": "2.0.0",