mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-23 01:03:08 +02:00
feat(frontend/MkUrlPreview): oEmbedのサポート (#10306)
* feat(frontend/MkUrlPreview): oEmbedのサポート * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * playerとoEmbedの統合 * Update CHANGELOG.md * loading=lazyはここでは不要 * border: 0 * プレビュー直後にautoplayできる機能の復旧 * add test * refactor test * explain about cache * expandPreviewはもう使わない * summaly v4 * update summaly * scrolling=no to fix pixiv --------- Co-authored-by: tamaina <tamaina@hotmail.co.jp>
This commit is contained in:
parent
4d73080da1
commit
c091d9e6d5
7 changed files with 207 additions and 60 deletions
|
@ -30,6 +30,10 @@ You should also include the user name that made the change.
|
|||
- アクティブユーザー数チャートの記録上限値を拡張
|
||||
- Playのソースコード上限文字数を2倍に拡張
|
||||
- 付箋ウィジェットの高さを設定可能に
|
||||
- oEmbedをサポートしているウェブサイトのプレビューができるように
|
||||
- YouTubeをoEmbedでロードし、プレビューで共有ボタンを押すとOSの共有画面がでるように
|
||||
- ([FirefoxでSpotifyのプレビューを開けるとフルサイズじゃなくプレビューサイズだけ再生できる問題](https://bugzilla.mozilla.org/show_bug.cgi?id=1792395)があります)
|
||||
- (すでにブラウザーでキャッシュされたリンクに対しては以前のプレビュー行動が行われてます。その場合、ブラウザーのキャッシュをクリアしてまた試してください。)
|
||||
- 配送先サーバーが410 Goneで応答してきた場合は自動で配送停止をするように
|
||||
- avatarBlurHash/bannerBlurHashの型をstringに限定
|
||||
- APオブジェクトを入力してフェッチする機能とユーザーやノートの検索機能を分離
|
||||
|
|
|
@ -19,9 +19,6 @@ export class UrlPreviewService {
|
|||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
private metaService: MetaService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private loggerService: LoggerService,
|
||||
|
@ -51,15 +48,15 @@ export class UrlPreviewService {
|
|||
reply.code(400);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const lang = request.query.lang;
|
||||
if (Array.isArray(lang)) {
|
||||
reply.code(400);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const meta = await this.metaService.fetch();
|
||||
|
||||
|
||||
this.logger.info(meta.summalyProxy
|
||||
? `(Proxy) Getting preview of ${url}@${lang} ...`
|
||||
: `Getting preview of ${url}@${lang} ...`);
|
||||
|
@ -85,16 +82,16 @@ export class UrlPreviewService {
|
|||
throw new Error('unsupported schema included');
|
||||
}
|
||||
|
||||
if (summary.player?.url && !(summary.player.url.startsWith('http://') || summary.player.url.startsWith('https://'))) {
|
||||
if (summary.player.url && !(summary.player.url.startsWith('http://') || summary.player.url.startsWith('https://'))) {
|
||||
throw new Error('unsupported schema included');
|
||||
}
|
||||
|
||||
|
||||
summary.icon = this.wrap(summary.icon);
|
||||
summary.thumbnail = this.wrap(summary.thumbnail);
|
||||
|
||||
|
||||
// Cache 7days
|
||||
reply.header('Cache-Control', 'max-age=604800, immutable');
|
||||
|
||||
|
||||
return summary;
|
||||
} catch (err) {
|
||||
this.logger.warn(`Failed to get preview of ${url}: ${err}`);
|
||||
|
|
|
@ -97,7 +97,9 @@
|
|||
"eslint-plugin-vue": "9.9.0",
|
||||
"happy-dom": "8.9.0",
|
||||
"start-server-and-test": "2.0.0",
|
||||
"summaly": "github:misskey-dev/summaly",
|
||||
"vitest": "^0.29.2",
|
||||
"vitest-fetch-mock": "^0.2.2",
|
||||
"vue-eslint-parser": "9.1.0",
|
||||
"vue-tsc": "1.2.0"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
<template>
|
||||
<template v-if="playerEnabled">
|
||||
<div :class="$style.player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`">
|
||||
<iframe v-if="player.url.startsWith('http://') || player.url.startsWith('https://')" :class="$style.playerIframe" :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen/>
|
||||
<template v-if="player.url && playerEnabled">
|
||||
<div
|
||||
:class="$style.player"
|
||||
:style="player.width ? `padding: ${(player.height || 0) / player.width * 100}% 0 0` : `padding: ${(player.height || 0)}px 0 0`"
|
||||
>
|
||||
<iframe
|
||||
v-if="player.url.startsWith('http://') || player.url.startsWith('https://')"
|
||||
sandbox="allow-popups allow-scripts allow-storage-access-by-user-activation allow-same-origin"
|
||||
scrolling="no"
|
||||
:allow="player.allow.join(';')"
|
||||
:class="$style.playerIframe"
|
||||
:src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')"
|
||||
:style="{ border: 0 }"
|
||||
></iframe>
|
||||
<span v-else>invalid url</span>
|
||||
</div>
|
||||
<div :class="$style.action">
|
||||
|
@ -28,7 +39,7 @@
|
|||
<header :class="$style.header">
|
||||
<h1 v-if="unknownUrl" :class="$style.title">{{ url }}</h1>
|
||||
<h1 v-else-if="fetching" :class="$style.title"><MkEllipsis/></h1>
|
||||
<h1 v-else :class="$style.title" :title="title">{{ title }}</h1>
|
||||
<h1 v-else :class="$style.title" :title="title ?? undefined">{{ title }}</h1>
|
||||
</header>
|
||||
<p v-if="unknownUrl" :class="$style.text">{{ i18n.ts.cannotLoad }}</p>
|
||||
<p v-else-if="fetching" :class="$style.text"><MkEllipsis/></p>
|
||||
|
@ -37,7 +48,7 @@
|
|||
<img v-if="icon" :class="$style.siteIcon" :src="icon"/>
|
||||
<p v-if="unknownUrl" :class="$style.siteName">?</p>
|
||||
<p v-else-if="fetching" :class="$style.siteName"><MkEllipsis/></p>
|
||||
<p v-else :class="$style.siteName" :title="sitename">{{ sitename }}</p>
|
||||
<p v-else :class="$style.siteName" :title="sitename ?? undefined">{{ sitename }}</p>
|
||||
</footer>
|
||||
</article>
|
||||
</component>
|
||||
|
@ -59,6 +70,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, onUnmounted } from 'vue';
|
||||
import type { summaly } from 'summaly';
|
||||
import { url as local } from '@/config';
|
||||
import { i18n } from '@/i18n';
|
||||
import * as os from '@/os';
|
||||
|
@ -66,6 +78,8 @@ import { deviceKind } from '@/scripts/device-kind';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import { versatileLang } from '@/scripts/intl-const';
|
||||
|
||||
type SummalyResult = Awaited<ReturnType<typeof summaly>>;
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
url: string;
|
||||
detail?: boolean;
|
||||
|
@ -91,7 +105,7 @@ let player = $ref({
|
|||
url: null,
|
||||
width: null,
|
||||
height: null,
|
||||
});
|
||||
} as SummalyResult['player']);
|
||||
let playerEnabled = $ref(false);
|
||||
let tweetId = $ref<string | null>(null);
|
||||
let tweetExpanded = $ref(props.detail);
|
||||
|
@ -114,11 +128,7 @@ if (requestUrl.hostname === 'music.youtube.com' && requestUrl.pathname.match('^/
|
|||
requestUrl.hash = '';
|
||||
|
||||
window.fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${versatileLang}`).then(res => {
|
||||
res.json().then(info => {
|
||||
if (info.url == null) {
|
||||
unknownUrl = true;
|
||||
return;
|
||||
}
|
||||
res.json().then((info: SummalyResult) => {
|
||||
title = info.title;
|
||||
description = info.description;
|
||||
thumbnail = info.thumbnail;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { vi } from 'vitest';
|
||||
import createFetchMock from 'vitest-fetch-mock';
|
||||
|
||||
const fetchMocker = createFetchMock(vi);
|
||||
fetchMocker.enableMocks();
|
||||
|
||||
// Set i18n
|
||||
import locales from '../../../locales';
|
||||
|
|
140
packages/frontend/test/url-preview.test.ts
Normal file
140
packages/frontend/test/url-preview.test.ts
Normal file
|
@ -0,0 +1,140 @@
|
|||
import { describe, test, assert, afterEach } from 'vitest';
|
||||
import { render, cleanup, type RenderResult } from '@testing-library/vue';
|
||||
import './init';
|
||||
import type { summaly } from 'summaly';
|
||||
import { directives } from '@/directives';
|
||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||
|
||||
type SummalyResult = Awaited<ReturnType<typeof summaly>>;
|
||||
|
||||
describe('MkMediaImage', () => {
|
||||
const renderPreviewBy = async (summary: Partial<SummalyResult>): Promise<RenderResult> => {
|
||||
if (!summary.player) {
|
||||
summary.player = {
|
||||
url: null,
|
||||
width: null,
|
||||
height: null,
|
||||
allow: [],
|
||||
};
|
||||
}
|
||||
|
||||
fetchMock.mockOnceIf(/^\/url?/, () => {
|
||||
return {
|
||||
status: 200,
|
||||
body: JSON.stringify(summary),
|
||||
};
|
||||
});
|
||||
|
||||
const result = render(MkUrlPreview, {
|
||||
props: { url: summary.url },
|
||||
global: { directives },
|
||||
});
|
||||
|
||||
await new Promise<void>(resolve => {
|
||||
const observer = new MutationObserver(() => {
|
||||
resolve();
|
||||
observer.disconnect();
|
||||
});
|
||||
observer.observe(result.container, { childList: true, subtree: true });
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const renderAndOpenPreview = async (summary: Partial<SummalyResult>): Promise<HTMLIFrameElement | null> => {
|
||||
const mkUrlPreview = await renderPreviewBy(summary);
|
||||
const buttons = mkUrlPreview.getAllByRole('button');
|
||||
buttons[0].click();
|
||||
// Wait for the click event to be fired
|
||||
await Promise.resolve();
|
||||
|
||||
return mkUrlPreview.container.querySelector('iframe');
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.resetMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
test('Should render the description', async () => {
|
||||
const mkUrlPreview = await renderPreviewBy({
|
||||
url: 'https://example.local',
|
||||
description: 'Mocked description',
|
||||
});
|
||||
mkUrlPreview.getByText('Mocked description');
|
||||
});
|
||||
|
||||
test('Having a player should render a button', async () => {
|
||||
const mkUrlPreview = await renderPreviewBy({
|
||||
url: 'https://example.local',
|
||||
player: {
|
||||
url: 'https://example.local/player',
|
||||
width: null,
|
||||
height: null,
|
||||
allow: [],
|
||||
},
|
||||
});
|
||||
const buttons = mkUrlPreview.getAllByRole('button');
|
||||
assert.strictEqual(buttons.length, 2, 'two buttons');
|
||||
});
|
||||
|
||||
test('Having a player should setup the iframe', async () => {
|
||||
const iframe = await renderAndOpenPreview({
|
||||
url: 'https://example.local',
|
||||
player: {
|
||||
url: 'https://example.local/player',
|
||||
width: null,
|
||||
height: null,
|
||||
allow: [],
|
||||
},
|
||||
});
|
||||
assert.exists(iframe, 'iframe should exist');
|
||||
assert.strictEqual(iframe?.src, 'https://example.local/player?autoplay=1&auto_play=1');
|
||||
assert.strictEqual(
|
||||
iframe?.sandbox.toString(),
|
||||
'allow-popups allow-scripts allow-storage-access-by-user-activation allow-same-origin',
|
||||
);
|
||||
});
|
||||
|
||||
test('Having a player with `allow` field should set permissions', async () => {
|
||||
const iframe = await renderAndOpenPreview({
|
||||
url: 'https://example.local',
|
||||
player: {
|
||||
url: 'https://example.local/player',
|
||||
width: null,
|
||||
height: null,
|
||||
allow: ['fullscreen', 'web-share'],
|
||||
},
|
||||
});
|
||||
assert.exists(iframe, 'iframe should exist');
|
||||
assert.strictEqual(iframe?.allow, 'fullscreen;web-share');
|
||||
});
|
||||
|
||||
test('Having a player width should keep the fixed aspect ratio', async () => {
|
||||
const iframe = await renderAndOpenPreview({
|
||||
url: 'https://example.local',
|
||||
player: {
|
||||
url: 'https://example.local/player',
|
||||
width: 400,
|
||||
height: 200,
|
||||
allow: [],
|
||||
},
|
||||
});
|
||||
assert.exists(iframe, 'iframe should exist');
|
||||
assert.strictEqual(iframe?.parentElement?.style.paddingTop, '50%');
|
||||
});
|
||||
|
||||
test('Having a player width should keep the fixed height', async () => {
|
||||
const iframe = await renderAndOpenPreview({
|
||||
url: 'https://example.local',
|
||||
player: {
|
||||
url: 'https://example.local/player',
|
||||
width: null,
|
||||
height: 200,
|
||||
allow: [],
|
||||
},
|
||||
});
|
||||
assert.exists(iframe, 'iframe should exist');
|
||||
assert.strictEqual(iframe?.parentElement?.style.paddingTop, '200px');
|
||||
});
|
||||
});
|
|
@ -462,6 +462,7 @@ importers:
|
|||
seedrandom: 3.0.5
|
||||
start-server-and-test: 2.0.0
|
||||
strict-event-emitter-types: 2.0.0
|
||||
summaly: github:misskey-dev/summaly
|
||||
syuilo-password-strength: 0.0.1
|
||||
textarea-caret: 3.1.0
|
||||
three: 0.150.1
|
||||
|
@ -475,6 +476,7 @@ importers:
|
|||
vanilla-tilt: 1.8.0
|
||||
vite: 4.1.4
|
||||
vitest: ^0.29.2
|
||||
vitest-fetch-mock: ^0.2.2
|
||||
vue: 3.2.47
|
||||
vue-eslint-parser: 9.1.0
|
||||
vue-plyr: 7.0.0
|
||||
|
@ -567,7 +569,9 @@ importers:
|
|||
eslint-plugin-vue: 9.9.0_eslint@8.35.0
|
||||
happy-dom: 8.9.0
|
||||
start-server-and-test: 2.0.0
|
||||
summaly: github.com/misskey-dev/summaly/1bab7afee616429b8bbf7a7cbcbb8ebcef66d992
|
||||
vitest: 0.29.2_zcjcryjt4bqcdu7ggonulipgea
|
||||
vitest-fetch-mock: 0.2.2_vitest@0.29.2
|
||||
vue-eslint-parser: 9.1.0_eslint@8.35.0
|
||||
vue-tsc: 1.2.0_typescript@4.9.5
|
||||
|
||||
|
@ -2134,7 +2138,6 @@ packages:
|
|||
/@sindresorhus/is/5.3.0:
|
||||
resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==}
|
||||
engines: {node: '>=14.16'}
|
||||
dev: false
|
||||
|
||||
/@sinonjs/commons/2.0.0:
|
||||
resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
|
||||
|
@ -2316,7 +2319,6 @@ packages:
|
|||
engines: {node: '>=14.16'}
|
||||
dependencies:
|
||||
defer-to-connect: 2.0.1
|
||||
dev: false
|
||||
|
||||
/@tabler/icons-webfont/2.10.0:
|
||||
resolution: {integrity: sha512-5WvGhztlM3la7NWf8Y6ktT+KD7zb/Hz/zdMeFjExXvEFupGvuANEnbGo1wXI4ADdSWUaRDtnQHcSGIjZ+gZ+OQ==}
|
||||
|
@ -2638,7 +2640,6 @@ packages:
|
|||
|
||||
/@types/http-cache-semantics/4.0.1:
|
||||
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
|
||||
dev: false
|
||||
|
||||
/@types/ioredis/4.28.10:
|
||||
resolution: {integrity: sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==}
|
||||
|
@ -3901,7 +3902,7 @@ packages:
|
|||
/axios/0.24.0:
|
||||
resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2
|
||||
follow-redirects: 1.15.2_debug@4.3.4
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
@ -3909,7 +3910,7 @@ packages:
|
|||
/axios/0.27.2_debug@4.3.4:
|
||||
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2
|
||||
follow-redirects: 1.15.2_debug@4.3.4
|
||||
form-data: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
@ -4348,7 +4349,6 @@ packages:
|
|||
/cacheable-lookup/7.0.0:
|
||||
resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
|
||||
engines: {node: '>=14.16'}
|
||||
dev: false
|
||||
|
||||
/cacheable-request/10.2.8:
|
||||
resolution: {integrity: sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==}
|
||||
|
@ -4361,7 +4361,6 @@ packages:
|
|||
mimic-response: 4.0.0
|
||||
normalize-url: 8.0.0
|
||||
responselike: 3.0.0
|
||||
dev: false
|
||||
|
||||
/cacheable-request/7.0.2:
|
||||
resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==}
|
||||
|
@ -4568,7 +4567,6 @@ packages:
|
|||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
dev: false
|
||||
|
||||
/cheerio/1.0.0-rc.12:
|
||||
resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
|
||||
|
@ -4581,7 +4579,6 @@ packages:
|
|||
htmlparser2: 8.0.1
|
||||
parse5: 7.1.2
|
||||
parse5-htmlparser2-tree-adapter: 7.0.0
|
||||
dev: false
|
||||
|
||||
/chokidar/3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
|
@ -5016,6 +5013,14 @@ packages:
|
|||
cross-spawn: 7.0.3
|
||||
dev: true
|
||||
|
||||
/cross-fetch/3.1.5:
|
||||
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
|
||||
dependencies:
|
||||
node-fetch: 2.6.7
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: true
|
||||
|
||||
/cross-spawn/5.1.0:
|
||||
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
|
||||
dependencies:
|
||||
|
@ -5044,12 +5049,10 @@ packages:
|
|||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
nth-check: 2.1.1
|
||||
dev: false
|
||||
|
||||
/css-what/6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: false
|
||||
|
||||
/css.escape/1.5.1:
|
||||
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
|
||||
|
@ -5325,7 +5328,6 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
dev: false
|
||||
|
||||
/dedent/0.7.0:
|
||||
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
|
||||
|
@ -5398,7 +5400,6 @@ packages:
|
|||
/defer-to-connect/2.0.1:
|
||||
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/define-properties/1.1.4:
|
||||
resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==}
|
||||
|
@ -6028,7 +6029,6 @@ packages:
|
|||
|
||||
/escape-regexp/0.0.1:
|
||||
resolution: {integrity: sha512-jVgdsYRa7RKxTT6MKNC3gdT+BF0Gfhpel19+HMRZJC2L0PufB0XOBuXBoXj29NKHwuktnAXd1Z1lyiH/8vOTpw==}
|
||||
dev: false
|
||||
|
||||
/escape-string-regexp/1.0.5:
|
||||
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||
|
@ -6952,7 +6952,7 @@ packages:
|
|||
readable-stream: 2.3.7
|
||||
dev: false
|
||||
|
||||
/follow-redirects/1.15.2:
|
||||
/follow-redirects/1.15.2_debug@4.3.4:
|
||||
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
|
@ -6960,6 +6960,8 @@ packages:
|
|||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
|
||||
/for-each/0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
|
@ -6992,7 +6994,6 @@ packages:
|
|||
/form-data-encoder/2.1.4:
|
||||
resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
|
||||
engines: {node: '>= 14.17'}
|
||||
dev: false
|
||||
|
||||
/form-data/2.3.3:
|
||||
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
|
||||
|
@ -7434,7 +7435,6 @@ packages:
|
|||
lowercase-keys: 3.0.0
|
||||
p-cancelable: 3.0.0
|
||||
responselike: 3.0.0
|
||||
dev: false
|
||||
|
||||
/graceful-fs/4.2.10:
|
||||
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
|
||||
|
@ -7686,7 +7686,6 @@ packages:
|
|||
|
||||
/html-entities/2.3.2:
|
||||
resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==}
|
||||
dev: false
|
||||
|
||||
/html-escaper/2.0.2:
|
||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||
|
@ -7702,7 +7701,6 @@ packages:
|
|||
|
||||
/http-cache-semantics/4.1.1:
|
||||
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
|
||||
dev: false
|
||||
|
||||
/http-errors/2.0.0:
|
||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||
|
@ -7758,7 +7756,6 @@ packages:
|
|||
dependencies:
|
||||
quick-lru: 5.1.1
|
||||
resolve-alpn: 1.2.1
|
||||
dev: false
|
||||
|
||||
/http_ece/1.1.0:
|
||||
resolution: {integrity: sha512-bptAfCDdPJxOs5zYSe7Y3lpr772s1G346R4Td5LgRUeCwIGpCGDUTJxRrhTNcAXbx37spge0kWEIH7QAYWNTlA==}
|
||||
|
@ -7976,7 +7973,6 @@ packages:
|
|||
/ip-regex/4.3.0:
|
||||
resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/ip-regex/5.0.0:
|
||||
resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==}
|
||||
|
@ -7995,7 +7991,6 @@ packages:
|
|||
/ipaddr.js/2.0.1:
|
||||
resolution: {integrity: sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==}
|
||||
engines: {node: '>= 10'}
|
||||
dev: false
|
||||
|
||||
/is-absolute-url/2.1.0:
|
||||
resolution: {integrity: sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==}
|
||||
|
@ -8206,7 +8201,6 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
ip-regex: 4.3.0
|
||||
dev: false
|
||||
|
||||
/is-lambda/1.0.1:
|
||||
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
|
||||
|
@ -9021,7 +9015,6 @@ packages:
|
|||
/jschardet/3.0.0:
|
||||
resolution: {integrity: sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
dev: false
|
||||
|
||||
/jsdom/21.1.0:
|
||||
resolution: {integrity: sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==}
|
||||
|
@ -9072,7 +9065,6 @@ packages:
|
|||
|
||||
/json-buffer/3.0.1:
|
||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||
dev: false
|
||||
|
||||
/json-parse-even-better-errors/2.3.1:
|
||||
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||
|
@ -9200,7 +9192,6 @@ packages:
|
|||
resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==}
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
dev: false
|
||||
|
||||
/kind-of/3.2.2:
|
||||
resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
|
||||
|
@ -9467,7 +9458,6 @@ packages:
|
|||
/lowercase-keys/3.0.0:
|
||||
resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
/lru-cache/4.1.5:
|
||||
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
||||
|
@ -9663,12 +9653,10 @@ packages:
|
|||
/mimic-response/3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/mimic-response/4.0.0:
|
||||
resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dev: false
|
||||
|
||||
/minimalistic-assert/1.0.1:
|
||||
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
|
||||
|
@ -9967,7 +9955,6 @@ packages:
|
|||
/netmask/2.0.2:
|
||||
resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dev: false
|
||||
|
||||
/next-tick/1.1.0:
|
||||
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
|
||||
|
@ -10114,7 +10101,6 @@ packages:
|
|||
/normalize-url/8.0.0:
|
||||
resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
|
||||
engines: {node: '>=14.16'}
|
||||
dev: false
|
||||
|
||||
/now-and-later/2.0.1:
|
||||
resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==}
|
||||
|
@ -10394,7 +10380,6 @@ packages:
|
|||
/p-cancelable/3.0.0:
|
||||
resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
|
||||
engines: {node: '>=12.20'}
|
||||
dev: false
|
||||
|
||||
/p-finally/1.0.0:
|
||||
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
|
||||
|
@ -10531,7 +10516,6 @@ packages:
|
|||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
parse5: 7.1.2
|
||||
dev: false
|
||||
|
||||
/parse5/5.1.1:
|
||||
resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==}
|
||||
|
@ -11139,7 +11123,6 @@ packages:
|
|||
ipaddr.js: 2.0.1
|
||||
is-ip: 3.1.0
|
||||
netmask: 2.0.2
|
||||
dev: false
|
||||
|
||||
/private-ip/3.0.0:
|
||||
resolution: {integrity: sha512-HkMBs4nMtrP+cvcw0bDi2BAZIGgiKI4Zq8Oc+dMqNBpHS8iGL4+WO/pRtc8Bwnv9rjnV0QwMDwEBymFtqv7Kww==}
|
||||
|
@ -11440,7 +11423,6 @@ packages:
|
|||
/quick-lru/5.1.1:
|
||||
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/random-seed/0.3.0:
|
||||
resolution: {integrity: sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA==}
|
||||
|
@ -11784,7 +11766,6 @@ packages:
|
|||
|
||||
/resolve-alpn/1.2.1:
|
||||
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
|
||||
dev: false
|
||||
|
||||
/resolve-cwd/3.0.0:
|
||||
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
|
||||
|
@ -11845,7 +11826,6 @@ packages:
|
|||
engines: {node: '>=14.16'}
|
||||
dependencies:
|
||||
lowercase-keys: 3.0.0
|
||||
dev: false
|
||||
|
||||
/restore-cursor/3.1.0:
|
||||
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
|
||||
|
@ -12994,7 +12974,6 @@ packages:
|
|||
|
||||
/trace-redirect/1.0.6:
|
||||
resolution: {integrity: sha512-UUfa1DjjU5flcjMdaFIiIEGDTyu2y/IiMjOX4uGXa7meKBS4vD4f2Uy/tken9Qkd4Jsm4sRsfZcIIPqrRVF3Mg==}
|
||||
dev: false
|
||||
|
||||
/traverse/0.3.9:
|
||||
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
|
||||
|
@ -13588,6 +13567,18 @@ packages:
|
|||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
/vitest-fetch-mock/0.2.2_vitest@0.29.2:
|
||||
resolution: {integrity: sha512-XmH6QgTSjCWrqXoPREIdbj40T7i1xnGmAsTAgfckoO75W1IEHKR8hcPCQ7SO16RsdW1t85oUm6pcQRLeBgjVYQ==}
|
||||
engines: {node: '>=14.14.0'}
|
||||
peerDependencies:
|
||||
vitest: '>=0.16.0'
|
||||
dependencies:
|
||||
cross-fetch: 3.1.5
|
||||
vitest: 0.29.2_zcjcryjt4bqcdu7ggonulipgea
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: true
|
||||
|
||||
/vitest/0.29.2_zcjcryjt4bqcdu7ggonulipgea:
|
||||
resolution: {integrity: sha512-ydK9IGbAvoY8wkg29DQ4ivcVviCaUi3ivuPKfZEVddMTenFHUfB8EEDXQV8+RasEk1ACFLgMUqAaDuQ/Nk+mQA==}
|
||||
engines: {node: '>=v14.16.0'}
|
||||
|
@ -14159,7 +14150,6 @@ packages:
|
|||
jschardet: 3.0.0
|
||||
private-ip: 2.3.3
|
||||
trace-redirect: 1.0.6
|
||||
dev: false
|
||||
|
||||
github.com/sampotts/plyr/d434c9af16e641400aaee93188594208d88f2658:
|
||||
resolution: {tarball: https://codeload.github.com/sampotts/plyr/tar.gz/d434c9af16e641400aaee93188594208d88f2658}
|
||||
|
|
Loading…
Reference in a new issue