mirror of
https://github.com/misskey-dev/media-proxy.git
synced 2025-08-07 08:43:53 +09:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e79a81f3d | |||
6bf5fbd794 | |||
72431d805e | |||
c3738a339a | |||
99f0160e17 | |||
bd6f63b60e | |||
384c51569f | |||
57aa87f370 | |||
d86823e32d | |||
405e6a5adb | |||
78cf2469d4 | |||
969d27e1b3 | |||
d5f5f4023c | |||
30c8088b8e | |||
4d3869020a | |||
4e2230d7cf | |||
cfaf017c15 | |||
808dacda41 | |||
0f65312eef | |||
495f655973 |
@ -1,32 +0,0 @@
|
||||
module.exports = {
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
extends: [
|
||||
'../shared/.eslintrc.js',
|
||||
],
|
||||
rules: {
|
||||
'import/order': ['warn', {
|
||||
'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
'pathGroups': [
|
||||
{
|
||||
'pattern': '@/**',
|
||||
'group': 'external',
|
||||
'position': 'after'
|
||||
}
|
||||
],
|
||||
}],
|
||||
'no-restricted-globals': [
|
||||
'error',
|
||||
{
|
||||
'name': '__dirname',
|
||||
'message': 'Not in ESModule. Use `import.meta.url` instead.'
|
||||
},
|
||||
{
|
||||
'name': '__filename',
|
||||
'message': 'Not in ESModule. Use `import.meta.url` instead.'
|
||||
}
|
||||
]
|
||||
},
|
||||
};
|
10
README.md
10
README.md
@ -1,8 +1,8 @@
|
||||
# Media Proxy for Misskey
|
||||
|
||||
Misskeyの/proxyが単体で動作します(Misskeyのコードがほぼそのまま移植されています)。
|
||||
[→ メディアプロキシの仕様](./SPECIFICATION.md)
|
||||
|
||||
/proxyは画像ではないと403を返しますが、Media Proxyではそのまま内容を送信します。
|
||||
Misskeyの/proxyが単体で動作します(Misskeyのコードがほぼそのまま移植されています)。
|
||||
|
||||
**Fastifyプラグインとして動作する気がします。**
|
||||
`pnpm start`は[fastify-cli](https://github.com/fastify/fastify-cli)が動作します。
|
||||
@ -61,11 +61,11 @@ export default {
|
||||
maxSize: 262144000,
|
||||
|
||||
// CORS
|
||||
['Access-Control-Allow-Origin']: '*',
|
||||
['Access-Control-Allow-Headers']: '*',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': '*',
|
||||
|
||||
// CSP
|
||||
['Content-Security-Policy']: `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`,
|
||||
'Content-Security-Policy': `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`,
|
||||
|
||||
// フォワードプロキシ
|
||||
// proxy: 'http://127.0.0.1:3128'
|
||||
|
85
SPECIFICATION.md
Normal file
85
SPECIFICATION.md
Normal file
@ -0,0 +1,85 @@
|
||||
# Misskeyメディアプロキシ仕様書
|
||||
|
||||
## メディアプロキシの種類と目的
|
||||
Misskeyメディアプロキシは、リモートのファイルをインスタンス管理者が管理するドメインでプロキシ配信し、また、縮小・加工された画像を提供するためのアプリケーションである。
|
||||
|
||||
Misskeyサーバー本体の/proxy/で提供されている「本体メディアプロキシ (local media proxy)」と、[github.com/misskey-dev/media-proxy](https://github.com/misskey-dev/media-proxy)で配布されている「外部メディアプロキシ (external media proxy)」がある。
|
||||
|
||||
外部メディアプロキシを設定・使用することで、本体のサーバー負荷を軽減できる。また、複数のインスタンスで外部プロキシを共用すると、さらなる負荷軽減が期待できる。
|
||||
|
||||
## 外部メディアプロキシの設定と使用
|
||||
外部メディアプロキシを設定するには、[README.md](./README.md)に記載されている通りインストールする。
|
||||
|
||||
外部メディアプロキシが設定されている場合、本体メディアプロキシは外部メディアプロキシへ301リダイレクトを返答する(originクエリが指定されている場合を除く)。
|
||||
|
||||
Misskeyサーバーのapi/metaの応答に、使用するべきメディアプロキシのURLを示す`mediaProxy`プロパティが存在する。
|
||||
外部メディアプロキシが指定されているならそのURLが、指定されていなければ本体メディアプロキシ(/proxy/)のURLが入っている。
|
||||
本体メディアプロキシはリダイレクトを行うものの、Misskeyクライアントは`mediaProxy`の値に応じて適切なメディアプロキシへ直接要求を行うべきである。
|
||||
|
||||
メディアプロキシへは、クエリ文字列によって命令を行う。
|
||||
|
||||
拡張子によってキャッシュの挙動を変えるCDNがあるため、image.webp、avatar.webp、static.webpなどの適当なファイル名を付加するべきである。
|
||||
例:
|
||||
`https://example.com/proxy/image.webp?url=https%3A%2F%2F......`
|
||||
|
||||
Acceptヘッダーは無視される。
|
||||
Cache-Controlは、正常なレスポンスの場合`max-age=31536000, immutable`、エラーレスポンスの場合`max-age=300`である。
|
||||
Content-Typeは、ファイルの内容について適切なものが挿入される。
|
||||
Content-Security-Policyは、`default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`となっている。
|
||||
Content-Dispositionは、filenameは元画像のContent-Disposition.filenameもしくはファイル名に基づいて挿入される。拡張子は適宜変更され、octet-streamの場合は拡張子として.unknownが付加される。inlineが指定される。
|
||||
|
||||
### クエリの一覧
|
||||
#### url (必須)
|
||||
変換ないしはプロキシを行う対象の、元画像のURLを指定する。
|
||||
指定がなかった場合はHTTPコード400が返される。
|
||||
|
||||
https://www.google.com/images/errors/robot.png をプロキシする場合:
|
||||
`https://example.com/proxy/image.webp?url=https%3A%2F%2Fwww.google.com%2Fimages%2Ferrors%2Frobot.png`
|
||||
|
||||
#### origin (本体のみ)
|
||||
存在すると、外部メディアプロキシへのリダイレクトを行わない。
|
||||
|
||||
`https://example.com/proxy/image.webp?url=https%3A%2F%2F...&origin=1`
|
||||
|
||||
「存在すると」というのは、Fastifyで`'origin' in request.query`がtureになる場合という意味である。以下同様。
|
||||
|
||||
#### fallback
|
||||
存在すると、元画像に到達できなかったり画像の変換中にエラーが起きたりした場合、正常なレスポンス(Cache-Controlは`max-age=300`)としてフォールバック画像(カラーバー)が表示される。
|
||||
|
||||
#### 変換クエリが存在しない場合の挙動
|
||||
次の項目からは変換形式を指定するクエリとなっている。
|
||||
|
||||
変換形式が指定されていなかった場合は、画像ファイルもしくは許可されたファイル(FILE_TYPE_BROWSERSAFE)である場合のみプロキシ(ファイルの再配信)が行われる。
|
||||
ただし、svgは、webpに変換される(最大サイズ2048x2048)。
|
||||
|
||||
#### 変換クエリ付加時の挙動
|
||||
一方、以下の変換クエリが指定されているが、元ファイルがsharp.jsで変換できない形式の場合、404が返される。
|
||||
|
||||
#### emoji
|
||||
存在すると、高さ128px以下のwebpが応答される。
|
||||
ただし、sharp.jsの都合により、元画像がapngの場合は無変換で応答される。
|
||||
|
||||
`https://example.com/proxy/emoji.webp?url=https%3A%2F%2F...&emoji=1`
|
||||
|
||||
「以下」というのは、元画像がこれ未満だった場合は拡大を行わないという意味である。以下同様。
|
||||
|
||||
#### avatar
|
||||
存在すると、高さ320px以下のwebpが応答される。
|
||||
ただし、sharp.jsの都合により、元画像がapngの場合は無変換で応答される。
|
||||
|
||||
`https://example.com/proxy/avatar.webp?url=https%3A%2F%2F...&avatar=1`
|
||||
|
||||
#### static
|
||||
存在すると、アニメーション画像では最初のフレームのみの静止画のwebpが応答される。
|
||||
|
||||
emojiまたはavatarとstaticが同時に指定された場合は、それぞれに応じた高さが、指定されていない場合は幅498px・高さ422pxに収まるサイズ以下に縮小される。
|
||||
|
||||
#### preview
|
||||
存在すると、幅200px・高さ200pxに収まるサイズ以下のwebpが応答される。
|
||||
|
||||
#### badge
|
||||
Webプッシュ通知のバッジに適したpngが応答される。
|
||||
|
||||
https://developer.mozilla.org/ja/docs/Web/API/Notification/badge
|
||||
|
||||
サイズは96x96で、元画像がアルファチャンネルのみで表現される。
|
BIN
assets/dummy.png
Normal file
BIN
assets/dummy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
@ -30,6 +30,10 @@ export const FILE_TYPE_BROWSERSAFE = [
|
||||
'video/webm',
|
||||
'audio/webm',
|
||||
'audio/aac',
|
||||
// see https://github.com/misskey-dev/misskey/pull/10686
|
||||
'audio/flac',
|
||||
'audio/wav',
|
||||
// backward compatibility
|
||||
'audio/x-flac',
|
||||
'audio/vnd.wave',
|
||||
];
|
||||
|
4
built/download.d.ts
vendored
4
built/download.d.ts
vendored
@ -19,4 +19,6 @@ export declare const defaultDownloadConfig: {
|
||||
maxSize: number;
|
||||
proxy: boolean;
|
||||
};
|
||||
export declare function downloadUrl(url: string, path: string, settings?: DownloadConfig): Promise<void>;
|
||||
export declare function downloadUrl(url: string, path: string, settings?: DownloadConfig): Promise<{
|
||||
filename: string;
|
||||
}>;
|
||||
|
@ -6,6 +6,7 @@ import IPCIDR from 'ip-cidr';
|
||||
import PrivateIp from 'private-ip';
|
||||
import { StatusError } from './status-error.js';
|
||||
import { getAgents } from './http.js';
|
||||
import { parse } from 'content-disposition';
|
||||
const pipeline = util.promisify(stream.pipeline);
|
||||
export const defaultDownloadConfig = {
|
||||
userAgent: `MisskeyMediaProxy/0.0.0`,
|
||||
@ -19,6 +20,8 @@ export async function downloadUrl(url, path, settings = defaultDownloadConfig) {
|
||||
console.log(`Downloading ${url} to ${path} ...`);
|
||||
const timeout = 30 * 1000;
|
||||
const operationTimeout = 60 * 1000;
|
||||
const urlObj = new URL(url);
|
||||
let filename = urlObj.pathname.split('/').pop() ?? 'unknown';
|
||||
const req = got.stream(url, {
|
||||
headers: {
|
||||
'User-Agent': settings.userAgent,
|
||||
@ -56,6 +59,18 @@ export async function downloadUrl(url, path, settings = defaultDownloadConfig) {
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
const contentDisposition = res.headers['content-disposition'];
|
||||
if (contentDisposition != null) {
|
||||
try {
|
||||
const parsed = parse(contentDisposition);
|
||||
if (parsed.parameters.filename) {
|
||||
filename = parsed.parameters.filename;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.log(`Failed to parse content-disposition: ${contentDisposition}\n${e}`);
|
||||
}
|
||||
}
|
||||
}).on('downloadProgress', (progress) => {
|
||||
if (progress.transferred > settings.maxSize) {
|
||||
console.log(`maxSize exceeded (${progress.transferred} > ${settings.maxSize}) on downloadProgress`);
|
||||
@ -75,6 +90,9 @@ export async function downloadUrl(url, path, settings = defaultDownloadConfig) {
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production')
|
||||
console.log(`Download finished: ${url}`);
|
||||
return {
|
||||
filename,
|
||||
};
|
||||
}
|
||||
function isPrivateIp(ip, allowedPrivateNetworks) {
|
||||
for (const net of allowedPrivateNetworks ?? []) {
|
||||
|
@ -30,7 +30,7 @@ export async function detectType(path) {
|
||||
return TYPE_OCTET_STREAM;
|
||||
}
|
||||
return {
|
||||
mime: type.mime,
|
||||
mime: fixMime(type.mime),
|
||||
ext: type.ext,
|
||||
};
|
||||
}
|
||||
@ -55,7 +55,17 @@ async function checkSvg(path) {
|
||||
import { FILE_TYPE_BROWSERSAFE } from './const.js';
|
||||
const dictionary = {
|
||||
'safe-file': FILE_TYPE_BROWSERSAFE,
|
||||
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml'],
|
||||
'sharp-animation-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/svg+xml'],
|
||||
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml', 'image/x-icon', 'image/bmp'],
|
||||
'sharp-animation-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/svg+xml', 'image/x-icon', 'image/bmp'],
|
||||
};
|
||||
export const isMimeImage = (mime, type) => dictionary[type].includes(mime);
|
||||
function fixMime(mime) {
|
||||
// see https://github.com/misskey-dev/misskey/pull/10686
|
||||
if (mime === "audio/x-flac") {
|
||||
return "audio/flac";
|
||||
}
|
||||
if (mime === "audio/vnd.wave") {
|
||||
return "audio/wav";
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import sharp from 'sharp';
|
||||
export const webpDefault = {
|
||||
quality: 85,
|
||||
quality: 77,
|
||||
alphaQuality: 95,
|
||||
lossless: false,
|
||||
nearLossless: false,
|
||||
smartSubsample: true,
|
||||
mixed: true,
|
||||
effort: 2,
|
||||
};
|
||||
export function convertToWebpStream(path, width, height, options = webpDefault) {
|
||||
return convertSharpToWebpStream(sharp(path), width, height, options);
|
||||
|
@ -3,15 +3,18 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import fastifyStatic from '@fastify/static';
|
||||
import { createTemp } from './create-temp.js';
|
||||
import { convertToWebpStream, webpDefault } from './image-processor.js';
|
||||
import { FILE_TYPE_BROWSERSAFE } from './const.js';
|
||||
import { convertToWebpStream, webpDefault, convertSharpToWebpStream } from './image-processor.js';
|
||||
import { detectType, isMimeImage } from './file-info.js';
|
||||
import sharp from 'sharp';
|
||||
import { sharpBmp } from 'sharp-read-bmp';
|
||||
import { StatusError } from './status-error.js';
|
||||
import { defaultDownloadConfig, downloadUrl } from './download.js';
|
||||
import { getAgents } from './http.js';
|
||||
import _contentDisposition from 'content-disposition';
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
const assets = `${_dirname}/../../server/file/assets/`;
|
||||
const assets = `${_dirname}/../assets/`;
|
||||
let config = defaultDownloadConfig;
|
||||
export function setMediaProxyConfig(setting) {
|
||||
const proxy = process.env.HTTP_PROXY ?? process.env.http_proxy;
|
||||
@ -41,11 +44,14 @@ export function setMediaProxyConfig(setting) {
|
||||
}
|
||||
export default function (fastify, options, done) {
|
||||
setMediaProxyConfig(options);
|
||||
const corsOrigin = options['Access-Control-Allow-Origin'] ?? '*';
|
||||
const corsHeader = options['Access-Control-Allow-Headers'] ?? '*';
|
||||
const csp = options['Content-Security-Policy'] ?? `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`;
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Access-Control-Allow-Origin', options['Access-Control-Allow-Origin'] ?? '*');
|
||||
reply.header('Access-Control-Allow-Headers', options['Access-Control-Allow-Headers'] ?? '*');
|
||||
reply.header('Access-Control-Allow-Origin', corsOrigin);
|
||||
reply.header('Access-Control-Allow-Headers', corsHeader);
|
||||
reply.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
reply.header('Content-Security-Policy', options['Content-Security-Policy'] ?? `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`);
|
||||
reply.header('Content-Security-Policy', csp);
|
||||
done();
|
||||
});
|
||||
fastify.register(fastifyStatic, {
|
||||
@ -102,7 +108,7 @@ async function proxyHandler(request, reply) {
|
||||
};
|
||||
}
|
||||
else {
|
||||
const data = sharp(file.path, { animated: !('static' in request.query) })
|
||||
const data = (await sharpBmp(file.path, file.mime, { animated: !('static' in request.query) }))
|
||||
.resize({
|
||||
height: 'emoji' in request.query ? 128 : 320,
|
||||
withoutEnlargement: true,
|
||||
@ -116,15 +122,16 @@ async function proxyHandler(request, reply) {
|
||||
}
|
||||
}
|
||||
else if ('static' in request.query) {
|
||||
image = convertToWebpStream(file.path, 498, 280);
|
||||
image = convertSharpToWebpStream(await sharpBmp(file.path, file.mime), 498, 422);
|
||||
}
|
||||
else if ('preview' in request.query) {
|
||||
image = convertToWebpStream(file.path, 200, 200);
|
||||
image = convertSharpToWebpStream(await sharpBmp(file.path, file.mime), 200, 200);
|
||||
}
|
||||
else if ('badge' in request.query) {
|
||||
const mask = sharp(file.path)
|
||||
const mask = (await sharpBmp(file.path, file.mime))
|
||||
.resize(96, 96, {
|
||||
fit: 'inside',
|
||||
fit: 'contain',
|
||||
position: 'centre',
|
||||
withoutEnlargement: false,
|
||||
})
|
||||
.greyscale()
|
||||
@ -151,6 +158,9 @@ async function proxyHandler(request, reply) {
|
||||
else if (file.mime === 'image/svg+xml') {
|
||||
image = convertToWebpStream(file.path, 2048, 2048);
|
||||
}
|
||||
else if (!file.mime.startsWith('image/') || !FILE_TYPE_BROWSERSAFE.includes(file.mime)) {
|
||||
throw new StatusError('Rejected type', 403, 'Rejected type');
|
||||
}
|
||||
if (!image) {
|
||||
image = {
|
||||
data: fs.createReadStream(file.path),
|
||||
@ -175,6 +185,7 @@ async function proxyHandler(request, reply) {
|
||||
}
|
||||
reply.header('Content-Type', image.type);
|
||||
reply.header('Cache-Control', 'max-age=31536000, immutable');
|
||||
reply.header('Content-Disposition', contentDisposition('inline', correctFilename(file.filename, image.ext)));
|
||||
return reply.send(image.data);
|
||||
}
|
||||
catch (e) {
|
||||
@ -186,12 +197,13 @@ async function proxyHandler(request, reply) {
|
||||
async function downloadAndDetectTypeFromUrl(url) {
|
||||
const [path, cleanup] = await createTemp();
|
||||
try {
|
||||
await downloadUrl(url, path, config);
|
||||
const { filename } = await downloadUrl(url, path, config);
|
||||
const { mime, ext } = await detectType(path);
|
||||
return {
|
||||
state: 'remote',
|
||||
mime, ext,
|
||||
path, cleanup,
|
||||
filename: correctFilename(filename, ext),
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
@ -199,3 +211,20 @@ async function downloadAndDetectTypeFromUrl(url) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
function correctFilename(filename, ext) {
|
||||
const dotExt = ext ? `.${ext}` : '.unknown';
|
||||
if (filename.endsWith(dotExt)) {
|
||||
return filename;
|
||||
}
|
||||
if (ext === 'jpg' && filename.endsWith('.jpeg')) {
|
||||
return filename;
|
||||
}
|
||||
if (ext === 'tif' && filename.endsWith('.tiff')) {
|
||||
return filename;
|
||||
}
|
||||
return `${filename}${dotExt}`;
|
||||
}
|
||||
function contentDisposition(type, filename) {
|
||||
const fallback = filename.replace(/[^\w.-]/g, '_');
|
||||
return _contentDisposition(filename, { type, fallback });
|
||||
}
|
||||
|
23
package.json
23
package.json
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "misskey-media-proxy",
|
||||
"version": "0.0.11",
|
||||
"version": "0.0.22",
|
||||
"description": "The Media Proxy for Misskey",
|
||||
"main": "built/index.js",
|
||||
"packageManager": "pnpm@7.26.0",
|
||||
"packageManager": "pnpm@7.28.0",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"built",
|
||||
@ -26,25 +26,28 @@
|
||||
},
|
||||
"homepage": "https://github.com/misskey-dev/media-proxy#readme",
|
||||
"devDependencies": {
|
||||
"@swc/cli": "^0.1.61",
|
||||
"@swc/core": "^1.3.32",
|
||||
"@types/node": "^18.11.19",
|
||||
"@swc/cli": "^0.1.62",
|
||||
"@swc/core": "^1.3.57",
|
||||
"@types/content-disposition": "^0.5.5",
|
||||
"@types/node": "^18.16.7",
|
||||
"@types/sharp": "^0.31.1",
|
||||
"@types/tmp": "^0.2.3",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/static": "^6.8.0",
|
||||
"@fastify/static": "^6.10.1",
|
||||
"cacheable-lookup": "^7.0.0",
|
||||
"fastify": "^4.12.0",
|
||||
"content-disposition": "^0.5.4",
|
||||
"fastify": "^4.17.0",
|
||||
"fastify-cli": "^5.7.1",
|
||||
"file-type": "^18.2.0",
|
||||
"got": "^12.5.3",
|
||||
"file-type": "^18.4.0",
|
||||
"got": "^12.6.0",
|
||||
"hpagent": "^1.2.0",
|
||||
"ip-cidr": "^3.1.0",
|
||||
"is-svg": "^4.3.2",
|
||||
"is-svg": "^4.4.0",
|
||||
"private-ip": "^3.0.0",
|
||||
"sharp": "^0.31.3",
|
||||
"sharp-read-bmp": "github:misskey-dev/sharp-read-bmp",
|
||||
"tmp": "^0.2.1"
|
||||
}
|
||||
}
|
||||
|
377
pnpm-lock.yaml
generated
377
pnpm-lock.yaml
generated
@ -1,49 +1,59 @@
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@fastify/static': ^6.8.0
|
||||
'@swc/cli': ^0.1.61
|
||||
'@swc/core': ^1.3.32
|
||||
'@types/node': ^18.11.19
|
||||
'@fastify/static': ^6.10.1
|
||||
'@swc/cli': ^0.1.62
|
||||
'@swc/core': ^1.3.57
|
||||
'@types/content-disposition': ^0.5.5
|
||||
'@types/node': ^18.16.7
|
||||
'@types/sharp': ^0.31.1
|
||||
'@types/tmp': ^0.2.3
|
||||
cacheable-lookup: ^7.0.0
|
||||
fastify: ^4.12.0
|
||||
content-disposition: ^0.5.4
|
||||
fastify: ^4.17.0
|
||||
fastify-cli: ^5.7.1
|
||||
file-type: ^18.2.0
|
||||
got: ^12.5.3
|
||||
file-type: ^18.4.0
|
||||
got: ^12.6.0
|
||||
hpagent: ^1.2.0
|
||||
ip-cidr: ^3.1.0
|
||||
is-svg: ^4.3.2
|
||||
is-svg: ^4.4.0
|
||||
private-ip: ^3.0.0
|
||||
sharp: ^0.31.3
|
||||
sharp-read-bmp: github:misskey-dev/sharp-read-bmp
|
||||
tmp: ^0.2.1
|
||||
typescript: ^4.9.5
|
||||
|
||||
dependencies:
|
||||
'@fastify/static': 6.8.0
|
||||
'@fastify/static': 6.10.1
|
||||
cacheable-lookup: 7.0.0
|
||||
fastify: 4.12.0
|
||||
content-disposition: 0.5.4
|
||||
fastify: 4.17.0
|
||||
fastify-cli: 5.7.1
|
||||
file-type: 18.2.0
|
||||
got: 12.5.3
|
||||
file-type: 18.4.0
|
||||
got: 12.6.0
|
||||
hpagent: 1.2.0
|
||||
ip-cidr: 3.1.0
|
||||
is-svg: 4.3.2
|
||||
is-svg: 4.4.0
|
||||
private-ip: 3.0.0
|
||||
sharp: 0.31.3
|
||||
sharp-read-bmp: github.com/misskey-dev/sharp-read-bmp/02d9dc189fa7df0c4bea09330be26741772dac01
|
||||
tmp: 0.2.1
|
||||
|
||||
devDependencies:
|
||||
'@swc/cli': 0.1.61_@swc+core@1.3.32
|
||||
'@swc/core': 1.3.32
|
||||
'@types/node': 18.11.19
|
||||
'@swc/cli': 0.1.62_@swc+core@1.3.57
|
||||
'@swc/core': 1.3.57
|
||||
'@types/content-disposition': 0.5.5
|
||||
'@types/node': 18.16.7
|
||||
'@types/sharp': 0.31.1
|
||||
'@types/tmp': 0.2.3
|
||||
typescript: 4.9.5
|
||||
|
||||
packages:
|
||||
|
||||
/@canvas/image-data/1.0.0:
|
||||
resolution: {integrity: sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==}
|
||||
dev: false
|
||||
|
||||
/@chainsafe/is-ip/2.0.1:
|
||||
resolution: {integrity: sha512-nqSJ8u2a1Rv9FYbyI8qpDhTYujaKEyLknNrTejLYoSWmdeg+2WB7R6BZqPZYfrJzDxVi3rl6ZQuoaEvpKRZWgQ==}
|
||||
dev: false
|
||||
@ -69,14 +79,14 @@ packages:
|
||||
resolution: {integrity: sha512-KAfcLa+CnknwVi5fWogrLXgidLic+GXnLjijXdpl8pvkvbXU5BGa37iZO9FGvsh9ZL4y+oFi5cbHBm5UOG+dmQ==}
|
||||
dev: false
|
||||
|
||||
/@fastify/fast-json-stringify-compiler/4.2.0:
|
||||
resolution: {integrity: sha512-ypZynRvXA3dibfPykQN3RB5wBdEUgSGgny8Qc6k163wYPLD4mEGEDkACp+00YmqkGvIm8D/xYoHajwyEdWD/eg==}
|
||||
/@fastify/fast-json-stringify-compiler/4.3.0:
|
||||
resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==}
|
||||
dependencies:
|
||||
fast-json-stringify: 5.5.0
|
||||
fast-json-stringify: 5.7.0
|
||||
dev: false
|
||||
|
||||
/@fastify/send/2.0.1:
|
||||
resolution: {integrity: sha512-8jdouu0o5d0FMq1+zCKeKXc1tmOQ5tTGYdQP3MpyF9+WWrZT1KCBdh6hvoEYxOm3oJG/akdE9BpehLiJgYRvGw==}
|
||||
/@fastify/send/2.1.0:
|
||||
resolution: {integrity: sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==}
|
||||
dependencies:
|
||||
'@lukeed/ms': 2.0.1
|
||||
escape-html: 1.0.3
|
||||
@ -85,16 +95,16 @@ packages:
|
||||
mime: 3.0.0
|
||||
dev: false
|
||||
|
||||
/@fastify/static/6.8.0:
|
||||
resolution: {integrity: sha512-MNQp7KM0NIC+722OPN3MholnfvM+Vg2ao4OwbWWNJhAJEWOKGe4fJsEjIh3OkN0z5ymhklc7EXGCG0zDaIU5ZQ==}
|
||||
/@fastify/static/6.10.1:
|
||||
resolution: {integrity: sha512-DNnG+5QenQcTQw37qk0/191STThnN6SbU+2XMpWtpYR3gQUfUvMax14jTT/jqNINNbCkQJaKMnPtpFPKo4/68g==}
|
||||
dependencies:
|
||||
'@fastify/accept-negotiator': 1.1.0
|
||||
'@fastify/send': 2.0.1
|
||||
'@fastify/send': 2.1.0
|
||||
content-disposition: 0.5.4
|
||||
fastify-plugin: 4.5.0
|
||||
glob: 8.1.0
|
||||
p-limit: 3.1.0
|
||||
readable-stream: 4.3.0
|
||||
readable-stream: 4.4.0
|
||||
dev: false
|
||||
|
||||
/@lukeed/ms/2.0.1:
|
||||
@ -147,8 +157,8 @@ packages:
|
||||
engines: {node: '>=14.16'}
|
||||
dev: false
|
||||
|
||||
/@swc/cli/0.1.61_@swc+core@1.3.32:
|
||||
resolution: {integrity: sha512-HeYMJ+8gKfJzM9xgcZqTpAHJYAJVGSljBSmWRUx2B6UiGraLsLjEcqxITwi6/t6Af+QboBMiQX5Wwll89oPK7g==}
|
||||
/@swc/cli/0.1.62_@swc+core@1.3.57:
|
||||
resolution: {integrity: sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==}
|
||||
engines: {node: '>= 12.13'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@ -159,16 +169,16 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@mole-inc/bin-wrapper': 8.0.1
|
||||
'@swc/core': 1.3.32
|
||||
'@swc/core': 1.3.57
|
||||
commander: 7.2.0
|
||||
fast-glob: 3.2.12
|
||||
semver: 7.3.8
|
||||
semver: 7.5.0
|
||||
slash: 3.0.0
|
||||
source-map: 0.7.4
|
||||
dev: true
|
||||
|
||||
/@swc/core-darwin-arm64/1.3.32:
|
||||
resolution: {integrity: sha512-o19bhlxuUgjUElm6i+QhXgZ0vD6BebiB/gQpK3en5aAwhOvinwr4sah3GqFXsQzz/prKVDuMkj9SW6F/Ug5hgg==}
|
||||
/@swc/core-darwin-arm64/1.3.57:
|
||||
resolution: {integrity: sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
@ -176,8 +186,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-darwin-x64/1.3.32:
|
||||
resolution: {integrity: sha512-hVEGd+v5Afh+YekGADOGKwhuS4/AXk91nLuk7pmhWkk8ceQ1cfmah90kXjIXUlCe2G172MLRfHNWlZxr29E/Og==}
|
||||
/@swc/core-darwin-x64/1.3.57:
|
||||
resolution: {integrity: sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
@ -185,8 +195,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm-gnueabihf/1.3.32:
|
||||
resolution: {integrity: sha512-5X01WqI9EbJ69oHAOGlI08YqvEIXMfT/mCJ1UWDQBb21xWRE2W1yFAAeuqOLtiagLrXjPv/UKQ0S2gyWQR5AXQ==}
|
||||
/@swc/core-linux-arm-gnueabihf/1.3.57:
|
||||
resolution: {integrity: sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
@ -194,8 +204,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm64-gnu/1.3.32:
|
||||
resolution: {integrity: sha512-PTJ6oPiutkNBg+m22bUUPa4tNuMmsgpSnsnv2wnWVOgK0lhvQT6bAPTUXDq/8peVAgR/SlpP2Ht8TRRqYMRjRQ==}
|
||||
/@swc/core-linux-arm64-gnu/1.3.57:
|
||||
resolution: {integrity: sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@ -203,8 +213,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm64-musl/1.3.32:
|
||||
resolution: {integrity: sha512-lG0VOuYNPWOCJ99Aza69cTljjeft/wuRQeYFF8d+1xCQS/OT7gnbgi7BOz39uSHIPTBqfzdIsuvzdKlp9QydrQ==}
|
||||
/@swc/core-linux-arm64-musl/1.3.57:
|
||||
resolution: {integrity: sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@ -212,8 +222,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-x64-gnu/1.3.32:
|
||||
resolution: {integrity: sha512-ecqtSWX4NBrs7Ji2VX3fDWeqUfrbLlYqBuufAziCM27xMxwlAVgmyGQk4FYgoQ3SAUAu3XFH87+3Q7uWm2X7xg==}
|
||||
/@swc/core-linux-x64-gnu/1.3.57:
|
||||
resolution: {integrity: sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@ -221,8 +231,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-x64-musl/1.3.32:
|
||||
resolution: {integrity: sha512-rl3dMcUuENVkpk5NGW/LXovjK0+JFm4GWPjy4NM3Q5cPvhBpGwSeLZlR+zAw9K0fdGoIXiayRTTfENrQwwsH+g==}
|
||||
/@swc/core-linux-x64-musl/1.3.57:
|
||||
resolution: {integrity: sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@ -230,8 +240,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-arm64-msvc/1.3.32:
|
||||
resolution: {integrity: sha512-VlybAZp8DcS66CH1LDnfp9zdwbPlnGXREtHDMHaBfK9+80AWVTg+zn0tCYz+HfcrRONqxbudwOUIPj+dwl/8jw==}
|
||||
/@swc/core-win32-arm64-msvc/1.3.57:
|
||||
resolution: {integrity: sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
@ -239,8 +249,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-ia32-msvc/1.3.32:
|
||||
resolution: {integrity: sha512-MEUMdpUFIQ+RD+K/iHhHKfu0TFNj9VXwIxT5hmPeqyboKo095CoFEFBJ0sHG04IGlnu8T9i+uE2Pi18qUEbFug==}
|
||||
/@swc/core-win32-ia32-msvc/1.3.57:
|
||||
resolution: {integrity: sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
@ -248,8 +258,8 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-x64-msvc/1.3.32:
|
||||
resolution: {integrity: sha512-DPMoneNFQco7SqmVVOUv1Vn53YmoImEfrAPMY9KrqQzgfzqNTuL2JvfxUqfAxwQ6pEKYAdyKJvZ483rIhgG9XQ==}
|
||||
/@swc/core-win32-x64-msvc/1.3.57:
|
||||
resolution: {integrity: sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@ -257,21 +267,26 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core/1.3.32:
|
||||
resolution: {integrity: sha512-Yx/n1j+uUkcqlJAW8IRg8Qymgkdow6NHJZPFShiR0YiaYq2sXY+JHmvh16O6GkL91Y+gTlDUS7uVgDz50czJUQ==}
|
||||
/@swc/core/1.3.57:
|
||||
resolution: {integrity: sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==}
|
||||
engines: {node: '>=10'}
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
'@swc/helpers': ^0.5.0
|
||||
peerDependenciesMeta:
|
||||
'@swc/helpers':
|
||||
optional: true
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.3.32
|
||||
'@swc/core-darwin-x64': 1.3.32
|
||||
'@swc/core-linux-arm-gnueabihf': 1.3.32
|
||||
'@swc/core-linux-arm64-gnu': 1.3.32
|
||||
'@swc/core-linux-arm64-musl': 1.3.32
|
||||
'@swc/core-linux-x64-gnu': 1.3.32
|
||||
'@swc/core-linux-x64-musl': 1.3.32
|
||||
'@swc/core-win32-arm64-msvc': 1.3.32
|
||||
'@swc/core-win32-ia32-msvc': 1.3.32
|
||||
'@swc/core-win32-x64-msvc': 1.3.32
|
||||
'@swc/core-darwin-arm64': 1.3.57
|
||||
'@swc/core-darwin-x64': 1.3.57
|
||||
'@swc/core-linux-arm-gnueabihf': 1.3.57
|
||||
'@swc/core-linux-arm64-gnu': 1.3.57
|
||||
'@swc/core-linux-arm64-musl': 1.3.57
|
||||
'@swc/core-linux-x64-gnu': 1.3.57
|
||||
'@swc/core-linux-x64-musl': 1.3.57
|
||||
'@swc/core-win32-arm64-msvc': 1.3.57
|
||||
'@swc/core-win32-ia32-msvc': 1.3.57
|
||||
'@swc/core-win32-x64-msvc': 1.3.57
|
||||
dev: true
|
||||
|
||||
/@szmarczak/http-timer/4.0.6:
|
||||
@ -296,33 +311,37 @@ packages:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.1
|
||||
'@types/keyv': 3.1.4
|
||||
'@types/node': 18.11.19
|
||||
'@types/node': 18.16.7
|
||||
'@types/responselike': 1.0.0
|
||||
dev: true
|
||||
|
||||
/@types/content-disposition/0.5.5:
|
||||
resolution: {integrity: sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA==}
|
||||
dev: true
|
||||
|
||||
/@types/http-cache-semantics/4.0.1:
|
||||
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
|
||||
|
||||
/@types/keyv/3.1.4:
|
||||
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.19
|
||||
'@types/node': 18.16.7
|
||||
dev: true
|
||||
|
||||
/@types/node/18.11.19:
|
||||
resolution: {integrity: sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==}
|
||||
/@types/node/18.16.7:
|
||||
resolution: {integrity: sha512-MFg7ua/bRtnA1hYE3pVyWxGd/r7aMqjNOdHvlSsXV3n8iaeGKkOaPzpJh6/ovf4bEXWcojkeMJpTsq3mzXW4IQ==}
|
||||
dev: true
|
||||
|
||||
/@types/responselike/1.0.0:
|
||||
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.19
|
||||
'@types/node': 18.16.7
|
||||
dev: true
|
||||
|
||||
/@types/sharp/0.31.1:
|
||||
resolution: {integrity: sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==}
|
||||
dependencies:
|
||||
'@types/node': 18.11.19
|
||||
'@types/node': 18.16.7
|
||||
dev: true
|
||||
|
||||
/@types/tmp/0.2.3:
|
||||
@ -386,8 +405,8 @@ packages:
|
||||
engines: {node: '>=8.0.0'}
|
||||
dev: false
|
||||
|
||||
/avvio/8.2.0:
|
||||
resolution: {integrity: sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==}
|
||||
/avvio/8.2.1:
|
||||
resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==}
|
||||
dependencies:
|
||||
archy: 1.0.0
|
||||
debug: 4.3.4
|
||||
@ -417,7 +436,7 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
bin-version: 6.0.0
|
||||
semver: 7.3.8
|
||||
semver: 7.5.0
|
||||
semver-truncate: 2.0.0
|
||||
dev: true
|
||||
|
||||
@ -439,7 +458,7 @@ packages:
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/brace-expansion/1.1.11:
|
||||
@ -485,8 +504,8 @@ packages:
|
||||
engines: {node: '>=14.16'}
|
||||
dev: false
|
||||
|
||||
/cacheable-request/10.2.6:
|
||||
resolution: {integrity: sha512-fhVLoXIFHvTizxQkAVohKPToSzdwzjrhL5SsjHT0umeSCxWeqJOS0oPqHg+yO1FPFST3VE5rxaqUvseyH9JHtg==}
|
||||
/cacheable-request/10.2.10:
|
||||
resolution: {integrity: sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==}
|
||||
engines: {node: '>=14.16'}
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.1
|
||||
@ -544,8 +563,8 @@ packages:
|
||||
mimic-response: 1.0.1
|
||||
dev: true
|
||||
|
||||
/close-with-grace/1.1.0:
|
||||
resolution: {integrity: sha512-6cCp71Y5tKw1o9sGVBOa9OwY4vJ+YoLpFcWiTt9YCBhYlcQi0z68EiiN9mJ6/401Za6TZ5YOZg012IHHZt15lw==}
|
||||
/close-with-grace/1.2.0:
|
||||
resolution: {integrity: sha512-Xga0jyAb4fX98u5pZAgqlbqHP8cHuy5M3Wto0k0L/36aP2C25Cjp51XfPw3Hz7dNC2L2/hF/PK/KJhO275L+VA==}
|
||||
dev: false
|
||||
|
||||
/color-convert/2.0.1:
|
||||
@ -574,8 +593,8 @@ packages:
|
||||
color-string: 1.9.1
|
||||
dev: false
|
||||
|
||||
/colorette/2.0.19:
|
||||
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
|
||||
/colorette/2.0.20:
|
||||
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||
dev: false
|
||||
|
||||
/commander/7.2.0:
|
||||
@ -635,6 +654,23 @@ packages:
|
||||
ms: 2.1.2
|
||||
dev: false
|
||||
|
||||
/decode-bmp/0.2.1:
|
||||
resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
dependencies:
|
||||
'@canvas/image-data': 1.0.0
|
||||
to-data-view: 1.1.0
|
||||
dev: false
|
||||
|
||||
/decode-ico/0.4.1:
|
||||
resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==}
|
||||
engines: {node: '>=8.6'}
|
||||
dependencies:
|
||||
'@canvas/image-data': 1.0.0
|
||||
decode-bmp: 0.2.1
|
||||
to-data-view: 1.1.0
|
||||
dev: false
|
||||
|
||||
/decompress-response/6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -748,8 +784,8 @@ packages:
|
||||
resolution: {integrity: sha512-Xbc4XcysUXcsP5aHUU7Nq3OwvHq97C+WnbkeIefpeYLX+ryzFJlU6OStFJhs6Ol0LkUGpcK+wL0JwfM+FCU5IA==}
|
||||
dev: false
|
||||
|
||||
/fast-copy/3.0.0:
|
||||
resolution: {integrity: sha512-4HzS+9pQ5Yxtv13Lhs1Z1unMXamBdn5nA4bEi1abYpDNSpSp7ODYQ1KPMF6nTatfEzgH6/zPvXKU1zvHiUjWlA==}
|
||||
/fast-copy/3.0.1:
|
||||
resolution: {integrity: sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==}
|
||||
dev: false
|
||||
|
||||
/fast-decode-uri-component/1.0.1:
|
||||
@ -771,8 +807,8 @@ packages:
|
||||
micromatch: 4.0.5
|
||||
dev: true
|
||||
|
||||
/fast-json-stringify/5.5.0:
|
||||
resolution: {integrity: sha512-rmw2Z8/mLkND8zI+3KTYIkNPEoF5v6GqDP/o+g7H3vjdWjBwuKpgAYFHIzL6ORRB+iqDjjtJnLIW9Mzxn5szOA==}
|
||||
/fast-json-stringify/5.7.0:
|
||||
resolution: {integrity: sha512-sBVPTgnAZseLu1Qgj6lUbQ0HfjFhZWXAmpZ5AaSGkyLh5gAXBga/uPJjQPHpDFjC9adWIpdOcCLSDTgrZ7snoQ==}
|
||||
dependencies:
|
||||
'@fastify/deepmerge': 1.3.0
|
||||
ajv: 8.12.0
|
||||
@ -782,8 +818,8 @@ packages:
|
||||
rfdc: 1.3.0
|
||||
dev: false
|
||||
|
||||
/fast-querystring/1.1.0:
|
||||
resolution: {integrity: sha512-LWkjBCZlxjnSanuPpZ6mHswjy8hQv3VcPJsQB3ltUF2zjvrycr0leP3TSTEEfvQ1WEMSRl5YNsGqaft9bjLqEw==}
|
||||
/fast-querystring/1.1.1:
|
||||
resolution: {integrity: sha512-qR2r+e3HvhEFmpdHMv//U8FnFlnYjaC6QKDuaXALDkw2kvHO8WDjxH+f/rHGR4Me4pnk8p9JAkRNTjYHAKRn2Q==}
|
||||
dependencies:
|
||||
fast-decode-uri-component: 1.0.1
|
||||
dev: false
|
||||
@ -801,8 +837,8 @@ packages:
|
||||
resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==}
|
||||
dev: false
|
||||
|
||||
/fast-xml-parser/3.21.1:
|
||||
resolution: {integrity: sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg==}
|
||||
/fast-xml-parser/4.2.2:
|
||||
resolution: {integrity: sha512-DLzIPtQqmvmdq3VUKR7T6omPK/VCRNqgFlGtbESfyhcH2R4I8EzK1/K6E8PkRCK2EabWrUHK32NjYRbEFnnz0Q==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
strnum: 1.0.5
|
||||
@ -815,19 +851,19 @@ packages:
|
||||
'@fastify/deepmerge': 1.3.0
|
||||
chalk: 4.1.2
|
||||
chokidar: 3.5.3
|
||||
close-with-grace: 1.1.0
|
||||
close-with-grace: 1.2.0
|
||||
commist: 3.2.0
|
||||
dotenv: 16.0.3
|
||||
fastify: 4.12.0
|
||||
fastify: 4.17.0
|
||||
fastify-plugin: 4.5.0
|
||||
generify: 4.2.0
|
||||
help-me: 4.2.0
|
||||
is-docker: 2.2.1
|
||||
make-promises-safe: 5.1.0
|
||||
pino-pretty: 9.1.1
|
||||
pino-pretty: 9.4.0
|
||||
pkg-up: 3.1.0
|
||||
resolve-from: 5.0.0
|
||||
semver: 7.3.8
|
||||
semver: 7.5.0
|
||||
yargs-parser: 21.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -837,24 +873,25 @@ packages:
|
||||
resolution: {integrity: sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg==}
|
||||
dev: false
|
||||
|
||||
/fastify/4.12.0:
|
||||
resolution: {integrity: sha512-Hh2GCsOCqnOuewWSvqXlpq5V/9VA+/JkVoooQWUhrU6gryO9+/UGOoF/dprGcKSDxkM/9TkMXSffYp8eA/YhYQ==}
|
||||
/fastify/4.17.0:
|
||||
resolution: {integrity: sha512-tzuY1tgWJo2Y6qEKwmLhFvACUmr68Io2pqP/sDKU71KRM6A6R3DrCDqLGqANbeLZcKUfdfY58ut35CGqemcTgg==}
|
||||
dependencies:
|
||||
'@fastify/ajv-compiler': 3.5.0
|
||||
'@fastify/error': 3.2.0
|
||||
'@fastify/fast-json-stringify-compiler': 4.2.0
|
||||
'@fastify/fast-json-stringify-compiler': 4.3.0
|
||||
abstract-logging: 2.0.1
|
||||
avvio: 8.2.0
|
||||
avvio: 8.2.1
|
||||
fast-content-type-parse: 1.0.0
|
||||
find-my-way: 7.4.0
|
||||
light-my-request: 5.8.0
|
||||
pino: 8.8.0
|
||||
process-warning: 2.1.0
|
||||
fast-json-stringify: 5.7.0
|
||||
find-my-way: 7.6.2
|
||||
light-my-request: 5.9.1
|
||||
pino: 8.14.1
|
||||
process-warning: 2.2.0
|
||||
proxy-addr: 2.0.7
|
||||
rfdc: 1.3.0
|
||||
secure-json-parse: 2.7.0
|
||||
semver: 7.3.8
|
||||
tiny-lru: 10.0.1
|
||||
semver: 7.5.0
|
||||
tiny-lru: 11.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
@ -873,8 +910,8 @@ packages:
|
||||
token-types: 5.0.1
|
||||
dev: true
|
||||
|
||||
/file-type/18.2.0:
|
||||
resolution: {integrity: sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg==}
|
||||
/file-type/18.4.0:
|
||||
resolution: {integrity: sha512-o6MQrZKTAK6WpvmQk3jqTVUmqxYBxW5bloUfrdH1ZnRFDvvAPNr+l+rgOxM3nkqWT+3khaj3FRMDydWe0xhu+w==}
|
||||
engines: {node: '>=14.16'}
|
||||
dependencies:
|
||||
readable-web-to-node-stream: 3.0.2
|
||||
@ -902,12 +939,12 @@ packages:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
|
||||
/find-my-way/7.4.0:
|
||||
resolution: {integrity: sha512-JFT7eURLU5FumlZ3VBGnveId82cZz7UR7OUu+THQJOwdQXxmS/g8v0KLoFhv97HreycOrmAbqjXD/4VG2j0uMQ==}
|
||||
/find-my-way/7.6.2:
|
||||
resolution: {integrity: sha512-0OjHn1b1nCX3eVbm9ByeEHiscPYiHLfhei1wOUU9qffQkk98wE0Lo8VrVYfSGMgnSnDh86DxedduAnBf4nwUEw==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-querystring: 1.1.0
|
||||
fast-querystring: 1.1.1
|
||||
safe-regex2: 2.0.0
|
||||
dev: false
|
||||
|
||||
@ -1026,14 +1063,14 @@ packages:
|
||||
responselike: 2.0.1
|
||||
dev: true
|
||||
|
||||
/got/12.5.3:
|
||||
resolution: {integrity: sha512-8wKnb9MGU8IPGRIo+/ukTy9XLJBwDiCpIf5TVzQ9Cpol50eMTpBq2GAuDsuDIz7hTYmZgMgC1e9ydr6kSDWs3w==}
|
||||
/got/12.6.0:
|
||||
resolution: {integrity: sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==}
|
||||
engines: {node: '>=14.16'}
|
||||
dependencies:
|
||||
'@sindresorhus/is': 5.3.0
|
||||
'@szmarczak/http-timer': 5.0.1
|
||||
cacheable-lookup: 7.0.0
|
||||
cacheable-request: 10.2.6
|
||||
cacheable-request: 10.2.10
|
||||
decompress-response: 6.0.0
|
||||
form-data-encoder: 2.1.4
|
||||
get-stream: 6.0.1
|
||||
@ -1052,7 +1089,7 @@ packages:
|
||||
resolution: {integrity: sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA==}
|
||||
dependencies:
|
||||
glob: 8.1.0
|
||||
readable-stream: 3.6.0
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/hpagent/1.2.0:
|
||||
@ -1189,11 +1226,11 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/is-svg/4.3.2:
|
||||
resolution: {integrity: sha512-mM90duy00JGMyjqIVHu9gNTjywdZV+8qNasX8cm/EEYZ53PHDgajvbBwNVvty5dwSAxLUD3p3bdo+7sR/UMrpw==}
|
||||
/is-svg/4.4.0:
|
||||
resolution: {integrity: sha512-v+AgVwiK5DsGtT9ng+m4mClp6zDAmwrW8nZi6Gg15qzvBnRWWdfWA1TGaXyCDnWq5g5asofIgMVl3PjKxvk1ug==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
fast-xml-parser: 3.21.1
|
||||
fast-xml-parser: 4.2.2
|
||||
dev: false
|
||||
|
||||
/isbinaryfile/4.0.10:
|
||||
@ -1226,12 +1263,12 @@ packages:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
|
||||
/light-my-request/5.8.0:
|
||||
resolution: {integrity: sha512-4BtD5C+VmyTpzlDPCZbsatZMJVgUIciSOwYhJDCbLffPZ35KoDkDj4zubLeHDEb35b4kkPeEv5imbh+RJxK/Pg==}
|
||||
/light-my-request/5.9.1:
|
||||
resolution: {integrity: sha512-UT7pUk8jNCR1wR7w3iWfIjx32DiB2f3hFdQSOwy3/EPQ3n3VocyipUxcyRZR0ahoev+fky69uA+GejPa9KuHKg==}
|
||||
dependencies:
|
||||
cookie: 0.5.0
|
||||
process-warning: 2.1.0
|
||||
set-cookie-parser: 2.5.1
|
||||
process-warning: 2.2.0
|
||||
set-cookie-parser: 2.6.0
|
||||
dev: false
|
||||
|
||||
/locate-path/3.0.0:
|
||||
@ -1335,8 +1372,8 @@ packages:
|
||||
brace-expansion: 2.0.1
|
||||
dev: false
|
||||
|
||||
/minimist/1.2.7:
|
||||
resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
|
||||
/minimist/1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
dev: false
|
||||
|
||||
/mkdirp-classic/0.5.3:
|
||||
@ -1356,11 +1393,11 @@ packages:
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dev: false
|
||||
|
||||
/node-abi/3.31.0:
|
||||
resolution: {integrity: sha512-eSKV6s+APenqVh8ubJyiu/YhZgxQpGP66ntzUb3lY1xB9ukSRaGnx0AIxI+IM+1+IVYC1oWobgG5L3Lt9ARykQ==}
|
||||
/node-abi/3.40.0:
|
||||
resolution: {integrity: sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
semver: 7.3.8
|
||||
semver: 7.5.0
|
||||
dev: false
|
||||
|
||||
/node-addon-api/5.1.0:
|
||||
@ -1496,48 +1533,48 @@ packages:
|
||||
/pino-abstract-transport/1.0.0:
|
||||
resolution: {integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==}
|
||||
dependencies:
|
||||
readable-stream: 4.3.0
|
||||
split2: 4.1.0
|
||||
readable-stream: 4.4.0
|
||||
split2: 4.2.0
|
||||
dev: false
|
||||
|
||||
/pino-pretty/9.1.1:
|
||||
resolution: {integrity: sha512-iJrnjgR4FWQIXZkUF48oNgoRI9BpyMhaEmihonHeCnZ6F50ZHAS4YGfGBT/ZVNsPmd+hzkIPGzjKdY08+/yAXw==}
|
||||
/pino-pretty/9.4.0:
|
||||
resolution: {integrity: sha512-NIudkNLxnl7MGj1XkvsqVyRgo6meFP82ECXF2PlOI+9ghmbGuBUUqKJ7IZPIxpJw4vhhSva0IuiDSAuGh6TV9g==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
colorette: 2.0.19
|
||||
colorette: 2.0.20
|
||||
dateformat: 4.6.3
|
||||
fast-copy: 3.0.0
|
||||
fast-copy: 3.0.1
|
||||
fast-safe-stringify: 2.1.1
|
||||
help-me: 4.2.0
|
||||
joycon: 3.1.1
|
||||
minimist: 1.2.7
|
||||
minimist: 1.2.8
|
||||
on-exit-leak-free: 2.1.0
|
||||
pino-abstract-transport: 1.0.0
|
||||
pump: 3.0.0
|
||||
readable-stream: 4.3.0
|
||||
readable-stream: 4.4.0
|
||||
secure-json-parse: 2.7.0
|
||||
sonic-boom: 3.2.1
|
||||
sonic-boom: 3.3.0
|
||||
strip-json-comments: 3.1.1
|
||||
dev: false
|
||||
|
||||
/pino-std-serializers/6.1.0:
|
||||
resolution: {integrity: sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==}
|
||||
/pino-std-serializers/6.2.1:
|
||||
resolution: {integrity: sha512-wHuWB+CvSVb2XqXM0W/WOYUkVSPbiJb9S5fNB7TBhd8s892Xq910bRxwHtC4l71hgztObTjXL6ZheZXFjhDrDQ==}
|
||||
dev: false
|
||||
|
||||
/pino/8.8.0:
|
||||
resolution: {integrity: sha512-cF8iGYeu2ODg2gIwgAHcPrtR63ILJz3f7gkogaHC/TXVVXxZgInmNYiIpDYEwgEkxZti2Se6P2W2DxlBIZe6eQ==}
|
||||
/pino/8.14.1:
|
||||
resolution: {integrity: sha512-8LYNv7BKWXSfS+k6oEc6occy5La+q2sPwU3q2ljTX5AZk7v+5kND2o5W794FyRaqha6DJajmkNRsWtPpFyMUdw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
atomic-sleep: 1.0.0
|
||||
fast-redact: 3.1.2
|
||||
on-exit-leak-free: 2.1.0
|
||||
pino-abstract-transport: 1.0.0
|
||||
pino-std-serializers: 6.1.0
|
||||
process-warning: 2.1.0
|
||||
pino-std-serializers: 6.2.1
|
||||
process-warning: 2.2.0
|
||||
quick-format-unescaped: 4.0.4
|
||||
real-require: 0.2.0
|
||||
safe-stable-stringify: 2.4.2
|
||||
sonic-boom: 3.2.1
|
||||
safe-stable-stringify: 2.4.3
|
||||
sonic-boom: 3.3.0
|
||||
thread-stream: 2.3.0
|
||||
dev: false
|
||||
|
||||
@ -1556,10 +1593,10 @@ packages:
|
||||
detect-libc: 2.0.1
|
||||
expand-template: 2.0.3
|
||||
github-from-package: 0.0.0
|
||||
minimist: 1.2.7
|
||||
minimist: 1.2.8
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 1.0.2
|
||||
node-abi: 3.31.0
|
||||
node-abi: 3.40.0
|
||||
pump: 3.0.0
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
@ -1577,8 +1614,8 @@ packages:
|
||||
netmask: 2.0.2
|
||||
dev: false
|
||||
|
||||
/process-warning/2.1.0:
|
||||
resolution: {integrity: sha512-9C20RLxrZU/rFnxWncDkuF6O999NdIf3E1ws4B0ZeY3sRVPzWBMsYDE2lxjxhiXxg464cQTgKUGm8/i6y2YGXg==}
|
||||
/process-warning/2.2.0:
|
||||
resolution: {integrity: sha512-/1WZ8+VQjR6avWOgHeEPd7SDQmFQ1B5mC1eRXsCm5TarlNmx/wCsa5GEaxGm05BORRtyG/Ex/3xq3TuRvq57qg==}
|
||||
dev: false
|
||||
|
||||
/process/0.11.10:
|
||||
@ -1627,20 +1664,20 @@ packages:
|
||||
dependencies:
|
||||
deep-extend: 0.6.0
|
||||
ini: 1.3.8
|
||||
minimist: 1.2.7
|
||||
minimist: 1.2.8
|
||||
strip-json-comments: 2.0.1
|
||||
dev: false
|
||||
|
||||
/readable-stream/3.6.0:
|
||||
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
|
||||
/readable-stream/3.6.2:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
/readable-stream/4.3.0:
|
||||
resolution: {integrity: sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==}
|
||||
/readable-stream/4.4.0:
|
||||
resolution: {integrity: sha512-kDMOq0qLtxV9f/SQv522h8cxZBqNZXuXNyjyezmfAAuribMyVXziljpQ/uQhfE1XLg2/TLTW2DsnoE4VAi/krg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
abort-controller: 3.0.0
|
||||
@ -1653,7 +1690,7 @@ packages:
|
||||
resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
readable-stream: 3.6.0
|
||||
readable-stream: 3.6.2
|
||||
|
||||
/readdirp/3.6.0:
|
||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||
@ -1728,8 +1765,8 @@ packages:
|
||||
ret: 0.2.2
|
||||
dev: false
|
||||
|
||||
/safe-stable-stringify/2.4.2:
|
||||
resolution: {integrity: sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==}
|
||||
/safe-stable-stringify/2.4.3:
|
||||
resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
@ -1754,15 +1791,15 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/semver/7.3.8:
|
||||
resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==}
|
||||
/semver/7.5.0:
|
||||
resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
|
||||
/set-cookie-parser/2.5.1:
|
||||
resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==}
|
||||
/set-cookie-parser/2.6.0:
|
||||
resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
|
||||
dev: false
|
||||
|
||||
/setprototypeof/1.2.0:
|
||||
@ -1778,7 +1815,7 @@ packages:
|
||||
detect-libc: 2.0.1
|
||||
node-addon-api: 5.1.0
|
||||
prebuild-install: 7.1.1
|
||||
semver: 7.3.8
|
||||
semver: 7.5.0
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
@ -1835,8 +1872,8 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/sonic-boom/3.2.1:
|
||||
resolution: {integrity: sha512-iITeTHxy3B9FGu8aVdiDXUVAcHMF9Ss0cCsAOo2HfCrmVGT3/DT5oYaeu0M/YKZDlKTvChEyPq0zI9Hf33EX6A==}
|
||||
/sonic-boom/3.3.0:
|
||||
resolution: {integrity: sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==}
|
||||
dependencies:
|
||||
atomic-sleep: 1.0.0
|
||||
dev: false
|
||||
@ -1863,11 +1900,11 @@ packages:
|
||||
/split2/3.2.2:
|
||||
resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==}
|
||||
dependencies:
|
||||
readable-stream: 3.6.0
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/split2/4.1.0:
|
||||
resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==}
|
||||
/split2/4.2.0:
|
||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||
engines: {node: '>= 10.x'}
|
||||
dev: false
|
||||
|
||||
@ -1945,7 +1982,7 @@ packages:
|
||||
end-of-stream: 1.4.4
|
||||
fs-constants: 1.0.0
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/thread-stream/2.3.0:
|
||||
@ -1954,9 +1991,9 @@ packages:
|
||||
real-require: 0.2.0
|
||||
dev: false
|
||||
|
||||
/tiny-lru/10.0.1:
|
||||
resolution: {integrity: sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==}
|
||||
engines: {node: '>=6'}
|
||||
/tiny-lru/11.0.1:
|
||||
resolution: {integrity: sha512-iNgFugVuQgBKrqeO/mpiTTgmBsTP0WL6yeuLfLs/Ctf0pI/ixGqIRm8sDCwMcXGe9WWvt2sGXI5mNqZbValmJg==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/tmp/0.2.1:
|
||||
@ -1970,6 +2007,10 @@ packages:
|
||||
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
|
||||
dev: false
|
||||
|
||||
/to-data-view/1.1.0:
|
||||
resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==}
|
||||
dev: false
|
||||
|
||||
/to-regex-range/5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
@ -2056,3 +2097,13 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
github.com/misskey-dev/sharp-read-bmp/02d9dc189fa7df0c4bea09330be26741772dac01:
|
||||
resolution: {tarball: https://codeload.github.com/misskey-dev/sharp-read-bmp/tar.gz/02d9dc189fa7df0c4bea09330be26741772dac01}
|
||||
name: sharp-read-bmp
|
||||
version: 1.0.0
|
||||
dependencies:
|
||||
decode-bmp: 0.2.1
|
||||
decode-ico: 0.4.1
|
||||
sharp: 0.31.3
|
||||
dev: false
|
||||
|
@ -36,6 +36,11 @@ export const FILE_TYPE_BROWSERSAFE = [
|
||||
'audio/webm',
|
||||
|
||||
'audio/aac',
|
||||
|
||||
// see https://github.com/misskey-dev/misskey/pull/10686
|
||||
'audio/flac',
|
||||
'audio/wav',
|
||||
// backward compatibility
|
||||
'audio/x-flac',
|
||||
'audio/vnd.wave',
|
||||
];
|
||||
|
@ -8,6 +8,7 @@ import IPCIDR from 'ip-cidr';
|
||||
import PrivateIp from 'private-ip';
|
||||
import { StatusError } from './status-error.js';
|
||||
import { getAgents } from './http.js';
|
||||
import { parse } from 'content-disposition';
|
||||
|
||||
const pipeline = util.promisify(stream.pipeline);
|
||||
|
||||
@ -29,12 +30,17 @@ export const defaultDownloadConfig = {
|
||||
...getAgents()
|
||||
}
|
||||
|
||||
export async function downloadUrl(url: string, path: string, settings:DownloadConfig = defaultDownloadConfig): Promise<void> {
|
||||
export async function downloadUrl(url: string, path: string, settings:DownloadConfig = defaultDownloadConfig): Promise<{
|
||||
filename: string;
|
||||
}> {
|
||||
if (process.env.NODE_ENV !== 'production') console.log(`Downloading ${url} to ${path} ...`);
|
||||
|
||||
const timeout = 30 * 1000;
|
||||
const operationTimeout = 60 * 1000;
|
||||
|
||||
const urlObj = new URL(url);
|
||||
let filename = urlObj.pathname.split('/').pop() ?? 'unknown';
|
||||
|
||||
const req = got.stream(url, {
|
||||
headers: {
|
||||
'User-Agent': settings.userAgent,
|
||||
@ -73,6 +79,18 @@ export async function downloadUrl(url: string, path: string, settings:DownloadCo
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
const contentDisposition = res.headers['content-disposition'];
|
||||
if (contentDisposition != null) {
|
||||
try {
|
||||
const parsed = parse(contentDisposition);
|
||||
if (parsed.parameters.filename) {
|
||||
filename = parsed.parameters.filename;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`Failed to parse content-disposition: ${contentDisposition}\n${e}`);
|
||||
}
|
||||
}
|
||||
}).on('downloadProgress', (progress: Got.Progress) => {
|
||||
if (progress.transferred > settings.maxSize) {
|
||||
console.log(`maxSize exceeded (${progress.transferred} > ${settings.maxSize}) on downloadProgress`);
|
||||
@ -91,6 +109,10 @@ export async function downloadUrl(url: string, path: string, settings:DownloadCo
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') console.log(`Download finished: ${url}`);
|
||||
|
||||
return {
|
||||
filename,
|
||||
}
|
||||
}
|
||||
|
||||
function isPrivateIp(ip: string, allowedPrivateNetworks: string[]): boolean {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import fs from 'node:fs';
|
||||
import { fileTypeFromFile } from 'file-type';
|
||||
import type fileType from 'file-type';
|
||||
import isSvg from 'is-svg';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
@ -39,7 +40,7 @@ export async function detectType(path: string): Promise<{
|
||||
}
|
||||
|
||||
return {
|
||||
mime: type.mime,
|
||||
mime: fixMime(type.mime),
|
||||
ext: type.ext,
|
||||
};
|
||||
}
|
||||
@ -66,8 +67,20 @@ import { FILE_TYPE_BROWSERSAFE } from './const.js';
|
||||
|
||||
const dictionary = {
|
||||
'safe-file': FILE_TYPE_BROWSERSAFE,
|
||||
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml'],
|
||||
'sharp-animation-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/svg+xml'],
|
||||
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml', 'image/x-icon', 'image/bmp'],
|
||||
'sharp-animation-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/svg+xml', 'image/x-icon', 'image/bmp'],
|
||||
};
|
||||
|
||||
export const isMimeImage = (mime: string, type: keyof typeof dictionary): boolean => dictionary[type].includes(mime);
|
||||
|
||||
function fixMime(mime: string | fileType.MimeType): string {
|
||||
// see https://github.com/misskey-dev/misskey/pull/10686
|
||||
if (mime === "audio/x-flac") {
|
||||
return "audio/flac";
|
||||
}
|
||||
if (mime === "audio/vnd.wave") {
|
||||
return "audio/wav";
|
||||
}
|
||||
|
||||
return mime;
|
||||
}
|
||||
|
@ -16,12 +16,13 @@ export type IImageStream = {
|
||||
export type IImageStreamable = IImage | IImageStream;
|
||||
|
||||
export const webpDefault: sharp.WebpOptions = {
|
||||
quality: 85,
|
||||
quality: 77,
|
||||
alphaQuality: 95,
|
||||
lossless: false,
|
||||
nearLossless: false,
|
||||
smartSubsample: true,
|
||||
mixed: true,
|
||||
effort: 2,
|
||||
};
|
||||
|
||||
export function convertToWebpStream(path: string, width: number, height: number, options: sharp.WebpOptions = webpDefault): IImageStream {
|
||||
|
69
src/index.ts
69
src/index.ts
@ -6,18 +6,20 @@ import { dirname } from 'node:path';
|
||||
import fastifyStatic from '@fastify/static';
|
||||
import { createTemp } from './create-temp.js';
|
||||
import { FILE_TYPE_BROWSERSAFE } from './const.js';
|
||||
import { IImageStreamable, convertToWebpStream, webpDefault } from './image-processor.js';
|
||||
import { IImageStreamable, convertToWebpStream, webpDefault, convertSharpToWebpStream } from './image-processor.js';
|
||||
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
|
||||
import { detectType, isMimeImage } from './file-info.js';
|
||||
import sharp from 'sharp';
|
||||
import { sharpBmp } from 'sharp-read-bmp';
|
||||
import { StatusError } from './status-error.js';
|
||||
import { DownloadConfig, defaultDownloadConfig, downloadUrl } from './download.js';
|
||||
import { getAgents } from './http.js';
|
||||
import _contentDisposition from 'content-disposition';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
|
||||
const assets = `${_dirname}/../../server/file/assets/`;
|
||||
const assets = `${_dirname}/../assets/`;
|
||||
|
||||
export type MediaProxyOptions = {
|
||||
['Access-Control-Allow-Origin']?: string;
|
||||
@ -68,11 +70,15 @@ export function setMediaProxyConfig(setting?: MediaProxyOptions | null) {
|
||||
export default function (fastify: FastifyInstance, options: MediaProxyOptions | null | undefined, done: (err?: Error) => void) {
|
||||
setMediaProxyConfig(options);
|
||||
|
||||
const corsOrigin = options!['Access-Control-Allow-Origin'] ?? '*';
|
||||
const corsHeader = options!['Access-Control-Allow-Headers'] ?? '*';
|
||||
const csp = options!['Content-Security-Policy'] ?? `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`;
|
||||
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Access-Control-Allow-Origin', options!['Access-Control-Allow-Origin'] ?? '*');
|
||||
reply.header('Access-Control-Allow-Headers', options!['Access-Control-Allow-Headers'] ?? '*');
|
||||
reply.header('Access-Control-Allow-Origin', corsOrigin);
|
||||
reply.header('Access-Control-Allow-Headers', corsHeader);
|
||||
reply.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
reply.header('Content-Security-Policy', options!['Content-Security-Policy'] ?? `default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'`);
|
||||
reply.header('Content-Security-Policy', csp);
|
||||
done();
|
||||
});
|
||||
|
||||
@ -148,12 +154,12 @@ async function proxyHandler(request: FastifyRequest<{ Params: { url: string; };
|
||||
type: file.mime,
|
||||
};
|
||||
} else {
|
||||
const data = sharp(file.path, { animated: !('static' in request.query) })
|
||||
.resize({
|
||||
height: 'emoji' in request.query ? 128 : 320,
|
||||
withoutEnlargement: true,
|
||||
})
|
||||
.webp(webpDefault);
|
||||
const data = (await sharpBmp(file.path, file.mime, { animated: !('static' in request.query) }))
|
||||
.resize({
|
||||
height: 'emoji' in request.query ? 128 : 320,
|
||||
withoutEnlargement: true,
|
||||
})
|
||||
.webp(webpDefault);
|
||||
|
||||
image = {
|
||||
data,
|
||||
@ -162,13 +168,14 @@ async function proxyHandler(request: FastifyRequest<{ Params: { url: string; };
|
||||
};
|
||||
}
|
||||
} else if ('static' in request.query) {
|
||||
image = convertToWebpStream(file.path, 498, 280);
|
||||
image = convertSharpToWebpStream(await sharpBmp(file.path, file.mime), 498, 422);
|
||||
} else if ('preview' in request.query) {
|
||||
image = convertToWebpStream(file.path, 200, 200);
|
||||
image = convertSharpToWebpStream(await sharpBmp(file.path, file.mime), 200, 200);
|
||||
} else if ('badge' in request.query) {
|
||||
const mask = sharp(file.path)
|
||||
const mask = (await sharpBmp(file.path, file.mime))
|
||||
.resize(96, 96, {
|
||||
fit: 'inside',
|
||||
fit: 'contain',
|
||||
position: 'centre',
|
||||
withoutEnlargement: false,
|
||||
})
|
||||
.greyscale()
|
||||
@ -197,6 +204,8 @@ async function proxyHandler(request: FastifyRequest<{ Params: { url: string; };
|
||||
};
|
||||
} else if (file.mime === 'image/svg+xml') {
|
||||
image = convertToWebpStream(file.path, 2048, 2048);
|
||||
} else if (!file.mime.startsWith('image/') || !FILE_TYPE_BROWSERSAFE.includes(file.mime)) {
|
||||
throw new StatusError('Rejected type', 403, 'Rejected type');
|
||||
}
|
||||
|
||||
if (!image) {
|
||||
@ -224,6 +233,12 @@ async function proxyHandler(request: FastifyRequest<{ Params: { url: string; };
|
||||
|
||||
reply.header('Content-Type', image.type);
|
||||
reply.header('Cache-Control', 'max-age=31536000, immutable');
|
||||
reply.header('Content-Disposition',
|
||||
contentDisposition(
|
||||
'inline',
|
||||
correctFilename(file.filename, image.ext)
|
||||
)
|
||||
);
|
||||
return reply.send(image.data);
|
||||
} catch (e) {
|
||||
if ('cleanup' in file) file.cleanup();
|
||||
@ -232,11 +247,11 @@ async function proxyHandler(request: FastifyRequest<{ Params: { url: string; };
|
||||
}
|
||||
|
||||
async function downloadAndDetectTypeFromUrl(url: string): Promise<
|
||||
{ state: 'remote'; mime: string; ext: string | null; path: string; cleanup: () => void; }
|
||||
{ state: 'remote'; mime: string; ext: string | null; path: string; cleanup: () => void; filename: string; }
|
||||
> {
|
||||
const [path, cleanup] = await createTemp();
|
||||
try {
|
||||
await downloadUrl(url, path, config);
|
||||
const { filename } = await downloadUrl(url, path, config);
|
||||
|
||||
const { mime, ext } = await detectType(path);
|
||||
|
||||
@ -244,9 +259,29 @@ async function downloadAndDetectTypeFromUrl(url: string): Promise<
|
||||
state: 'remote',
|
||||
mime, ext,
|
||||
path, cleanup,
|
||||
filename: correctFilename(filename, ext),
|
||||
}
|
||||
} catch (e) {
|
||||
cleanup();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function correctFilename(filename: string, ext: string | null) {
|
||||
const dotExt = ext ? `.${ext}` : '.unknown';
|
||||
if (filename.endsWith(dotExt)) {
|
||||
return filename;
|
||||
}
|
||||
if (ext === 'jpg' && filename.endsWith('.jpeg')) {
|
||||
return filename;
|
||||
}
|
||||
if (ext === 'tif' && filename.endsWith('.tiff')) {
|
||||
return filename;
|
||||
}
|
||||
return `${filename}${dotExt}`;
|
||||
}
|
||||
|
||||
function contentDisposition(type: 'inline' | 'attachment', filename: string): string {
|
||||
const fallback = filename.replace(/[^\w.-]/g, '_');
|
||||
return _contentDisposition(filename, { type, fallback });
|
||||
}
|
||||
|
Reference in New Issue
Block a user