@abtnode/blocklet-services 1.16.15-beta-e3a24907 → 1.16.15-beta-18951729
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/fonts/noto-sans-sc-regular.otf +0 -0
- package/api/index.js +2 -1
- package/api/libs/fetch.js +11 -0
- package/api/libs/open-graph/index.js +155 -0
- package/api/libs/open-graph/template.js +212 -0
- package/api/routes/blocklet.js +46 -6
- package/build/asset-manifest.json +11 -11
- 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/6186.e711ab85.chunk.js +2 -0
- package/build/static/js/6737.6432760e.chunk.js +2 -0
- package/build/static/js/main.e29a7133.js +3 -0
- package/package.json +21 -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/6186.2a5f97da.chunk.js +0 -2
- package/build/static/js/6737.5aef67e7.chunk.js +0 -2
- package/build/static/js/main.1b821566.js +0 -3
- /package/build/static/js/{main.1b821566.js.LICENSE.txt → main.e29a7133.js.LICENSE.txt} +0 -0
|
Binary file
|
package/api/index.js
CHANGED
|
@@ -19,6 +19,7 @@ const eventHub =
|
|
|
19
19
|
process.env.NODE_ENV === 'test' ? require('@arcblock/event-hub/single') : require('@arcblock/event-hub');
|
|
20
20
|
const logger = require('@abtnode/logger')(require('../package.json').name);
|
|
21
21
|
|
|
22
|
+
require('./libs/fetch');
|
|
22
23
|
const cache = require('./cache');
|
|
23
24
|
const { ensureProxyUrl } = require('./util');
|
|
24
25
|
const { isProduction, isE2E } = require('./libs/env');
|
|
@@ -252,7 +253,7 @@ module.exports = function createServer(node, serverOptions = {}) {
|
|
|
252
253
|
createFederatedRoutes.init(server, node, options);
|
|
253
254
|
createUserRoutes.init(server, node, options);
|
|
254
255
|
createEnvRoutes.init(server, node, options);
|
|
255
|
-
createBlockletRoutes.init(server, node);
|
|
256
|
+
createBlockletRoutes.init(server, node, eventHub);
|
|
256
257
|
createConnectSessionRoutes.init(server, node, options);
|
|
257
258
|
createConnectRelayRoutes.init(server, node, options, wsRouter);
|
|
258
259
|
authRoutes.attachDidAuthHandlers(server);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This polyfill is required for open-graph generator to work
|
|
2
|
+
const fetch = require('node-fetch');
|
|
3
|
+
|
|
4
|
+
const { Headers, Request, Response } = fetch;
|
|
5
|
+
|
|
6
|
+
if (!global.fetch) {
|
|
7
|
+
global.fetch = fetch;
|
|
8
|
+
global.Headers = Headers;
|
|
9
|
+
global.Request = Request;
|
|
10
|
+
global.Response = Response;
|
|
11
|
+
}
|
|
@@ -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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
const fs = require('fs');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const cloneDeep = require('lodash/cloneDeep');
|
|
5
5
|
const dayjs = require('@abtnode/util/lib/dayjs');
|
|
@@ -34,15 +34,17 @@ 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
|
|
|
40
41
|
const { createDownloadLogStream } = require('@abtnode/core/lib/util/log');
|
|
41
42
|
|
|
42
|
-
const { BlockletStatus } = require('@blocklet/constant');
|
|
43
|
+
const { BlockletStatus, BlockletInternalEvents } = require('@blocklet/constant');
|
|
43
44
|
|
|
44
45
|
const { checkAdminPermission } = require('../middlewares/check-permission');
|
|
45
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);
|
|
@@ -53,7 +55,7 @@ const polishBlocklet = (doc) => {
|
|
|
53
55
|
const prefix = WELLKNOWN_SERVICE_PATH_PREFIX;
|
|
54
56
|
|
|
55
57
|
module.exports = {
|
|
56
|
-
init(server, node) {
|
|
58
|
+
init(server, node, events) {
|
|
57
59
|
const onSendFallbackLogo = ({ res, sendOptions }) => {
|
|
58
60
|
res.sendStaticFile('/images/blocklet.png', sendOptions);
|
|
59
61
|
};
|
|
@@ -114,8 +116,6 @@ module.exports = {
|
|
|
114
116
|
|
|
115
117
|
const cacheDir = path.join(node.dataDirs.cache, 'services', 'image');
|
|
116
118
|
server.get(`${prefix}${USER_AVATAR_PATH_PREFIX}/:fileName`, async (req, res) => {
|
|
117
|
-
const sendOptions = { maxAge: '1y' };
|
|
118
|
-
|
|
119
119
|
try {
|
|
120
120
|
const blocklet = await req.getBlocklet();
|
|
121
121
|
let { fileName } = req.params;
|
|
@@ -140,7 +140,7 @@ module.exports = {
|
|
|
140
140
|
Promise.resolve([fs.createReadStream(avatarFile), path.extname(avatarFile).slice(1)])
|
|
141
141
|
);
|
|
142
142
|
} else {
|
|
143
|
-
res.sendFile(avatarFile,
|
|
143
|
+
res.sendFile(avatarFile, { maxAge: '365d', immutable: true });
|
|
144
144
|
}
|
|
145
145
|
} catch (err) {
|
|
146
146
|
logger.error('failed to send user avatar', { fileName: req.params.fileName, error: err });
|
|
@@ -465,5 +465,45 @@ module.exports = {
|
|
|
465
465
|
],
|
|
466
466
|
});
|
|
467
467
|
});
|
|
468
|
+
|
|
469
|
+
server.get(`${prefix}/blocklet/og.(png|html)`, async (req, res) => {
|
|
470
|
+
try {
|
|
471
|
+
const format = req.path.split('.').pop();
|
|
472
|
+
const info = await req.getBlockletInfo();
|
|
473
|
+
const blocklet = await req.getBlocklet();
|
|
474
|
+
const cache = req.query.nocache !== '1';
|
|
475
|
+
|
|
476
|
+
const dataDir = path.join(blocklet.env.dataDir, OPEN_GRAPH_DIR);
|
|
477
|
+
const sourceFile = await getOgImage(req.query, info, dataDir, format);
|
|
478
|
+
if (format === 'png' && isImageAccepted(req) && isImageRequest(req)) {
|
|
479
|
+
const appDir = path.join(cacheDir, blocklet.appPid);
|
|
480
|
+
processAndRespond(req, res, appDir, () =>
|
|
481
|
+
Promise.resolve([fs.createReadStream(sourceFile), path.extname(sourceFile).slice(1)])
|
|
482
|
+
);
|
|
483
|
+
} else {
|
|
484
|
+
res.sendFile(sourceFile, cache ? { maxAge: '365d', immutable: true } : { maxAge: 0 });
|
|
485
|
+
}
|
|
486
|
+
} catch (err) {
|
|
487
|
+
logger.error('failed to send open graph', { fileName: req.params.fileName, error: err });
|
|
488
|
+
res.status(500).send(err.message);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
// Bust cache on blocklet config change
|
|
492
|
+
if (events) {
|
|
493
|
+
events.on(BlockletInternalEvents.appConfigChanged, ({ appDid }) => {
|
|
494
|
+
['png', 'html'].forEach((format) => {
|
|
495
|
+
const cached = path.join(node.dataDirs.data, appDid, `og.${format}`);
|
|
496
|
+
if (fs.existsSync(cached)) {
|
|
497
|
+
logger.info('bust og cache on blocklet config change', { appDid, cached });
|
|
498
|
+
try {
|
|
499
|
+
fs.unlinkSync(cached);
|
|
500
|
+
logger.info('bust og cache on blocklet config change', { appDid, format });
|
|
501
|
+
} catch (err) {
|
|
502
|
+
logger.error('bust og cache on blocklet config change', { appDid, format, error: err });
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
}
|
|
468
508
|
},
|
|
469
509
|
};
|
|
@@ -1,16 +1,16 @@
|
|
|
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",
|
|
8
8
|
"static/js/9899.18509ac9.chunk.js": "/.well-known/service/static/static/js/9899.18509ac9.chunk.js",
|
|
9
|
-
"static/js/6737.
|
|
9
|
+
"static/js/6737.6432760e.chunk.js": "/.well-known/service/static/static/js/6737.6432760e.chunk.js",
|
|
10
10
|
"static/js/1760.3318c7ca.chunk.js": "/.well-known/service/static/static/js/1760.3318c7ca.chunk.js",
|
|
11
11
|
"static/js/9620.4b7c9e8b.chunk.js": "/.well-known/service/static/static/js/9620.4b7c9e8b.chunk.js",
|
|
12
12
|
"static/js/1480.f89236fc.chunk.js": "/.well-known/service/static/static/js/1480.f89236fc.chunk.js",
|
|
13
|
-
"static/js/6186.
|
|
13
|
+
"static/js/6186.e711ab85.chunk.js": "/.well-known/service/static/static/js/6186.e711ab85.chunk.js",
|
|
14
14
|
"static/js/4682.23dd054e.chunk.js": "/.well-known/service/static/static/js/4682.23dd054e.chunk.js",
|
|
15
15
|
"static/js/6711.38948be4.chunk.js": "/.well-known/service/static/static/js/6711.38948be4.chunk.js",
|
|
16
16
|
"static/js/8437.0d88b9db.chunk.js": "/.well-known/service/static/static/js/8437.0d88b9db.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,16 +98,16 @@
|
|
|
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",
|
|
105
105
|
"9899.18509ac9.chunk.js.map": "/.well-known/service/static/static/js/9899.18509ac9.chunk.js.map",
|
|
106
|
-
"6737.
|
|
106
|
+
"6737.6432760e.chunk.js.map": "/.well-known/service/static/static/js/6737.6432760e.chunk.js.map",
|
|
107
107
|
"1760.3318c7ca.chunk.js.map": "/.well-known/service/static/static/js/1760.3318c7ca.chunk.js.map",
|
|
108
108
|
"9620.4b7c9e8b.chunk.js.map": "/.well-known/service/static/static/js/9620.4b7c9e8b.chunk.js.map",
|
|
109
109
|
"1480.f89236fc.chunk.js.map": "/.well-known/service/static/static/js/1480.f89236fc.chunk.js.map",
|
|
110
|
-
"6186.
|
|
110
|
+
"6186.e711ab85.chunk.js.map": "/.well-known/service/static/static/js/6186.e711ab85.chunk.js.map",
|
|
111
111
|
"4682.23dd054e.chunk.js.map": "/.well-known/service/static/static/js/4682.23dd054e.chunk.js.map",
|
|
112
112
|
"6711.38948be4.chunk.js.map": "/.well-known/service/static/static/js/6711.38948be4.chunk.js.map",
|
|
113
113
|
"8437.0d88b9db.chunk.js.map": "/.well-known/service/static/static/js/8437.0d88b9db.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>
|