diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index d2cf4bf6297b3a7337d30cdbad780178646b446b..63dc940e24c4bf3fae65c9d291f83a278a18ab50 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -31,3 +31,5 @@ jobs: push: true tags: misskey/misskey:develop labels: develop + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 48e2b19d6adb0983ed991c02283e6c5721cf9f8f..9135b4f60a4af170921041f8a45161d7aa5fd365 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -109,8 +109,12 @@ jobs: # https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091 - name: ALSA Env run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc + # XXX: This tries reinstalling Cypress if the binary is not cached + # Remove this when the cache issue is fixed + - name: Cypress install + run: pnpm exec cypress install - name: Cypress run - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 with: install: false start: pnpm start:test diff --git a/.node-version b/.node-version index e44a38e0803edbf4823dcabc9ee9623b03771e60..0e9dc6b586773815d114216e9e3a954c1c843eec 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -v18.12.1 +v18.13.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index b0dbb6e24087c587f812a34ef0304bd2797cbaad..e767c15df4a1cc4e97731edc388f6ed90cac55af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ You should also include the user name that made the change. --> +## 13.2.4 (2023/01/27) +### Improvements +- リモートカスタム絵文å—表示時ã®ãƒ‘フォーマンスを改善 +- Default to `animation: false` when prefers-reduced-motion is set +- リアクション履æ´ãŒå…¬é–‹ãªã‚‰ã€ãƒã‚°ã‚¤ãƒ³ã—ã¦ã„ãªãã¦ã‚‚表示ã§ãるよã†ã« +- tweak blur setting +- tweak custom emoji cache + +### Bugfixes +- fix aggregation of retention +- ダッシュボードã§ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ãŒè¡¨ç¤ºã•ã‚Œãªã„å•é¡Œã‚’ä¿®æ£ +- フォãƒãƒ¼ç”³è«‹ãƒ»ãƒ•ã‚©ãƒãƒ¼ã®ãƒœã‚¿ãƒ³ãŒã€é€šçŸ¥ã‹ã‚‰æ¶ˆãˆã¦ã„ã‚‹å•é¡Œã‚’ä¿®æ£ + ## 13.2.3 (2023/01/26) ### Improvements - カスタム絵文å—ã®æ›´æ–°ã‚’リアルタイムã§åæ˜ ã™ã‚‹ã‚ˆã†ã« diff --git a/Dockerfile b/Dockerfile index 47fe31bca7ae6e3e9c913cff08c2d8d49b277fb9..3876b5f6ce2e758f38b2be1acd084d2edffc82ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,8 +2,12 @@ ARG NODE_VERSION=18.13.0-bullseye FROM node:${NODE_VERSION} AS builder -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + rm -f /etc/apt/apt.conf.d/docker-clean \ + ; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \ + && apt-get update \ + && apt-get install -yqq --no-install-recommends \ build-essential RUN corepack enable @@ -16,7 +20,8 @@ COPY ["packages/backend/package.json", "./packages/backend/"] COPY ["packages/frontend/package.json", "./packages/frontend/"] COPY ["packages/sw/package.json", "./packages/sw/"] -RUN pnpm i --frozen-lockfile +RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ + pnpm i --frozen-lockfile --aggregate-output COPY . ./ @@ -30,11 +35,13 @@ FROM node:${NODE_VERSION}-slim AS runner ARG UID="991" ARG GID="991" -RUN apt-get update \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + rm -f /etc/apt/apt.conf.d/docker-clean \ + ; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \ + && apt-get update \ && apt-get install -y --no-install-recommends \ ffmpeg tini \ - && apt-get -y clean \ - && rm -rf /var/lib/apt/lists/* \ && corepack enable \ && groupadd -g "${GID}" misskey \ && useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index a85233996983aed6df3a843aa6191308b386d853..a6ba27e4fe282b73dc993205ff680582a08204f3 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -688,7 +688,7 @@ pageLikesCount: "КількіÑÑ‚ÑŒ отриманих вподобань Ñто pageLikedCount: "КількіÑÑ‚ÑŒ вподобаних Ñторінок" contact: "Контакт" useSystemFont: "ВикориÑтовувати Ñтандартний шрифт ÑиÑтеми" -clips: "Добірка" +clips: "Добірки" experimentalFeatures: "ЕкÑпериментальні функції" developer: "Розробник" makeExplorable: "Зробіть обліковий Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¸Ð´Ð¸Ð¼Ð¸Ð¼ у розділі \"ОглÑд\"" @@ -1003,9 +1003,19 @@ _achievements: title: "МайÑтер нотаток III" description: "1000 днів кориÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð³Ð°Ð»ÑŒÐ½Ð¾" flavor: "ДÑкуємо, що кориÑтуєтеÑÑ Misskey!" + _noteClipped1: + title: "Ðе можна не зберегти" + description: "Перша нотатка у добірці" + _noteFavorited1: + title: "ДивитиÑÑ Ð½Ð° зірки" _myNoteFavorited1: title: "У пошуках зірок" + _profileFilled: + title: "Повна готовніÑÑ‚ÑŒ" + description: "Профіль заповнено" _markedAsCat: + title: "Я кіт" + description: "Позначено Ñк акаунт кота" flavor: "Я дам тобі ім'Ñ Ð¿Ñ–Ð·Ð½Ñ–ÑˆÐµ" _following1: title: "Перша підпиÑка" @@ -1034,6 +1044,7 @@ _achievements: _followers300: description: "КількіÑÑ‚ÑŒ підпиÑників доÑÑгла 300" _followers500: + title: "Радіовежа" description: "КількіÑÑ‚ÑŒ підпиÑників доÑÑгла 500" _followers1000: title: "ІнфлюенÑер" @@ -1047,6 +1058,8 @@ _achievements: description: "Минуло 3 роки з моменту ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð°ÐºÐ°ÑƒÐ½Ñ‚Ð°" _loggedInOnBirthday: title: "З Днем народженнÑ!" + _loggedInOnNewYearsDay: + description: "Увійшли в перший день року" _brainDiver: title: "Brain Diver" flavor: "Misskey-Misskey La-Tu-Ma" @@ -1586,6 +1599,7 @@ _notification: youReceivedFollowRequest: "Ви отримали запит на підпиÑку" yourFollowRequestAccepted: "Запит на підпиÑку прийнÑто" youWereInvitedToGroup: "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ групи" + achievementEarned: "ДоÑÑÐ³Ð½ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¾" _types: all: "Ð’Ñе" follow: "ПідпиÑки" diff --git a/package.json b/package.json index c5a556aead6ca7da89caccb91f58eab87719eb76..06ec191b5cf9d91f883275adc9f89b3b4890cef3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.2.3", + "version": "13.2.4", "codename": "nasubi", "repository": { "type": "git", @@ -57,7 +57,7 @@ "@typescript-eslint/eslint-plugin": "5.49.0", "@typescript-eslint/parser": "5.49.0", "cross-env": "7.0.3", - "cypress": "12.3.0", + "cypress": "12.4.0", "eslint": "^8.32.0", "start-server-and-test": "1.15.3" }, diff --git a/packages/backend/package.json b/packages/backend/package.json index c3b45f6bf402a8e34c2ba2b0b7038f9a15a247cd..f68fde8b4c3b2b2426bc3877e57f8958285c9f1b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -32,8 +32,8 @@ "@fastify/cors": "8.2.0", "@fastify/http-proxy": "^8.4.0", "@fastify/multipart": "7.4.0", - "@fastify/static": "6.6.1", - "@fastify/view": "7.4.0", + "@fastify/static": "6.7.0", + "@fastify/view": "7.4.1", "@nestjs/common": "9.2.1", "@nestjs/core": "9.2.1", "@nestjs/testing": "9.2.1", @@ -110,7 +110,7 @@ "stringz": "2.1.0", "summaly": "2.7.0", "syslog-pro": "git+https://github.com/misskey-dev/SyslogPro#0.2.9-misskey.2", - "systeminformation": "5.17.3", + "systeminformation": "5.17.4", "tinycolor2": "1.5.2", "tmp": "0.2.1", "tsc-alias": "1.8.2", @@ -131,7 +131,7 @@ "devDependencies": { "@redocly/openapi-core": "1.0.0-beta.120", "@swc/cli": "^0.1.59", - "@swc/core": "1.3.27", + "@swc/core": "1.3.29", "@swc/jest": "0.2.24", "@types/accepts": "1.3.5", "@types/archiver": "5.3.1", @@ -143,11 +143,11 @@ "@types/escape-regexp": "0.0.1", "@types/fluent-ffmpeg": "2.1.20", "@types/ioredis": "4.28.10", - "@types/jest": "29.2.6", + "@types/jest": "29.4.0", "@types/js-yaml": "4.0.5", "@types/jsdom": "20.0.1", "@types/jsonld": "1.5.8", - "@types/jsrsasign": "10.5.4", + "@types/jsrsasign": "10.5.5", "@types/mime-types": "2.1.1", "@types/node": "18.11.18", "@types/node-fetch": "3.0.3", @@ -181,7 +181,7 @@ "eslint": "8.32.0", "eslint-plugin-import": "2.27.5", "execa": "6.1.0", - "jest": "29.3.1", - "jest-mock": "^29.3.1" + "jest": "29.4.1", + "jest-mock": "^29.4.1" } } diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 1f0b214159fc9109141b2a07b54037adf132bc5f..39814e1be68e5bd1cfbb12db9eab249ce98141ed 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -6,22 +6,35 @@ import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { Emoji } from '@/models/entities/Emoji.js'; -import type { EmojisRepository } from '@/models/index.js'; +import type { EmojisRepository, Note } from '@/models/index.js'; import { bindThis } from '@/decorators.js'; +import { Cache } from '@/misc/cache.js'; +import { UtilityService } from '@/core/UtilityService.js'; +import type { Config } from '@/config.js'; +import { ReactionService } from '@/core/ReactionService.js'; +import { query } from '@/misc/prelude/url.js'; @Injectable() export class CustomEmojiService { + private cache: Cache<Emoji | null>; + constructor( + @Inject(DI.config) + private config: Config, + @Inject(DI.db) private db: DataSource, @Inject(DI.emojisRepository) private emojisRepository: EmojisRepository, + private utilityService: UtilityService, private idService: IdService, private emojiEntityService: EmojiEntityService, private globalEventService: GlobalEventService, + private reactionService: ReactionService, ) { + this.cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12); } @bindThis @@ -44,12 +57,135 @@ export class CustomEmojiService { type: data.driveFile.webpublicType ?? data.driveFile.type, }).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); - await this.db.queryResultCache!.remove(['meta_emojis']); + if (data.host == null) { + await this.db.queryResultCache!.remove(['meta_emojis']); - this.globalEventService.publishBroadcastStream('emojiAdded', { - emoji: await this.emojiEntityService.pack(emoji.id), - }); + this.globalEventService.publishBroadcastStream('emojiAdded', { + emoji: await this.emojiEntityService.pack(emoji.id), + }); + } return emoji; } + + @bindThis + private normalizeHost(src: string | undefined, noteUserHost: string | null): string | null { + // クエリã«ä½¿ã†ãƒ›ã‚¹ãƒˆ + let host = src === '.' ? null // .ã¯ãƒãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆ (ã“ã“ãŒãƒžãƒƒãƒã™ã‚‹ã®ã¯ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã®ã¿) + : src === undefined ? noteUserHost // ノートãªã©ã§ãƒ›ã‚¹ãƒˆçœç•¥è¡¨è¨˜ã®å ´åˆã¯ãƒãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆ (ã“ã“ãŒãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ãƒžãƒƒãƒã™ã‚‹ã“ã¨ã¯ãªã„) + : this.utilityService.isSelfHost(src) ? null // 自ホスト指定 + : (src || noteUserHost); // 指定ã•ã‚ŒãŸãƒ›ã‚¹ãƒˆ || ノートãªã©ã®æ‰€æœ‰è€…ã®ãƒ›ã‚¹ãƒˆ (ã“ã£ã¡ãŒãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã«ãƒžãƒƒãƒã™ã‚‹ã“ã¨ã¯ãªã„) + + host = this.utilityService.toPunyNullable(host); + + return host; + } + + @bindThis + private parseEmojiStr(emojiName: string, noteUserHost: string | null) { + const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/); + if (!match) return { name: null, host: null }; + + const name = match[1]; + + // ホストæ£è¦åŒ– + const host = this.utilityService.toPunyNullable(this.normalizeHost(match[2], noteUserHost)); + + return { name, host }; + } + + /** + * 添付用(リモート)カスタム絵文å—URLを解決ã™ã‚‹ + * @param emojiName ノートやユーザープãƒãƒ•ã‚£ãƒ¼ãƒ«ã«æ·»ä»˜ã•ã‚ŒãŸã€ã¾ãŸã¯ãƒªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã®ã‚«ã‚¹ã‚¿ãƒ 絵文å—å (:ã¯å«ã‚ãªã„, リアクションã§ãƒãƒ¼ã‚«ãƒ«ãƒ›ã‚¹ãƒˆã®å ´åˆã¯@.を付ã‘ã‚‹ (ã“ã‚Œã¯decodeReactionã§å¯èƒ½)) + * @param noteUserHost ノートやユーザープãƒãƒ•ã‚£ãƒ¼ãƒ«ã®æ‰€æœ‰è€…ã®ãƒ›ã‚¹ãƒˆ + * @returns URL, nullã¯æœªãƒžãƒƒãƒã‚’æ„味ã™ã‚‹ + */ + @bindThis + public async populateEmoji(emojiName: string, noteUserHost: string | null): Promise<string | null> { + const { name, host } = this.parseEmojiStr(emojiName, noteUserHost); + if (name == null) return null; + if (host == null) return null; + + const queryOrNull = async () => (await this.emojisRepository.findOneBy({ + name, + host: host ?? IsNull(), + })) ?? null; + + const emoji = await this.cache.fetch(`${name} ${host}`, queryOrNull); + + if (emoji == null) return null; + + const isLocal = emoji.host == null; + const emojiUrl = emoji.publicUrl || emoji.originalUrl; // || emoji.originalUrl ã—ã¦ã‚‹ã®ã¯å¾Œæ–¹äº’æ›æ€§ã®ãŸã‚(publicUrlã¯stringãªã®ã§??ã¯ã ã‚) + const url = isLocal + ? emojiUrl + : this.config.proxyRemoteFiles + ? `${this.config.url}/proxy/${encodeURIComponent((new URL(emojiUrl)).pathname)}?${query({ url: emojiUrl })}` + : emojiUrl; + + return url; + } + + /** + * 複数ã®æ·»ä»˜ç”¨(リモート)カスタム絵文å—URLを解決ã™ã‚‹ (ã‚ャシュ付ã, å˜åœ¨ã—ãªã„ã‚‚ã®ã¯çµæžœã‹ã‚‰é™¤å¤–ã•ã‚Œã‚‹) + */ + @bindThis + public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<Record<string, string>> { + const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost))); + const res = {} as any; + for (let i = 0; i < emojiNames.length; i++) { + if (emojis[i] != null) { + res[emojiNames[i]] = emojis[i]; + } + } + return res; + } + + @bindThis + public aggregateNoteEmojis(notes: Note[]) { + let emojis: { name: string | null; host: string | null; }[] = []; + for (const note of notes) { + emojis = emojis.concat(note.emojis + .map(e => this.parseEmojiStr(e, note.userHost))); + if (note.renote) { + emojis = emojis.concat(note.renote.emojis + .map(e => this.parseEmojiStr(e, note.renote!.userHost))); + if (note.renote.user) { + emojis = emojis.concat(note.renote.user.emojis + .map(e => this.parseEmojiStr(e, note.renote!.userHost))); + } + } + const customReactions = Object.keys(note.reactions).map(x => this.reactionService.decodeReaction(x)).filter(x => x.name != null) as typeof emojis; + emojis = emojis.concat(customReactions); + if (note.user) { + emojis = emojis.concat(note.user.emojis + .map(e => this.parseEmojiStr(e, note.userHost))); + } + } + return emojis.filter(x => x.name != null && x.host != null) as { name: string; host: string; }[]; + } + + /** + * 与ãˆã‚‰ã‚ŒãŸçµµæ–‡å—ã®ãƒªã‚¹ãƒˆã‚’データベースã‹ã‚‰å–å¾—ã—ã€ã‚ャッシュã«è¿½åŠ ã—ã¾ã™ + */ + @bindThis + public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> { + const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null); + const emojisQuery: any[] = []; + const hosts = new Set(notCachedEmojis.map(e => e.host)); + for (const host of hosts) { + if (host == null) continue; + emojisQuery.push({ + name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)), + host: host, + }); + } + const _emojis = emojisQuery.length > 0 ? await this.emojisRepository.find({ + where: emojisQuery, + select: ['name', 'host', 'originalUrl', 'publicUrl'], + }) : []; + for (const emoji of _emojis) { + this.cache.set(`${emoji.name} ${emoji.host}`, emoji); + } + } } diff --git a/packages/backend/src/core/ImageProcessingService.ts b/packages/backend/src/core/ImageProcessingService.ts index 312189eea4ed9779e0e67b2a9d5ea13aa5978591..fbc02f504b16fa829455f22e998a73a5cae8d654 100644 --- a/packages/backend/src/core/ImageProcessingService.ts +++ b/packages/backend/src/core/ImageProcessingService.ts @@ -9,6 +9,14 @@ export type IImage = { type: string; }; +export type IImageStream = { + data: Readable; + ext: string | null; + type: string; +}; + +export type IImageStreamable = IImage | IImageStream; + export const webpDefault: sharp.WebpOptions = { quality: 85, alphaQuality: 95, @@ -19,6 +27,7 @@ export const webpDefault: sharp.WebpOptions = { }; import { bindThis } from '@/decorators.js'; +import { Readable } from 'node:stream'; @Injectable() export class ImageProcessingService { @@ -64,7 +73,7 @@ export class ImageProcessingService { */ @bindThis public async convertToWebp(path: string, width: number, height: number, options: sharp.WebpOptions = webpDefault): Promise<IImage> { - return this.convertSharpToWebp(await sharp(path), width, height, options); + return this.convertSharpToWebp(sharp(path), width, height, options); } @bindThis @@ -85,6 +94,27 @@ export class ImageProcessingService { }; } + @bindThis + public convertToWebpStream(path: string, width: number, height: number, options: sharp.WebpOptions = webpDefault): IImageStream { + return this.convertSharpToWebpStream(sharp(path), width, height, options); + } + + @bindThis + public convertSharpToWebpStream(sharp: sharp.Sharp, width: number, height: number, options: sharp.WebpOptions = webpDefault): IImageStream { + const data = sharp + .resize(width, height, { + fit: 'inside', + withoutEnlargement: true, + }) + .rotate() + .webp(options) + + return { + data, + ext: 'webp', + type: 'image/webp', + }; + } /** * Convert to PNG * with resize, remove metadata, resolve orientation, stop animation diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 2b179643f3ed7621b46d426d40d41bc36dbcc10f..bd6971adb345b6be5e9dd1499e4a4a8aac32f970 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -282,7 +282,9 @@ export class NoteEntityService implements OnModuleInit { : await this.channelsRepository.findOneBy({ id: note.channelId }) : null; - const reactionEmojiNames = Object.keys(note.reactions).filter(x => x.startsWith(':')).map(x => this.reactionService.decodeReaction(x).reaction).map(x => x.replace(/:/g, '')); + const reactionEmojiNames = Object.keys(note.reactions) + .filter(x => x.startsWith(':') && x.includes('@') && !x.includes('@.')) // リモートカスタム絵文å—ã®ã¿ + .map(x => this.reactionService.decodeReaction(x).reaction.replaceAll(':', '')); const packed: Packed<'Note'> = await awaitAll({ id: note.id, @@ -299,6 +301,8 @@ export class NoteEntityService implements OnModuleInit { renoteCount: note.renoteCount, repliesCount: note.repliesCount, reactions: this.reactionService.convertLegacyReactions(note.reactions), + reactionEmojis: this.customEmojiService.populateEmojis(reactionEmojiNames, host), + emojis: host != null ? this.customEmojiService.populateEmojis(note.emojis, host) : undefined, tags: note.tags.length > 0 ? note.tags : undefined, fileIds: note.fileIds, files: this.driveFileEntityService.packMany(note.fileIds), @@ -384,6 +388,8 @@ export class NoteEntityService implements OnModuleInit { } } + await this.customEmojiService.prefetchEmojis(this.customEmojiService.aggregateNoteEmojis(notes)); + return await Promise.all(notes.map(n => this.pack(n, me, { ...options, _hint_: { diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index a8210eea02a6bb4487652da3c75057e0d419901a..ded1b512a193e41a560ec5fc8e2747c028fda942 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -146,6 +146,8 @@ export class NotificationEntityService implements OnModuleInit { myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) ?? null); } + await this.customEmojiService.prefetchEmojis(this.customEmojiService.aggregateNoteEmojis(notes)); + return await Promise.all(notifications.map(x => this.pack(x, { _hintForEachNotes_: { myReactions: myReactionsMap, diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index f532b5bf6eea746ad906592fa15ea628b749cb52..546e61a26ed0e9304036da19cca81f49d73bdf26 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -413,6 +413,7 @@ export class UserEntityService implements OnModuleInit { faviconUrl: instance.faviconUrl, themeColor: instance.themeColor, } : undefined) : undefined, + emojis: this.customEmojiService.populateEmojis(user.emojis, user.host), onlineStatus: this.getOnlineStatus(user), ...(opts.detail ? { diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts index e7d705163091f5723a1e75dd70eb79953dd27e9b..5d275bc7b2ce1b31656f2670088e2aa5da290540 100644 --- a/packages/backend/src/logger.ts +++ b/packages/backend/src/logger.ts @@ -68,6 +68,7 @@ export default class Logger { if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log; console.log(important ? chalk.bold(log) : log); + if (level === 'error' && data) console.log(data); if (store) { if (this.syslogClient) { diff --git a/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts b/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts index 4650da76bb3ad4210a4ce2a88bab8a181cbcd9e6..da4ae88557dc594808038eb304a8975ab56e05d3 100644 --- a/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts +++ b/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts @@ -57,8 +57,15 @@ export class AggregateRetentionProcessorService { usersCount: targetUserIds.length, }); + // 今日活動ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’å…¨ã¦å–å¾— + const activeUsers = await this.usersRepository.findBy({ + host: IsNull(), + lastActiveDate: MoreThan(new Date(Date.now() - (1000 * 60 * 60 * 24))), + }); + const activeUsersIds = activeUsers.map(u => u.id); + for (const record of pastRecords) { - const retention = record.userIds.filter(id => targetUserIds.includes(id)).length; + const retention = record.userIds.filter(id => activeUsersIds.includes(id)).length; const data = deepClone(record.data); data[dateKey] = retention; diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index 134b3df3270747c4bd8bbf048d0a2f0cd06fc336..40024270ae1f56d78935589af708a5bb2d4f3297 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -5,14 +5,14 @@ import { Inject, Injectable } from '@nestjs/common'; import fastifyStatic from '@fastify/static'; import rename from 'rename'; import type { Config } from '@/config.js'; -import type { DriveFilesRepository } from '@/models/index.js'; +import type { DriveFile, DriveFilesRepository } from '@/models/index.js'; import { DI } from '@/di-symbols.js'; import { createTemp } from '@/misc/create-temp.js'; import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; import { StatusError } from '@/misc/status-error.js'; import type Logger from '@/logger.js'; import { DownloadService } from '@/core/DownloadService.js'; -import { ImageProcessingService } from '@/core/ImageProcessingService.js'; +import { IImageStreamable, ImageProcessingService, webpDefault } from '@/core/ImageProcessingService.js'; import { VideoProcessingService } from '@/core/VideoProcessingService.js'; import { InternalStorageService } from '@/core/InternalStorageService.js'; import { contentDisposition } from '@/misc/content-disposition.js'; @@ -20,6 +20,8 @@ import { FileInfoService } from '@/core/FileInfoService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify'; +import { isMimeImage } from '@/misc/is-mime-image.js'; +import sharp from 'sharp'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); @@ -57,7 +59,7 @@ export class FileServerService { reply.header('Cache-Control', 'max-age=300'); }; } - + @bindThis public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { fastify.addHook('onRequest', (request, reply, done) => { @@ -70,113 +72,351 @@ export class FileServerService { serve: false, }); - fastify.get('/app-default.jpg', (request, reply) => { + fastify.get('/files/app-default.jpg', (request, reply) => { const file = fs.createReadStream(`${_dirname}/assets/dummy.png`); reply.header('Content-Type', 'image/jpeg'); reply.header('Cache-Control', 'max-age=31536000, immutable'); return reply.send(file); }); - fastify.get<{ Params: { key: string; } }>('/:key', async (request, reply) => await this.sendDriveFile(request, reply)); - fastify.get<{ Params: { key: string; } }>('/:key/*', async (request, reply) => await this.sendDriveFile(request, reply)); + fastify.get<{ Params: { key: string; } }>('/files/:key', async (request, reply) => { + return await this.sendDriveFile(request, reply) + .catch(err => this.errorHandler(request, reply, err)); + }); + fastify.get<{ Params: { key: string; } }>('/files/:key/*', async (request, reply) => { + return await this.sendDriveFile(request, reply) + .catch(err => this.errorHandler(request, reply, err)); + }); + + fastify.get<{ + Params: { url: string; }; + Querystring: { url?: string; }; + }>('/proxy/:url*', async (request, reply) => { + return await this.proxyHandler(request, reply) + .catch(err => this.errorHandler(request, reply, err)); + }); done(); } @bindThis - private async sendDriveFile(request: FastifyRequest<{ Params: { key: string; } }>, reply: FastifyReply) { - const key = request.params.key; + private async errorHandler(request: FastifyRequest<{ Params?: { [x: string]: any }; Querystring?: { [x: string]: any }; }>, reply: FastifyReply, err?: any) { + this.logger.error(`${err}`); - // Fetch drive file - const file = await this.driveFilesRepository.createQueryBuilder('file') - .where('file.accessKey = :accessKey', { accessKey: key }) - .orWhere('file.thumbnailAccessKey = :thumbnailAccessKey', { thumbnailAccessKey: key }) - .orWhere('file.webpublicAccessKey = :webpublicAccessKey', { webpublicAccessKey: key }) - .getOne(); + reply.header('Cache-Control', 'max-age=300'); - if (file == null) { - reply.code(404); - reply.header('Cache-Control', 'max-age=86400'); + if (request.query && 'fallback' in request.query) { return reply.sendFile('/dummy.png', assets); } - const isThumbnail = file.thumbnailAccessKey === key; - const isWebpublic = file.webpublicAccessKey === key; + if (err instanceof StatusError && (err.statusCode === 302 || err.isClientError)) { + reply.code(err.statusCode); + return; + } - if (!file.storedInternal) { - if (file.isLink && file.uri) { // 期é™åˆ‡ã‚Œãƒªãƒ¢ãƒ¼ãƒˆãƒ•ã‚¡ã‚¤ãƒ« - const [path, cleanup] = await createTemp(); + reply.code(500); + return; + } - try { - await this.downloadService.downloadUrl(file.uri, path); + @bindThis + private async sendDriveFile(request: FastifyRequest<{ Params: { key: string; } }>, reply: FastifyReply) { + const key = request.params.key; + const file = await this.getFileFromKey(key).then(); - const { mime, ext } = await this.fileInfoService.detectType(path); + if (file === '404') { + reply.code(404); + reply.header('Cache-Control', 'max-age=86400'); + return reply.sendFile('/dummy.png', assets); + } - const convertFile = async () => { - if (isThumbnail) { - if (['image/jpeg', 'image/webp', 'image/avif', 'image/png', 'image/svg+xml'].includes(mime)) { - return await this.imageProcessingService.convertToWebp(path, 498, 280); - } else if (mime.startsWith('video/')) { - return await this.videoProcessingService.generateVideoThumbnail(path); - } + if (file === '204') { + reply.code(204); + reply.header('Cache-Control', 'max-age=86400'); + return; + } + + try { + if (file.state === 'remote') { + const convertFile = async () => { + if (file.fileRole === 'thumbnail') { + if (['image/jpeg', 'image/webp', 'image/avif', 'image/png', 'image/svg+xml'].includes(file.mime)) { + return this.imageProcessingService.convertToWebpStream( + file.path, + 498, + 280 + ); + } else if (file.mime.startsWith('video/')) { + return await this.videoProcessingService.generateVideoThumbnail(file.path); } + } - if (isWebpublic) { - if (['image/svg+xml'].includes(mime)) { - return await this.imageProcessingService.convertToPng(path, 2048, 2048); - } + if (file.fileRole === 'webpublic') { + if (['image/svg+xml'].includes(file.mime)) { + return this.imageProcessingService.convertToWebpStream( + file.path, + 2048, + 2048, + { ...webpDefault, lossless: true } + ) } + } - return { - data: fs.readFileSync(path), - ext, - type: mime, - }; + return { + data: fs.createReadStream(file.path), + ext: file.ext, + type: file.mime, }; + }; - const image = await convertFile(); - reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream'); - reply.header('Cache-Control', 'max-age=31536000, immutable'); - return image.data; - } catch (err) { - this.logger.error(`${err}`); - - if (err instanceof StatusError && err.isClientError) { - reply.code(err.statusCode); - reply.header('Cache-Control', 'max-age=86400'); - } else { - reply.code(500); - reply.header('Cache-Control', 'max-age=300'); - } - } finally { - cleanup(); + const image = await convertFile(); + + if ('pipe' in image.data && typeof image.data.pipe === 'function') { + // image.dataãŒstreamãªã‚‰ã€stream終了後ã«cleanup + image.data.on('end', file.cleanup); + image.data.on('close', file.cleanup); + } else { + // image.dataãŒstreamã§ãªã„ãªã‚‰ç›´ã¡ã«cleanup + file.cleanup(); } - return; + + reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream'); + reply.header('Cache-Control', 'max-age=31536000, immutable'); + return image.data; } + if (file.fileRole !== 'original') { + const filename = rename(file.file.name, { + suffix: file.fileRole === 'thumbnail' ? '-thumb' : '-web', + extname: file.ext ? `.${file.ext}` : undefined, + }).toString(); + + reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.mime) ? file.mime : 'application/octet-stream'); + reply.header('Cache-Control', 'max-age=31536000, immutable'); + reply.header('Content-Disposition', contentDisposition('inline', filename)); + return fs.createReadStream(file.path); + } else { + const stream = fs.createReadStream(file.path); + stream.on('error', this.commonReadableHandlerGenerator(reply)); + reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.file.type) ? file.file.type : 'application/octet-stream'); + reply.header('Cache-Control', 'max-age=31536000, immutable'); + reply.header('Content-Disposition', contentDisposition('inline', file.file.name)); + return stream; + } + } catch (e) { + if ('cleanup' in file) file.cleanup(); + throw e; + } + } + + @bindThis + private async proxyHandler(request: FastifyRequest<{ Params: { url: string; }; Querystring: { url?: string; }; }>, reply: FastifyReply) { + const url = 'url' in request.query ? request.query.url : 'https://' + request.params.url; + + if (typeof url !== 'string') { + reply.code(400); + return; + } + + // Create temp file + const file = await this.getStreamAndTypeFromUrl(url); + if (file === '404') { + reply.code(404); + reply.header('Cache-Control', 'max-age=86400'); + return reply.sendFile('/dummy.png', assets); + } + + if (file === '204') { reply.code(204); reply.header('Cache-Control', 'max-age=86400'); return; } - if (isThumbnail || isWebpublic) { - const { mime, ext } = await this.fileInfoService.detectType(this.internalStorageService.resolvePath(key)); - const filename = rename(file.name, { - suffix: isThumbnail ? '-thumb' : '-web', - extname: ext ? `.${ext}` : undefined, - }).toString(); + try { + const isConvertibleImage = isMimeImage(file.mime, 'sharp-convertible-image'); + const isAnimationConvertibleImage = isMimeImage(file.mime, 'sharp-animation-convertible-image'); - reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : 'application/octet-stream'); - reply.header('Cache-Control', 'max-age=31536000, immutable'); - reply.header('Content-Disposition', contentDisposition('inline', filename)); - return this.internalStorageService.read(key); - } else { - const readable = this.internalStorageService.read(file.accessKey!); - readable.on('error', this.commonReadableHandlerGenerator(reply)); - reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.type) ? file.type : 'application/octet-stream'); + let image: IImageStreamable | null = null; + if ('emoji' in request.query && isConvertibleImage) { + if (!isAnimationConvertibleImage && !('static' in request.query)) { + image = { + data: fs.createReadStream(file.path), + ext: file.ext, + type: file.mime, + }; + } else { + const data = sharp(file.path, { animated: !('static' in request.query) }) + .resize({ + height: 128, + withoutEnlargement: true, + }) + .webp(webpDefault); + + image = { + data, + ext: 'webp', + type: 'image/webp', + }; + } + } else if ('static' in request.query && isConvertibleImage) { + image = this.imageProcessingService.convertToWebpStream(file.path, 498, 280); + } else if ('preview' in request.query && isConvertibleImage) { + image = this.imageProcessingService.convertToWebpStream(file.path, 200, 200); + } else if ('badge' in request.query) { + if (!isConvertibleImage) { + // ç”»åƒã§ãªã„ãªã‚‰404ã§ãŠèŒ¶ã‚’æ¿ã™ + throw new StatusError('Unexpected mime', 404); + } + + const mask = sharp(file.path) + .resize(96, 96, { + fit: 'inside', + withoutEnlargement: false, + }) + .greyscale() + .normalise() + .linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast + .flatten({ background: '#000' }) + .toColorspace('b-w'); + + const stats = await mask.clone().stats(); + + if (stats.entropy < 0.1) { + // エントãƒãƒ”ーãŒã‚ã¾ã‚Šãªã„å ´åˆã¯404ã«ã™ã‚‹ + throw new StatusError('Skip to provide badge', 404); + } + + const data = sharp({ + create: { width: 96, height: 96, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } }, + }) + .pipelineColorspace('b-w') + .boolean(await mask.png().toBuffer(), 'eor'); + + image = { + data: await data.png().toBuffer(), + ext: 'png', + type: 'image/png', + }; + } else if (file.mime === 'image/svg+xml') { + image = this.imageProcessingService.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), + ext: file.ext, + type: file.mime, + }; + } + + if ('cleanup' in file) { + if ('pipe' in image.data && typeof image.data.pipe === 'function') { + // image.dataãŒstreamãªã‚‰ã€stream終了後ã«cleanup + image.data.on('end', file.cleanup); + image.data.on('close', file.cleanup); + } else { + // image.dataãŒstreamã§ãªã„ãªã‚‰ç›´ã¡ã«cleanup + file.cleanup(); + } + } + + reply.header('Content-Type', image.type); reply.header('Cache-Control', 'max-age=31536000, immutable'); - reply.header('Content-Disposition', contentDisposition('inline', file.name)); - return readable; + return image.data; + } catch (e) { + if ('cleanup' in file) file.cleanup(); + throw e; + } + } + + @bindThis + private async getStreamAndTypeFromUrl(url: string): Promise< + { state: 'remote'; fileRole?: 'thumbnail' | 'webpublic' | 'original'; file?: DriveFile; mime: string; ext: string | null; path: string; cleanup: () => void; } + | { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; } + | '404' + | '204' + > { + if (url.startsWith(`${this.config.url}/files/`)) { + const key = url.replace(`${this.config.url}/files/`, '').split('/').shift(); + if (!key) throw new StatusError('Invalid File Key', 400, 'Invalid File Key'); + + return await this.getFileFromKey(key); + } + + return await this.downloadAndDetectTypeFromUrl(url); + } + + @bindThis + private async downloadAndDetectTypeFromUrl(url: string): Promise< + { state: 'remote' ; mime: string; ext: string | null; path: string; cleanup: () => void; } + > { + const [path, cleanup] = await createTemp(); + try { + await this.downloadService.downloadUrl(url, path); + + const { mime, ext } = await this.fileInfoService.detectType(path); + + return { + state: 'remote', + mime, ext, + path, cleanup, + } + } catch (e) { + cleanup(); + throw e; + } + } + + @bindThis + private async getFileFromKey(key: string): Promise< + { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; cleanup: () => void; } + | { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; } + | '404' + | '204' + > { + // Fetch drive file + const file = await this.driveFilesRepository.createQueryBuilder('file') + .where('file.accessKey = :accessKey', { accessKey: key }) + .orWhere('file.thumbnailAccessKey = :thumbnailAccessKey', { thumbnailAccessKey: key }) + .orWhere('file.webpublicAccessKey = :webpublicAccessKey', { webpublicAccessKey: key }) + .getOne(); + + if (file == null) return '404'; + + const isThumbnail = file.thumbnailAccessKey === key; + const isWebpublic = file.webpublicAccessKey === key; + + if (!file.storedInternal) { + if (!(file.isLink && file.uri)) return '204'; + const result = await this.downloadAndDetectTypeFromUrl(file.uri); + return { + ...result, + fileRole: isThumbnail ? 'thumbnail' : isWebpublic ? 'webpublic' : 'original', + file, + } + } + + const path = this.internalStorageService.resolvePath(key); + + if (isThumbnail || isWebpublic) { + const { mime, ext } = await this.fileInfoService.detectType(path); + return { + state: 'stored_internal', + fileRole: isThumbnail ? 'thumbnail' : 'webpublic', + file, + mime, ext, + path, + }; + } + + return { + state: 'stored_internal', + fileRole: 'original', + file, + mime: file.type, + ext: null, + path, } } } diff --git a/packages/backend/src/server/MediaProxyServerService.ts b/packages/backend/src/server/MediaProxyServerService.ts deleted file mode 100644 index 5b76f15020befe2fb464e232ccd8e151bd421bfa..0000000000000000000000000000000000000000 --- a/packages/backend/src/server/MediaProxyServerService.ts +++ /dev/null @@ -1,177 +0,0 @@ -import * as fs from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { dirname } from 'node:path'; -import { Inject, Injectable } from '@nestjs/common'; -import sharp from 'sharp'; -import fastifyStatic from '@fastify/static'; -import { DI } from '@/di-symbols.js'; -import type { Config } from '@/config.js'; -import { isMimeImage } from '@/misc/is-mime-image.js'; -import { createTemp } from '@/misc/create-temp.js'; -import { DownloadService } from '@/core/DownloadService.js'; -import { ImageProcessingService, webpDefault } from '@/core/ImageProcessingService.js'; -import type { IImage } from '@/core/ImageProcessingService.js'; -import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; -import { StatusError } from '@/misc/status-error.js'; -import type Logger from '@/logger.js'; -import { FileInfoService } from '@/core/FileInfoService.js'; -import { LoggerService } from '@/core/LoggerService.js'; -import { bindThis } from '@/decorators.js'; -import type { FastifyInstance, FastifyPluginOptions, FastifyReply, FastifyRequest } from 'fastify'; - -const _filename = fileURLToPath(import.meta.url); -const _dirname = dirname(_filename); - -const assets = `${_dirname}/../../src/server/assets/`; - -@Injectable() -export class MediaProxyServerService { - private logger: Logger; - - constructor( - @Inject(DI.config) - private config: Config, - - private fileInfoService: FileInfoService, - private downloadService: DownloadService, - private imageProcessingService: ImageProcessingService, - private loggerService: LoggerService, - ) { - this.logger = this.loggerService.getLogger('server', 'gray', false); - - //this.createServer = this.createServer.bind(this); - } - - @bindThis - public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { - fastify.addHook('onRequest', (request, reply, done) => { - reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\''); - done(); - }); - - fastify.register(fastifyStatic, { - root: _dirname, - serve: false, - }); - - fastify.get<{ - Params: { url: string; }; - Querystring: { url?: string; }; - }>('/:url*', async (request, reply) => await this.handler(request, reply)); - - done(); - } - - @bindThis - private async handler(request: FastifyRequest<{ Params: { url: string; }; Querystring: { url?: string; }; }>, reply: FastifyReply) { - const url = 'url' in request.query ? request.query.url : 'https://' + request.params.url; - - if (typeof url !== 'string') { - reply.code(400); - return; - } - - // Create temp file - const [path, cleanup] = await createTemp(); - - try { - await this.downloadService.downloadUrl(url, path); - - const { mime, ext } = await this.fileInfoService.detectType(path); - const isConvertibleImage = isMimeImage(mime, 'sharp-convertible-image'); - const isAnimationConvertibleImage = isMimeImage(mime, 'sharp-animation-convertible-image'); - - let image: IImage; - if ('emoji' in request.query && isConvertibleImage) { - if (!isAnimationConvertibleImage && !('static' in request.query)) { - image = { - data: fs.readFileSync(path), - ext, - type: mime, - }; - } else { - const data = await sharp(path, { animated: !('static' in request.query) }) - .resize({ - height: 128, - withoutEnlargement: true, - }) - .webp(webpDefault) - .toBuffer(); - - image = { - data, - ext: 'webp', - type: 'image/webp', - }; - } - } else if ('static' in request.query && isConvertibleImage) { - image = await this.imageProcessingService.convertToWebp(path, 498, 280); - } else if ('preview' in request.query && isConvertibleImage) { - image = await this.imageProcessingService.convertToWebp(path, 200, 200); - } else if ('badge' in request.query) { - if (!isConvertibleImage) { - // ç”»åƒã§ãªã„ãªã‚‰404ã§ãŠèŒ¶ã‚’æ¿ã™ - throw new StatusError('Unexpected mime', 404); - } - - const mask = sharp(path) - .resize(96, 96, { - fit: 'inside', - withoutEnlargement: false, - }) - .greyscale() - .normalise() - .linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast - .flatten({ background: '#000' }) - .toColorspace('b-w'); - - const stats = await mask.clone().stats(); - - if (stats.entropy < 0.1) { - // エントãƒãƒ”ーãŒã‚ã¾ã‚Šãªã„å ´åˆã¯404ã«ã™ã‚‹ - throw new StatusError('Skip to provide badge', 404); - } - - const data = sharp({ - create: { width: 96, height: 96, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } }, - }) - .pipelineColorspace('b-w') - .boolean(await mask.png().toBuffer(), 'eor'); - - image = { - data: await data.png().toBuffer(), - ext: 'png', - type: 'image/png', - }; - } else if (mime === 'image/svg+xml') { - image = await this.imageProcessingService.convertToWebp(path, 2048, 2048, webpDefault); - } else if (!mime.startsWith('image/') || !FILE_TYPE_BROWSERSAFE.includes(mime)) { - throw new StatusError('Rejected type', 403, 'Rejected type'); - } else { - image = { - data: fs.readFileSync(path), - ext, - type: mime, - }; - } - - reply.header('Content-Type', image.type); - reply.header('Cache-Control', 'max-age=31536000, immutable'); - return image.data; - } catch (err) { - this.logger.error(`${err}`); - - if ('fallback' in request.query) { - return reply.sendFile('/dummy.png', assets); - } - - if (err instanceof StatusError && (err.statusCode === 302 || err.isClientError)) { - reply.code(err.statusCode); - } else { - reply.code(500); - } - } finally { - cleanup(); - } - } -} diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index 474edafe41ce35b9024de9b5bac235d20c7fc51f..9dc1527698091e5963ecad41b75ce6a1ef682030 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -3,7 +3,6 @@ import { EndpointsModule } from '@/server/api/EndpointsModule.js'; import { CoreModule } from '@/core/CoreModule.js'; import { ApiCallService } from './api/ApiCallService.js'; import { FileServerService } from './FileServerService.js'; -import { MediaProxyServerService } from './MediaProxyServerService.js'; import { NodeinfoServerService } from './NodeinfoServerService.js'; import { ServerService } from './ServerService.js'; import { WellKnownServerService } from './WellKnownServerService.js'; @@ -51,7 +50,6 @@ import { UserListChannelService } from './api/stream/channels/user-list.js'; UrlPreviewService, ActivityPubServerService, FileServerService, - MediaProxyServerService, NodeinfoServerService, ServerService, WellKnownServerService, diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index eb6a3795eba24855f9065d4367a02c7e3fd32fe8..beb3a34ecdd25e966e95956a6ea2397cb2432955 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -20,7 +20,6 @@ import { NodeinfoServerService } from './NodeinfoServerService.js'; import { ApiServerService } from './api/ApiServerService.js'; import { StreamingApiServerService } from './api/StreamingApiServerService.js'; import { WellKnownServerService } from './WellKnownServerService.js'; -import { MediaProxyServerService } from './MediaProxyServerService.js'; import { FileServerService } from './FileServerService.js'; import { ClientServerService } from './web/ClientServerService.js'; @@ -48,7 +47,6 @@ export class ServerService { private wellKnownServerService: WellKnownServerService, private nodeinfoServerService: NodeinfoServerService, private fileServerService: FileServerService, - private mediaProxyServerService: MediaProxyServerService, private clientServerService: ClientServerService, private globalEventService: GlobalEventService, private loggerService: LoggerService, @@ -73,8 +71,7 @@ export class ServerService { } fastify.register(this.apiServerService.createServer, { prefix: '/api' }); - fastify.register(this.fileServerService.createServer, { prefix: '/files' }); - fastify.register(this.mediaProxyServerService.createServer, { prefix: '/proxy' }); + fastify.register(this.fileServerService.createServer); fastify.register(this.activityPubServerService.createServer); fastify.register(this.nodeinfoServerService.createServer); fastify.register(this.wellKnownServerService.createServer); diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 9ec911f32297ed300404313bfc79aaa3a0d16658..ac401a60ee1ec2b3d8a9aa379b3c2fd83565cc67 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -61,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { super(meta, paramDef, async (ps, me) => { const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId }); - if (me == null || (me.id !== ps.userId && !profile.publicReactions)) { + if ((me == null || me.id !== ps.userId) && !profile.publicReactions) { throw new ApiError(meta.errors.reactionsNotPublic); } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index da568a9eac694b9c09e61544281254c57650e4fc..12f890aa536817d75809fae4e4db805d0cf9f383 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -12,7 +12,7 @@ "@rollup/plugin-json": "6.0.0", "@rollup/pluginutils": "5.0.2", "@syuilo/aiscript": "0.12.2", - "@tabler/icons-webfont": "^2.0.0", + "@tabler/icons-webfont": "^2.1.2", "@vitejs/plugin-vue": "4.0.0", "@vue/compiler-sfc": "3.2.45", "autobind-decorator": "2.4.0", @@ -44,7 +44,7 @@ "punycode": "2.3.0", "querystring": "0.2.1", "rndstr": "1.0.0", - "rollup": "3.10.1", + "rollup": "3.11.0", "s-age": "1.1.2", "sanitize-html": "^2.8.1", "sass": "1.57.1", @@ -53,7 +53,7 @@ "stringz": "2.1.0", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", - "three": "0.148.0", + "three": "0.149.0", "throttle-debounce": "5.0.0", "tinycolor2": "1.5.2", "tsc-alias": "1.8.2", @@ -86,7 +86,7 @@ "@typescript-eslint/parser": "5.49.0", "@vue/runtime-core": "3.2.45", "cross-env": "7.0.3", - "cypress": "12.3.0", + "cypress": "12.4.0", "eslint": "8.32.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-vue": "9.9.0", diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 2cb3aeb3d832791553157a3c56eb9b3daed8c59e..27997eb330ed8a0adc3dabd375c7fe1f4bc4ee58 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -17,7 +17,7 @@ </ol> <ol v-else-if="emojis.length > 0" ref="suggests" :class="$style.list"> <li v-for="emoji in emojis" :key="emoji.emoji" :class="$style.item" tabindex="-1" @click="complete(type, emoji.emoji)" @keydown="onKeydown"> - <MkEmoji :emoji="emoji.emoji" :class="$style.emoji"/> + <MkCustomEmoji :name="emoji.emoji" :class="$style.emoji"/> <!-- eslint-disable-next-line vue/no-v-html --> <span v-if="q" :class="$style.emojiName" v-html="sanitizeHtml(emoji.name.replace(q, `<b>${q}</b>`))"></span> <span v-else v-text="emoji.name"></span> @@ -112,7 +112,7 @@ const emojiDb = computed(() => { customEmojiDB.sort((a, b) => a.name.length - b.name.length); //#endregion - return markRaw([ ...customEmojiDB, ...unicodeEmojiDB ]); + return markRaw([...customEmojiDB, ...unicodeEmojiDB]); }); export default { diff --git a/packages/frontend/src/components/MkEmojiPicker.section.vue b/packages/frontend/src/components/MkEmojiPicker.section.vue index acced447930c96754ec3afc8f3256b3323e48d3b..c418ac2c522938f639f4292bef73260299c9bad5 100644 --- a/packages/frontend/src/components/MkEmojiPicker.section.vue +++ b/packages/frontend/src/components/MkEmojiPicker.section.vue @@ -11,7 +11,8 @@ class="_button item" @click="emit('chosen', emoji, $event)" > - <MkEmoji class="emoji" :emoji="emoji" :normal="true"/> + <MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> + <MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> </button> </div> </section> diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index f64cc6e9aaa0d9bdc83e41612a7eaa0d922d3118..39e274ba1115b2adfc16e3501ad6f9f9c8b5c5b0 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -12,7 +12,7 @@ tabindex="0" @click="chosen(emoji, $event)" > - <MkEmoji class="emoji" :emoji="`:${emoji.name}:`"/> + <MkCustomEmoji class="emoji" :name="emoji.name"/> </button> </div> <div v-if="searchResultUnicode.length > 0" class="body"> @@ -39,7 +39,8 @@ tabindex="0" @click="chosen(emoji, $event)" > - <MkEmoji class="emoji" :emoji="emoji" :normal="true"/> + <MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> + <MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> </button> </div> </section> @@ -53,7 +54,8 @@ class="_button item" @click="chosen(emoji, $event)" > - <MkEmoji class="emoji" :emoji="emoji" :normal="true"/> + <MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> + <MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> </button> </div> </section> diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 1f6a2883d7a1166ba6275048fcd9c33c7109ff5d..351861ac17dc11bc29d36592ae20216da4c4068f 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -48,12 +48,12 @@ <div :class="$style.text"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="appearNote.text" v-once :text="appearNote.text" :author="appearNote.user" :i="$i"/> + <Mfm v-if="appearNote.text" v-once :text="appearNote.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> <div v-if="translating || translation" :class="$style.translation"> <MkLoading v-if="translating" mini/> <div v-else :class="$style.translated"> <b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}: </b> - <Mfm :text="translation.text" :author="appearNote.user" :i="$i"/> + <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> </div> </div> </div> diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 48ace56d9c3c4c37e1a0f4660fb08f01fe111825..0da06c4f145abd1a32727cca90c9b90958d6fd0b 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -65,13 +65,13 @@ <div class="text"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i"/> + <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> <a v-if="appearNote.renote != null" class="rp">RN:</a> <div v-if="translating || translation" class="translation"> <MkLoading v-if="translating" mini/> <div v-else class="translated"> <b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}: </b> - <Mfm :text="translation.text" :author="appearNote.user" :i="$i"/> + <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> </div> </div> </div> diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue index 828bbee5af564e760260e13f153ee8dfa654db33..757b325a06bc327fc6caaf33eed033b9a8dce1bb 100644 --- a/packages/frontend/src/components/MkNoteSimple.vue +++ b/packages/frontend/src/components/MkNoteSimple.vue @@ -5,7 +5,7 @@ <MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <div> <p v-if="note.cw != null" :class="$style.cw"> - <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :i="$i"/> + <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :i="$i" :emoji-urls="note.emojis"/> <MkCwButton v-model="showContent" :note="note"/> </p> <div v-show="note.cw == null || showContent"> diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index a8b8fec3464a3e0ccd4032240f3ecdcab64c8e1c..b51d456eab50b1f08e248a7e88aa0a61d89b7eee 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -38,26 +38,26 @@ <div v-once :class="$style.content"> <MkA v-if="notification.type === 'reaction'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <i class="ti ti-quote" :class="$style.quote"></i> - <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :author="notification.note.user"/> + <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <i class="ti ti-quote" :class="$style.quote"></i> </MkA> <MkA v-else-if="notification.type === 'renote'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)"> <i class="ti ti-quote" :class="$style.quote"></i> - <Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full" :author="notification.note.renote.user"/> + <Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="true" :author="notification.note.renote.user"/> <i class="ti ti-quote" :class="$style.quote"></i> </MkA> <MkA v-else-if="notification.type === 'reply'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> - <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :author="notification.note.user"/> + <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> </MkA> <MkA v-else-if="notification.type === 'mention'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> - <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :author="notification.note.user"/> + <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> </MkA> <MkA v-else-if="notification.type === 'quote'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> - <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :author="notification.note.user"/> + <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> </MkA> <MkA v-else-if="notification.type === 'pollEnded'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <i class="ti ti-quote" :class="$style.quote"></i> - <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :author="notification.note.user"/> + <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> <i class="ti ti-quote" :class="$style.quote"></i> </MkA> <MkA v-else-if="notification.type === 'achievementEarned'" :class="$style.text" to="/my/achievements"> @@ -68,7 +68,7 @@ <span v-else-if="notification.type === 'receiveFollowRequest'" :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.receiveFollowRequest }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ i18n.ts.reject }}</button></div></span> <span v-else-if="notification.type === 'groupInvited'" :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.groupInvited }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ i18n.ts.reject }}</button></div></span> <span v-else-if="notification.type === 'app'" :class="$style.text"> - <Mfm :text="notification.body" :nowrap="!full"/> + <Mfm :text="notification.body" :nowrap="false"/> </span> </div> </div> diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index f5ae7bcee443c4ed39f55072390ac787bd16f241..ab5dff8db54adf0830b1cc72d7f9084ca49c400a 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -10,7 +10,7 @@ <template #default="{ items: notifications }"> <MkDateSeparatedList v-slot="{ item: notification }" :class="$style.list" :items="notifications" :no-gap="true"> <XNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :key="notification.id" :note="notification.note"/> - <XNotification v-else :key="notification.id" :notification="notification" :with-time="true" :full="false" class="_panel notification"/> + <XNotification v-else :key="notification.id" :notification="notification" :with-time="true" :full="true" class="_panel notification"/> </MkDateSeparatedList> </template> </MkPagination> diff --git a/packages/frontend/src/components/MkReactionIcon.vue b/packages/frontend/src/components/MkReactionIcon.vue index 6e9d2b1a6c6be83486e7fea59e127666f63b7904..29b3f9b85b451b0aedc195066f2e18a7843b9633 100644 --- a/packages/frontend/src/components/MkReactionIcon.vue +++ b/packages/frontend/src/components/MkReactionIcon.vue @@ -1,5 +1,6 @@ <template> -<MkEmoji :emoji="reaction" :is-reaction="true" :normal="true" :no-style="noStyle"/> +<MkCustomEmoji v-if="reaction[0] === ':'" :name="reaction" :normal="true" :no-style="noStyle" :url="emojiUrl"/> +<MkEmoji v-else :emoji="reaction" :normal="true" :no-style="noStyle"/> </template> <script lang="ts" setup> @@ -8,5 +9,6 @@ import { } from 'vue'; const props = defineProps<{ reaction: string; noStyle?: boolean; + emojiUrl?: string; }>(); </script> diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index eed6b465945071aed44462cc3cd013b6c12164d4..83fdf0f9882c2676ab04b13a14bb6f0f8a9b5bd0 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -6,7 +6,7 @@ :class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle }]" @click="toggleReaction()" > - <MkReactionIcon :class="$style.icon" :reaction="reaction"/> + <MkReactionIcon :class="$style.icon" :reaction="reaction" :emoji-url="note.reactionEmojis[reaction.substr(1, reaction.length - 2)]"/> <span :class="$style.count">{{ count }}</span> </button> </template> diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue index 482a43f47481dde2aa3d32e2c1fe28dee946a78e..7e6833dae99d5212ec6b145a36c6ed997d9095d5 100644 --- a/packages/frontend/src/components/MkSubNoteContent.vue +++ b/packages/frontend/src/components/MkSubNoteContent.vue @@ -4,7 +4,7 @@ <span v-if="note.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <span v-if="note.deletedAt" style="opacity: 0.5">({{ i18n.ts.deleted }})</span> <MkA v-if="note.replyId" :class="$style.reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="note.text" v-once :text="note.text" :author="note.user" :i="$i"/> + <Mfm v-if="note.text" v-once :text="note.text" :author="note.user" :i="$i" :emoji-urls="note.emojis"/> <MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> </div> <details v-if="note.files.length > 0"> diff --git a/packages/frontend/src/components/global/MkCustomEmoji.vue b/packages/frontend/src/components/global/MkCustomEmoji.vue new file mode 100644 index 0000000000000000000000000000000000000000..93c47f0c2751a4ecf16ff7615107a8fe65359e91 --- /dev/null +++ b/packages/frontend/src/components/global/MkCustomEmoji.vue @@ -0,0 +1,61 @@ +<template> +<span v-if="errored">:{{ customEmojiName }}:</span> +<img v-else :class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]" :src="url" :alt="alt" :title="alt" decoding="async" @error="errored = true" @load="errored = false"/> +</template> + +<script lang="ts" setup> +import { computed } from 'vue'; +import { getStaticImageUrl } from '@/scripts/media-proxy'; +import { defaultStore } from '@/store'; +import { customEmojis } from '@/custom-emojis'; + +const props = defineProps<{ + name: string; + normal?: boolean; + noStyle?: boolean; + host?: string | null; + url?: string; +}>(); + +const customEmojiName = computed(() => (props.name[0] === ':' ? props.name.substr(1, props.name.length - 2) : props.name).replace('@.', '')); +const url = computed(() => { + if (props.url) { + return props.url; + } else if (props.host == null && !customEmojiName.value.includes('@')) { + const found = customEmojis.value.find(x => x.name === customEmojiName.value); + return found ? defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(found.url) : found.url : null; + } else { + const rawUrl = props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; + return defaultStore.state.disableShowingAnimatedImages + ? getStaticImageUrl(rawUrl) + : rawUrl; + } +}); +const alt = computed(() => `:${customEmojiName.value}:`); +let errored = $ref(url.value == null); +</script> + +<style lang="scss" module> +.root { + height: 2.5em; + vertical-align: middle; + transition: transform 0.2s ease; + + &:hover { + transform: scale(1.2); + } +} + +.normal { + height: 1.25em; + vertical-align: -0.25em; + + &:hover { + transform: none; + } +} + +.noStyle { + height: auto !important; +} +</style> diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue index b554d5e47c46972a1c6e48f0311aef56602a4579..1b0d34a445c223b7d2b7fc032fde5ed94c3c8e36 100644 --- a/packages/frontend/src/components/global/MkEmoji.vue +++ b/packages/frontend/src/components/global/MkEmoji.vue @@ -1,54 +1,29 @@ <template> -<span v-if="isCustom && errored">:{{ customEmojiName }}:</span> -<img v-else-if="isCustom" :class="[$style.root, $style.custom, { [$style.normal]: normal, [$style.noStyle]: noStyle }]" :src="url" :alt="alt" :title="alt" decoding="async" @error="errored = true" @load="errored = false"/> -<img v-else-if="char && !useOsNativeEmojis" :class="$style.root" :src="url" :alt="alt" decoding="async" @pointerenter="computeTitle"/> -<span v-else-if="char && useOsNativeEmojis" :alt="alt" @pointerenter="computeTitle">{{ char }}</span> +<img v-if="!useOsNativeEmojis" :class="$style.root" :src="url" :alt="props.emoji" decoding="async" @pointerenter="computeTitle"/> +<span v-else-if="useOsNativeEmojis" :alt="props.emoji" @pointerenter="computeTitle">{{ props.emoji }}</span> <span v-else>{{ emoji }}</span> </template> <script lang="ts" setup> import { computed } from 'vue'; -import { getStaticImageUrl } from '@/scripts/media-proxy'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; import { defaultStore } from '@/store'; import { getEmojiName } from '@/scripts/emojilist'; -import { customEmojis } from '@/custom-emojis'; const props = defineProps<{ emoji: string; - normal?: boolean; - noStyle?: boolean; - isReaction?: boolean; - host?: string | null; }>(); const char2path = defaultStore.state.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath; -const isCustom = computed(() => props.emoji.startsWith(':')); -const customEmojiName = computed(() => props.emoji.substr(1, props.emoji.length - 2).replace('@.', '')); -const char = computed(() => isCustom.value ? undefined : props.emoji); -const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'native' && !props.isReaction); +const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'native'); const url = computed(() => { - if (char.value) { - return char2path(char.value); - } else if (props.host == null && !customEmojiName.value.includes('@')) { - const found = customEmojis.value.find(x => x.name === customEmojiName.value); - return found ? defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(found.url) : found.url : null; - } else { - const rawUrl = props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; - return defaultStore.state.disableShowingAnimatedImages - ? getStaticImageUrl(rawUrl) - : rawUrl; - } + return char2path(props.emoji); }); -const alt = computed(() => isCustom.value ? `:${customEmojiName.value}:` : char.value); -let errored = $ref(isCustom.value && url.value == null); // Searching from an array with 2000 items for every emoji felt like too energy-consuming, so I decided to do it lazily on pointerenter function computeTitle(event: PointerEvent): void { - const title = isCustom.value - ? `:${customEmojiName.value}:` - : (getEmojiName(char.value as string) ?? char.value as string); + const title = getEmojiName(props.emoji as string) ?? props.emoji as string; (event.target as HTMLElement).title = title; } </script> @@ -58,27 +33,4 @@ function computeTitle(event: PointerEvent): void { height: 1.25em; vertical-align: -0.25em; } - -.custom { - height: 2.5em; - vertical-align: middle; - transition: transform 0.2s ease; - - &:hover { - transform: scale(1.2); - } -} - -.normal { - height: 1.25em; - vertical-align: -0.25em; - - &:hover { - transform: none; - } -} - -.noStyle { - height: auto !important; -} </style> diff --git a/packages/frontend/src/components/global/MkUserName.vue b/packages/frontend/src/components/global/MkUserName.vue index fc08310acc7ccedc64af85562aa4191c5ba80fe8..4186a4a4fb4c0b14fd024abe78f4dabbf3d8ad0f 100644 --- a/packages/frontend/src/components/global/MkUserName.vue +++ b/packages/frontend/src/components/global/MkUserName.vue @@ -1,5 +1,5 @@ <template> -<Mfm :text="user.name ?? user.username" :author="user" :plain="true" :nowrap="nowrap"/> +<Mfm :text="user.name ?? user.username" :author="user" :plain="true" :nowrap="nowrap" :emoji-urls="user.emojis"/> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 863925700382a9e8e48e2fca50585f1983436ad6..560870f84c2fbf8fe53e8ee5b18db16c4a6ca689 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -5,6 +5,7 @@ import MkA from './global/MkA.vue'; import MkAcct from './global/MkAcct.vue'; import MkAvatar from './global/MkAvatar.vue'; import MkEmoji from './global/MkEmoji.vue'; +import MkCustomEmoji from './global/MkCustomEmoji.vue'; import MkUserName from './global/MkUserName.vue'; import MkEllipsis from './global/MkEllipsis.vue'; import MkTime from './global/MkTime.vue'; @@ -26,6 +27,7 @@ export default function(app: App) { app.component('MkAcct', MkAcct); app.component('MkAvatar', MkAvatar); app.component('MkEmoji', MkEmoji); + app.component('MkCustomEmoji', MkCustomEmoji); app.component('MkUserName', MkUserName); app.component('MkEllipsis', MkEllipsis); app.component('MkTime', MkTime); @@ -47,6 +49,7 @@ declare module '@vue/runtime-core' { MkAcct: typeof MkAcct; MkAvatar: typeof MkAvatar; MkEmoji: typeof MkEmoji; + MkCustomEmoji: typeof MkCustomEmoji; MkUserName: typeof MkUserName; MkEllipsis: typeof MkEllipsis; MkTime: typeof MkTime; diff --git a/packages/frontend/src/components/mfm.ts b/packages/frontend/src/components/mfm.ts index b9ed9002ac0379089b65710b7eae3d90be9eec5c..7cfb19aeb66267769c30550748aebcd6c1c03389 100644 --- a/packages/frontend/src/components/mfm.ts +++ b/packages/frontend/src/components/mfm.ts @@ -4,6 +4,7 @@ import MkUrl from '@/components/global/MkUrl.vue'; import MkLink from '@/components/MkLink.vue'; import MkMention from '@/components/MkMention.vue'; import MkEmoji from '@/components/global/MkEmoji.vue'; +import MkCustomEmoji from '@/components/global/MkCustomEmoji.vue'; import { concat } from '@/scripts/array'; import MkCode from '@/components/MkCode.vue'; import MkGoogle from '@/components/MkGoogle.vue'; @@ -47,6 +48,10 @@ export default defineComponent({ type: Boolean, default: true, }, + emojiUrls: { + type: Object, + default: null, + }, }, render() { @@ -301,20 +306,35 @@ export default defineComponent({ } case 'emojiCode': { - return [h(MkEmoji, { - key: Math.random(), - emoji: `:${token.props.name}:`, - normal: this.plain, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (this.author?.host == null) { + return [h(MkCustomEmoji, { + key: Math.random(), + name: token.props.name, + normal: this.plain, + host: null, + })]; + } else { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - host: this.author?.host, - })]; + if (this.emojiUrls && (this.emojiUrls[token.props.name] == null)) { + return [h('span', `:${token.props.name}:`)]; + } else { + return [h(MkCustomEmoji, { + key: Math.random(), + name: token.props.name, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + url: this.emojiUrls ? this.emojiUrls[token.props.name] : null, + normal: this.plain, + host: this.author.host, + })]; + } + } } case 'unicodeEmoji': { return [h(MkEmoji, { key: Math.random(), emoji: token.props.emoji, - normal: this.plain, })]; } diff --git a/packages/frontend/src/custom-emojis.ts b/packages/frontend/src/custom-emojis.ts index 0ba7cab5e20121b68a59160efc30f47e6322c8f6..9ce370e7e89733cf51ee5e1f7601504a66a0183d 100644 --- a/packages/frontend/src/custom-emojis.ts +++ b/packages/frontend/src/custom-emojis.ts @@ -1,6 +1,6 @@ import { shallowRef, computed, markRaw } from 'vue'; import * as Misskey from 'misskey-js'; -import { apiGet } from './os'; +import { api, apiGet } from './os'; import { miLocalStorage } from './local-storage'; import { stream } from '@/stream'; @@ -28,12 +28,17 @@ stream.on('emojiDeleted', emojiData => { customEmojis.value = customEmojis.value.filter(item => !emojiData.emojis.some(search => search.name === item.name)); }); -export async function fetchCustomEmojis() { +export async function fetchCustomEmojis(force = false) { const now = Date.now(); - const lastFetchedAt = miLocalStorage.getItem('lastEmojisFetchedAt'); - if (lastFetchedAt && (now - parseInt(lastFetchedAt)) < 1000 * 60 * 60) return; - const res = await apiGet('emojis', {}); + let res; + if (force) { + res = await api('emojis', {}); + } else { + const lastFetchedAt = miLocalStorage.getItem('lastEmojisFetchedAt'); + if (lastFetchedAt && (now - parseInt(lastFetchedAt)) < 1000 * 60 * 60) return; + res = await apiGet('emojis', {}); + } customEmojis.value = res.emojis; miLocalStorage.setItem('emojis', JSON.stringify(res.emojis)); diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index bc63d7159adb7aa73439b2894efa626c4a704116..6d88feceaf6c9b41ea828f9684284092e5b5f6cd 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -9,7 +9,10 @@ <img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/> <div class="misskey">Misskey</div> <div class="version">v{{ version }}</div> - <span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span> + <span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"> + <MkCustomEmoji v-if="emoji.emoji[0] === ':'" class="emoji" :name="emoji.emoji" :normal="true" :no-style="true"/> + <MkEmoji v-else class="emoji" :emoji="emoji.emoji" :normal="true" :no-style="true"/> + </span> </div> <button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button> </div> diff --git a/packages/frontend/src/pages/admin/overview.stats.vue b/packages/frontend/src/pages/admin/overview.stats.vue index ce68222fbbacf64e5d0d1d3dc34931359e0e7bee..bd636cc3ef703234a7b46e2e67b2ef0d6e12b809 100644 --- a/packages/frontend/src/pages/admin/overview.stats.vue +++ b/packages/frontend/src/pages/admin/overview.stats.vue @@ -45,7 +45,7 @@ <div class="icon"><i class="ti ti-access-point"></i></div> <div class="body"> <div class="value"> - <MkNumber :value="stats.onlineUsersCount" style="margin-right: 0.5em;"/> + <MkNumber :value="onlineUsersCount" style="margin-right: 0.5em;"/> </div> <div class="label">Online</div> </div> diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index e1e050ee70d839e1850be005c237f55e008ee9a5..4dbc6ec74c184643bde6539345eb880f19920d45 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -34,6 +34,7 @@ import { useRouter } from '@/router'; import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import * as os from '@/os'; import { miLocalStorage } from '@/local-storage'; +import { fetchCustomEmojis } from '@/custom-emojis'; const indexInfo = { title: i18n.ts.settings, @@ -180,11 +181,13 @@ const menuDef = computed(() => [{ type: 'button', icon: 'ti ti-trash', text: i18n.ts.clearCache, - action: () => { + action: async () => { + os.waiting(); miLocalStorage.removeItem('locale'); miLocalStorage.removeItem('theme'); miLocalStorage.removeItem('emojis'); miLocalStorage.removeItem('lastEmojisFetchedAt'); + await fetchCustomEmojis(); unisonReload(); }, }, { diff --git a/packages/frontend/src/pages/settings/reaction.vue b/packages/frontend/src/pages/settings/reaction.vue index e307abe2d49938ab38d560f30cce757b73e2714e..c8b47b8299eb3ff68c2f9999bd70e30b13248235 100644 --- a/packages/frontend/src/pages/settings/reaction.vue +++ b/packages/frontend/src/pages/settings/reaction.vue @@ -6,7 +6,8 @@ <Sortable v-model="reactions" class="zoaiodol" :item-key="item => item" :animation="150" :delay="100" :delay-on-touch-only="true"> <template #item="{element}"> <button class="_button item" @click="remove(element, $event)"> - <MkEmoji :emoji="element" :normal="true"/> + <MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true"/> + <MkEmoji v-else :emoji="element" :normal="true"/> </button> </template> <template #footer> diff --git a/packages/frontend/src/scripts/device-kind.ts b/packages/frontend/src/scripts/device-kind.ts index 544cac0604d3e370e703e93d509624f60a3cb8e3..6bb349c554d6f67d7d9878d6f8437cc7c48da32a 100644 --- a/packages/frontend/src/scripts/device-kind.ts +++ b/packages/frontend/src/scripts/device-kind.ts @@ -4,7 +4,7 @@ const ua = navigator.userAgent.toLowerCase(); const isTablet = /ipad/.test(ua) || (/mobile|iphone|android/.test(ua) && window.innerWidth > 700); const isSmartphone = !isTablet && /mobile|iphone|android/.test(ua); -export const deviceKind = defaultStore.state.overridedDeviceKind ? defaultStore.state.overridedDeviceKind +export const deviceKind: 'smartphone' | 'tablet' | 'desktop' = defaultStore.state.overridedDeviceKind ? defaultStore.state.overridedDeviceKind : isSmartphone ? 'smartphone' : isTablet ? 'tablet' : 'desktop'; diff --git a/packages/frontend/src/scripts/use-note-capture.ts b/packages/frontend/src/scripts/use-note-capture.ts index 389ee1256132618dbff60ea899dc6e78a1b8231a..ffe33cccc09c1def1789ea04efd98b8494ac6c54 100644 --- a/packages/frontend/src/scripts/use-note-capture.ts +++ b/packages/frontend/src/scripts/use-note-capture.ts @@ -20,11 +20,8 @@ export function useNoteCapture(props: { case 'reacted': { const reaction = body.reaction; - if (body.emoji) { - const emojis = note.value.emojis || []; - if (!emojis.includes(body.emoji)) { - note.value.emojis = [...emojis, body.emoji]; - } + if (body.emoji && !(body.emoji.name in note.value.reactionEmojis)) { + note.value.reactionEmojis[body.emoji.name] = body.emoji.url; } // TODO: reactionsプãƒãƒ‘ティãŒãªã„å ´åˆã£ã¦ã‚ã£ãŸã£ã‘? ãªã‘れ㰠|| {} ã¯æ¶ˆã›ã‚‹ diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index b29d9355ba104342e3f4d42d35f77cedec0fcee9..f9ad50b30d7855edbaccb9ad75bbab0692de1a1d 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -156,7 +156,7 @@ export const defaultStore = markRaw(new Storage('base', { }, animation: { where: 'device', - default: true, + default: !matchMedia('(prefers-reduced-motion)').matches, }, animatedMfm: { where: 'device', @@ -184,11 +184,11 @@ export const defaultStore = markRaw(new Storage('base', { }, useBlurEffectForModal: { where: 'device', - default: true, + default: !/mobile|iphone|android/.test(navigator.userAgent.toLowerCase()), // 循環å‚ç…§ã™ã‚‹ã®ã§device-kind.tsã¯å‚ç…§ã§ããªã„ }, useBlurEffect: { where: 'device', - default: true, + default: !/mobile|iphone|android/.test(navigator.userAgent.toLowerCase()), // 循環å‚ç…§ã™ã‚‹ã®ã§device-kind.tsã¯å‚ç…§ã§ããªã„ }, showFixedPostForm: { where: 'device', diff --git a/packages/frontend/src/ui/_common_/notification.vue b/packages/frontend/src/ui/_common_/notification.vue index 1f9c675a15312fd6ea1d8e0a64c1512e9bdbe6fe..06dfcb0a2393d3eb0d4dd56b26b98002b2fe35cb 100644 --- a/packages/frontend/src/ui/_common_/notification.vue +++ b/packages/frontend/src/ui/_common_/notification.vue @@ -1,6 +1,6 @@ <template> <div :class="$style.root"> - <XNotification :notification="notification" class="notification _acrylic"/> + <XNotification :notification="notification" class="notification _acrylic" :full="false"/> </div> </template> diff --git a/packages/sw/package.json b/packages/sw/package.json index 163cdf592688dd49e9865076387bb70f30ff6d2e..ef46112dacc8d7ac8f358d3ecccddc9a3920e196 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -7,15 +7,15 @@ "lint": "tsc --noEmit && eslint --quiet src/**/*.ts" }, "dependencies": { - "esbuild": "^0.14.42", - "idb-keyval": "^6.1.0", + "esbuild": "^0.17.4", + "idb-keyval": "^6.2.0", "misskey-js": "0.0.14" }, "devDependencies": { - "@typescript-eslint/parser": "^5.45.0", - "@typescript/lib-webworker": "npm:@types/serviceworker@^0.0.58", - "eslint": "^8.16.0", - "eslint-plugin-import": "^2.26.0", + "@typescript-eslint/parser": "^5.49.0", + "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.61", + "eslint": "^8.32.0", + "eslint-plugin-import": "^2.27.5", "typescript": "4.9.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6b7699e2c321a0cf563fcd9568eb35e2fa31f30..dda76c38f0d1f84e45232482eebfe1b36f2a9c41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: '@typescript-eslint/eslint-plugin': 5.49.0 '@typescript-eslint/parser': 5.49.0 cross-env: 7.0.3 - cypress: 12.3.0 + cypress: 12.4.0 eslint: ^8.32.0 execa: 5.1.1 gulp: 4.0.2 @@ -42,7 +42,7 @@ importers: '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje cross-env: 7.0.3 - cypress: 12.3.0 + cypress: 12.4.0 eslint: 8.32.0 start-server-and-test: 1.15.3 @@ -57,8 +57,8 @@ importers: '@fastify/cors': 8.2.0 '@fastify/http-proxy': ^8.4.0 '@fastify/multipart': 7.4.0 - '@fastify/static': 6.6.1 - '@fastify/view': 7.4.0 + '@fastify/static': 6.7.0 + '@fastify/view': 7.4.1 '@nestjs/common': 9.2.1 '@nestjs/core': 9.2.1 '@nestjs/testing': 9.2.1 @@ -66,7 +66,7 @@ importers: '@redocly/openapi-core': 1.0.0-beta.120 '@sinonjs/fake-timers': 10.0.2 '@swc/cli': ^0.1.59 - '@swc/core': 1.3.27 + '@swc/core': 1.3.29 '@swc/jest': 0.2.24 '@tensorflow/tfjs': ^4.2.0 '@tensorflow/tfjs-node': 4.2.0 @@ -80,11 +80,11 @@ importers: '@types/escape-regexp': 0.0.1 '@types/fluent-ffmpeg': 2.1.20 '@types/ioredis': 4.28.10 - '@types/jest': 29.2.6 + '@types/jest': 29.4.0 '@types/js-yaml': 4.0.5 '@types/jsdom': 20.0.1 '@types/jsonld': 1.5.8 - '@types/jsrsasign': 10.5.4 + '@types/jsrsasign': 10.5.5 '@types/mime-types': 2.1.1 '@types/node': 18.11.18 '@types/node-fetch': 3.0.3 @@ -147,8 +147,8 @@ importers: ioredis: 4.28.5 ip-cidr: 3.0.11 is-svg: 4.3.2 - jest: 29.3.1 - jest-mock: ^29.3.1 + jest: 29.4.1 + jest-mock: ^29.4.1 js-yaml: 4.1.0 jsdom: 21.1.0 json5: 2.2.3 @@ -192,7 +192,7 @@ importers: stringz: 2.1.0 summaly: 2.7.0 syslog-pro: git+https://github.com/misskey-dev/SyslogPro#0.2.9-misskey.2 - systeminformation: 5.17.3 + systeminformation: 5.17.4 tinycolor2: 1.5.2 tmp: 0.2.1 tsc-alias: 1.8.2 @@ -218,8 +218,8 @@ importers: '@fastify/cors': 8.2.0 '@fastify/http-proxy': 8.4.0 '@fastify/multipart': 7.4.0 - '@fastify/static': 6.6.1 - '@fastify/view': 7.4.0 + '@fastify/static': 6.7.0 + '@fastify/view': 7.4.1 '@nestjs/common': 9.2.1_mnr6j2del53muneqly5h4y27ai '@nestjs/core': 9.2.1_b4pxbpa7chblgbyake5iz5rdmu '@nestjs/testing': 9.2.1_hjcqpoaebdr7gdo5hgc22hthbe @@ -297,7 +297,7 @@ importers: stringz: 2.1.0 summaly: 2.7.0 syslog-pro: github.com/misskey-dev/SyslogPro/2772b33fa126784fc6e21377786471a918b22dc7 - systeminformation: 5.17.3 + systeminformation: 5.17.4 tinycolor2: 1.5.2 tmp: 0.2.1 tsc-alias: 1.8.2 @@ -318,9 +318,9 @@ importers: '@tensorflow/tfjs-node': 4.2.0_seedrandom@3.0.5 devDependencies: '@redocly/openapi-core': 1.0.0-beta.120 - '@swc/cli': 0.1.59_2w2rsb5d2wh3txrlxuiknf4vra - '@swc/core': 1.3.27 - '@swc/jest': 0.2.24_@swc+core@1.3.27 + '@swc/cli': 0.1.59_dbbgdut2njxjatv5n3st5z6gqa + '@swc/core': 1.3.29 + '@swc/jest': 0.2.24_@swc+core@1.3.29 '@types/accepts': 1.3.5 '@types/archiver': 5.3.1 '@types/bcryptjs': 2.4.2 @@ -331,11 +331,11 @@ importers: '@types/escape-regexp': 0.0.1 '@types/fluent-ffmpeg': 2.1.20 '@types/ioredis': 4.28.10 - '@types/jest': 29.2.6 + '@types/jest': 29.4.0 '@types/js-yaml': 4.0.5 '@types/jsdom': 20.0.1 '@types/jsonld': 1.5.8 - '@types/jsrsasign': 10.5.4 + '@types/jsrsasign': 10.5.5 '@types/mime-types': 2.1.1 '@types/node': 18.11.18 '@types/node-fetch': 3.0.3 @@ -369,8 +369,8 @@ importers: eslint: 8.32.0 eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64 execa: 6.1.0 - jest: 29.3.1_@types+node@18.11.18 - jest-mock: 29.3.1 + jest: 29.4.1_@types+node@18.11.18 + jest-mock: 29.4.1 packages/frontend: specifiers: @@ -379,7 +379,7 @@ importers: '@rollup/plugin-json': 6.0.0 '@rollup/pluginutils': 5.0.2 '@syuilo/aiscript': 0.12.2 - '@tabler/icons-webfont': ^2.0.0 + '@tabler/icons-webfont': ^2.1.2 '@types/escape-regexp': 0.0.1 '@types/glob': 8.0.1 '@types/gulp': 4.0.10 @@ -413,7 +413,7 @@ importers: compare-versions: 5.0.1 cropperjs: 2.0.0-beta.2 cross-env: 7.0.3 - cypress: 12.3.0 + cypress: 12.4.0 date-fns: 2.29.3 escape-regexp: 0.0.1 eslint: 8.32.0 @@ -433,7 +433,7 @@ importers: punycode: 2.3.0 querystring: 0.2.1 rndstr: 1.0.0 - rollup: 3.10.1 + rollup: 3.11.0 s-age: 1.1.2 sanitize-html: ^2.8.1 sass: 1.57.1 @@ -443,7 +443,7 @@ importers: stringz: 2.1.0 syuilo-password-strength: 0.0.1 textarea-caret: 3.1.0 - three: 0.148.0 + three: 0.149.0 throttle-debounce: 5.0.0 tinycolor2: 1.5.2 tsc-alias: 1.8.2 @@ -460,11 +460,11 @@ importers: vuedraggable: next dependencies: '@discordapp/twemoji': 14.0.2 - '@rollup/plugin-alias': 4.0.3_rollup@3.10.1 - '@rollup/plugin-json': 6.0.0_rollup@3.10.1 - '@rollup/pluginutils': 5.0.2_rollup@3.10.1 + '@rollup/plugin-alias': 4.0.3_rollup@3.11.0 + '@rollup/plugin-json': 6.0.0_rollup@3.11.0 + '@rollup/pluginutils': 5.0.2_rollup@3.11.0 '@syuilo/aiscript': 0.12.2 - '@tabler/icons-webfont': 2.0.0 + '@tabler/icons-webfont': 2.1.2 '@vitejs/plugin-vue': 4.0.0_vite@4.0.4+vue@3.2.45 '@vue/compiler-sfc': 3.2.45 autobind-decorator: 2.4.0 @@ -496,7 +496,7 @@ importers: punycode: 2.3.0 querystring: 0.2.1 rndstr: 1.0.0 - rollup: 3.10.1 + rollup: 3.11.0 s-age: 1.1.2 sanitize-html: 2.8.1 sass: 1.57.1 @@ -505,7 +505,7 @@ importers: stringz: 2.1.0 syuilo-password-strength: 0.0.1 textarea-caret: 3.1.0 - three: 0.148.0 + three: 0.149.0 throttle-debounce: 5.0.0 tinycolor2: 1.5.2 tsc-alias: 1.8.2 @@ -537,7 +537,7 @@ importers: '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje '@vue/runtime-core': 3.2.45 cross-env: 7.0.3 - cypress: 12.3.0 + cypress: 12.4.0 eslint: 8.32.0 eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64 eslint-plugin-vue: 9.9.0_eslint@8.32.0 @@ -547,23 +547,23 @@ importers: packages/sw: specifiers: - '@typescript-eslint/parser': ^5.45.0 - '@typescript/lib-webworker': npm:@types/serviceworker@^0.0.58 - esbuild: ^0.14.42 - eslint: ^8.16.0 - eslint-plugin-import: ^2.26.0 - idb-keyval: ^6.1.0 + '@typescript-eslint/parser': ^5.49.0 + '@typescript/lib-webworker': npm:@types/serviceworker@0.0.61 + esbuild: ^0.17.4 + eslint: ^8.32.0 + eslint-plugin-import: ^2.27.5 + idb-keyval: ^6.2.0 misskey-js: 0.0.14 typescript: 4.9.4 dependencies: - esbuild: 0.14.54 + esbuild: 0.17.4 idb-keyval: 6.2.0 misskey-js: 0.0.14 devDependencies: - '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe - '@typescript/lib-webworker': /@types/serviceworker/0.0.58 - eslint: 8.31.0 - eslint-plugin-import: 2.27.4_qdjeohovcytra7xto5vgmxssaq + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje + '@typescript/lib-webworker': /@types/serviceworker/0.0.61 + eslint: 8.32.0 + eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64 typescript: 4.9.4 packages: @@ -922,8 +922,8 @@ packages: dependencies: '@bull-board/api': 4.11.0 '@bull-board/ui': 4.11.0 - '@fastify/static': 6.6.1 - '@fastify/view': 7.4.0 + '@fastify/static': 6.7.0 + '@fastify/view': 7.4.1 ejs: 3.1.8 transitivePeerDependencies: - supports-color @@ -1096,6 +1096,15 @@ packages: dev: false optional: true + /@esbuild/android-arm/0.17.4: + resolution: {integrity: sha512-R9GCe2xl2XDSc2XbQB63mFiFXHIVkOP+ltIxICKXqUPrFX97z6Z7vONCLQM1pSOLGqfLrGi3B7nbhxmFY/fomg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-arm64/0.16.17: resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} engines: {node: '>=12'} @@ -1105,6 +1114,15 @@ packages: dev: false optional: true + /@esbuild/android-arm64/0.17.4: + resolution: {integrity: sha512-91VwDrl4EpxBCiG6h2LZZEkuNvVZYJkv2T9gyLG/mhGG1qrM7i5SwUcg/hlSPnL/4hDT0TFcF35/XMGSn0bemg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-x64/0.16.17: resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} engines: {node: '>=12'} @@ -1114,6 +1132,15 @@ packages: dev: false optional: true + /@esbuild/android-x64/0.17.4: + resolution: {integrity: sha512-mGSqhEPL7029XL7QHNPxPs15JVa02hvZvysUcyMP9UXdGFwncl2WU0bqx+Ysgzd+WAbv8rfNa73QveOxAnAM2w==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-arm64/0.16.17: resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} engines: {node: '>=12'} @@ -1123,6 +1150,15 @@ packages: dev: false optional: true + /@esbuild/darwin-arm64/0.17.4: + resolution: {integrity: sha512-tTyJRM9dHvlMPt1KrBFVB5OW1kXOsRNvAPtbzoKazd5RhD5/wKlXk1qR2MpaZRYwf4WDMadt0Pv0GwxB41CVow==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-x64/0.16.17: resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} engines: {node: '>=12'} @@ -1132,6 +1168,15 @@ packages: dev: false optional: true + /@esbuild/darwin-x64/0.17.4: + resolution: {integrity: sha512-phQuC2Imrb3TjOJwLN8EO50nb2FHe8Ew0OwgZDH1SV6asIPGudnwTQtighDF2EAYlXChLoMJwqjAp4vAaACq6w==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-arm64/0.16.17: resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} engines: {node: '>=12'} @@ -1141,6 +1186,15 @@ packages: dev: false optional: true + /@esbuild/freebsd-arm64/0.17.4: + resolution: {integrity: sha512-oH6JUZkocgmjzzYaP5juERLpJQSwazdjZrTPgLRmAU2bzJ688x0vfMB/WTv4r58RiecdHvXOPC46VtsMy/mepg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-x64/0.16.17: resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} engines: {node: '>=12'} @@ -1150,6 +1204,15 @@ packages: dev: false optional: true + /@esbuild/freebsd-x64/0.17.4: + resolution: {integrity: sha512-U4iWGn/9TrAfpAdfd56eO0pRxIgb0a8Wj9jClrhT8hvZnOnS4dfMPW7o4fn15D/KqoiVYHRm43jjBaTt3g/2KA==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm/0.16.17: resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} engines: {node: '>=12'} @@ -1159,6 +1222,15 @@ packages: dev: false optional: true + /@esbuild/linux-arm/0.17.4: + resolution: {integrity: sha512-S2s9xWTGMTa/fG5EyMGDeL0wrWVgOSQcNddJWgu6rG1NCSXJHs76ZP9AsxjB3f2nZow9fWOyApklIgiTGZKhiw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm64/0.16.17: resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} engines: {node: '>=12'} @@ -1168,6 +1240,15 @@ packages: dev: false optional: true + /@esbuild/linux-arm64/0.17.4: + resolution: {integrity: sha512-UkGfQvYlwOaeYJzZG4cLV0hCASzQZnKNktRXUo3/BMZvdau40AOz9GzmGA063n1piq6VrFFh43apRDQx8hMP2w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ia32/0.16.17: resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} engines: {node: '>=12'} @@ -1177,10 +1258,10 @@ packages: dev: false optional: true - /@esbuild/linux-loong64/0.14.54: - resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} + /@esbuild/linux-ia32/0.17.4: + resolution: {integrity: sha512-3lqFi4VFo/Vwvn77FZXeLd0ctolIJH/uXkH3yNgEk89Eh6D3XXAC9/iTPEzeEpsNE5IqGIsFa5Z0iPeOh25IyA==} engines: {node: '>=12'} - cpu: [loong64] + cpu: [ia32] os: [linux] requiresBuild: true dev: false @@ -1195,6 +1276,15 @@ packages: dev: false optional: true + /@esbuild/linux-loong64/0.17.4: + resolution: {integrity: sha512-HqpWZkVslDHIwdQ9D+gk7NuAulgQvRxF9no54ut/M55KEb3mi7sQS3GwpPJzSyzzP0UkjQVN7/tbk88/CaX4EQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-mips64el/0.16.17: resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} engines: {node: '>=12'} @@ -1204,6 +1294,15 @@ packages: dev: false optional: true + /@esbuild/linux-mips64el/0.17.4: + resolution: {integrity: sha512-d/nMCKKh/SVDbqR9ju+b78vOr0tNXtfBjcp5vfHONCCOAL9ad8gN9dC/u+UnH939pz7wO+0u/x9y1MaZcb/lKA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ppc64/0.16.17: resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} engines: {node: '>=12'} @@ -1213,6 +1312,15 @@ packages: dev: false optional: true + /@esbuild/linux-ppc64/0.17.4: + resolution: {integrity: sha512-lOD9p2dmjZcNiTU+sGe9Nn6G3aYw3k0HBJies1PU0j5IGfp6tdKOQ6mzfACRFCqXjnBuTqK7eTYpwx09O5LLfg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-riscv64/0.16.17: resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} engines: {node: '>=12'} @@ -1222,6 +1330,15 @@ packages: dev: false optional: true + /@esbuild/linux-riscv64/0.17.4: + resolution: {integrity: sha512-mTGnwWwVshAjGsd8rP+K6583cPDgxOunsqqldEYij7T5/ysluMHKqUIT4TJHfrDFadUwrghAL6QjER4FeqQXoA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-s390x/0.16.17: resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} engines: {node: '>=12'} @@ -1231,6 +1348,15 @@ packages: dev: false optional: true + /@esbuild/linux-s390x/0.17.4: + resolution: {integrity: sha512-AQYuUGp50XM29/N/dehADxvc2bUqDcoqrVuijop1Wv72SyxT6dDB9wjUxuPZm2HwIM876UoNNBMVd+iX/UTKVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-x64/0.16.17: resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} engines: {node: '>=12'} @@ -1240,6 +1366,15 @@ packages: dev: false optional: true + /@esbuild/linux-x64/0.17.4: + resolution: {integrity: sha512-+AsFBwKgQuhV2shfGgA9YloxLDVjXgUEWZum7glR5lLmV94IThu/u2JZGxTgjYby6kyXEx8lKOqP5rTEVBR0Rw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/netbsd-x64/0.16.17: resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} engines: {node: '>=12'} @@ -1249,6 +1384,15 @@ packages: dev: false optional: true + /@esbuild/netbsd-x64/0.17.4: + resolution: {integrity: sha512-zD1TKYX9553OiLS/qkXPMlWoELYkH/VkzRYNKEU+GwFiqkq0SuxsKnsCg5UCdxN3cqd+1KZ8SS3R+WG/Hxy2jQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/openbsd-x64/0.16.17: resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} engines: {node: '>=12'} @@ -1258,6 +1402,15 @@ packages: dev: false optional: true + /@esbuild/openbsd-x64/0.17.4: + resolution: {integrity: sha512-PY1NjEsLRhPEFFg1AV0/4Or/gR+q2dOb9s5rXcPuCjyHRzbt8vnHJl3vYj+641TgWZzTFmSUnZbzs1zwTzjeqw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/sunos-x64/0.16.17: resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} engines: {node: '>=12'} @@ -1267,6 +1420,15 @@ packages: dev: false optional: true + /@esbuild/sunos-x64/0.17.4: + resolution: {integrity: sha512-B3Z7s8QZQW9tKGleMRXvVmwwLPAUoDCHs4WZ2ElVMWiortLJFowU1NjAhXOKjDgC7o9ByeVcwyOlJ+F2r6ZgmQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-arm64/0.16.17: resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} engines: {node: '>=12'} @@ -1276,6 +1438,15 @@ packages: dev: false optional: true + /@esbuild/win32-arm64/0.17.4: + resolution: {integrity: sha512-0HCu8R3mY/H5V7N6kdlsJkvrT591bO/oRZy8ztF1dhgNU5xD5tAh5bKByT1UjTGjp/VVBsl1PDQ3L18SfvtnBQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-ia32/0.16.17: resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} engines: {node: '>=12'} @@ -1285,6 +1456,15 @@ packages: dev: false optional: true + /@esbuild/win32-ia32/0.17.4: + resolution: {integrity: sha512-VUjhVDQycse1gLbe06pC/uaA0M+piQXJpdpNdhg8sPmeIZZqu5xPoGWVCmcsOO2gaM2cywuTYTHkXRozo3/Nkg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-x64/0.16.17: resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} engines: {node: '>=12'} @@ -1294,6 +1474,15 @@ packages: dev: false optional: true + /@esbuild/win32-x64/0.17.4: + resolution: {integrity: sha512-0kLAjs+xN5OjhTt/aUA6t48SfENSCKgGPfExADYTOo/UCn0ivxos9/anUVeSfg+L+2O9xkFxvJXIJfG+Q4sYSg==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@eslint/eslintrc/1.4.1: resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1422,8 +1611,8 @@ packages: - supports-color dev: false - /@fastify/static/6.6.1: - resolution: {integrity: sha512-sylhlmhclqwkyZy/SD5wzd4yjmMuqW8cRmfnuPXPhftZuEwJ8G2apm0kECQRnHJnk+W3Ksx2fpIHHcthzxNRTA==} + /@fastify/static/6.7.0: + resolution: {integrity: sha512-GYFDTSK83OL3mlzEDhgZXwFqPpGPiOsOr+dx63y2hcDF+NF4j1Ps2Swvmq/tMc5CFGoEDhkVN+P9fWG+/4a30Q==} dependencies: '@fastify/accept-negotiator': 1.0.0 '@fastify/send': 1.0.0 @@ -1436,8 +1625,8 @@ packages: - supports-color dev: false - /@fastify/view/7.4.0: - resolution: {integrity: sha512-0AzLsS7+Vbn2ElN2w1MqbHacecv4FJxWuiDg9LrqeWeG8suUIV5qBnF1ZGbf023NQUchgR++g2hY7uAyk5PaWA==} + /@fastify/view/7.4.1: + resolution: {integrity: sha512-ahmRmSbNVM8bIoz0BAFnY0jNigom+xbPQ9Q1ZjmNOtGVVT3nYXCxw2OMkTr9iXwrJ4Le3EtWDHlFkZ2fCQ2hJA==} dependencies: fastify-plugin: 4.5.0 hashlru: 2.3.0 @@ -1496,20 +1685,20 @@ packages: engines: {node: '>=8'} dev: true - /@jest/console/29.3.1: - resolution: {integrity: sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==} + /@jest/console/29.4.1: + resolution: {integrity: sha512-m+XpwKSi3PPM9znm5NGS8bBReeAJJpSkL1OuFCqaMaJL2YX9YXLkkI+MBchMPwu+ZuM2rynL51sgfkQteQ1CKQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 chalk: 4.1.2 - jest-message-util: 29.3.1 - jest-util: 29.3.1 + jest-message-util: 29.4.1 + jest-util: 29.4.1 slash: 3.0.0 dev: true - /@jest/core/29.3.1: - resolution: {integrity: sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==} + /@jest/core/29.4.1: + resolution: {integrity: sha512-RXFTohpBqpaTebNdg5l3I5yadnKo9zLBajMT0I38D0tDhreVBYv3fA8kywthI00sWxPztWLD3yjiUkewwu/wKA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -1517,32 +1706,32 @@ packages: node-notifier: optional: true dependencies: - '@jest/console': 29.3.1 - '@jest/reporters': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 + '@jest/console': 29.4.1 + '@jest/reporters': 29.4.1 + '@jest/test-result': 29.4.1 + '@jest/transform': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.10 - jest-changed-files: 29.2.0 - jest-config: 29.3.1_@types+node@18.11.18 - jest-haste-map: 29.3.1 - jest-message-util: 29.3.1 + jest-changed-files: 29.4.0 + jest-config: 29.4.1_@types+node@18.11.18 + jest-haste-map: 29.4.1 + jest-message-util: 29.4.1 jest-regex-util: 29.2.0 - jest-resolve: 29.3.1 - jest-resolve-dependencies: 29.3.1 - jest-runner: 29.3.1 - jest-runtime: 29.3.1 - jest-snapshot: 29.3.1 - jest-util: 29.3.1 - jest-validate: 29.3.1 - jest-watcher: 29.3.1 + jest-resolve: 29.4.1 + jest-resolve-dependencies: 29.4.1 + jest-runner: 29.4.1 + jest-runtime: 29.4.1 + jest-snapshot: 29.4.1 + jest-util: 29.4.1 + jest-validate: 29.4.1 + jest-watcher: 29.4.1 micromatch: 4.0.5 - pretty-format: 29.3.1 + pretty-format: 29.4.1 slash: 3.0.0 strip-ansi: 6.0.1 transitivePeerDependencies: @@ -1557,14 +1746,14 @@ packages: '@jest/types': 27.5.1 dev: true - /@jest/environment/29.3.1: - resolution: {integrity: sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==} + /@jest/environment/29.4.1: + resolution: {integrity: sha512-pJ14dHGSQke7Q3mkL/UZR9ZtTOxqskZaC91NzamEH4dlKRt42W+maRBXiw/LWkdJe+P0f/zDR37+SPMplMRlPg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/fake-timers': 29.3.1 - '@jest/types': 29.3.1 + '@jest/fake-timers': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 - jest-mock: 29.3.1 + jest-mock: 29.4.1 dev: true /@jest/expect-utils/29.3.1: @@ -1574,42 +1763,49 @@ packages: jest-get-type: 29.2.0 dev: true - /@jest/expect/29.3.1: - resolution: {integrity: sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==} + /@jest/expect-utils/29.4.1: + resolution: {integrity: sha512-w6YJMn5DlzmxjO00i9wu2YSozUYRBhIoJ6nQwpMYcBMtiqMGJm1QBzOf6DDgRao8dbtpDoaqLg6iiQTvv0UHhQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - expect: 29.3.1 - jest-snapshot: 29.3.1 + jest-get-type: 29.2.0 + dev: true + + /@jest/expect/29.4.1: + resolution: {integrity: sha512-ZxKJP5DTUNF2XkpJeZIzvnzF1KkfrhEF6Rz0HGG69fHl6Bgx5/GoU3XyaeFYEjuuKSOOsbqD/k72wFvFxc3iTw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.4.1 + jest-snapshot: 29.4.1 transitivePeerDependencies: - supports-color dev: true - /@jest/fake-timers/29.3.1: - resolution: {integrity: sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==} + /@jest/fake-timers/29.4.1: + resolution: {integrity: sha512-/1joI6rfHFmmm39JxNfmNAO3Nwm6Y0VoL5fJDy7H1AtWrD1CgRtqJbN9Ld6rhAkGO76qqp4cwhhxJ9o9kYjQMw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 - '@sinonjs/fake-timers': 9.1.2 + '@jest/types': 29.4.1 + '@sinonjs/fake-timers': 10.0.2 '@types/node': 18.11.18 - jest-message-util: 29.3.1 - jest-mock: 29.3.1 - jest-util: 29.3.1 + jest-message-util: 29.4.1 + jest-mock: 29.4.1 + jest-util: 29.4.1 dev: true - /@jest/globals/29.3.1: - resolution: {integrity: sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==} + /@jest/globals/29.4.1: + resolution: {integrity: sha512-znoK2EuFytbHH0ZSf2mQK2K1xtIgmaw4Da21R2C/NE/+NnItm5mPEFQmn8gmF3f0rfOlmZ3Y3bIf7bFj7DHxAA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/environment': 29.3.1 - '@jest/expect': 29.3.1 - '@jest/types': 29.3.1 - jest-mock: 29.3.1 + '@jest/environment': 29.4.1 + '@jest/expect': 29.4.1 + '@jest/types': 29.4.1 + jest-mock: 29.4.1 transitivePeerDependencies: - supports-color dev: true - /@jest/reporters/29.3.1: - resolution: {integrity: sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==} + /@jest/reporters/29.4.1: + resolution: {integrity: sha512-AISY5xpt2Xpxj9R6y0RF1+O6GRy9JsGa8+vK23Lmzdy1AYcpQn5ItX79wJSsTmfzPKSAcsY1LNt/8Y5Xe5LOSg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -1618,10 +1814,10 @@ packages: optional: true dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 + '@jest/console': 29.4.1 + '@jest/test-result': 29.4.1 + '@jest/transform': 29.4.1 + '@jest/types': 29.4.1 '@jridgewell/trace-mapping': 0.3.17 '@types/node': 18.11.18 chalk: 4.1.2 @@ -1634,9 +1830,9 @@ packages: istanbul-lib-report: 3.0.0 istanbul-lib-source-maps: 4.0.1 istanbul-reports: 3.1.5 - jest-message-util: 29.3.1 - jest-util: 29.3.1 - jest-worker: 29.3.1 + jest-message-util: 29.4.1 + jest-util: 29.4.1 + jest-worker: 29.4.1 slash: 3.0.0 string-length: 4.0.2 strip-ansi: 6.0.1 @@ -1652,6 +1848,13 @@ packages: '@sinclair/typebox': 0.24.51 dev: true + /@jest/schemas/29.4.0: + resolution: {integrity: sha512-0E01f/gOZeNTG76i5eWWSupvSHaIINrTie7vCyjiYFKgzNdyEGd12BUv4oNBFHOqlHDbtoJi3HrQ38KCC90NsQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.25.21 + dev: true + /@jest/source-map/29.2.0: resolution: {integrity: sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1661,45 +1864,45 @@ packages: graceful-fs: 4.2.10 dev: true - /@jest/test-result/29.3.1: - resolution: {integrity: sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==} + /@jest/test-result/29.4.1: + resolution: {integrity: sha512-WRt29Lwt+hEgfN8QDrXqXGgCTidq1rLyFqmZ4lmJOpVArC8daXrZWkWjiaijQvgd3aOUj2fM8INclKHsQW9YyQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/console': 29.3.1 - '@jest/types': 29.3.1 + '@jest/console': 29.4.1 + '@jest/types': 29.4.1 '@types/istanbul-lib-coverage': 2.0.4 collect-v8-coverage: 1.0.1 dev: true - /@jest/test-sequencer/29.3.1: - resolution: {integrity: sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==} + /@jest/test-sequencer/29.4.1: + resolution: {integrity: sha512-v5qLBNSsM0eHzWLXsQ5fiB65xi49A3ILPSFQKPXzGL4Vyux0DPZAIN7NAFJa9b4BiTDP9MBF/Zqc/QA1vuiJ0w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/test-result': 29.3.1 + '@jest/test-result': 29.4.1 graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 + jest-haste-map: 29.4.1 slash: 3.0.0 dev: true - /@jest/transform/29.3.1: - resolution: {integrity: sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==} + /@jest/transform/29.4.1: + resolution: {integrity: sha512-5w6YJrVAtiAgr0phzKjYd83UPbCXsBRTeYI4BXokv9Er9CcrH9hfXL/crCvP2d2nGOcovPUnlYiLPFLZrkG5Hg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/core': 7.20.12 - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 '@jridgewell/trace-mapping': 0.3.17 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 + jest-haste-map: 29.4.1 jest-regex-util: 29.2.0 - jest-util: 29.3.1 + jest-util: 29.4.1 micromatch: 4.0.5 pirates: 4.0.5 slash: 3.0.0 - write-file-atomic: 4.0.2 + write-file-atomic: 5.0.0 transitivePeerDependencies: - supports-color dev: true @@ -1715,11 +1918,11 @@ packages: chalk: 4.1.2 dev: true - /@jest/types/29.3.1: - resolution: {integrity: sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==} + /@jest/types/29.4.1: + resolution: {integrity: sha512-zbrAXDUOnpJ+FMST2rV7QZOgec8rskg2zv8g2ajeqitp4tvZiyqTCYXANrKsM+ryj5o+LI+ZN2EgU9drrkiwSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/schemas': 29.0.0 + '@jest/schemas': 29.4.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 '@types/node': 18.11.18 @@ -2055,7 +2258,7 @@ packages: - encoding dev: true - /@rollup/plugin-alias/4.0.3_rollup@3.10.1: + /@rollup/plugin-alias/4.0.3_rollup@3.11.0: resolution: {integrity: sha512-ZuDWE1q4PQDhvm/zc5Prun8sBpLJy41DMptYrS6MhAy9s9kL/doN1613BWfEchGVfKxzliJ3BjbOPizXX38DbQ==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2064,11 +2267,11 @@ packages: rollup: optional: true dependencies: - rollup: 3.10.1 + rollup: 3.11.0 slash: 4.0.0 dev: false - /@rollup/plugin-json/6.0.0_rollup@3.10.1: + /@rollup/plugin-json/6.0.0_rollup@3.11.0: resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2077,11 +2280,11 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2_rollup@3.10.1 - rollup: 3.10.1 + '@rollup/pluginutils': 5.0.2_rollup@3.11.0 + rollup: 3.11.0 dev: false - /@rollup/pluginutils/5.0.2_rollup@3.10.1: + /@rollup/pluginutils/5.0.2_rollup@3.11.0: resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -2093,7 +2296,7 @@ packages: '@types/estree': 1.0.0 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 3.10.1 + rollup: 3.11.0 dev: false /@sideway/address/4.1.4: @@ -2114,6 +2317,10 @@ packages: resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} dev: true + /@sinclair/typebox/0.25.21: + resolution: {integrity: sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g==} + dev: true + /@sindresorhus/is/0.7.0: resolution: {integrity: sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==} engines: {node: '>=4'} @@ -2129,35 +2336,21 @@ packages: engines: {node: '>=14.16'} dev: false - /@sinonjs/commons/1.8.6: - resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - dependencies: - type-detect: 4.0.8 - dev: true - /@sinonjs/commons/2.0.0: resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} dependencies: type-detect: 4.0.8 - dev: false /@sinonjs/fake-timers/10.0.2: resolution: {integrity: sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==} dependencies: '@sinonjs/commons': 2.0.0 - dev: false - - /@sinonjs/fake-timers/9.1.2: - resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} - dependencies: - '@sinonjs/commons': 1.8.6 - dev: true /@sqltools/formatter/1.2.5: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@swc/cli/0.1.59_2w2rsb5d2wh3txrlxuiknf4vra: + /@swc/cli/0.1.59_dbbgdut2njxjatv5n3st5z6gqa: resolution: {integrity: sha512-BlX3wIxYTwdtR22dIqZ3FEIOJPqnlByAp4JY46OMZi2UXMB3ZbOzefawD2ZlLafRUWyy5NtiZZty5waKzaYRnA==} engines: {node: '>= 12.13'} hasBin: true @@ -2168,7 +2361,7 @@ packages: chokidar: optional: true dependencies: - '@swc/core': 1.3.27 + '@swc/core': 1.3.29 bin-wrapper: 4.1.0 chokidar: 3.5.3 commander: 7.2.0 @@ -2178,8 +2371,8 @@ packages: source-map: 0.7.4 dev: true - /@swc/core-darwin-arm64/1.3.27: - resolution: {integrity: sha512-IKlxkhEy99CnP9nduaf5IJWIFcr6D5cZCjYmCs7nWkjMV+aAieyDO9AX4LT8AcHy6CF7ByOX7SKoqk+gVMAaKw==} + /@swc/core-darwin-arm64/1.3.29: + resolution: {integrity: sha512-1RQ0MCmWOQmo3qG60vhbNaO/qMZ25lDfjhTayAzHjS1k7WyoUv3M8Em2Fip2VKJz5cN2M7MWiP5aHMotMovuaQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] @@ -2187,8 +2380,8 @@ packages: dev: true optional: true - /@swc/core-darwin-x64/1.3.27: - resolution: {integrity: sha512-MtabZIhFf/dL3vs6UMbd+vJsjIkm2NaFqulGV0Jofy2bfVZPTj/b5pXeOlUsTWy7JcH1uixjdx4RvJRyvqJxQA==} + /@swc/core-darwin-x64/1.3.29: + resolution: {integrity: sha512-UXiVOkt9i/mwarhHiN6o5RAi3Q7riCQTiOO2e98c/qi3SiYqbgd6kil+2gBcpVB0CGEFyyGB9rECwNBkaYe7zw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -2196,8 +2389,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm-gnueabihf/1.3.27: - resolution: {integrity: sha512-XELMoGcUTAkk+G4buwIIhu6AIr1U418Odt22HUW8+ZvV+Wty2ICgR/myOIhM3xMb6U2L8ay+evMqoVNMQ0RRTg==} + /@swc/core-linux-arm-gnueabihf/1.3.29: + resolution: {integrity: sha512-0B7+FoYgEE1Yg6j5EAtEpKVbHby3jnJo6Y4g0dGxecRtXUhu8TKVI4P93sj4PJ+l4XkAyzdhSsQ+ytFRsbOJ6w==} engines: {node: '>=10'} cpu: [arm] os: [linux] @@ -2205,8 +2398,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-gnu/1.3.27: - resolution: {integrity: sha512-O6vtT6bnrVR9PzEIuA5U7tIfYo7bv97H9K9Vqy2oyHNeGN0H36DKwS4UqPreHtziXNF5+7ubdUYUkrG/j8UnUQ==} + /@swc/core-linux-arm64-gnu/1.3.29: + resolution: {integrity: sha512-XN9axiTuiFOm+UBnDDOQV3b2OekziXHtVPBAPSEssRsNGS4uN7YvCyVAcS8GYdK7GoZ+cmoZBYwD4trir48WXw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -2214,8 +2407,8 @@ packages: dev: true optional: true - /@swc/core-linux-arm64-musl/1.3.27: - resolution: {integrity: sha512-Oa0E1i7dOTWpaEZumKoNbTE/Ap+da6nlhqKVUdYrFDrOBi25tz76SdxZIyvAszzmgY89b5yd1naourKmkPXpww==} + /@swc/core-linux-arm64-musl/1.3.29: + resolution: {integrity: sha512-M6eE02Dzl1efRLozitGvgjiNEee0VQInqMX4tvfpzQwqZsKNAD8/NGPeTG4763BLDHc4hnMZbnt5wncDLjFq7A==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -2223,8 +2416,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-gnu/1.3.27: - resolution: {integrity: sha512-S3v9H8oL2a8Ur6AjQyhkC6HfBVPOxKMdBhcZmdNuVgEUHbHdbf/Lka85F9IOYXEarMn0FtQw3ywowS22O9L5Uw==} + /@swc/core-linux-x64-gnu/1.3.29: + resolution: {integrity: sha512-t2e9byHRpxKyUsLeODlb3yKJcm8wMirsLIxjr24q5YbnChD3QUMQwA8aA9w2PWc86ihukw7Ksx3RYT7uR706HA==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -2232,8 +2425,8 @@ packages: dev: true optional: true - /@swc/core-linux-x64-musl/1.3.27: - resolution: {integrity: sha512-6DDkdXlOADpwICFZTRphCR+cIeS8aEYh4NlyzBito0mOWwIIdfCgALzhkTQOzTOkcD42bP97CIoZ97hqV/puOg==} + /@swc/core-linux-x64-musl/1.3.29: + resolution: {integrity: sha512-3jDzDYIyHXrXKOSnTtsN56eINbTPuVQj65D3K8+zo1o52GGwNGyCvQt2RpxNfM8+ptb4j6v7weSU8kVvbUzGTQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -2241,8 +2434,8 @@ packages: dev: true optional: true - /@swc/core-win32-arm64-msvc/1.3.27: - resolution: {integrity: sha512-baxfH4AbEcaTNo08wxV0W6hiMXwVCxPS4qc0amHpXPti92unvSqeDR1W3C9GjHqzXlWtmCRsq8Ww1pal6ZVLrw==} + /@swc/core-win32-arm64-msvc/1.3.29: + resolution: {integrity: sha512-3PadPieyslG++7SQ42OApfiXtQdzFpnCv/i/UJ6gOL5d0MluNzZ2nIxD8LwXXizVdmcm8bmc0WRhK3JhvhzVJA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] @@ -2250,8 +2443,8 @@ packages: dev: true optional: true - /@swc/core-win32-ia32-msvc/1.3.27: - resolution: {integrity: sha512-7iLJnH71k5qCwxv9NcM/P7nIEzTsC7r1sIiQW6bu+CpC8qZvwl0PS+XvQRlLly2gCZM+Le98tksYG14MEh+Hrw==} + /@swc/core-win32-ia32-msvc/1.3.29: + resolution: {integrity: sha512-tUFrHxxYz9Cfz07yGwDXdtRziC3q1ia2SHodzZ3obTpY+HQiBDHs0QO/HkbUBNF+du0vhnsgtWilnsMQDILFDQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] @@ -2259,8 +2452,8 @@ packages: dev: true optional: true - /@swc/core-win32-x64-msvc/1.3.27: - resolution: {integrity: sha512-mFM907PDw/jrQ44+TRjIVGEOy2Mu06mMMz0HPMFuRsBzl5t0Kajp3vmn8FkkpS9wH5982VPi6hPYVTb7QJo5Qg==} + /@swc/core-win32-x64-msvc/1.3.29: + resolution: {integrity: sha512-/Z3kxMXGKlIhtkxBxsCSZl8j/qYfbA4dtW7RKv1RNxbPLbwk8k3Owhgk/Y3JeRavcUKwja1rUX5rhMjLYeN3tw==} engines: {node: '>=10'} cpu: [x64] os: [win32] @@ -2268,31 +2461,31 @@ packages: dev: true optional: true - /@swc/core/1.3.27: - resolution: {integrity: sha512-praRNgpeYGvwDIm/Cl6JU+yHMvwVraL0U6ejMgGyzvpcm1FVsZd1/EYXGqzbBJ0ALv7Gx4eK56h4GnwV6d4L0w==} + /@swc/core/1.3.29: + resolution: {integrity: sha512-BYDBEqQ77ASZNQYTP7PlKnMLwbHh3lhtlzD/gQP2zIK9XhqQlcy/zIcLljYDn0EOogLn3IyaUiXgAzDWoAmWMg==} engines: {node: '>=10'} requiresBuild: true optionalDependencies: - '@swc/core-darwin-arm64': 1.3.27 - '@swc/core-darwin-x64': 1.3.27 - '@swc/core-linux-arm-gnueabihf': 1.3.27 - '@swc/core-linux-arm64-gnu': 1.3.27 - '@swc/core-linux-arm64-musl': 1.3.27 - '@swc/core-linux-x64-gnu': 1.3.27 - '@swc/core-linux-x64-musl': 1.3.27 - '@swc/core-win32-arm64-msvc': 1.3.27 - '@swc/core-win32-ia32-msvc': 1.3.27 - '@swc/core-win32-x64-msvc': 1.3.27 - dev: true - - /@swc/jest/0.2.24_@swc+core@1.3.27: + '@swc/core-darwin-arm64': 1.3.29 + '@swc/core-darwin-x64': 1.3.29 + '@swc/core-linux-arm-gnueabihf': 1.3.29 + '@swc/core-linux-arm64-gnu': 1.3.29 + '@swc/core-linux-arm64-musl': 1.3.29 + '@swc/core-linux-x64-gnu': 1.3.29 + '@swc/core-linux-x64-musl': 1.3.29 + '@swc/core-win32-arm64-msvc': 1.3.29 + '@swc/core-win32-ia32-msvc': 1.3.29 + '@swc/core-win32-x64-msvc': 1.3.29 + dev: true + + /@swc/jest/0.2.24_@swc+core@1.3.29: resolution: {integrity: sha512-fwgxQbM1wXzyKzl1+IW0aGrRvAA8k0Y3NxFhKigbPjOJ4mCKnWEcNX9HQS3gshflcxq8YKhadabGUVfdwjCr6Q==} engines: {npm: '>= 7.0.0'} peerDependencies: '@swc/core': '*' dependencies: '@jest/create-cache-key-function': 27.5.1 - '@swc/core': 1.3.27 + '@swc/core': 1.3.29 jsonc-parser: 3.2.0 dev: true @@ -2319,14 +2512,14 @@ packages: defer-to-connect: 2.0.1 dev: false - /@tabler/icons-webfont/2.0.0: - resolution: {integrity: sha512-ApVVupe7WKZOJzK6T2iw15/k6VrTALsL5YzAmvgvcriuX8sRCKlcWaRljcf2sZMUrqyY+Yq6xiOpL2p2NHgQBQ==} + /@tabler/icons-webfont/2.1.2: + resolution: {integrity: sha512-UoLIUeaZSDH4ORAbxvt/jO3RZ4AjaNV/qw7LXMWmEfsDUY3teaB4xrwW1WkyMqMU1HjkX5dR1z7P8Ajxxucjyw==} dependencies: - '@tabler/icons': 2.0.0 + '@tabler/icons': 2.1.2 dev: false - /@tabler/icons/2.0.0: - resolution: {integrity: sha512-ye93cVD8baCwJJ7J3GKlUM3FN+qW6lsEz4uaH8bHCwC8un2R4p+ZzyRNc/ksqVgMQJ4PKQ8xbYpv4dnbbRffsA==} + /@tabler/icons/2.1.2: + resolution: {integrity: sha512-+CPB+BSqVDP4+/d+cHSaGwG460C3sob7EJkQ+ZS8xV6bRER64OsCP92O7M+uYBhJFDWuf6poCeSETNZNcFa2nA==} dev: false /@tensorflow/tfjs-backend-cpu/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: @@ -2624,8 +2817,8 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest/29.2.6: - resolution: {integrity: sha512-XEUC/Tgw3uMh6Ho8GkUtQ2lPhY5Fmgyp3TdlkTJs1W9VgNxs+Ow/x3Elh8lHQKqCbZL0AubQuqWjHVT033Hhrw==} + /@types/jest/29.4.0: + resolution: {integrity: sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==} dependencies: expect: 29.3.1 pretty-format: 29.3.1 @@ -2655,8 +2848,8 @@ packages: resolution: {integrity: sha512-4l5t/jDnJpqZ+i7CLTTgPcT5BYXnAnwJupb07aAokPufCV0SjDHcwctUkSTuhIuSU9yHok+WOOngIGCtpL96gw==} dev: true - /@types/jsrsasign/10.5.4: - resolution: {integrity: sha512-05S2f4lGaWgCwFHsa3OEirc4VJf/sJRfhofzxUbuFbmm6NbffPXZrnJqquQAtS3g4C8Z0L9NHgW0znmtDxNoTQ==} + /@types/jsrsasign/10.5.5: + resolution: {integrity: sha512-M2Et4hgTigFoArTu6ylK3hYFEH+UuXfgFXRXZ+flpCfux8j7fQ2D+0zEwiu6ehx0h5otaauhLSFzMzEtNA784A==} dev: true /@types/keyv/3.1.4: @@ -2793,8 +2986,8 @@ packages: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true - /@types/serviceworker/0.0.58: - resolution: {integrity: sha512-bFRpZYjYbEgfPYBVR9Vfn/95ao7PvXCjQy6Eh1rbPnZBbTPpQlurLAciLF8qWN54F0WoVwE5xcaJPeDRdLGivg==} + /@types/serviceworker/0.0.61: + resolution: {integrity: sha512-j/FCintE+6dLM4Wyej1OMTPJy8rBHOmZ9O4XgEy9OQ4B7SfAHwWEZQQk/PXuBl/tFyE+r87eOm+x+wQiiiHIag==} dev: true /@types/sharp/0.31.1: @@ -2960,26 +3153,6 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.48.1_iukboom6ndih5an6iafl45j2fe: - resolution: {integrity: sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 5.48.1 - '@typescript-eslint/types': 5.48.1 - '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4 - debug: 4.3.4 - eslint: 8.31.0 - typescript: 4.9.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser/5.49.0_7uibuqfxkfaozanbtbziikiqje: resolution: {integrity: sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3000,14 +3173,6 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager/5.48.1: - resolution: {integrity: sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.48.1 - '@typescript-eslint/visitor-keys': 5.48.1 - dev: true - /@typescript-eslint/scope-manager/5.49.0: resolution: {integrity: sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3036,37 +3201,11 @@ packages: - supports-color dev: true - /@typescript-eslint/types/5.48.1: - resolution: {integrity: sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/types/5.49.0: resolution: {integrity: sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.48.1_typescript@4.9.4: - resolution: {integrity: sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.48.1 - '@typescript-eslint/visitor-keys': 5.48.1 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.4 - typescript: 4.9.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree/5.49.0_typescript@4.9.4: resolution: {integrity: sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3108,14 +3247,6 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys/5.48.1: - resolution: {integrity: sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.48.1 - eslint-visitor-keys: 3.3.0 - dev: true - /@typescript-eslint/visitor-keys/5.49.0: resolution: {integrity: sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3813,17 +3944,17 @@ packages: - debug dev: true - /babel-jest/29.3.1_@babel+core@7.20.12: - resolution: {integrity: sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==} + /babel-jest/29.4.1_@babel+core@7.20.12: + resolution: {integrity: sha512-xBZa/pLSsF/1sNpkgsiT3CmY7zV1kAsZ9OxxtrFqYucnOuRftXAfcJqcDVyOPeN4lttWTwhLdu0T9f8uvoPEUg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: '@babel/core': 7.20.12 - '@jest/transform': 29.3.1 + '@jest/transform': 29.4.1 '@types/babel__core': 7.1.20 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.2.0_@babel+core@7.20.12 + babel-preset-jest: 29.4.0_@babel+core@7.20.12 chalk: 4.1.2 graceful-fs: 4.2.10 slash: 3.0.0 @@ -3844,8 +3975,8 @@ packages: - supports-color dev: true - /babel-plugin-jest-hoist/29.2.0: - resolution: {integrity: sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==} + /babel-plugin-jest-hoist/29.4.0: + resolution: {integrity: sha512-a/sZRLQJEmsmejQ2rPEUe35nO1+C9dc9O1gplH1SXmJxveQSRUYdBk8yGZG/VOUuZs1u2aHZJusEGoRMbhhwCg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/template': 7.20.7 @@ -3874,14 +4005,14 @@ packages: '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.20.12 dev: true - /babel-preset-jest/29.2.0_@babel+core@7.20.12: - resolution: {integrity: sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==} + /babel-preset-jest/29.4.0_@babel+core@7.20.12: + resolution: {integrity: sha512-fUB9vZflUSM3dO/6M2TCAepTzvA4VkOvl67PjErcrQMGt9Eve7uazaeyCZ2th3UtI7ljpiBJES0F7A1vBRsLZA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.20.12 - babel-plugin-jest-hoist: 29.2.0 + babel-plugin-jest-hoist: 29.4.0 babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.12 dev: true @@ -5078,8 +5209,8 @@ packages: uniq: 1.0.1 dev: false - /cypress/12.3.0: - resolution: {integrity: sha512-ZQNebibi6NBt51TRxRMYKeFvIiQZ01t50HSy7z/JMgRVqBUey3cdjog5MYEbzG6Ktti5ckDt1tfcC47lmFwXkw==} + /cypress/12.4.0: + resolution: {integrity: sha512-//h93K/yGC/7pxv1KamlkADbKHLp5h3f9rZDE2McRjXZDagMETH0sXowOOanvhsH8cFt/JWspIcK+p9cuaoAqg==} engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} hasBin: true requiresBuild: true @@ -5715,281 +5846,72 @@ packages: object-inspect: 1.12.2 object-keys: 1.1.1 object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 - safe-regex-test: 1.0.0 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - unbox-primitive: 1.0.2 - dev: true - - /es-shim-unscopables/1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - dependencies: - has: 1.0.3 - dev: true - - /es-to-primitive/1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - dev: true - - /es5-ext/0.10.62: - resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} - engines: {node: '>=0.10'} - requiresBuild: true - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - next-tick: 1.1.0 - dev: false - - /es6-iterator/2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - dependencies: - d: 1.0.1 - es5-ext: 0.10.62 - es6-symbol: 3.1.3 - dev: false - - /es6-promise/4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - dev: false - optional: true - - /es6-promisify/5.0.0: - resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - dependencies: - es6-promise: 4.2.8 - dev: false - optional: true - - /es6-symbol/3.1.3: - resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} - dependencies: - d: 1.0.1 - ext: 1.7.0 - dev: false - - /es6-weak-map/2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - dependencies: - d: 1.0.1 - es5-ext: 0.10.62 - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - dev: false - - /esbuild-android-64/0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: false - optional: true - - /esbuild-android-arm64/0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: false - optional: true - - /esbuild-darwin-64/0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - - /esbuild-darwin-arm64/0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - - /esbuild-freebsd-64/0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: false - optional: true - - /esbuild-freebsd-arm64/0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-32/0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-64/0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-arm/0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-arm64/0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-mips64le/0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-ppc64le/0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /esbuild-linux-riscv64/0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: false - optional: true + regexp.prototype.flags: 1.4.3 + safe-regex-test: 1.0.0 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + unbox-primitive: 1.0.2 + dev: true - /esbuild-linux-s390x/0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: false - optional: true + /es-shim-unscopables/1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + dependencies: + has: 1.0.3 + dev: true - /esbuild-netbsd-64/0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: false - optional: true + /es-to-primitive/1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: true - /esbuild-openbsd-64/0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] + /es5-ext/0.10.62: + resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} + engines: {node: '>=0.10'} requiresBuild: true + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 + next-tick: 1.1.0 dev: false - optional: true - /esbuild-sunos-64/0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true + /es6-iterator/2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-symbol: 3.1.3 dev: false - optional: true - /esbuild-windows-32/0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true + /es6-promise/4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} dev: false optional: true - /esbuild-windows-64/0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true + /es6-promisify/5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + dependencies: + es6-promise: 4.2.8 dev: false optional: true - /esbuild-windows-arm64/0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true + /es6-symbol/3.1.3: + resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} + dependencies: + d: 1.0.1 + ext: 1.7.0 dev: false - optional: true - /esbuild/0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/linux-loong64': 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 + /es6-weak-map/2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + dependencies: + d: 1.0.1 + es5-ext: 0.10.62 + es6-iterator: 2.0.3 + es6-symbol: 3.1.3 dev: false /esbuild/0.16.17: @@ -6022,6 +5944,36 @@ packages: '@esbuild/win32-x64': 0.16.17 dev: false + /esbuild/0.17.4: + resolution: {integrity: sha512-zBn9MeCwT7W5F1a3lXClD61ip6vQM+H8Msb0w8zMT4ZKBpDg+rFAraNyWCDelB/2L6M3g6AXHPnsyvjMFnxtFw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.17.4 + '@esbuild/android-arm64': 0.17.4 + '@esbuild/android-x64': 0.17.4 + '@esbuild/darwin-arm64': 0.17.4 + '@esbuild/darwin-x64': 0.17.4 + '@esbuild/freebsd-arm64': 0.17.4 + '@esbuild/freebsd-x64': 0.17.4 + '@esbuild/linux-arm': 0.17.4 + '@esbuild/linux-arm64': 0.17.4 + '@esbuild/linux-ia32': 0.17.4 + '@esbuild/linux-loong64': 0.17.4 + '@esbuild/linux-mips64el': 0.17.4 + '@esbuild/linux-ppc64': 0.17.4 + '@esbuild/linux-riscv64': 0.17.4 + '@esbuild/linux-s390x': 0.17.4 + '@esbuild/linux-x64': 0.17.4 + '@esbuild/netbsd-x64': 0.17.4 + '@esbuild/openbsd-x64': 0.17.4 + '@esbuild/sunos-x64': 0.17.4 + '@esbuild/win32-arm64': 0.17.4 + '@esbuild/win32-ia32': 0.17.4 + '@esbuild/win32-x64': 0.17.4 + dev: false + /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -6099,68 +6051,6 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_sqt5xxn4ciiurbqrzlaarm6ama: - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe - debug: 3.2.7 - eslint: 8.31.0 - eslint-import-resolver-node: 0.3.7 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-import/2.27.4_qdjeohovcytra7xto5vgmxssaq: - resolution: {integrity: sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.31.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4_sqt5xxn4ciiurbqrzlaarm6ama - has: 1.0.3 - is-core-module: 2.11.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.1 - semver: 6.3.0 - tsconfig-paths: 3.14.1 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-plugin-import/2.27.5_6savw6y3b7jng6f64kgkyoij64: resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} @@ -6228,16 +6118,6 @@ packages: estraverse: 5.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.31.0: - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.31.0 - eslint-visitor-keys: 2.1.0 - dev: true - /eslint-utils/3.0.0_eslint@8.32.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} @@ -6258,54 +6138,6 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.31.0: - resolution: {integrity: sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint/eslintrc': 1.4.1 - '@humanwhocodes/config-array': 0.11.8 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.31.0 - eslint-visitor-keys: 3.3.0 - espree: 9.4.1 - esquery: 1.4.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.19.0 - grapheme-splitter: 1.0.4 - ignore: 5.2.4 - import-fresh: 3.3.0 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-sdsl: 4.2.0 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.1 - regexpp: 3.2.0 - strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - /eslint/8.32.0: resolution: {integrity: sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6565,7 +6397,18 @@ packages: jest-get-type: 29.2.0 jest-matcher-utils: 29.3.1 jest-message-util: 29.3.1 - jest-util: 29.3.1 + jest-util: 29.4.1 + dev: true + + /expect/29.4.1: + resolution: {integrity: sha512-OKrGESHOaMxK3b6zxIq9SOW8kEXztKff/Dvg88j4xIJxur1hspEbedVkR3GpHe5LO+WB2Qw7OWN0RMTdp6as5A==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.4.1 + jest-get-type: 29.2.0 + jest-matcher-utils: 29.4.1 + jest-message-util: 29.4.1 + jest-util: 29.4.1 dev: true /ext-list/2.2.2: @@ -8598,43 +8441,43 @@ packages: minimatch: 3.1.2 dev: false - /jest-changed-files/29.2.0: - resolution: {integrity: sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==} + /jest-changed-files/29.4.0: + resolution: {integrity: sha512-rnI1oPxgFghoz32Y8eZsGJMjW54UlqT17ycQeCEktcxxwqqKdlj9afl8LNeO0Pbu+h2JQHThQP0BzS67eTRx4w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: execa: 5.1.1 p-limit: 3.1.0 dev: true - /jest-circus/29.3.1: - resolution: {integrity: sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==} + /jest-circus/29.4.1: + resolution: {integrity: sha512-v02NuL5crMNY4CGPHBEflLzl4v91NFb85a+dH9a1pUNx6Xjggrd8l9pPy4LZ1VYNRXlb+f65+7O/MSIbLir6pA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/environment': 29.3.1 - '@jest/expect': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/types': 29.3.1 + '@jest/environment': 29.4.1 + '@jest/expect': 29.4.1 + '@jest/test-result': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 is-generator-fn: 2.1.0 - jest-each: 29.3.1 - jest-matcher-utils: 29.3.1 - jest-message-util: 29.3.1 - jest-runtime: 29.3.1 - jest-snapshot: 29.3.1 - jest-util: 29.3.1 + jest-each: 29.4.1 + jest-matcher-utils: 29.4.1 + jest-message-util: 29.4.1 + jest-runtime: 29.4.1 + jest-snapshot: 29.4.1 + jest-util: 29.4.1 p-limit: 3.1.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: - supports-color dev: true - /jest-cli/29.3.1_@types+node@18.11.18: - resolution: {integrity: sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==} + /jest-cli/29.4.1_@types+node@18.11.18: + resolution: {integrity: sha512-jz7GDIhtxQ37M+9dlbv5K+/FVcIo1O/b1sX3cJgzlQUf/3VG25nvuWzlDC4F1FLLzUThJeWLu8I7JF9eWpuURQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true peerDependencies: @@ -8643,16 +8486,16 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/types': 29.3.1 + '@jest/core': 29.4.1 + '@jest/test-result': 29.4.1 + '@jest/types': 29.4.1 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.10 import-local: 3.1.0 - jest-config: 29.3.1_@types+node@18.11.18 - jest-util: 29.3.1 - jest-validate: 29.3.1 + jest-config: 29.4.1_@types+node@18.11.18 + jest-util: 29.4.1 + jest-validate: 29.4.1 prompts: 2.4.2 yargs: 17.6.2 transitivePeerDependencies: @@ -8661,8 +8504,8 @@ packages: - ts-node dev: true - /jest-config/29.3.1_@types+node@18.11.18: - resolution: {integrity: sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==} + /jest-config/29.4.1_@types+node@18.11.18: + resolution: {integrity: sha512-g7p3q4NuXiM4hrS4XFATTkd+2z0Ml2RhFmFPM8c3WyKwVDNszbl4E7cV7WIx1YZeqqCtqbtTtZhGZWJlJqngzg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@types/node': '*' @@ -8674,26 +8517,26 @@ packages: optional: true dependencies: '@babel/core': 7.20.12 - '@jest/test-sequencer': 29.3.1 - '@jest/types': 29.3.1 + '@jest/test-sequencer': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 - babel-jest: 29.3.1_@babel+core@7.20.12 + babel-jest: 29.4.1_@babel+core@7.20.12 chalk: 4.1.2 ci-info: 3.7.1 deepmerge: 4.2.2 glob: 7.2.3 graceful-fs: 4.2.10 - jest-circus: 29.3.1 - jest-environment-node: 29.3.1 + jest-circus: 29.4.1 + jest-environment-node: 29.4.1 jest-get-type: 29.2.0 jest-regex-util: 29.2.0 - jest-resolve: 29.3.1 - jest-runner: 29.3.1 - jest-util: 29.3.1 - jest-validate: 29.3.1 + jest-resolve: 29.4.1 + jest-runner: 29.4.1 + jest-util: 29.4.1 + jest-validate: 29.4.1 micromatch: 4.0.5 parse-json: 5.2.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 slash: 3.0.0 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -8707,7 +8550,17 @@ packages: chalk: 4.1.2 diff-sequences: 29.3.1 jest-get-type: 29.2.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 + dev: true + + /jest-diff/29.4.1: + resolution: {integrity: sha512-uazdl2g331iY56CEyfbNA0Ut7Mn2ulAG5vUaEHXycf1L6IPyuImIxSz4F0VYBKi7LYIuxOwTZzK3wh5jHzASMw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.3.1 + jest-get-type: 29.2.0 + pretty-format: 29.4.1 dev: true /jest-docblock/29.2.0: @@ -8717,27 +8570,27 @@ packages: detect-newline: 3.1.0 dev: true - /jest-each/29.3.1: - resolution: {integrity: sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==} + /jest-each/29.4.1: + resolution: {integrity: sha512-QlYFiX3llJMWUV0BtWht/esGEz9w+0i7BHwODKCze7YzZzizgExB9MOfiivF/vVT0GSQ8wXLhvHXh3x2fVD4QQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 chalk: 4.1.2 jest-get-type: 29.2.0 - jest-util: 29.3.1 - pretty-format: 29.3.1 + jest-util: 29.4.1 + pretty-format: 29.4.1 dev: true - /jest-environment-node/29.3.1: - resolution: {integrity: sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==} + /jest-environment-node/29.4.1: + resolution: {integrity: sha512-x/H2kdVgxSkxWAIlIh9MfMuBa0hZySmfsC5lCsWmWr6tZySP44ediRKDUiNggX/eHLH7Cd5ZN10Rw+XF5tXsqg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/environment': 29.3.1 - '@jest/fake-timers': 29.3.1 - '@jest/types': 29.3.1 + '@jest/environment': 29.4.1 + '@jest/fake-timers': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 - jest-mock: 29.3.1 - jest-util: 29.3.1 + jest-mock: 29.4.1 + jest-util: 29.4.1 dev: true /jest-get-type/29.2.0: @@ -8745,31 +8598,31 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /jest-haste-map/29.3.1: - resolution: {integrity: sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==} + /jest-haste-map/29.4.1: + resolution: {integrity: sha512-imTjcgfVVTvg02khXL11NNLTx9ZaofbAWhilrMg/G8dIkp+HYCswhxf0xxJwBkfhWb3e8dwbjuWburvxmcr58w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 '@types/graceful-fs': 4.1.6 '@types/node': 18.11.18 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.10 jest-regex-util: 29.2.0 - jest-util: 29.3.1 - jest-worker: 29.3.1 + jest-util: 29.4.1 + jest-worker: 29.4.1 micromatch: 4.0.5 walker: 1.0.8 optionalDependencies: fsevents: 2.3.2 dev: true - /jest-leak-detector/29.3.1: - resolution: {integrity: sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==} + /jest-leak-detector/29.4.1: + resolution: {integrity: sha512-akpZv7TPyGMnH2RimOCgy+hPmWZf55EyFUvymQ4LMsQP8xSPlZumCPtXGoDhFNhUE2039RApZkTQDKU79p/FiQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: jest-get-type: 29.2.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 dev: true /jest-matcher-utils/29.3.1: @@ -8779,7 +8632,17 @@ packages: chalk: 4.1.2 jest-diff: 29.3.1 jest-get-type: 29.2.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 + dev: true + + /jest-matcher-utils/29.4.1: + resolution: {integrity: sha512-k5h0u8V4nAEy6lSACepxL/rw78FLDkBnXhZVgFneVpnJONhb2DhZj/Gv4eNe+1XqQ5IhgUcqj745UwH0HJmMnA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.4.1 + jest-get-type: 29.2.0 + pretty-format: 29.4.1 dev: true /jest-message-util/29.3.1: @@ -8787,26 +8650,41 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/code-frame': 7.18.6 - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.10 micromatch: 4.0.5 - pretty-format: 29.3.1 + pretty-format: 29.4.1 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-message-util/29.4.1: + resolution: {integrity: sha512-H4/I0cXUaLeCw6FM+i4AwCnOwHRgitdaUFOdm49022YD5nfyr8C/DrbXOBEyJaj+w/y0gGJ57klssOaUiLLQGQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.18.6 + '@jest/types': 29.4.1 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + pretty-format: 29.4.1 slash: 3.0.0 stack-utils: 2.0.6 dev: true - /jest-mock/29.3.1: - resolution: {integrity: sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==} + /jest-mock/29.4.1: + resolution: {integrity: sha512-MwA4hQ7zBOcgVCVnsM8TzaFLVUD/pFWTfbkY953Y81L5ret3GFRZtmPmRFAjKQSdCKoJvvqOu6Bvfpqlwwb0dQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 - jest-util: 29.3.1 + jest-util: 29.4.1 dev: true - /jest-pnp-resolver/1.2.3_jest-resolve@29.3.1: + /jest-pnp-resolver/1.2.3_jest-resolve@29.4.1: resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} peerDependencies: @@ -8815,7 +8693,7 @@ packages: jest-resolve: optional: true dependencies: - jest-resolve: 29.3.1 + jest-resolve: 29.4.1 dev: true /jest-regex-util/29.2.0: @@ -8823,92 +8701,93 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /jest-resolve-dependencies/29.3.1: - resolution: {integrity: sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==} + /jest-resolve-dependencies/29.4.1: + resolution: {integrity: sha512-Y3QG3M1ncAMxfjbYgtqNXC5B595zmB6e//p/qpA/58JkQXu/IpLDoLeOa8YoYfsSglBKQQzNUqtfGJJT/qLmJg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: jest-regex-util: 29.2.0 - jest-snapshot: 29.3.1 + jest-snapshot: 29.4.1 transitivePeerDependencies: - supports-color dev: true - /jest-resolve/29.3.1: - resolution: {integrity: sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==} + /jest-resolve/29.4.1: + resolution: {integrity: sha512-j/ZFNV2lm9IJ2wmlq1uYK0Y/1PiyDq9g4HEGsNTNr3viRbJdV+8Lf1SXIiLZXFvyiisu0qUyIXGBnw+OKWkJwQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 - jest-pnp-resolver: 1.2.3_jest-resolve@29.3.1 - jest-util: 29.3.1 - jest-validate: 29.3.1 + jest-haste-map: 29.4.1 + jest-pnp-resolver: 1.2.3_jest-resolve@29.4.1 + jest-util: 29.4.1 + jest-validate: 29.4.1 resolve: 1.22.1 - resolve.exports: 1.1.1 + resolve.exports: 2.0.0 slash: 3.0.0 dev: true - /jest-runner/29.3.1: - resolution: {integrity: sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==} + /jest-runner/29.4.1: + resolution: {integrity: sha512-8d6XXXi7GtHmsHrnaqBKWxjKb166Eyj/ksSaUYdcBK09VbjPwIgWov1VwSmtupCIz8q1Xv4Qkzt/BTo3ZqiCeg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/console': 29.3.1 - '@jest/environment': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 + '@jest/console': 29.4.1 + '@jest/environment': 29.4.1 + '@jest/test-result': 29.4.1 + '@jest/transform': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.10 jest-docblock: 29.2.0 - jest-environment-node: 29.3.1 - jest-haste-map: 29.3.1 - jest-leak-detector: 29.3.1 - jest-message-util: 29.3.1 - jest-resolve: 29.3.1 - jest-runtime: 29.3.1 - jest-util: 29.3.1 - jest-watcher: 29.3.1 - jest-worker: 29.3.1 + jest-environment-node: 29.4.1 + jest-haste-map: 29.4.1 + jest-leak-detector: 29.4.1 + jest-message-util: 29.4.1 + jest-resolve: 29.4.1 + jest-runtime: 29.4.1 + jest-util: 29.4.1 + jest-watcher: 29.4.1 + jest-worker: 29.4.1 p-limit: 3.1.0 source-map-support: 0.5.13 transitivePeerDependencies: - supports-color dev: true - /jest-runtime/29.3.1: - resolution: {integrity: sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==} + /jest-runtime/29.4.1: + resolution: {integrity: sha512-UXTMU9uKu2GjYwTtoAw5rn4STxWw/nadOfW7v1sx6LaJYa3V/iymdCLQM6xy3+7C6mY8GfX22vKpgxY171UIoA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/environment': 29.3.1 - '@jest/fake-timers': 29.3.1 - '@jest/globals': 29.3.1 + '@jest/environment': 29.4.1 + '@jest/fake-timers': 29.4.1 + '@jest/globals': 29.4.1 '@jest/source-map': 29.2.0 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 + '@jest/test-result': 29.4.1 + '@jest/transform': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 glob: 7.2.3 graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 - jest-message-util: 29.3.1 - jest-mock: 29.3.1 + jest-haste-map: 29.4.1 + jest-message-util: 29.4.1 + jest-mock: 29.4.1 jest-regex-util: 29.2.0 - jest-resolve: 29.3.1 - jest-snapshot: 29.3.1 - jest-util: 29.3.1 + jest-resolve: 29.4.1 + jest-snapshot: 29.4.1 + jest-util: 29.4.1 + semver: 7.3.8 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /jest-snapshot/29.3.1: - resolution: {integrity: sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==} + /jest-snapshot/29.4.1: + resolution: {integrity: sha512-l4iV8EjGgQWVz3ee/LR9sULDk2pCkqb71bjvlqn+qp90lFwpnulHj4ZBT8nm1hA1C5wowXLc7MGnw321u0tsYA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/core': 7.20.12 @@ -8917,33 +8796,33 @@ packages: '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.20.12 '@babel/traverse': 7.20.12 '@babel/types': 7.20.7 - '@jest/expect-utils': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 + '@jest/expect-utils': 29.4.1 + '@jest/transform': 29.4.1 + '@jest/types': 29.4.1 '@types/babel__traverse': 7.18.3 '@types/prettier': 2.7.2 babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.12 chalk: 4.1.2 - expect: 29.3.1 + expect: 29.4.1 graceful-fs: 4.2.10 - jest-diff: 29.3.1 + jest-diff: 29.4.1 jest-get-type: 29.2.0 - jest-haste-map: 29.3.1 - jest-matcher-utils: 29.3.1 - jest-message-util: 29.3.1 - jest-util: 29.3.1 + jest-haste-map: 29.4.1 + jest-matcher-utils: 29.4.1 + jest-message-util: 29.4.1 + jest-util: 29.4.1 natural-compare: 1.4.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 semver: 7.3.8 transitivePeerDependencies: - supports-color dev: true - /jest-util/29.3.1: - resolution: {integrity: sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==} + /jest-util/29.4.1: + resolution: {integrity: sha512-bQy9FPGxVutgpN4VRc0hk6w7Hx/m6L53QxpDreTZgJd9gfx/AV2MjyPde9tGyZRINAUrSv57p2inGBu2dRLmkQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 chalk: 4.1.2 ci-info: 3.7.1 @@ -8951,44 +8830,44 @@ packages: picomatch: 2.3.1 dev: true - /jest-validate/29.3.1: - resolution: {integrity: sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==} + /jest-validate/29.4.1: + resolution: {integrity: sha512-qNZXcZQdIQx4SfUB/atWnI4/I2HUvhz8ajOSYUu40CSmf9U5emil8EDHgE7M+3j9/pavtk3knlZBDsgFvv/SWw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.3.1 + '@jest/types': 29.4.1 camelcase: 6.3.0 chalk: 4.1.2 jest-get-type: 29.2.0 leven: 3.1.0 - pretty-format: 29.3.1 + pretty-format: 29.4.1 dev: true - /jest-watcher/29.3.1: - resolution: {integrity: sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==} + /jest-watcher/29.4.1: + resolution: {integrity: sha512-vFOzflGFs27nU6h8dpnVRER3O2rFtL+VMEwnG0H3KLHcllLsU8y9DchSh0AL/Rg5nN1/wSiQ+P4ByMGpuybaVw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/test-result': 29.3.1 - '@jest/types': 29.3.1 + '@jest/test-result': 29.4.1 + '@jest/types': 29.4.1 '@types/node': 18.11.18 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 - jest-util: 29.3.1 + jest-util: 29.4.1 string-length: 4.0.2 dev: true - /jest-worker/29.3.1: - resolution: {integrity: sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==} + /jest-worker/29.4.1: + resolution: {integrity: sha512-O9doU/S1EBe+yp/mstQ0VpPwpv0Clgn68TkNwGxL6/usX/KUW9Arnn4ag8C3jc6qHcXznhsT5Na1liYzAsuAbQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@types/node': 18.11.18 - jest-util: 29.3.1 + jest-util: 29.4.1 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest/29.3.1_@types+node@18.11.18: - resolution: {integrity: sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==} + /jest/29.4.1_@types+node@18.11.18: + resolution: {integrity: sha512-cknimw7gAXPDOmj0QqztlxVtBVCw2lYY9CeIE5N6kD+kET1H4H79HSNISJmijb1HF+qk+G+ploJgiDi5k/fRlg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true peerDependencies: @@ -8997,10 +8876,10 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.3.1 - '@jest/types': 29.3.1 + '@jest/core': 29.4.1 + '@jest/types': 29.4.1 import-local: 3.1.0 - jest-cli: 29.3.1_@types+node@18.11.18 + jest-cli: 29.4.1_@types+node@18.11.18 transitivePeerDependencies: - '@types/node' - supports-color @@ -11304,6 +11183,15 @@ packages: react-is: 18.2.0 dev: true + /pretty-format/29.4.1: + resolution: {integrity: sha512-dt/Z761JUVsrIKaY215o1xQJBGlSmTx/h4cSqXqjHLnU1+Kt+mavVE7UgqJJO5ukx5HjSswHfmXz4LjS2oIJfg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.4.0 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + /pretty-hrtime/1.0.3: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} @@ -12017,8 +11905,8 @@ packages: deprecated: https://github.com/lydell/resolve-url#deprecated dev: false - /resolve.exports/1.1.1: - resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} + /resolve.exports/2.0.0: + resolution: {integrity: sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==} engines: {node: '>=10'} dev: true @@ -12099,8 +11987,8 @@ packages: seedrandom: 2.4.2 dev: false - /rollup/3.10.1: - resolution: {integrity: sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==} + /rollup/3.11.0: + resolution: {integrity: sha512-+uWPPkpWQ2H3Qi7sNBcRfhhHJyUNgBYhG4wKe5wuGRj2m55kpo+0p5jubKNBjQODyPe6tSBE3tNpdDwEisQvAQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -12913,8 +12801,8 @@ packages: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: false - /systeminformation/5.17.3: - resolution: {integrity: sha512-IAmnUJdeFUWqY+YneAWJ9rceTdRRIaTiwspvd1B6SG7yhqpxLrSosHgGZKiE8lcaBlBYpLQpY3BRLtus4n8PNQ==} + /systeminformation/5.17.4: + resolution: {integrity: sha512-mEiIYrw7X5ABX8tJUgzbumQAuFQxNyHdZDz6+UtwNKUbKgIoZqLtug2z1spFB/LiXZne5tdPBJOlvVckbvfhiQ==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -13039,8 +12927,8 @@ packages: real-require: 0.2.0 dev: false - /three/0.148.0: - resolution: {integrity: sha512-8uzVV+qhTPi0bOFs/3te3RW6hb3urL8jYEl6irjCWo/l6sr8MPNMcClFev/MMYeIxr0gmDcoXTy/8LXh/LXkfw==} + /three/0.149.0: + resolution: {integrity: sha512-tohpUxPDht0qExRLDTM8sjRLc5d9STURNrdnK3w9A+V4pxaTBfKWWT/IqtiLfg23Vfc3Z+ImNfvRw1/0CtxrkQ==} dev: false /throttle-debounce/5.0.0: @@ -13794,7 +13682,7 @@ packages: esbuild: 0.16.17 postcss: 8.4.21 resolve: 1.22.1 - rollup: 3.10.1 + rollup: 3.11.0 sass: 1.57.1 optionalDependencies: fsevents: 2.3.2 @@ -14058,9 +13946,9 @@ packages: /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - /write-file-atomic/4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /write-file-atomic/5.0.0: + resolution: {integrity: sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: imurmurhash: 0.1.4 signal-exit: 3.0.7