ghost 6.0.7 → 6.0.8
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.
- package/components/tryghost-i18n-6.0.8.tgz +0 -0
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +2 -2
- package/core/built/admin/assets/admin-x-activitypub/{index-B-ckGCDl.mjs → index-1EXYCtPI.mjs} +13252 -12300
- package/core/built/admin/assets/admin-x-activitypub/{index-C81KQoIh.mjs → index-If44c6h0.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-BfL5FINN.mjs → CodeEditorView-CzXlGImM.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
- package/core/built/admin/assets/admin-x-settings/{index-Bmm3Xeuw.mjs → index-BgCSf8S1.mjs} +4 -5
- package/core/built/admin/assets/admin-x-settings/{index-DiNZ3HQD.mjs → index-D2pIApbM.mjs} +18 -11
- package/core/built/admin/assets/admin-x-settings/{index-C_ZS-INP.mjs → index-RKA3H0Lh.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{modals-BEiWgHsk.mjs → modals-D0f6kxWg.mjs} +8799 -8807
- package/core/built/admin/assets/{chunk.524.9f989b3664418d6271a7.js → chunk.524.099dcd3975a0e60c5579.js} +7 -7
- package/core/built/admin/assets/{chunk.582.2421014e45b977b43b68.js → chunk.582.6830378a89a17aeedd0b.js} +10 -10
- package/core/built/admin/assets/{ghost-182ed60de3f37fff8a40cdd65d3bd2ef.js → ghost-138bb4718f8b9d666bdd7a2b45330d58.js} +10 -11
- package/core/built/admin/assets/posts/posts.js +26648 -26478
- package/core/built/admin/assets/stats/stats.js +24477 -24344
- package/core/built/admin/index.html +3 -3
- package/core/frontend/helpers/ghost_head.js +9 -9
- package/core/frontend/public/ghost-stats.min.js +3 -3
- package/core/frontend/public/member-attribution.min.js +1 -1
- package/core/frontend/src/ghost-stats/ghost-stats.js +18 -4
- package/core/frontend/src/member-attribution/member-attribution.js +28 -18
- package/core/frontend/src/utils/url-attribution.js +53 -40
- package/core/server/api/endpoints/utils/serializers/input/posts.js +7 -5
- package/core/server/services/members/emails/signin.js +3 -2
- package/core/server/services/tinybird/TinybirdService.js +6 -1
- package/core/server/services/update-check/UpdateCheckService.js +1 -1
- package/package.json +5 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/yarn.lock +331 -49
- package/components/tryghost-i18n-6.0.7.tgz +0 -0
|
@@ -3,63 +3,76 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
6
|
+
* @typedef {Object} AttributionData
|
|
7
|
+
* @property {string|null} source - Primary attribution source (ref || source || utm_source)
|
|
8
|
+
* @property {string|null} medium - UTM medium parameter
|
|
9
|
+
* @property {string|null} url - Browser's document.referrer
|
|
10
|
+
* @property {string|null} utmSource - UTM source parameter
|
|
11
|
+
* @property {string|null} utmMedium - UTM medium parameter
|
|
12
|
+
* @property {string|null} utmTerm - UTM term/keyword parameter
|
|
13
|
+
* @property {string|null} utmCampaign - UTM campaign parameter
|
|
14
|
+
* @property {string|null} utmContent - UTM content/variant parameter
|
|
10
15
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extracts attribution parameters from URL search params
|
|
19
|
+
* @private
|
|
20
|
+
* @param {URLSearchParams} searchParams - The search params to parse
|
|
21
|
+
* @returns {AttributionData} Parsed attribution data with all UTM parameters
|
|
22
|
+
*/
|
|
23
|
+
function extractParams(searchParams) {
|
|
24
|
+
const refParam = searchParams.get('ref');
|
|
25
|
+
const sourceParam = searchParams.get('source');
|
|
26
|
+
const utmSourceParam = searchParams.get('utm_source');
|
|
27
|
+
const utmMediumParam = searchParams.get('utm_medium');
|
|
28
|
+
const utmTermParam = searchParams.get('utm_term');
|
|
29
|
+
const utmCampaignParam = searchParams.get('utm_campaign');
|
|
30
|
+
const utmContentParam = searchParams.get('utm_content');
|
|
20
31
|
|
|
21
32
|
// Determine primary source
|
|
22
33
|
const referrerSource = refParam || sourceParam || utmSourceParam || null;
|
|
23
34
|
|
|
24
|
-
// Check portal hash if needed
|
|
25
|
-
if (!referrerSource && currentUrl.hash && currentUrl.hash.includes('#/portal')) {
|
|
26
|
-
return parsePortalHash(currentUrl);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
35
|
return {
|
|
30
36
|
source: referrerSource,
|
|
31
37
|
medium: utmMediumParam || null,
|
|
32
|
-
url: window.document.referrer || null
|
|
38
|
+
url: window.document.referrer || null,
|
|
39
|
+
utmSource: utmSourceParam || null,
|
|
40
|
+
utmMedium: utmMediumParam || null,
|
|
41
|
+
utmTerm: utmTermParam || null,
|
|
42
|
+
utmCampaign: utmCampaignParam || null,
|
|
43
|
+
utmContent: utmContentParam || null
|
|
33
44
|
};
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
/**
|
|
37
|
-
* Parses
|
|
48
|
+
* Parses URL parameters to extract complete referrer/attribution data
|
|
38
49
|
*
|
|
39
|
-
* @param {
|
|
40
|
-
* @returns {
|
|
50
|
+
* @param {string} url - The URL to parse (defaults to current URL)
|
|
51
|
+
* @returns {AttributionData} Complete attribution data including all UTM parameters
|
|
41
52
|
*/
|
|
42
|
-
export function
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const utmSourceParam = hashUrl.searchParams.get('utm_source');
|
|
47
|
-
const utmMediumParam = hashUrl.searchParams.get('utm_medium');
|
|
53
|
+
export function parseReferrerData(url) {
|
|
54
|
+
// Extract current URL parameters
|
|
55
|
+
const currentUrl = new URL(url || window.location.href);
|
|
56
|
+
let searchParams = currentUrl.searchParams;
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
58
|
+
// Handle portal hash URLs - extract params from hash instead
|
|
59
|
+
if (currentUrl.hash && currentUrl.hash.includes('#/portal')) {
|
|
60
|
+
const hashUrl = new URL(currentUrl.href.replace('/#/portal', ''));
|
|
61
|
+
searchParams = hashUrl.searchParams;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return extractParams(searchParams);
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* @
|
|
68
|
+
* Selects the primary referrer value from parsed attribution data
|
|
69
|
+
* Prioritizes: source → medium → url
|
|
70
|
+
* Filters out same-domain referrers
|
|
71
|
+
* @private
|
|
72
|
+
* @param {AttributionData} referrerData - Parsed referrer data
|
|
73
|
+
* @returns {string|null} Primary referrer value or null
|
|
61
74
|
*/
|
|
62
|
-
|
|
75
|
+
function selectPrimaryReferrer(referrerData) {
|
|
63
76
|
const { source, medium, url } = referrerData;
|
|
64
77
|
const finalReferrer = source || medium || url || null;
|
|
65
78
|
|
|
@@ -87,6 +100,6 @@ export function getFinalReferrer(referrerData) {
|
|
|
87
100
|
* @returns {string|null} Final referrer value
|
|
88
101
|
*/
|
|
89
102
|
export function getReferrer(url) {
|
|
90
|
-
const referrerData =
|
|
91
|
-
return
|
|
103
|
+
const referrerData = parseReferrerData(url);
|
|
104
|
+
return selectPrimaryReferrer(referrerData);
|
|
92
105
|
}
|
|
@@ -19,10 +19,10 @@ const messages = {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Selects all allowed columns for the given frame.
|
|
22
|
-
*
|
|
22
|
+
*
|
|
23
23
|
* NOTE: This doesn't stop them from being FETCHED, just returned in the response. This causes
|
|
24
24
|
* the output serializer to remove them from the data object before returning.
|
|
25
|
-
*
|
|
25
|
+
*
|
|
26
26
|
* NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
|
|
27
27
|
*
|
|
28
28
|
* @param {Object} frame - The frame object.
|
|
@@ -37,10 +37,10 @@ function removeSourceFormats(frame) {
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Selects all allowed columns for the given frame.
|
|
40
|
-
*
|
|
40
|
+
*
|
|
41
41
|
* This removes the lexical and mobiledoc columns from the query. This is a performance improvement as we never intend
|
|
42
42
|
* to expose those columns in the content API and they are very large datasets to be passing around and de/serializing.
|
|
43
|
-
*
|
|
43
|
+
*
|
|
44
44
|
* NOTE: This is only intended for the Content API. We need these fields within Admin API responses.
|
|
45
45
|
*
|
|
46
46
|
* @param {Object} frame - The frame object.
|
|
@@ -97,7 +97,9 @@ function setDefaultOrder(frame) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (!frame.options.order && !frame.options.autoOrder) {
|
|
100
|
-
|
|
100
|
+
// use id as fallback to ensure consistent ordering across pages when posts
|
|
101
|
+
// have the same published_at timestamp
|
|
102
|
+
frame.options.order = 'published_at desc, id desc';
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -112,8 +112,9 @@ module.exports = ({t, siteTitle, email, url, otc, accentColor = '#15212A', siteD
|
|
|
112
112
|
|
|
113
113
|
<!-- START CENTERED CONTAINER -->
|
|
114
114
|
<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;">${otc ? t('Welcome back to {siteTitle}! Your verification code is {otc}.', {siteTitle, otc, interpolation: {escapeValue: false}}) : t('Welcome back to {siteTitle}!', {siteTitle, interpolation: {escapeValue: false}})}</span>
|
|
115
|
+
<!-- SPACING FOR PREVIEW TEXT -->
|
|
115
116
|
<div style="display:none; max-height:0; overflow:hidden; mso-hide: all;" aria-hidden="true" role="presentation">
|
|
116
|
-
&
|
|
117
|
+
${'‌ '.repeat(75)}
|
|
117
118
|
</div>
|
|
118
119
|
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 8px;">
|
|
119
120
|
|
|
@@ -151,7 +152,7 @@ module.exports = ({t, siteTitle, email, url, otc, accentColor = '#15212A', siteD
|
|
|
151
152
|
</tr>
|
|
152
153
|
</tbody>
|
|
153
154
|
</table>
|
|
154
|
-
<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: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 24px;">${t('You can also copy & paste this URL into your browser:')}
|
|
155
|
+
<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: 15px; color: #3A464C; font-weight: normal; margin: 0; line-height: 24px;">${t('You can also copy & paste this URL into your browser:')}</p>`
|
|
155
156
|
:
|
|
156
157
|
`<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: 32px;">${t('Welcome back! Use this link to securely sign in to your {siteTitle} account:', {siteTitle, interpolation: {escapeValue: false}})}</p>
|
|
157
158
|
<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;">
|
|
@@ -53,7 +53,12 @@ const TINYBIRD_PIPES = [
|
|
|
53
53
|
'api_top_locations',
|
|
54
54
|
'api_top_os',
|
|
55
55
|
'api_top_pages',
|
|
56
|
-
'api_top_sources'
|
|
56
|
+
'api_top_sources',
|
|
57
|
+
'api_top_utm_sources',
|
|
58
|
+
'api_top_utm_mediums',
|
|
59
|
+
'api_top_utm_campaigns',
|
|
60
|
+
'api_top_utm_contents',
|
|
61
|
+
'api_top_utm_terms'
|
|
57
62
|
];
|
|
58
63
|
|
|
59
64
|
/**
|
|
@@ -189,7 +189,7 @@ class UpdateCheckService {
|
|
|
189
189
|
|
|
190
190
|
try {
|
|
191
191
|
const response = await this.request(checkEndpoint, reqObj);
|
|
192
|
-
return response.body;
|
|
192
|
+
return JSON.parse(response.body);
|
|
193
193
|
} catch (err) {
|
|
194
194
|
// CASE: no notifications available, ignore
|
|
195
195
|
if (err.statusCode === 404) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghost",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.8",
|
|
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.
|
|
89
|
+
"@tryghost/i18n": "file:components/tryghost-i18n-6.0.8.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",
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"heic-convert": "2.1.0",
|
|
167
167
|
"html-to-text": "5.1.1",
|
|
168
168
|
"html5parser": "2.0.2",
|
|
169
|
-
"human-number": "2.0.
|
|
169
|
+
"human-number": "2.0.6",
|
|
170
170
|
"iconv-lite": "0.6.3",
|
|
171
171
|
"image-size": "1.2.1",
|
|
172
172
|
"intl": "1.2.5",
|
|
@@ -232,7 +232,7 @@
|
|
|
232
232
|
"@types/bookshelf": "1.2.9",
|
|
233
233
|
"@types/common-tags": "1.8.4",
|
|
234
234
|
"@types/jsonwebtoken": "9.0.10",
|
|
235
|
-
"@types/node": "22.18.
|
|
235
|
+
"@types/node": "22.18.3",
|
|
236
236
|
"@types/node-jose": "1.1.13",
|
|
237
237
|
"@types/nodemailer": "6.4.19",
|
|
238
238
|
"@types/sinon": "17.0.4",
|
|
@@ -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.
|
|
276
|
+
"@tryghost/i18n": "file:components/tryghost-i18n-6.0.8.tgz"
|
|
277
277
|
},
|
|
278
278
|
"nx": {
|
|
279
279
|
"targets": {
|