ghost 6.9.1 → 6.9.3
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.9.3.tgz +0 -0
- package/content/themes/source/package.json +1 -1
- package/core/built/admin/assets/activitypub/activitypub.js +2 -2
- package/core/built/admin/assets/activitypub/{index-C19nEXqT.mjs → index-D-0TWnTq.mjs} +2447 -2443
- package/core/built/admin/assets/activitypub/{index-B29oZuTp.mjs → index-Dz4ykJpN.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-C0HG4CwA.mjs → CodeEditorView-C4K2SFCa.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-Cjl9AHTm.mjs → index-D1JNSNMf.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-DRpMCs_c.mjs → index-DLS4G2Af.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{index-Cz3Y1eRN.mjs → index-jt7mifza.mjs} +23310 -22917
- package/core/built/admin/assets/admin-x-settings/{modals-DXD3MDLp.mjs → modals-Bkrvssih.mjs} +8884 -8879
- package/core/built/admin/assets/{chunk.524.56454d8add89b041f4df.js → chunk.524.6d040cb21c767f0236ae.js} +7 -7
- package/core/built/admin/assets/{chunk.582.a4916bd533becb58fd9c.js → chunk.582.e35aed09ef750c552601.js} +10 -10
- package/core/built/admin/assets/ghost-192beb3c8f2f6e58b70d3aade481ae15.css +1 -0
- package/core/built/admin/assets/{ghost-94d0fbb20e8e880fa9ba144cf26ab050.js → ghost-5fd8d4d5e1ffe4d8405d30f3efba12b7.js} +105 -89
- package/core/built/admin/assets/ghost-dark-e50f4c063ecc977f023e78da2dd67b42.css +1 -0
- package/core/built/admin/assets/posts/posts.js +6745 -6741
- package/core/built/admin/assets/stats/stats.js +16015 -16011
- package/core/built/admin/index.html +4 -4
- package/core/server/data/tinybird/datasources/_mv_hits.datasource +4 -1
- package/core/server/data/tinybird/endpoints/README.md +109 -0
- package/core/server/data/tinybird/endpoints/api_kpis.pipe +2 -23
- package/core/server/data/tinybird/endpoints/api_monitoring_ingestion.pipe +14 -13
- package/core/server/data/tinybird/endpoints/api_monitoring_ingestion_aggregated.pipe +13 -12
- package/core/server/data/tinybird/endpoints/api_top_locations.pipe +0 -19
- package/core/server/data/tinybird/endpoints/api_top_pages.pipe +0 -23
- package/core/server/data/tinybird/endpoints/api_top_sources.pipe +0 -11
- package/core/server/data/tinybird/endpoints/api_top_utm_campaigns.pipe +0 -6
- package/core/server/data/tinybird/endpoints/api_top_utm_contents.pipe +0 -6
- package/core/server/data/tinybird/endpoints/api_top_utm_mediums.pipe +0 -6
- package/core/server/data/tinybird/endpoints/api_top_utm_sources.pipe +0 -6
- package/core/server/data/tinybird/endpoints/api_top_utm_terms.pipe +0 -6
- package/core/server/data/tinybird/pipes/filtered_sessions.pipe +28 -8
- package/core/server/data/tinybird/pipes/mv_hits.pipe +23 -11
- package/core/server/data/tinybird/tests/api_top_pages.yaml +5 -2
- package/core/server/services/email-service/DomainWarmingService.js +47 -9
- package/core/server/services/email-service/DomainWarmingService.ts +62 -11
- package/core/server/services/email-service/EmailServiceWrapper.js +2 -1
- package/core/server/services/member-welcome-emails/jobs/index.js +13 -9
- package/package.json +3 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/yarn.lock +5 -50
- package/components/tryghost-i18n-6.9.1.tgz +0 -0
- package/core/built/admin/assets/ghost-dark-6c9cfa9c364e28c57e5983f68ec6f2fc.css +0 -1
- package/core/built/admin/assets/ghost-f724c1d53f5402f78a2d8cf8beb7c716.css +0 -1
- package/core/built/admin/assets/img/google-docs-1e42cc272fc088da49e4b0ddfb01b006.svg +0 -6
- package/core/built/admin/assets/img/mailchimp-f22b1e130aac764965b9306d7265a6b2.svg +0 -8
- package/core/built/admin/assets/img/patreon-b19a5e6418a72977a16b30039d374d04.svg +0 -7
- package/core/built/admin/assets/img/paypal-38e9448ce7549ea4caf8e7753ae661d6.svg +0 -8
- package/core/built/admin/assets/img/slackicon-406aadea8994ca2ddee9c1d7157208db.png +0 -0
- package/core/built/admin/assets/img/themes/Alto-0dfe76694ed222d6d96fc9c8db979a38.png +0 -0
- package/core/built/admin/assets/img/themes/Bulletin-d66dec818ad0ba2965dd7eb3130c621c.png +0 -0
- package/core/built/admin/assets/img/themes/Casper-9a0ce71df3a1c589c1414ad2aa5b8aeb.png +0 -0
- package/core/built/admin/assets/img/themes/Dawn-302fbfdbc352098a256137159bd83dd8.png +0 -0
- package/core/built/admin/assets/img/themes/Digest-698e78d8e8481daff8ae4a8647528dc9.png +0 -0
- package/core/built/admin/assets/img/themes/Dope-d099dfca697adae16baa76f89520c5b3.png +0 -0
- package/core/built/admin/assets/img/themes/Ease-7075f809892f10c58892e15a57a4aae4.png +0 -0
- package/core/built/admin/assets/img/themes/Edge-1e5e0eec6941d7bdca02cebb66187357.png +0 -0
- package/core/built/admin/assets/img/themes/Edition-10111a2b8458168dcff81b7fb151be70.png +0 -0
- package/core/built/admin/assets/img/themes/Episode-e4c86d1f75ef1d8a77791d7fd519fdd4.png +0 -0
- package/core/built/admin/assets/img/themes/Headline-f70eaf49b9fcae1ddfe3d4496d8be54d.png +0 -0
- package/core/built/admin/assets/img/themes/Journal-07d35b2311501d2738bad1907ba2f7e1.png +0 -0
- package/core/built/admin/assets/img/themes/London-4e042390da16fecef947f3a7001d03db.png +0 -0
- package/core/built/admin/assets/img/themes/Ruby-b896885448e0f28ca62c6dcd56c732aa.png +0 -0
- package/core/built/admin/assets/img/themes/Solo-0292eb9ae0ca7b578cff50824d40cc86.png +0 -0
- package/core/built/admin/assets/img/themes/Source-Magazine-176385eb99561485ce6385598f7599b0.png +0 -0
- package/core/built/admin/assets/img/themes/Source-Newsletter-bb1a8611a326edb78f9ecb8bc1838c81.png +0 -0
- package/core/built/admin/assets/img/themes/Source-f29c6d6abe774ea7d5940a7431069fce.png +0 -0
- package/core/built/admin/assets/img/themes/Taste-a24d2a786900d9caff7e773ca0040991.png +0 -0
- package/core/built/admin/assets/img/themes/Wave-b98fadfd3ed16e8b2e383dd8e8e5dca2.png +0 -0
- package/core/built/admin/assets/img/typeform-9f23f8712d776a7515594676285266f5.svg +0 -7
- package/core/built/admin/assets/img/zero-bounce-ee799eddb1f88e33ab8c462858cbfed9.png +0 -0
|
@@ -1,32 +1,62 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DomainWarmingService = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for domain warming email volume scaling.
|
|
6
|
+
*
|
|
7
|
+
* | Volume Range | Multiplier |
|
|
8
|
+
* |--------------|--------------------------------------------------|
|
|
9
|
+
* | ≤100 (base) | 200 messages |
|
|
10
|
+
* | 101 – 1k | 1.25× (conservative early ramp) |
|
|
11
|
+
* | 1k – 5k | 1.5× (moderate increase) |
|
|
12
|
+
* | 5k – 100k | 1.75× (faster ramp after proving deliverability) |
|
|
13
|
+
* | 100k – 400k | 2× |
|
|
14
|
+
* | 400k+ | min(1.2×, +75k) cap |
|
|
15
|
+
*/
|
|
4
16
|
const WARMUP_SCALING_TABLE = {
|
|
5
17
|
base: {
|
|
6
18
|
limit: 100,
|
|
7
19
|
value: 200
|
|
8
20
|
},
|
|
9
21
|
thresholds: [{
|
|
22
|
+
limit: 1_000,
|
|
23
|
+
scale: 1.25
|
|
24
|
+
}, {
|
|
25
|
+
limit: 5_000,
|
|
26
|
+
scale: 1.5
|
|
27
|
+
}, {
|
|
10
28
|
limit: 100_000,
|
|
11
|
-
scale:
|
|
29
|
+
scale: 1.75
|
|
12
30
|
}, {
|
|
13
31
|
limit: 400_000,
|
|
14
|
-
scale:
|
|
32
|
+
scale: 2
|
|
15
33
|
}],
|
|
16
|
-
|
|
34
|
+
highVolume: {
|
|
35
|
+
threshold: 400_000,
|
|
36
|
+
maxScale: 1.2,
|
|
37
|
+
maxAbsoluteIncrease: 75_000
|
|
38
|
+
}
|
|
17
39
|
};
|
|
18
40
|
class DomainWarmingService {
|
|
19
41
|
#emailModel;
|
|
20
42
|
#labs;
|
|
43
|
+
#config;
|
|
21
44
|
constructor(dependencies) {
|
|
22
45
|
this.#emailModel = dependencies.models.Email;
|
|
23
46
|
this.#labs = dependencies.labs;
|
|
47
|
+
this.#config = dependencies.config;
|
|
24
48
|
}
|
|
25
49
|
/**
|
|
26
50
|
* @returns Whether the domain warming feature is enabled
|
|
27
51
|
*/
|
|
28
52
|
isEnabled() {
|
|
29
|
-
|
|
53
|
+
const hasLabsFlag = this.#labs.isSet('domainWarmup');
|
|
54
|
+
if (!hasLabsFlag) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const fallbackDomain = this.#config.get('hostSettings:managedEmail:fallbackDomain');
|
|
58
|
+
const fallbackAddress = this.#config.get('hostSettings:managedEmail:fallbackAddress');
|
|
59
|
+
return Boolean(fallbackDomain && fallbackAddress);
|
|
30
60
|
}
|
|
31
61
|
/**
|
|
32
62
|
* Get the maximum amount of emails that should be sent from the warming sending domain in today's newsletter
|
|
@@ -41,14 +71,15 @@ class DomainWarmingService {
|
|
|
41
71
|
* @returns The highest number of messages sent from the CSD in a single email (excluding today)
|
|
42
72
|
*/
|
|
43
73
|
async #getHighestCount() {
|
|
44
|
-
const
|
|
74
|
+
const result = await this.#emailModel.findPage({
|
|
45
75
|
filter: `created_at:<${new Date().toISOString().split('T')[0]}`,
|
|
46
|
-
order: 'csd_email_count DESC'
|
|
76
|
+
order: 'csd_email_count DESC',
|
|
77
|
+
limit: 1
|
|
47
78
|
});
|
|
48
|
-
if (!
|
|
79
|
+
if (!result.data.length) {
|
|
49
80
|
return 0;
|
|
50
81
|
}
|
|
51
|
-
const count =
|
|
82
|
+
const count = result.data[0].get('csd_email_count');
|
|
52
83
|
return count || 0;
|
|
53
84
|
}
|
|
54
85
|
/**
|
|
@@ -59,12 +90,19 @@ class DomainWarmingService {
|
|
|
59
90
|
if (lastCount <= WARMUP_SCALING_TABLE.base.limit) {
|
|
60
91
|
return WARMUP_SCALING_TABLE.base.value;
|
|
61
92
|
}
|
|
93
|
+
// For high volume senders (400k+), cap the increase at 20% or 75k absolute
|
|
94
|
+
if (lastCount > WARMUP_SCALING_TABLE.highVolume.threshold) {
|
|
95
|
+
const scaledIncrease = Math.ceil(lastCount * WARMUP_SCALING_TABLE.highVolume.maxScale);
|
|
96
|
+
const absoluteIncrease = lastCount + WARMUP_SCALING_TABLE.highVolume.maxAbsoluteIncrease;
|
|
97
|
+
return Math.min(scaledIncrease, absoluteIncrease);
|
|
98
|
+
}
|
|
62
99
|
for (const threshold of WARMUP_SCALING_TABLE.thresholds.sort((a, b) => a.limit - b.limit)) {
|
|
63
100
|
if (lastCount <= threshold.limit) {
|
|
64
101
|
return Math.ceil(lastCount * threshold.scale);
|
|
65
102
|
}
|
|
66
103
|
}
|
|
67
|
-
|
|
104
|
+
// This should not be reached given the thresholds cover all cases up to highVolume.threshold
|
|
105
|
+
return Math.ceil(lastCount * WARMUP_SCALING_TABLE.highVolume.maxScale);
|
|
68
106
|
}
|
|
69
107
|
}
|
|
70
108
|
exports.DomainWarmingService = DomainWarmingService;
|
|
@@ -2,8 +2,12 @@ type LabsService = {
|
|
|
2
2
|
isSet: (flag: string) => boolean;
|
|
3
3
|
};
|
|
4
4
|
|
|
5
|
+
type ConfigService = {
|
|
6
|
+
get: (key: string) => string | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
type EmailModel = {
|
|
6
|
-
|
|
10
|
+
findPage: (options: {filter: string; order: string; limit: number}) => Promise<{data: EmailRecord[]}>;
|
|
7
11
|
};
|
|
8
12
|
|
|
9
13
|
type EmailRecord = {
|
|
@@ -20,41 +24,79 @@ type WarmupScalingTable = {
|
|
|
20
24
|
limit: number;
|
|
21
25
|
scale: number;
|
|
22
26
|
}[];
|
|
23
|
-
|
|
27
|
+
highVolume: {
|
|
28
|
+
threshold: number;
|
|
29
|
+
maxScale: number;
|
|
30
|
+
maxAbsoluteIncrease: number;
|
|
31
|
+
};
|
|
24
32
|
}
|
|
25
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Configuration for domain warming email volume scaling.
|
|
36
|
+
*
|
|
37
|
+
* | Volume Range | Multiplier |
|
|
38
|
+
* |--------------|--------------------------------------------------|
|
|
39
|
+
* | ≤100 (base) | 200 messages |
|
|
40
|
+
* | 101 – 1k | 1.25× (conservative early ramp) |
|
|
41
|
+
* | 1k – 5k | 1.5× (moderate increase) |
|
|
42
|
+
* | 5k – 100k | 1.75× (faster ramp after proving deliverability) |
|
|
43
|
+
* | 100k – 400k | 2× |
|
|
44
|
+
* | 400k+ | min(1.2×, +75k) cap |
|
|
45
|
+
*/
|
|
26
46
|
const WARMUP_SCALING_TABLE: WarmupScalingTable = {
|
|
27
47
|
base: {
|
|
28
48
|
limit: 100,
|
|
29
49
|
value: 200
|
|
30
50
|
},
|
|
31
51
|
thresholds: [{
|
|
52
|
+
limit: 1_000,
|
|
53
|
+
scale: 1.25
|
|
54
|
+
}, {
|
|
55
|
+
limit: 5_000,
|
|
56
|
+
scale: 1.5
|
|
57
|
+
}, {
|
|
32
58
|
limit: 100_000,
|
|
33
|
-
scale:
|
|
59
|
+
scale: 1.75
|
|
34
60
|
}, {
|
|
35
61
|
limit: 400_000,
|
|
36
|
-
scale:
|
|
62
|
+
scale: 2
|
|
37
63
|
}],
|
|
38
|
-
|
|
64
|
+
highVolume: {
|
|
65
|
+
threshold: 400_000,
|
|
66
|
+
maxScale: 1.2,
|
|
67
|
+
maxAbsoluteIncrease: 75_000
|
|
68
|
+
}
|
|
39
69
|
};
|
|
40
70
|
|
|
41
71
|
export class DomainWarmingService {
|
|
42
72
|
#emailModel: EmailModel;
|
|
43
73
|
#labs: LabsService;
|
|
74
|
+
#config: ConfigService;
|
|
44
75
|
|
|
45
76
|
constructor(dependencies: {
|
|
46
77
|
models: {Email: EmailModel};
|
|
47
78
|
labs: LabsService;
|
|
79
|
+
config: ConfigService;
|
|
48
80
|
}) {
|
|
49
81
|
this.#emailModel = dependencies.models.Email;
|
|
50
82
|
this.#labs = dependencies.labs;
|
|
83
|
+
this.#config = dependencies.config;
|
|
51
84
|
}
|
|
52
85
|
|
|
53
86
|
/**
|
|
54
87
|
* @returns Whether the domain warming feature is enabled
|
|
55
88
|
*/
|
|
56
89
|
isEnabled(): boolean {
|
|
57
|
-
|
|
90
|
+
const hasLabsFlag = this.#labs.isSet('domainWarmup');
|
|
91
|
+
|
|
92
|
+
if (!hasLabsFlag) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const fallbackDomain = this.#config.get('hostSettings:managedEmail:fallbackDomain');
|
|
97
|
+
const fallbackAddress = this.#config.get('hostSettings:managedEmail:fallbackAddress');
|
|
98
|
+
|
|
99
|
+
return Boolean(fallbackDomain && fallbackAddress);
|
|
58
100
|
}
|
|
59
101
|
|
|
60
102
|
/**
|
|
@@ -72,16 +114,17 @@ export class DomainWarmingService {
|
|
|
72
114
|
* @returns The highest number of messages sent from the CSD in a single email (excluding today)
|
|
73
115
|
*/
|
|
74
116
|
async #getHighestCount(): Promise<number> {
|
|
75
|
-
const
|
|
117
|
+
const result = await this.#emailModel.findPage({
|
|
76
118
|
filter: `created_at:<${new Date().toISOString().split('T')[0]}`,
|
|
77
|
-
order: 'csd_email_count DESC'
|
|
119
|
+
order: 'csd_email_count DESC',
|
|
120
|
+
limit: 1
|
|
78
121
|
});
|
|
79
122
|
|
|
80
|
-
if (!
|
|
123
|
+
if (!result.data.length) {
|
|
81
124
|
return 0;
|
|
82
125
|
}
|
|
83
126
|
|
|
84
|
-
const count =
|
|
127
|
+
const count = result.data[0].get('csd_email_count');
|
|
85
128
|
return count || 0;
|
|
86
129
|
}
|
|
87
130
|
|
|
@@ -94,12 +137,20 @@ export class DomainWarmingService {
|
|
|
94
137
|
return WARMUP_SCALING_TABLE.base.value;
|
|
95
138
|
}
|
|
96
139
|
|
|
140
|
+
// For high volume senders (400k+), cap the increase at 20% or 75k absolute
|
|
141
|
+
if (lastCount > WARMUP_SCALING_TABLE.highVolume.threshold) {
|
|
142
|
+
const scaledIncrease = Math.ceil(lastCount * WARMUP_SCALING_TABLE.highVolume.maxScale);
|
|
143
|
+
const absoluteIncrease = lastCount + WARMUP_SCALING_TABLE.highVolume.maxAbsoluteIncrease;
|
|
144
|
+
return Math.min(scaledIncrease, absoluteIncrease);
|
|
145
|
+
}
|
|
146
|
+
|
|
97
147
|
for (const threshold of WARMUP_SCALING_TABLE.thresholds.sort((a, b) => a.limit - b.limit)) {
|
|
98
148
|
if (lastCount <= threshold.limit) {
|
|
99
149
|
return Math.ceil(lastCount * threshold.scale);
|
|
100
150
|
}
|
|
101
151
|
}
|
|
102
152
|
|
|
103
|
-
|
|
153
|
+
// This should not be reached given the thresholds cover all cases up to highVolume.threshold
|
|
154
|
+
return Math.ceil(lastCount * WARMUP_SCALING_TABLE.highVolume.maxScale);
|
|
104
155
|
}
|
|
105
156
|
}
|
|
@@ -8,20 +8,24 @@ let hasScheduled = {
|
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
10
10
|
async scheduleMemberWelcomeEmailJob() {
|
|
11
|
-
|
|
11
|
+
const testInboxDisabled = !config.get('memberWelcomeEmailTestInbox');
|
|
12
|
+
const alreadyScheduledProcessing = hasScheduled.processOutbox;
|
|
13
|
+
|
|
14
|
+
if (testInboxDisabled || alreadyScheduledProcessing) {
|
|
12
15
|
return false;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
job: path.resolve(__dirname, 'process-outbox.js'),
|
|
19
|
-
name: 'process-member-welcome-emails'
|
|
20
|
-
});
|
|
18
|
+
const configValue = config.get('memberWelcomeEmailSendInstantly');
|
|
19
|
+
const testEmailSendInstantly = configValue === true || configValue === 'true';
|
|
20
|
+
const cronSchedule = testEmailSendInstantly ? '*/3 * * * * *' : '0 */5 * * * *';
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
jobsService.addJob({
|
|
23
|
+
at: cronSchedule,
|
|
24
|
+
job: path.resolve(__dirname, 'process-outbox.js'),
|
|
25
|
+
name: 'process-member-welcome-emails'
|
|
26
|
+
});
|
|
24
27
|
|
|
28
|
+
hasScheduled.processOutbox = true;
|
|
25
29
|
return hasScheduled.processOutbox;
|
|
26
30
|
}
|
|
27
31
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghost",
|
|
3
|
-
"version": "6.9.
|
|
3
|
+
"version": "6.9.3",
|
|
4
4
|
"description": "The professional publishing platform",
|
|
5
5
|
"author": "Ghost Foundation",
|
|
6
6
|
"homepage": "https://ghost.org",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"@tryghost/helpers": "1.1.97",
|
|
88
88
|
"@tryghost/html-to-plaintext": "1.0.4",
|
|
89
89
|
"@tryghost/http-cache-utils": "0.1.20",
|
|
90
|
-
"@tryghost/i18n": "file:components/tryghost-i18n-6.9.
|
|
90
|
+
"@tryghost/i18n": "file:components/tryghost-i18n-6.9.3.tgz",
|
|
91
91
|
"@tryghost/image-transform": "1.4.6",
|
|
92
92
|
"@tryghost/job-manager": "1.0.3",
|
|
93
93
|
"@tryghost/kg-card-factory": "5.1.2",
|
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
"jackspeak": "2.3.6",
|
|
275
275
|
"moment": "2.24.0",
|
|
276
276
|
"moment-timezone": "0.5.45",
|
|
277
|
-
"@tryghost/i18n": "file:components/tryghost-i18n-6.9.
|
|
277
|
+
"@tryghost/i18n": "file:components/tryghost-i18n-6.9.3.tgz"
|
|
278
278
|
},
|
|
279
279
|
"nx": {
|
|
280
280
|
"targets": {
|