@abtnode/blocklet-services 1.16.15-beta-e3a24907 → 1.16.15-beta-933eb977
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/image.js +61 -0
- package/api/routes/blocklet.js +49 -7
- package/build/asset-manifest.json +7 -7
- package/build/index.html +1 -1
- package/build/service-worker.js +1 -1
- 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.4cc7f3ab.js +3 -0
- package/package.json +21 -18
- 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.4cc7f3ab.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
|
+
}
|
package/api/libs/image.js
CHANGED
|
@@ -3,11 +3,14 @@
|
|
|
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');
|
|
6
7
|
const toLower = require('lodash/toLower');
|
|
7
8
|
const { Joi } = require('@arcblock/validator');
|
|
8
9
|
const stringify = require('json-stable-stringify');
|
|
9
10
|
const md5 = require('@abtnode/util/lib/md5');
|
|
10
11
|
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');
|
|
11
14
|
|
|
12
15
|
const logger = require('@abtnode/logger')('@abtnode/blocklet-services/image');
|
|
13
16
|
|
|
@@ -243,11 +246,69 @@ const processImage = (src, extension, dest, params) => {
|
|
|
243
246
|
});
|
|
244
247
|
};
|
|
245
248
|
|
|
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
|
+
|
|
246
306
|
module.exports = {
|
|
247
307
|
isImageAccepted,
|
|
248
308
|
isImageRequest,
|
|
249
309
|
processAndRespond,
|
|
250
310
|
processImage,
|
|
311
|
+
generateOgImage,
|
|
251
312
|
EXTENSIONS,
|
|
252
313
|
MODES,
|
|
253
314
|
};
|
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');
|
|
@@ -39,10 +39,10 @@ const logger = require('@abtnode/logger')(require('../../package.json').name);
|
|
|
39
39
|
|
|
40
40
|
const { createDownloadLogStream } = require('@abtnode/core/lib/util/log');
|
|
41
41
|
|
|
42
|
-
const { BlockletStatus } = require('@blocklet/constant');
|
|
42
|
+
const { BlockletStatus, BlockletInternalEvents } = require('@blocklet/constant');
|
|
43
43
|
|
|
44
44
|
const { checkAdminPermission } = require('../middlewares/check-permission');
|
|
45
|
-
const { isImageAccepted, isImageRequest, processAndRespond } = require('../libs/image');
|
|
45
|
+
const { isImageAccepted, isImageRequest, processAndRespond, generateOgImage } = require('../libs/image');
|
|
46
46
|
|
|
47
47
|
const polishBlocklet = (doc) => {
|
|
48
48
|
const res = cloneDeep(doc);
|
|
@@ -53,7 +53,7 @@ const polishBlocklet = (doc) => {
|
|
|
53
53
|
const prefix = WELLKNOWN_SERVICE_PATH_PREFIX;
|
|
54
54
|
|
|
55
55
|
module.exports = {
|
|
56
|
-
init(server, node) {
|
|
56
|
+
init(server, node, events) {
|
|
57
57
|
const onSendFallbackLogo = ({ res, sendOptions }) => {
|
|
58
58
|
res.sendStaticFile('/images/blocklet.png', sendOptions);
|
|
59
59
|
};
|
|
@@ -114,8 +114,6 @@ module.exports = {
|
|
|
114
114
|
|
|
115
115
|
const cacheDir = path.join(node.dataDirs.cache, 'services', 'image');
|
|
116
116
|
server.get(`${prefix}${USER_AVATAR_PATH_PREFIX}/:fileName`, async (req, res) => {
|
|
117
|
-
const sendOptions = { maxAge: '1y' };
|
|
118
|
-
|
|
119
117
|
try {
|
|
120
118
|
const blocklet = await req.getBlocklet();
|
|
121
119
|
let { fileName } = req.params;
|
|
@@ -140,7 +138,7 @@ module.exports = {
|
|
|
140
138
|
Promise.resolve([fs.createReadStream(avatarFile), path.extname(avatarFile).slice(1)])
|
|
141
139
|
);
|
|
142
140
|
} else {
|
|
143
|
-
res.sendFile(avatarFile,
|
|
141
|
+
res.sendFile(avatarFile, { maxAge: '365d', immutable: true });
|
|
144
142
|
}
|
|
145
143
|
} catch (err) {
|
|
146
144
|
logger.error('failed to send user avatar', { fileName: req.params.fileName, error: err });
|
|
@@ -465,5 +463,49 @@ module.exports = {
|
|
|
465
463
|
],
|
|
466
464
|
});
|
|
467
465
|
});
|
|
466
|
+
|
|
467
|
+
server.get(`${prefix}/blocklet/og.(png|svg|html)`, async (req, res) => {
|
|
468
|
+
try {
|
|
469
|
+
const format = req.path.split('.').pop();
|
|
470
|
+
const info = await req.getBlockletInfo();
|
|
471
|
+
const blocklet = await req.getBlocklet();
|
|
472
|
+
const cache = req.query.nocache !== '1';
|
|
473
|
+
|
|
474
|
+
const sourceFile = path.join(blocklet.env.dataDir, `og.${format}`);
|
|
475
|
+
if (!fs.existsSync(sourceFile) || !cache) {
|
|
476
|
+
const sourceData = await generateOgImage(info, format);
|
|
477
|
+
fs.writeFileSync(sourceFile, sourceData);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (format === 'png' && isImageAccepted(req) && isImageRequest(req)) {
|
|
481
|
+
const appDir = path.join(cacheDir, blocklet.appPid);
|
|
482
|
+
processAndRespond(req, res, appDir, () =>
|
|
483
|
+
Promise.resolve([fs.createReadStream(sourceFile), path.extname(sourceFile).slice(1)])
|
|
484
|
+
);
|
|
485
|
+
} else {
|
|
486
|
+
res.sendFile(sourceFile, cache ? { maxAge: '365d', immutable: true } : { maxAge: 0 });
|
|
487
|
+
}
|
|
488
|
+
} catch (err) {
|
|
489
|
+
logger.error('failed to send open graph', { fileName: req.params.fileName, error: err });
|
|
490
|
+
res.status(500).send(err.message);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
// Bust cache on blocklet config change
|
|
494
|
+
if (events) {
|
|
495
|
+
events.on(BlockletInternalEvents.appConfigChanged, ({ appDid }) => {
|
|
496
|
+
['png', 'svg', 'html'].forEach((format) => {
|
|
497
|
+
const cached = path.join(node.dataDirs.data, appDid, `og.${format}`);
|
|
498
|
+
if (fs.existsSync(cached)) {
|
|
499
|
+
logger.info('bust og cache on blocklet config change', { appDid, cached });
|
|
500
|
+
try {
|
|
501
|
+
fs.unlinkSync(cached);
|
|
502
|
+
logger.info('bust og cache on blocklet config change', { appDid, format });
|
|
503
|
+
} catch (err) {
|
|
504
|
+
logger.error('bust og cache on blocklet config change', { appDid, format, error: err });
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
}
|
|
468
510
|
},
|
|
469
511
|
};
|
|
@@ -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.4cc7f3ab.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",
|
|
@@ -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.4cc7f3ab.js.map": "/.well-known/service/static/static/js/main.4cc7f3ab.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",
|
|
@@ -174,6 +174,6 @@
|
|
|
174
174
|
},
|
|
175
175
|
"entrypoints": [
|
|
176
176
|
"static/css/main.7ea79dc8.css",
|
|
177
|
-
"static/js/main.
|
|
177
|
+
"static/js/main.4cc7f3ab.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.4cc7f3ab.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>
|