ghost 5.0.2 → 5.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.
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/screen.css +303 -35
- package/content/themes/casper/default.hbs +17 -7
- package/content/themes/casper/package.json +3 -2
- package/content/themes/casper/partials/icons/facebook.hbs +1 -1
- package/content/themes/casper/partials/icons/fire.hbs +3 -0
- package/content/themes/casper/partials/icons/lock.hbs +5 -0
- package/content/themes/casper/partials/icons/twitter.hbs +1 -1
- package/content/themes/casper/partials/post-card.hbs +39 -19
- package/content/themes/casper/post.hbs +20 -9
- package/core/built/assets/{chunk.3.52b444495dfcf50afb0b.js → chunk.3.dc389a0f93cb5fabd695.js} +19 -19
- package/core/built/assets/{ghost-dark-b6e3268bcae976a8675b0d9ae54540f2.css → ghost-dark-2eb4d82f3efada72f3beaae7b6ca8db3.css} +1 -1
- package/core/built/assets/{ghost.min-b37a2752b0abda202c14c948b8bc3587.js → ghost.min-1e4e29e84772e7a2af07258b4d089bfc.js} +297 -301
- package/core/built/assets/{ghost.min-a40c7b301c702bd84c2fae19366ab5d7.css → ghost.min-39cecb1bdd781ae091204535bf9df8c7.css} +1 -1
- package/core/built/assets/{vendor.min-2bca41946dea27dc292428db605d466d.js → vendor.min-ea369e6487643585f35409d474b06789.js} +77 -94
- package/core/frontend/helpers/tiers.js +1 -16
- package/core/frontend/services/rendering/context.js +0 -3
- package/core/frontend/services/rendering/format-response.js +5 -1
- package/core/frontend/services/routing/controllers/static.js +4 -1
- package/core/frontend/services/routing/controllers/unsubscribe.js +10 -34
- package/core/frontend/web/middleware/handle-image-sizes.js +50 -10
- package/core/frontend/web/middleware/serve-favicon.js +3 -18
- package/core/server/api/canary/utils/serializers/output/mappers/posts.js +1 -4
- package/core/server/api/canary/utils/serializers/output/members.js +11 -14
- package/core/server/api/canary/utils/serializers/output/settings.js +13 -0
- package/core/server/api/canary/utils/validators/input/images.js +32 -18
- package/core/server/api/canary/utils/validators/input/settings.js +6 -0
- package/core/server/lib/image/blog-icon.js +51 -27
- package/core/server/lib/mobiledoc.js +1 -1
- package/core/server/models/member.js +0 -12
- package/core/server/models/relations/authors.js +0 -19
- package/core/server/services/invites/invites.js +1 -0
- package/core/server/services/mega/mega.js +0 -55
- package/core/server/services/members/utils.js +1 -3
- package/core/server/services/webhooks/webhooks-service.js +1 -1
- package/core/server/web/admin/views/default-prod.html +4 -4
- package/core/server/web/admin/views/default.html +4 -4
- package/core/server/web/api/middleware/normalize-image.js +1 -1
- package/core/shared/config/overrides.json +5 -2
- package/core/shared/labs.js +2 -13
- package/package.json +16 -16
- package/yarn.lock +137 -98
|
@@ -2,7 +2,6 @@ const _ = require('lodash');
|
|
|
2
2
|
const Promise = require('bluebird');
|
|
3
3
|
const debug = require('@tryghost/debug')('mega');
|
|
4
4
|
const tpl = require('@tryghost/tpl');
|
|
5
|
-
const url = require('url');
|
|
6
5
|
const moment = require('moment');
|
|
7
6
|
const ObjectID = require('bson-objectid');
|
|
8
7
|
const errors = require('@tryghost/errors');
|
|
@@ -15,7 +14,6 @@ const jobsService = require('../jobs');
|
|
|
15
14
|
const db = require('../../data/db');
|
|
16
15
|
const models = require('../../models');
|
|
17
16
|
const postEmailSerializer = require('./post-email-serializer');
|
|
18
|
-
const labs = require('../../../shared/labs');
|
|
19
17
|
const {getSegmentsFromHtml} = require('./segment-parser');
|
|
20
18
|
|
|
21
19
|
// Used to listen to email.added and email.edited model events originally, I think to offload this - ideally would just use jobs now if possible
|
|
@@ -267,58 +265,6 @@ const retryFailedEmail = async (emailModel) => {
|
|
|
267
265
|
});
|
|
268
266
|
};
|
|
269
267
|
|
|
270
|
-
/**
|
|
271
|
-
* handleUnsubscribeRequest
|
|
272
|
-
*
|
|
273
|
-
* Takes a request/response pair and reads the `unsubscribe` query parameter,
|
|
274
|
-
* using the content to update the members service to set the `subscribed` flag
|
|
275
|
-
* to false on the member
|
|
276
|
-
*
|
|
277
|
-
* If any operation fails, or the request is invalid the function will error - so using
|
|
278
|
-
* as middleware should consider wrapping with `try/catch`
|
|
279
|
-
*
|
|
280
|
-
* @param {Request} req
|
|
281
|
-
* @returns {Promise<void>}
|
|
282
|
-
*/
|
|
283
|
-
async function handleUnsubscribeRequest(req) {
|
|
284
|
-
if (!req.url) {
|
|
285
|
-
throw new errors.BadRequestError({
|
|
286
|
-
message: 'Email address not found.'
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const {query} = url.parse(req.url, true);
|
|
291
|
-
if (!query || !query.uuid) {
|
|
292
|
-
throw new errors.BadRequestError({
|
|
293
|
-
message: (query.preview ? 'Unsubscribe preview' : 'Email address not found.')
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const member = await membersService.api.members.get({
|
|
298
|
-
uuid: query.uuid
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
if (!member) {
|
|
302
|
-
throw new errors.BadRequestError({
|
|
303
|
-
message: 'Email address not found.'
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
try {
|
|
308
|
-
let memberData = {subscribed: false};
|
|
309
|
-
if (labs.isSet('multipleNewsletters')) {
|
|
310
|
-
memberData.newsletters = [];
|
|
311
|
-
}
|
|
312
|
-
const memberModel = await membersService.api.members.update(memberData, {id: member.id});
|
|
313
|
-
return memberModel.toJSON();
|
|
314
|
-
} catch (err) {
|
|
315
|
-
throw new errors.InternalServerError({
|
|
316
|
-
err,
|
|
317
|
-
message: 'Failed to unsubscribe this email address'
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
268
|
async function pendingEmailHandler(emailModel, options) {
|
|
323
269
|
// CASE: do not send email if we import a database
|
|
324
270
|
// TODO: refactor post.published events to never fire on importing
|
|
@@ -590,7 +536,6 @@ module.exports = {
|
|
|
590
536
|
addEmail,
|
|
591
537
|
retryFailedEmail,
|
|
592
538
|
sendTestEmail,
|
|
593
|
-
handleUnsubscribeRequest,
|
|
594
539
|
// NOTE: below are only exposed for testing purposes
|
|
595
540
|
_transformEmailRecipientFilter: transformEmailRecipientFilter,
|
|
596
541
|
_partitionMembersBySegment: partitionMembersBySegment,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const labsService = require('../../../shared/labs');
|
|
2
|
-
|
|
3
1
|
function formatNewsletterResponse(newsletters) {
|
|
4
2
|
return newsletters.map(({id, name, description, sort_order: sortOrder}) => {
|
|
5
3
|
return {id, name, description, sort_order: sortOrder};
|
|
@@ -20,7 +18,7 @@ module.exports.formattedMemberResponse = function formattedMemberResponse(member
|
|
|
20
18
|
subscriptions: member.subscriptions || [],
|
|
21
19
|
paid: member.status !== 'free'
|
|
22
20
|
};
|
|
23
|
-
if (member.newsletters
|
|
21
|
+
if (member.newsletters) {
|
|
24
22
|
data.newsletters = formatNewsletterResponse(member.newsletters);
|
|
25
23
|
}
|
|
26
24
|
return data;
|
|
@@ -50,7 +50,7 @@ class WebhooksService {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
* @returns {WebhooksService} instance of the
|
|
53
|
+
* @returns {WebhooksService} instance of the WebhooksService
|
|
54
54
|
*/
|
|
55
55
|
const getWebhooksServiceInstance = ({WebhookModel}) => {
|
|
56
56
|
return new WebhooksService({WebhookModel});
|
|
@@ -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%225.
|
|
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%225.1%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%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" />
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
<link rel="stylesheet" href="assets/vendor.min-ba66b98f7c24fa40e061c7ffc94f4e23.css">
|
|
41
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
41
|
+
<link rel="stylesheet" href="assets/ghost.min-39cecb1bdd781ae091204535bf9df8c7.css" title="light">
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor.min-
|
|
60
|
-
<script src="assets/ghost.min-
|
|
59
|
+
<script src="assets/vendor.min-ea369e6487643585f35409d474b06789.js"></script>
|
|
60
|
+
<script src="assets/ghost.min-1e4e29e84772e7a2af07258b4d089bfc.js"></script>
|
|
61
61
|
|
|
62
62
|
</body>
|
|
63
63
|
</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%225.
|
|
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%225.1%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%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" />
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
<link rel="stylesheet" href="assets/vendor.min-ba66b98f7c24fa40e061c7ffc94f4e23.css">
|
|
41
|
-
<link rel="stylesheet" href="assets/ghost.min-
|
|
41
|
+
<link rel="stylesheet" href="assets/ghost.min-39cecb1bdd781ae091204535bf9df8c7.css" title="light">
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
<div id="ember-basic-dropdown-wormhole"></div>
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
<script src="assets/vendor.min-
|
|
60
|
-
<script src="assets/ghost.min-
|
|
59
|
+
<script src="assets/vendor.min-ea369e6487643585f35409d474b06789.js"></script>
|
|
60
|
+
<script src="assets/ghost.min-1e4e29e84772e7a2af07258b4d089bfc.js"></script>
|
|
61
61
|
|
|
62
62
|
</body>
|
|
63
63
|
</html>
|
|
@@ -7,7 +7,7 @@ module.exports = function normalize(req, res, next) {
|
|
|
7
7
|
const imageOptimizationOptions = config.get('imageOptimization');
|
|
8
8
|
|
|
9
9
|
// CASE: image transform is not capable of transforming file (e.g. .gif)
|
|
10
|
-
if (!imageTransform.
|
|
10
|
+
if (!imageTransform.shouldResizeFileExtension(req.file.ext) || !imageOptimizationOptions.resize) {
|
|
11
11
|
return next();
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"contentTypes": ["image/jpeg", "image/png", "image/gif", "image/svg+xml", "image/x-icon", "image/vnd.microsoft.icon", "image/webp"]
|
|
50
50
|
},
|
|
51
51
|
"icons": {
|
|
52
|
-
"extensions": [".png", ".ico"],
|
|
53
|
-
"contentTypes": ["image/png", "image/x-icon", "image/vnd.microsoft.icon"]
|
|
52
|
+
"extensions": [".jpg", ".jpeg", ".gif", ".png", ".svg", ".svgz", ".ico", ".webp"],
|
|
53
|
+
"contentTypes": ["image/jpeg", "image/png", "image/gif", "image/svg+xml", "image/x-icon", "image/vnd.microsoft.icon", "image/webp"]
|
|
54
54
|
},
|
|
55
55
|
"db": {
|
|
56
56
|
"extensions": [".json", ".zip"],
|
|
@@ -84,6 +84,9 @@
|
|
|
84
84
|
"w1000": {"width": 1000},
|
|
85
85
|
"w1600": {"width": 1600},
|
|
86
86
|
"w2400": {"width": 2400}
|
|
87
|
+
},
|
|
88
|
+
"internalImageSizes": {
|
|
89
|
+
"icon": {"width": 256, "height": 256}
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
}
|
package/core/shared/labs.js
CHANGED
|
@@ -14,17 +14,7 @@ const messages = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// flags in this list always return `true`, allows quick global enable prior to full flag removal
|
|
17
|
-
const GA_FEATURES = [
|
|
18
|
-
'multipleProducts',
|
|
19
|
-
'tierWelcomePages',
|
|
20
|
-
'tierName',
|
|
21
|
-
'selectablePortalLinks',
|
|
22
|
-
'membersTableStatus',
|
|
23
|
-
'multipleNewsletters',
|
|
24
|
-
'multipleNewslettersUI',
|
|
25
|
-
'membersActivityFeed',
|
|
26
|
-
'dashboardV5'
|
|
27
|
-
];
|
|
17
|
+
const GA_FEATURES = [];
|
|
28
18
|
|
|
29
19
|
// NOTE: this allowlist is meant to be used to filter out any unexpected
|
|
30
20
|
// input for the "labs" setting value
|
|
@@ -34,8 +24,7 @@ const BETA_FEATURES = [
|
|
|
34
24
|
|
|
35
25
|
const ALPHA_FEATURES = [
|
|
36
26
|
'urlCache',
|
|
37
|
-
'beforeAfterCard'
|
|
38
|
-
'tweetGridCard'
|
|
27
|
+
'beforeAfterCard'
|
|
39
28
|
];
|
|
40
29
|
|
|
41
30
|
module.exports.GA_KEYS = [...GA_FEATURES];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghost",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "The professional publishing platform",
|
|
5
5
|
"author": "Ghost Foundation",
|
|
6
6
|
"homepage": "https://ghost.org",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"@tryghost/email-content-generator": "0.1.3",
|
|
74
74
|
"@tryghost/errors": "1.2.12",
|
|
75
75
|
"@tryghost/express-dynamic-redirects": "0.2.13",
|
|
76
|
-
"@tryghost/helpers": "1.1.
|
|
77
|
-
"@tryghost/image-transform": "1.0
|
|
76
|
+
"@tryghost/helpers": "1.1.70",
|
|
77
|
+
"@tryghost/image-transform": "1.1.0",
|
|
78
78
|
"@tryghost/job-manager": "0.8.24",
|
|
79
79
|
"@tryghost/kg-card-factory": "3.1.3",
|
|
80
80
|
"@tryghost/kg-default-atoms": "3.1.2",
|
|
@@ -85,9 +85,9 @@
|
|
|
85
85
|
"@tryghost/logging": "2.1.8",
|
|
86
86
|
"@tryghost/magic-link": "1.0.26",
|
|
87
87
|
"@tryghost/member-events": "0.4.6",
|
|
88
|
-
"@tryghost/members-api": "8.1.
|
|
88
|
+
"@tryghost/members-api": "8.1.2",
|
|
89
89
|
"@tryghost/members-events-service": "0.4.3",
|
|
90
|
-
"@tryghost/members-importer": "0.5.
|
|
90
|
+
"@tryghost/members-importer": "0.5.16",
|
|
91
91
|
"@tryghost/members-offers": "0.11.6",
|
|
92
92
|
"@tryghost/members-ssr": "1.0.28",
|
|
93
93
|
"@tryghost/members-stripe-service": "0.10.5",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"ghost-storage-base": "1.0.0",
|
|
145
145
|
"glob": "8.0.3",
|
|
146
146
|
"got": "9.6.0",
|
|
147
|
-
"gscan": "4.
|
|
147
|
+
"gscan": "4.31.0",
|
|
148
148
|
"html-to-text": "8.2.0",
|
|
149
149
|
"image-size": "1.0.1",
|
|
150
150
|
"intl": "1.2.5",
|
|
@@ -154,20 +154,20 @@
|
|
|
154
154
|
"jsonwebtoken": "8.5.1",
|
|
155
155
|
"juice": "8.0.0",
|
|
156
156
|
"keypair": "1.0.4",
|
|
157
|
-
"knex": "2.
|
|
157
|
+
"knex": "2.1.0",
|
|
158
158
|
"knex-migrator": "4.2.10",
|
|
159
159
|
"lodash": "4.17.21",
|
|
160
160
|
"luxon": "2.4.0",
|
|
161
161
|
"mailgun-js": "0.22.0",
|
|
162
|
-
"metascraper": "5.29.
|
|
163
|
-
"metascraper-author": "5.29.
|
|
164
|
-
"metascraper-description": "5.29.
|
|
165
|
-
"metascraper-image": "5.29.
|
|
166
|
-
"metascraper-logo": "5.29.
|
|
167
|
-
"metascraper-logo-favicon": "5.29.
|
|
168
|
-
"metascraper-publisher": "5.29.
|
|
169
|
-
"metascraper-title": "5.29.
|
|
170
|
-
"metascraper-url": "5.29.
|
|
162
|
+
"metascraper": "5.29.6",
|
|
163
|
+
"metascraper-author": "5.29.6",
|
|
164
|
+
"metascraper-description": "5.29.6",
|
|
165
|
+
"metascraper-image": "5.29.6",
|
|
166
|
+
"metascraper-logo": "5.29.6",
|
|
167
|
+
"metascraper-logo-favicon": "5.29.6",
|
|
168
|
+
"metascraper-publisher": "5.29.6",
|
|
169
|
+
"metascraper-title": "5.29.6",
|
|
170
|
+
"metascraper-url": "5.29.6",
|
|
171
171
|
"moment": "2.24.0",
|
|
172
172
|
"moment-timezone": "0.5.23",
|
|
173
173
|
"multer": "1.4.4",
|