@abtnode/blocklet-services 1.16.15-beta-933eb977 → 1.16.15-beta-d8e7b6c0
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/api/libs/image.js +0 -61
- package/api/libs/open-graph/index.js +155 -0
- package/api/libs/open-graph/template.js +212 -0
- package/api/routes/blocklet.js +7 -9
- package/build/asset-manifest.json +7 -7
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- package/build/static/js/5355.2eaad302.chunk.js +2 -0
- package/build/static/js/5541.581f1db7.chunk.js +2 -0
- package/build/static/js/main.e29a7133.js +3 -0
- package/package.json +18 -18
- package/build/static/js/5355.4b07ad55.chunk.js +0 -2
- package/build/static/js/5541.1d065ac6.chunk.js +0 -2
- package/build/static/js/main.4cc7f3ab.js +0 -3
- /package/build/static/js/{main.4cc7f3ab.js.LICENSE.txt → main.e29a7133.js.LICENSE.txt} +0 -0
package/api/libs/image.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const sharp = require('sharp');
|
|
6
|
-
const joinUrl = require('url-join');
|
|
7
6
|
const toLower = require('lodash/toLower');
|
|
8
7
|
const { Joi } = require('@arcblock/validator');
|
|
9
8
|
const stringify = require('json-stable-stringify');
|
|
10
9
|
const md5 = require('@abtnode/util/lib/md5');
|
|
11
10
|
const formatError = require('@abtnode/util/lib/format-error');
|
|
12
|
-
const { getPassportColor } = require('@abtnode/auth/lib/util/create-passport-svg');
|
|
13
|
-
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
14
11
|
|
|
15
12
|
const logger = require('@abtnode/logger')('@abtnode/blocklet-services/image');
|
|
16
13
|
|
|
@@ -246,69 +243,11 @@ const processImage = (src, extension, dest, params) => {
|
|
|
246
243
|
});
|
|
247
244
|
};
|
|
248
245
|
|
|
249
|
-
const fallbackFont = fs.readFile(path.resolve(__dirname, '../fonts/noto-sans-sc-regular.otf'));
|
|
250
|
-
const generateOgImage = async (info, format = 'png', width = 1200, height = 630) => {
|
|
251
|
-
const { default: satori } = await import('satori'); // eslint-disable-line import/no-unresolved
|
|
252
|
-
const { html } = await import('satori-html'); // eslint-disable-line import/no-unresolved
|
|
253
|
-
const styles = {
|
|
254
|
-
container: 'display: flex; flex-direction: column; justify-content: center; align-items: center;',
|
|
255
|
-
font: 'color: #FFF; font-weight: 400; font-family: Arial,sans-serif; text-align: center; text-transform: capitalize; padding: 0 24px;',
|
|
256
|
-
};
|
|
257
|
-
const color = getPassportColor(info.passportColor, info.did);
|
|
258
|
-
// Do not delete following code block, it's used to debug the og image, please request with `/blocklet/og.html?nocache=1`
|
|
259
|
-
// const markup = `<div style="width: ${width}px; height: ${height}px; background: ${color.start}; ${styles.container}">
|
|
260
|
-
// <img
|
|
261
|
-
// src="${joinUrl(info.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo')}"
|
|
262
|
-
// width="180"
|
|
263
|
-
// height="180"
|
|
264
|
-
// style="width: 180px; height: 180px; border-radius: 50%"
|
|
265
|
-
// />
|
|
266
|
-
// <h2 style="font-size: 3rem; margin: 16px 0; ${styles.font}">${info.name}</h2>
|
|
267
|
-
// <h3 style="font-size: 2rem; margin: 0; ${styles.font}">${info.description}</h3>
|
|
268
|
-
// </div>`;
|
|
269
|
-
// if (format === 'html') {
|
|
270
|
-
// return markup;
|
|
271
|
-
// }
|
|
272
|
-
|
|
273
|
-
const svg = await satori(
|
|
274
|
-
// @ts-ignore
|
|
275
|
-
html`<div style="width: ${width}px; height: ${height}px; background: ${color.start}; ${styles.container}">
|
|
276
|
-
<img
|
|
277
|
-
src="${joinUrl(info.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo')}"
|
|
278
|
-
width="180"
|
|
279
|
-
height="180"
|
|
280
|
-
style="width: 180px; height: 180px; border-radius: 50%"
|
|
281
|
-
/>
|
|
282
|
-
<h2 style="font-size: 3rem; margin: 16px 0; ${styles.font}">${info.name}</h2>
|
|
283
|
-
<h3 style="font-size: 2rem; margin: 0; ${styles.font}">${info.description}</h3>
|
|
284
|
-
</div>`,
|
|
285
|
-
{
|
|
286
|
-
width,
|
|
287
|
-
height,
|
|
288
|
-
fonts: [
|
|
289
|
-
{
|
|
290
|
-
name: 'Noto',
|
|
291
|
-
data: await fallbackFont,
|
|
292
|
-
weight: 400,
|
|
293
|
-
style: 'normal',
|
|
294
|
-
},
|
|
295
|
-
],
|
|
296
|
-
}
|
|
297
|
-
);
|
|
298
|
-
|
|
299
|
-
if (format === 'svg') {
|
|
300
|
-
return svg;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return sharp(Buffer.from(svg)).png().toBuffer();
|
|
304
|
-
};
|
|
305
|
-
|
|
306
246
|
module.exports = {
|
|
307
247
|
isImageAccepted,
|
|
308
248
|
isImageRequest,
|
|
309
249
|
processAndRespond,
|
|
310
250
|
processImage,
|
|
311
|
-
generateOgImage,
|
|
312
251
|
EXTENSIONS,
|
|
313
252
|
MODES,
|
|
314
253
|
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// A simple open graph service based on satori and sharp
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const sharp = require('sharp');
|
|
5
|
+
const joinUrl = require('url-join');
|
|
6
|
+
const { Joi } = require('@arcblock/validator');
|
|
7
|
+
const stringify = require('json-stable-stringify');
|
|
8
|
+
const md5 = require('@abtnode/util/lib/md5');
|
|
9
|
+
const formatError = require('@abtnode/util/lib/format-error');
|
|
10
|
+
const { getPassportColor } = require('@abtnode/auth/lib/util/create-passport-svg');
|
|
11
|
+
const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
|
|
12
|
+
|
|
13
|
+
const logger = require('@abtnode/logger')('@abtnode/blocklet-services/og');
|
|
14
|
+
|
|
15
|
+
const { getTemplate, getLogoSvg } = require('./template');
|
|
16
|
+
|
|
17
|
+
const TEMPLATES = ['default', 'section', 'cover'];
|
|
18
|
+
|
|
19
|
+
const schema = Joi.object({
|
|
20
|
+
template: Joi.string()
|
|
21
|
+
.lowercase()
|
|
22
|
+
.valid(...TEMPLATES)
|
|
23
|
+
.optional()
|
|
24
|
+
.default('default'),
|
|
25
|
+
|
|
26
|
+
title: Joi.string()
|
|
27
|
+
.max(128)
|
|
28
|
+
.when('template', {
|
|
29
|
+
is: 'default',
|
|
30
|
+
then: Joi.optional().default(''),
|
|
31
|
+
otherwise: Joi.required(),
|
|
32
|
+
}),
|
|
33
|
+
|
|
34
|
+
description: Joi.string()
|
|
35
|
+
.max(512)
|
|
36
|
+
.when('template', {
|
|
37
|
+
is: 'section',
|
|
38
|
+
then: Joi.required(),
|
|
39
|
+
otherwise: Joi.optional().default(''),
|
|
40
|
+
}),
|
|
41
|
+
|
|
42
|
+
section: Joi.string()
|
|
43
|
+
.max(64)
|
|
44
|
+
.when('template', {
|
|
45
|
+
is: 'section',
|
|
46
|
+
then: Joi.required(),
|
|
47
|
+
otherwise: Joi.optional().default(''),
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
cover: Joi.string()
|
|
51
|
+
.uri({ scheme: ['https'] })
|
|
52
|
+
.when('template', {
|
|
53
|
+
is: 'cover',
|
|
54
|
+
then: Joi.required(),
|
|
55
|
+
otherwise: Joi.optional().default(''),
|
|
56
|
+
}),
|
|
57
|
+
}).options({ stripUnknown: true, allowUnknown: true, noDefaults: false });
|
|
58
|
+
|
|
59
|
+
const tasks = {};
|
|
60
|
+
const getOgImage = (input, info, dataDir, format) => {
|
|
61
|
+
if (fs.existsSync(dataDir) === false) {
|
|
62
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const color = getPassportColor(info.passportColor, info.did);
|
|
66
|
+
const logoUrl = joinUrl(info.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo');
|
|
67
|
+
const { value, error } = schema.validate(input);
|
|
68
|
+
if (error) {
|
|
69
|
+
throw new Error(`open graph service params invalid: ${formatError(error)}`);
|
|
70
|
+
}
|
|
71
|
+
if (!value.title) {
|
|
72
|
+
value.title = info.name;
|
|
73
|
+
}
|
|
74
|
+
if (!value.description) {
|
|
75
|
+
value.description = info.description;
|
|
76
|
+
}
|
|
77
|
+
if (value.template === 'cover') {
|
|
78
|
+
value.description = value.title;
|
|
79
|
+
value.title = info.name;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const params = { ...value, width: 1200, height: 630, color, logoUrl, format };
|
|
83
|
+
const cacheKey = md5(stringify(params));
|
|
84
|
+
const nocache = input.nocache === '1';
|
|
85
|
+
const destPath = path.join(dataDir, `${cacheKey}.${format}`);
|
|
86
|
+
if (!nocache && fs.existsSync(destPath)) {
|
|
87
|
+
return destPath;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
tasks[cacheKey] ??= generateOgImage(params).finally(() => {
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
delete tasks[cacheKey];
|
|
93
|
+
}, 1000);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
tasks[cacheKey]
|
|
98
|
+
.then((buffer) => {
|
|
99
|
+
logger.info('open graph generate succeed', { params, destPath });
|
|
100
|
+
fs.writeFileSync(destPath, buffer);
|
|
101
|
+
resolve(destPath);
|
|
102
|
+
})
|
|
103
|
+
.catch((err) => {
|
|
104
|
+
logger.error('open graph generate failed', { error: err, params });
|
|
105
|
+
reject(err);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const fallbackFont = fs.readFile(path.resolve(__dirname, '../../fonts/noto-sans-sc-regular.otf'));
|
|
111
|
+
const generateOgImage = async (params) => {
|
|
112
|
+
const { default: satori } = await import('satori');
|
|
113
|
+
const raw = await getTemplate(params);
|
|
114
|
+
if (params.format === 'html') {
|
|
115
|
+
return raw;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const svg = await satori(raw, {
|
|
119
|
+
width: params.width,
|
|
120
|
+
height: params.height,
|
|
121
|
+
// debug: true,
|
|
122
|
+
fonts: [
|
|
123
|
+
{
|
|
124
|
+
name: 'Noto',
|
|
125
|
+
data: await fallbackFont,
|
|
126
|
+
weight: 400,
|
|
127
|
+
style: 'normal',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (params.format === 'svg') {
|
|
133
|
+
return svg;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (['default', 'section'].includes(params.template)) {
|
|
137
|
+
return sharp(Buffer.from(getLogoSvg(params.color.start)))
|
|
138
|
+
.png()
|
|
139
|
+
.toBuffer()
|
|
140
|
+
.then((buffer) => {
|
|
141
|
+
return sharp(Buffer.from(svg))
|
|
142
|
+
.composite([{ input: buffer, top: 190, left: 816 }])
|
|
143
|
+
.png()
|
|
144
|
+
.toBuffer();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return sharp(Buffer.from(svg)).png().toBuffer();
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
getOgImage,
|
|
153
|
+
generateOgImage,
|
|
154
|
+
TEMPLATES,
|
|
155
|
+
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Join the raw strings and values to reconstruct the original string
|
|
2
|
+
const join = (strings, ...values) => {
|
|
3
|
+
const original = strings.raw.reduce((result, str, i) => {
|
|
4
|
+
return result + str + (values[i] !== undefined ? values[i] : '');
|
|
5
|
+
}, '');
|
|
6
|
+
|
|
7
|
+
return original;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const getLogoSvg = (color) => {
|
|
11
|
+
return `<svg
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
style="position: absolute; right: 24px; bottom: 24px; opacity: 0.1"
|
|
14
|
+
width="360"
|
|
15
|
+
height="416"
|
|
16
|
+
viewBox="0 0 45 52"
|
|
17
|
+
>
|
|
18
|
+
<g fill="none" fill-rule="evenodd" stroke="${color}">
|
|
19
|
+
<path
|
|
20
|
+
d="M.5 13.077L22.15.577l21.651 12.5v25l-21.65 12.5L.5 38.077zM22.15.577v50M.5 13.077l43.301 25m-43.301 0l43.301-25"
|
|
21
|
+
></path>
|
|
22
|
+
<path d="M22.15 38.077l10.826-6.25-10.825-18.75-10.825 18.75z"></path>
|
|
23
|
+
</g>
|
|
24
|
+
</svg>`;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getDefaultTemplate = ({ width, height, logoUrl, format, color, title, description }, fn) => {
|
|
28
|
+
return fn`<div
|
|
29
|
+
style="
|
|
30
|
+
width: ${width}px;
|
|
31
|
+
height: ${height}px;
|
|
32
|
+
background: linear-gradient(to bottom right, #000000 40%, ${color.start});
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
align-items: flex-start;
|
|
37
|
+
position: relative;
|
|
38
|
+
"
|
|
39
|
+
>
|
|
40
|
+
<img
|
|
41
|
+
src="${logoUrl}"
|
|
42
|
+
height="120"
|
|
43
|
+
width="120"
|
|
44
|
+
style="margin-left: 96px; height: 120px; width: 120px; margin-bottom: 64px"
|
|
45
|
+
/>
|
|
46
|
+
<h2
|
|
47
|
+
style="
|
|
48
|
+
font-size: 4.8rem;
|
|
49
|
+
letter-spacing: -2px;
|
|
50
|
+
margin: 32px 0;
|
|
51
|
+
color: #ddd;
|
|
52
|
+
font-weight: 400;
|
|
53
|
+
font-family: Arial, sans-serif;
|
|
54
|
+
text-align: left;
|
|
55
|
+
text-transform: capitalize;
|
|
56
|
+
padding: 0 96px;
|
|
57
|
+
"
|
|
58
|
+
>
|
|
59
|
+
${title}
|
|
60
|
+
</h2>
|
|
61
|
+
<h3
|
|
62
|
+
style="
|
|
63
|
+
font-size: 2.4rem;
|
|
64
|
+
margin: 0;
|
|
65
|
+
color: #aaa;
|
|
66
|
+
font-weight: 400;
|
|
67
|
+
font-family: Arial, sans-serif;
|
|
68
|
+
text-align: left;
|
|
69
|
+
padding: 0 96px;
|
|
70
|
+
"
|
|
71
|
+
>
|
|
72
|
+
${description}
|
|
73
|
+
</h3>
|
|
74
|
+
${format !== 'png' ? getLogoSvg(color.start) : ''}
|
|
75
|
+
</div>`;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const getSectionTemplate = ({ width, height, logoUrl, color, format, title, description, section }, fn) => {
|
|
79
|
+
return fn` <div
|
|
80
|
+
style="
|
|
81
|
+
width: ${width};
|
|
82
|
+
height: ${height}px;
|
|
83
|
+
background: radial-gradient(circle at 83% 63%, ${color.start}, #000000 50%);
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
justify-content: center;
|
|
87
|
+
align-items: flex-start;
|
|
88
|
+
position: relative;
|
|
89
|
+
"
|
|
90
|
+
>
|
|
91
|
+
<img
|
|
92
|
+
src="${logoUrl}"
|
|
93
|
+
height="90"
|
|
94
|
+
width="90"
|
|
95
|
+
style="margin-left: 96px; height: 90px; width: 90px; margin-bottom: 96px"
|
|
96
|
+
/>
|
|
97
|
+
<p
|
|
98
|
+
style="
|
|
99
|
+
font-size: 1.8rem;
|
|
100
|
+
margin: 0;
|
|
101
|
+
color: ${color.start};
|
|
102
|
+
font-weight: 400;
|
|
103
|
+
font-family: Arial, sans-serif;
|
|
104
|
+
text-align: left;
|
|
105
|
+
padding: 0 96px;
|
|
106
|
+
"
|
|
107
|
+
>
|
|
108
|
+
${section}
|
|
109
|
+
</p>
|
|
110
|
+
<h2
|
|
111
|
+
style="
|
|
112
|
+
font-size: 4.8rem;
|
|
113
|
+
margin: 32px 0;
|
|
114
|
+
color: #eee;
|
|
115
|
+
letter-spacing: -2px;
|
|
116
|
+
font-weight: 400;
|
|
117
|
+
font-family: Arial, sans-serif;
|
|
118
|
+
text-align: center;
|
|
119
|
+
text-transform: capitalize;
|
|
120
|
+
padding: 0 96px;
|
|
121
|
+
"
|
|
122
|
+
>
|
|
123
|
+
${title}
|
|
124
|
+
</h2>
|
|
125
|
+
<h3
|
|
126
|
+
style="
|
|
127
|
+
font-size: 2.4rem;
|
|
128
|
+
margin: 0;
|
|
129
|
+
color: #bbb;
|
|
130
|
+
font-weight: 400;
|
|
131
|
+
font-family: Arial, sans-serif;
|
|
132
|
+
text-align: left;
|
|
133
|
+
padding: 0 96px;
|
|
134
|
+
"
|
|
135
|
+
>
|
|
136
|
+
${description}
|
|
137
|
+
</h3>
|
|
138
|
+
${format !== 'png' ? getLogoSvg(color.start) : ''}
|
|
139
|
+
</div>`;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const getCoverTemplate = ({ width, height, logoUrl, color, title, description, cover }, fn) => {
|
|
143
|
+
return fn`<div style="width: ${width}px; height: ${height}px; display: flex; background: ${color.start};">
|
|
144
|
+
<div style="display: flex; height: ${height}px; background: ${color.start}; width: 45%">
|
|
145
|
+
<div style="margin-left: 32px; display: flex; flex-direction: column; align-items: flex-start; justify-content: space-around;">
|
|
146
|
+
<h2
|
|
147
|
+
style="
|
|
148
|
+
font-size: 3.6rem;
|
|
149
|
+
color: #ddd;
|
|
150
|
+
font-weight: 400;
|
|
151
|
+
font-family: Arial, sans-serif;
|
|
152
|
+
margin: 32px 0 0;
|
|
153
|
+
text-align: left;
|
|
154
|
+
"
|
|
155
|
+
>
|
|
156
|
+
${description}
|
|
157
|
+
</h2>
|
|
158
|
+
<div style="display: flex; justify-content: flex-start; align-items: center">
|
|
159
|
+
<img src="${logoUrl}" height="60" width="60" style="height: 60px; width: 60px" />
|
|
160
|
+
<h3
|
|
161
|
+
style="
|
|
162
|
+
font-size: 2rem;
|
|
163
|
+
margin: 0 0 0 16px;
|
|
164
|
+
color: #ddd;
|
|
165
|
+
font-weight: 400;
|
|
166
|
+
font-family: Arial, sans-serif;
|
|
167
|
+
text-align: left;
|
|
168
|
+
text-transform: capitalize;
|
|
169
|
+
"
|
|
170
|
+
>
|
|
171
|
+
${title}
|
|
172
|
+
</h3>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
<div style="display: flex; height: 630px; width: 55%; background-color: ${color.start}">
|
|
177
|
+
<img src="${cover}" height="630" width="100%" style="height: 630px; width: 100%; object-fit: cover" />
|
|
178
|
+
<div style="
|
|
179
|
+
display: flex;
|
|
180
|
+
background: ${color.start};
|
|
181
|
+
height: ${height * 2}px;
|
|
182
|
+
width: 125px;
|
|
183
|
+
position: absolute;
|
|
184
|
+
transform: rotate(10deg);
|
|
185
|
+
left: -120px;
|
|
186
|
+
top: -25px;"></div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>`;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const getTemplate = async (params) => {
|
|
192
|
+
// eslint-disable-next-line import/no-unresolved
|
|
193
|
+
const { html } = await import('satori-html');
|
|
194
|
+
const fn = params.format === 'html' ? join : html;
|
|
195
|
+
|
|
196
|
+
if (params.template === 'default') {
|
|
197
|
+
return getDefaultTemplate(params, fn);
|
|
198
|
+
}
|
|
199
|
+
if (params.template === 'section') {
|
|
200
|
+
return getSectionTemplate(params, fn);
|
|
201
|
+
}
|
|
202
|
+
if (params.template === 'cover') {
|
|
203
|
+
return getCoverTemplate(params, fn);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
throw new Error('Invalid open graph template');
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
getTemplate,
|
|
211
|
+
getLogoSvg,
|
|
212
|
+
};
|
package/api/routes/blocklet.js
CHANGED
|
@@ -34,6 +34,7 @@ const {
|
|
|
34
34
|
USER_AVATAR_PATH_PREFIX,
|
|
35
35
|
ROLES,
|
|
36
36
|
USER_AVATAR_URL_PREFIX,
|
|
37
|
+
OPEN_GRAPH_DIR,
|
|
37
38
|
} = require('@abtnode/constant');
|
|
38
39
|
const logger = require('@abtnode/logger')(require('../../package.json').name);
|
|
39
40
|
|
|
@@ -42,7 +43,8 @@ const { createDownloadLogStream } = require('@abtnode/core/lib/util/log');
|
|
|
42
43
|
const { BlockletStatus, BlockletInternalEvents } = require('@blocklet/constant');
|
|
43
44
|
|
|
44
45
|
const { checkAdminPermission } = require('../middlewares/check-permission');
|
|
45
|
-
const { isImageAccepted, isImageRequest, processAndRespond
|
|
46
|
+
const { isImageAccepted, isImageRequest, processAndRespond } = require('../libs/image');
|
|
47
|
+
const { getOgImage } = require('../libs/open-graph');
|
|
46
48
|
|
|
47
49
|
const polishBlocklet = (doc) => {
|
|
48
50
|
const res = cloneDeep(doc);
|
|
@@ -464,19 +466,15 @@ module.exports = {
|
|
|
464
466
|
});
|
|
465
467
|
});
|
|
466
468
|
|
|
467
|
-
server.get(`${prefix}/blocklet/og.(png|
|
|
469
|
+
server.get(`${prefix}/blocklet/og.(png|html)`, async (req, res) => {
|
|
468
470
|
try {
|
|
469
471
|
const format = req.path.split('.').pop();
|
|
470
472
|
const info = await req.getBlockletInfo();
|
|
471
473
|
const blocklet = await req.getBlocklet();
|
|
472
474
|
const cache = req.query.nocache !== '1';
|
|
473
475
|
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
const sourceData = await generateOgImage(info, format);
|
|
477
|
-
fs.writeFileSync(sourceFile, sourceData);
|
|
478
|
-
}
|
|
479
|
-
|
|
476
|
+
const dataDir = path.join(blocklet.env.dataDir, OPEN_GRAPH_DIR);
|
|
477
|
+
const sourceFile = await getOgImage(req.query, info, dataDir, format);
|
|
480
478
|
if (format === 'png' && isImageAccepted(req) && isImageRequest(req)) {
|
|
481
479
|
const appDir = path.join(cacheDir, blocklet.appPid);
|
|
482
480
|
processAndRespond(req, res, appDir, () =>
|
|
@@ -493,7 +491,7 @@ module.exports = {
|
|
|
493
491
|
// Bust cache on blocklet config change
|
|
494
492
|
if (events) {
|
|
495
493
|
events.on(BlockletInternalEvents.appConfigChanged, ({ appDid }) => {
|
|
496
|
-
['png', '
|
|
494
|
+
['png', 'html'].forEach((format) => {
|
|
497
495
|
const cached = path.join(node.dataDirs.data, appDid, `og.${format}`);
|
|
498
496
|
if (fs.existsSync(cached)) {
|
|
499
497
|
logger.info('bust og cache on blocklet config change', { appDid, cached });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "/.well-known/service/static/static/css/main.7ea79dc8.css",
|
|
4
|
-
"main.js": "/.well-known/service/static/static/js/main.
|
|
4
|
+
"main.js": "/.well-known/service/static/static/js/main.e29a7133.js",
|
|
5
5
|
"static/js/4716.58477c5c.chunk.js": "/.well-known/service/static/static/js/4716.58477c5c.chunk.js",
|
|
6
6
|
"static/js/6856.163537c7.chunk.js": "/.well-known/service/static/static/js/6856.163537c7.chunk.js",
|
|
7
7
|
"static/js/1660.e2ff5a21.chunk.js": "/.well-known/service/static/static/js/1660.e2ff5a21.chunk.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"static/js/2653.58a5430b.chunk.js": "/.well-known/service/static/static/js/2653.58a5430b.chunk.js",
|
|
28
28
|
"static/js/3593.98d9341a.chunk.js": "/.well-known/service/static/static/js/3593.98d9341a.chunk.js",
|
|
29
29
|
"static/css/5355.c4fb5c4a.chunk.css": "/.well-known/service/static/static/css/5355.c4fb5c4a.chunk.css",
|
|
30
|
-
"static/js/5355.
|
|
30
|
+
"static/js/5355.2eaad302.chunk.js": "/.well-known/service/static/static/js/5355.2eaad302.chunk.js",
|
|
31
31
|
"static/js/6771.583c16c9.chunk.js": "/.well-known/service/static/static/js/6771.583c16c9.chunk.js",
|
|
32
32
|
"static/css/5982.ac464505.chunk.css": "/.well-known/service/static/static/css/5982.ac464505.chunk.css",
|
|
33
33
|
"static/js/5982.19c5663f.chunk.js": "/.well-known/service/static/static/js/5982.19c5663f.chunk.js",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"static/js/9107.967c2ac1.chunk.js": "/.well-known/service/static/static/js/9107.967c2ac1.chunk.js",
|
|
74
74
|
"static/css/3154.e954fcda.chunk.css": "/.well-known/service/static/static/css/3154.e954fcda.chunk.css",
|
|
75
75
|
"static/js/9657.e974d577.chunk.js": "/.well-known/service/static/static/js/9657.e974d577.chunk.js",
|
|
76
|
-
"static/js/5541.
|
|
76
|
+
"static/js/5541.581f1db7.chunk.js": "/.well-known/service/static/static/js/5541.581f1db7.chunk.js",
|
|
77
77
|
"static/media/ubuntu-mono-all-400-normal.woff": "/.well-known/service/static/static/media/ubuntu-mono-all-400-normal.c879328bc62e9c68268f.woff",
|
|
78
78
|
"service-worker.js": "/.well-known/service/static/service-worker.js",
|
|
79
79
|
"static/media/lato-all-400-normal.woff": "/.well-known/service/static/static/media/lato-all-400-normal.3dc1eff492ab1f598560.woff",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"index.html": "/.well-known/service/static/index.html",
|
|
99
99
|
"static/media/space-connected.svg": "/.well-known/service/static/static/media/space-connected.9a4e18fd2bc7d065191b0d241a131c28.svg",
|
|
100
100
|
"main.7ea79dc8.css.map": "/.well-known/service/static/static/css/main.7ea79dc8.css.map",
|
|
101
|
-
"main.
|
|
101
|
+
"main.e29a7133.js.map": "/.well-known/service/static/static/js/main.e29a7133.js.map",
|
|
102
102
|
"4716.58477c5c.chunk.js.map": "/.well-known/service/static/static/js/4716.58477c5c.chunk.js.map",
|
|
103
103
|
"6856.163537c7.chunk.js.map": "/.well-known/service/static/static/js/6856.163537c7.chunk.js.map",
|
|
104
104
|
"1660.e2ff5a21.chunk.js.map": "/.well-known/service/static/static/js/1660.e2ff5a21.chunk.js.map",
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"2653.58a5430b.chunk.js.map": "/.well-known/service/static/static/js/2653.58a5430b.chunk.js.map",
|
|
125
125
|
"3593.98d9341a.chunk.js.map": "/.well-known/service/static/static/js/3593.98d9341a.chunk.js.map",
|
|
126
126
|
"5355.c4fb5c4a.chunk.css.map": "/.well-known/service/static/static/css/5355.c4fb5c4a.chunk.css.map",
|
|
127
|
-
"5355.
|
|
127
|
+
"5355.2eaad302.chunk.js.map": "/.well-known/service/static/static/js/5355.2eaad302.chunk.js.map",
|
|
128
128
|
"6771.583c16c9.chunk.js.map": "/.well-known/service/static/static/js/6771.583c16c9.chunk.js.map",
|
|
129
129
|
"5982.ac464505.chunk.css.map": "/.well-known/service/static/static/css/5982.ac464505.chunk.css.map",
|
|
130
130
|
"5982.19c5663f.chunk.js.map": "/.well-known/service/static/static/js/5982.19c5663f.chunk.js.map",
|
|
@@ -170,10 +170,10 @@
|
|
|
170
170
|
"9107.967c2ac1.chunk.js.map": "/.well-known/service/static/static/js/9107.967c2ac1.chunk.js.map",
|
|
171
171
|
"3154.e954fcda.chunk.css.map": "/.well-known/service/static/static/css/3154.e954fcda.chunk.css.map",
|
|
172
172
|
"9657.e974d577.chunk.js.map": "/.well-known/service/static/static/js/9657.e974d577.chunk.js.map",
|
|
173
|
-
"5541.
|
|
173
|
+
"5541.581f1db7.chunk.js.map": "/.well-known/service/static/static/js/5541.581f1db7.chunk.js.map"
|
|
174
174
|
},
|
|
175
175
|
"entrypoints": [
|
|
176
176
|
"static/css/main.7ea79dc8.css",
|
|
177
|
-
"static/js/main.
|
|
177
|
+
"static/js/main.e29a7133.js"
|
|
178
178
|
]
|
|
179
179
|
}
|
package/build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><link rel="manifest" href="/.well-known/service/manifest.json"/><script src="/.well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.well-known/service/static/static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#000000"/><title>Blocklet Service</title><link rel="manifest" href="/.well-known/service/manifest.json"/><script src="/.well-known/service/api/env"></script><script src="/__blocklet__.js"></script><script defer="defer" src="/.well-known/service/static/static/js/main.e29a7133.js"></script><link href="/.well-known/service/static/static/css/main.7ea79dc8.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|