diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f54948619..a3bf19573f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ - Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正 - Fix: 連合無しモードでも外部から照会可能だった問題を修正 - Fix: テスト用WebHookのペイロードの`emojis`パラメータが実際のものと異なる問題を修正 +- Enhance: add LLM translation support with OpenAI compatible API ## 2025.3.1 diff --git a/packages/backend/migration/1740989976502-addLlmTranslatorSupport.js b/packages/backend/migration/1740989976502-addLlmTranslatorSupport.js new file mode 100644 index 0000000000..7a9b7c94ce --- /dev/null +++ b/packages/backend/migration/1740989976502-addLlmTranslatorSupport.js @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class AddLlmTranslatorSupport1740989976502 { + name = 'AddLlmTranslatorSupport1740989976502' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "enableLlmTranslator" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "enableLlmTranslatorRedisCache" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorRedisCacheTtl" integer NOT NULL DEFAULT '2880'`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorBaseUrl" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorApiKey" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorModel" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorTemperature" real`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorTopP" real`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorMaxTokens" integer`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorSysPrompt" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "llmTranslatorUserPrompt" character varying(1024)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableLlmTranslator"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableLlmTranslatorRedisCache"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorRedisCacheTtl"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorBaseUrl"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorApiKey"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorModel"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorTemperature"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorTopP"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorMaxTokens"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorSysPrompt"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "llmTranslatorUserPrompt"`); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index d7705b2b9e..0e23018452 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -147,6 +147,7 @@ "oauth": "0.10.2", "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", + "openai": "4.86.1", "os-utils": "0.0.14", "otpauth": "9.3.6", "parse5": "7.2.1", diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 02783dc450..bd2f57e7a5 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -121,7 +121,7 @@ export class MetaEntityService { enableEmail: instance.enableEmail, enableServiceWorker: instance.enableServiceWorker, - translatorAvailable: instance.deeplAuthKey != null, + translatorAvailable: instance.deeplAuthKey != null || instance.enableLlmTranslator, serverRules: instance.serverRules, diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 1fbf5371bc..9f1da8b0fd 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -664,4 +664,64 @@ export class MiMeta { nullable: true, }) public googleAnalyticsMeasurementId: string | null; + + @Column('boolean', { + default: false, + }) + public enableLlmTranslator: boolean; + + @Column('boolean', { + default: false, + }) + public enableLlmTranslatorRedisCache: boolean; + + @Column('integer', { + default: 2880, + }) + public llmTranslatorRedisCacheTtl: number; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public llmTranslatorBaseUrl: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public llmTranslatorApiKey: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public llmTranslatorModel: string | null; + + @Column('real', { + nullable: true, + }) + public llmTranslatorTemperature: number | null; + + @Column('real', { + nullable: true, + }) + public llmTranslatorTopP: number | null; + + @Column('integer', { + nullable: true, + }) + public llmTranslatorMaxTokens: number | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public llmTranslatorSysPrompt: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public llmTranslatorUserPrompt: string | null; } diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 53e2b2b237..c25c16e5f3 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -528,6 +528,50 @@ export const meta = { optional: false, nullable: false, }, }, + enableLlmTranslator: { + type: 'boolean', + optional: false, nullable: false, + }, + enableLlmTranslatorRedisCache: { + type: 'boolean', + optional: false, nullable: false, + }, + llmTranslatorRedisCacheTtl: { + type: 'number', + optional: false, nullable: false, + }, + llmTranslatorBaseUrl: { + type: 'string', + optional: false, nullable: true, + }, + llmTranslatorApiKey: { + type: 'string', + optional: false, nullable: true, + }, + llmTranslatorModel: { + type: 'string', + optional: false, nullable: true, + }, + llmTranslatorTemperature: { + type: 'number', + optional: false, nullable: true, + }, + llmTranslatorTopP: { + type: 'number', + optional: false, nullable: true, + }, + llmTranslatorMaxTokens: { + type: 'number', + optional: false, nullable: true, + }, + llmTranslatorSysPrompt: { + type: 'string', + optional: false, nullable: true, + }, + llmTranslatorUserPrompt: { + type: 'string', + optional: false, nullable: true, + }, }, }, } as const; @@ -597,7 +641,7 @@ export default class extends Endpoint { // eslint- defaultDarkTheme: instance.defaultDarkTheme, enableEmail: instance.enableEmail, enableServiceWorker: instance.enableServiceWorker, - translatorAvailable: instance.deeplAuthKey != null, + translatorAvailable: instance.deeplAuthKey != null || instance.enableLlmTranslator, cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, pinnedUsers: instance.pinnedUsers, @@ -672,6 +716,17 @@ export default class extends Endpoint { // eslint- urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl, federation: instance.federation, federationHosts: instance.federationHosts, + enableLlmTranslator: instance.enableLlmTranslator, + enableLlmTranslatorRedisCache: instance.enableLlmTranslatorRedisCache, + llmTranslatorRedisCacheTtl: instance.llmTranslatorRedisCacheTtl, + llmTranslatorBaseUrl: instance.llmTranslatorBaseUrl, + llmTranslatorApiKey: instance.llmTranslatorApiKey, + llmTranslatorModel: instance.llmTranslatorModel, + llmTranslatorMaxTokens: instance.llmTranslatorMaxTokens, + llmTranslatorTemperature: instance.llmTranslatorTemperature, + llmTranslatorTopP: instance.llmTranslatorTopP, + llmTranslatorSysPrompt: instance.llmTranslatorSysPrompt, + llmTranslatorUserPrompt: instance.llmTranslatorUserPrompt, }; }); } diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index bc05587668..521814179f 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -185,6 +185,17 @@ export const paramDef = { type: 'string', }, }, + enableLlmTranslator: { type: 'boolean' }, + enableLlmTranslatorRedisCache: { type: 'boolean' }, + llmTranslatorRedisCacheTtl: { type: 'integer' }, + llmTranslatorBaseUrl: { type: 'string', nullable: true }, + llmTranslatorApiKey: { type: 'string', nullable: true }, + llmTranslatorModel: { type: 'string', nullable: true }, + llmTranslatorTemperature: { type: 'number', nullable: true }, + llmTranslatorTopP: { type: 'number', nullable: true }, + llmTranslatorMaxTokens: { type: 'integer', nullable: true }, + llmTranslatorSysPrompt: { type: 'string', nullable: true }, + llmTranslatorUserPrompt: { type: 'string', nullable: true }, }, required: [], } as const; @@ -675,6 +686,70 @@ export default class extends Endpoint { // eslint- set.federationHosts = ps.federationHosts.filter(Boolean).map(x => x.toLowerCase()); } + if (ps.enableLlmTranslator !== undefined) { + set.enableLlmTranslator = ps.enableLlmTranslator; + } + + if (ps.enableLlmTranslatorRedisCache !== undefined) { + set.enableLlmTranslatorRedisCache = ps.enableLlmTranslatorRedisCache; + } + + if (ps.llmTranslatorRedisCacheTtl !== undefined) { + set.llmTranslatorRedisCacheTtl = ps.llmTranslatorRedisCacheTtl; + } + + if (ps.llmTranslatorBaseUrl !== undefined) { + if (ps.llmTranslatorBaseUrl === '') { + set.llmTranslatorBaseUrl = null; + } else { + set.llmTranslatorBaseUrl = ps.llmTranslatorBaseUrl; + } + } + + if (ps.llmTranslatorApiKey !== undefined) { + if (ps.llmTranslatorApiKey === '') { + set.llmTranslatorApiKey = null; + } else { + set.llmTranslatorApiKey = ps.llmTranslatorApiKey; + } + } + + if (ps.llmTranslatorModel !== undefined) { + if (ps.llmTranslatorModel === '') { + set.llmTranslatorModel = null; + } else { + set.llmTranslatorModel = ps.llmTranslatorModel; + } + } + + if (ps.llmTranslatorTemperature !== undefined) { + set.llmTranslatorTemperature = ps.llmTranslatorTemperature; + } + + if (ps.llmTranslatorTopP !== undefined) { + set.llmTranslatorTopP = ps.llmTranslatorTopP; + } + + if (ps.llmTranslatorMaxTokens !== undefined) { + set.llmTranslatorMaxTokens = ps.llmTranslatorMaxTokens; + } + + if (ps.llmTranslatorSysPrompt !== undefined) { + if (ps.llmTranslatorSysPrompt === '') { + set.llmTranslatorSysPrompt = null; + } else { + set.llmTranslatorSysPrompt = ps.llmTranslatorSysPrompt; + } + } + + if (ps.llmTranslatorUserPrompt !== undefined) { + if (ps.llmTranslatorUserPrompt === '') { + set.llmTranslatorUserPrompt = null; + } else { + set.llmTranslatorUserPrompt = ps.llmTranslatorUserPrompt; + } + } + const before = await this.metaService.fetch(true); await this.metaService.update(set); diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index e9a6a36b02..e85d063e0e 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -5,14 +5,16 @@ import { URLSearchParams } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; +import { OpenAI } from 'openai'; +import * as Redis from 'ioredis'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; import { GetterService } from '@/server/api/GetterService.js'; import { RoleService } from '@/core/RoleService.js'; -import { ApiError } from '../../error.js'; import { MiMeta } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; +import { ApiError } from '../../error.js'; export const meta = { tags: ['notes'], @@ -63,6 +65,9 @@ export default class extends Endpoint { // eslint- @Inject(DI.meta) private serverSettings: MiMeta, + @Inject(DI.redis) + private redisClient: Redis.Redis, + private noteEntityService: NoteEntityService, private getterService: GetterService, private httpRequestService: HttpRequestService, @@ -87,6 +92,13 @@ export default class extends Endpoint { // eslint- return; } + if (this.serverSettings.enableLlmTranslator) { + const res = await this.llmTranslate(note.text, ps.targetLang, note.id); + return { + text: res, + }; + } + if (this.serverSettings.deeplAuthKey == null) { throw new ApiError(meta.errors.unavailable); } @@ -123,4 +135,44 @@ export default class extends Endpoint { // eslint- }; }); } + + private async llmTranslate(text: string, targetLang: string, noteId: string): Promise { + if (this.serverSettings.enableLlmTranslatorRedisCache) { + const key = `llmTranslate:${targetLang}:${noteId}`; + const cached = await this.redisClient.get(key); + if (cached != null) { + this.redisClient.expire(key, this.serverSettings.llmTranslatorRedisCacheTtl * 60); + return cached; + } + const res = await this.getLlmRes(text, targetLang); + await this.redisClient.set(key, res); + this.redisClient.expire(key, this.serverSettings.llmTranslatorRedisCacheTtl * 60); + return res; + } else { + return this.getLlmRes(text, targetLang); + } + } + + private async getLlmRes(text: string, targetLang: string): Promise { + const client = new OpenAI({ + baseURL: this.serverSettings.llmTranslatorBaseUrl, + apiKey: this.serverSettings.llmTranslatorApiKey ?? '', + }); + const message = []; + if (this.serverSettings.llmTranslatorSysPrompt) { + message.push({ role: 'system' as const, content: this.serverSettings.llmTranslatorSysPrompt.replace('{targetLang}', targetLang).replace('{text}', text) }); + } + if (this.serverSettings.llmTranslatorUserPrompt) { + message.push({ role: 'user' as const, content: this.serverSettings.llmTranslatorUserPrompt.replace('{targetLang}', targetLang).replace('{text}', text) }); + } + const completion = await client.chat.completions.create({ + messages: message, + model: this.serverSettings.llmTranslatorModel ?? '', + temperature: this.serverSettings.llmTranslatorTemperature, + max_tokens: this.serverSettings.llmTranslatorMaxTokens, + top_p: this.serverSettings.llmTranslatorTopP, + }); + + return completion.choices[0].message.content ?? ''; + } } diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index ab70a11b9b..dfd85ab417 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: + {{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}:
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index a26eb808e4..a985d030a1 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -103,7 +103,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}: + {{ i18n.tsx.translatedFrom({ x: translation.sourceLang }) }}:
diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index a6557114dc..d64f14c57e 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -35,6 +35,58 @@ SPDX-License-Identifier: AGPL-3.0-only Save + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Save +
+
@@ -45,6 +97,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { ref, computed } from 'vue'; import XHeader from './_header_.vue'; import MkInput from '@/components/MkInput.vue'; +import MkTextarea from '@/components/MkTextarea.vue'; import MkButton from '@/components/MkButton.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import FormSuspense from '@/components/form/suspense.vue'; @@ -60,11 +113,34 @@ const deeplIsPro = ref(false); const googleAnalyticsMeasurementId = ref(''); +const llmTranslatorEnabled = ref(false); +const llmTranslatorBaseUrl = ref(''); +const llmTranslatorApiKey = ref(''); +const llmTranslatorModel = ref(''); +const llmTranslatorTemperature = ref(1); +const llmTranslatorTopP = ref(1); +const llmTranslatorMaxTokens = ref(1); +const llmTranslatorSysPrompt = ref(''); +const llmTranslatorUserPrompt = ref(''); +const llmTranslatorRedisCacheEnabled = ref(false); +const llmTranslatorRedisCacheTtl = ref(0); + async function init() { const meta = await misskeyApi('admin/meta'); deeplAuthKey.value = meta.deeplAuthKey ?? ''; deeplIsPro.value = meta.deeplIsPro; googleAnalyticsMeasurementId.value = meta.googleAnalyticsMeasurementId ?? ''; + llmTranslatorEnabled.value = meta.enableLlmTranslator; + llmTranslatorBaseUrl.value = meta.llmTranslatorBaseUrl ?? ''; + llmTranslatorApiKey.value = meta.llmTranslatorApiKey ?? ''; + llmTranslatorModel.value = meta.llmTranslatorModel ?? ''; + llmTranslatorTemperature.value = meta.llmTranslatorTemperature; + llmTranslatorTopP.value = meta.llmTranslatorTopP; + llmTranslatorMaxTokens.value = meta.llmTranslatorMaxTokens; + llmTranslatorSysPrompt.value = meta.llmTranslatorSysPrompt ?? ''; + llmTranslatorUserPrompt.value = meta.llmTranslatorUserPrompt ?? ''; + llmTranslatorRedisCacheEnabled.value = meta.enableLlmTranslatorRedisCache; + llmTranslatorRedisCacheTtl.value = meta.llmTranslatorRedisCacheTtl; } function save_deepl() { @@ -84,6 +160,24 @@ function save_googleAnalytics() { }); } +function save_llm() { + os.apiWithDialog('admin/update-meta', { + enableLlmTranslator: llmTranslatorEnabled.value, + llmTranslatorBaseUrl: llmTranslatorBaseUrl.value, + llmTranslatorApiKey: llmTranslatorApiKey.value, + llmTranslatorModel: llmTranslatorModel.value, + llmTranslatorTemperature: llmTranslatorTemperature.value, + llmTranslatorTopP: llmTranslatorTopP.value, + llmTranslatorMaxTokens: llmTranslatorMaxTokens.value, + llmTranslatorSysPrompt: llmTranslatorSysPrompt.value, + llmTranslatorUserPrompt: llmTranslatorUserPrompt.value, + enableLlmTranslatorRedisCache: llmTranslatorRedisCacheEnabled.value, + llmTranslatorRedisCacheTtl: llmTranslatorRedisCacheTtl.value, + }).then(() => { + fetchInstance(true); + }); +} + const headerActions = computed(() => []); const headerTabs = computed(() => []); diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 037b09660c..930c5646ff 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -8679,6 +8679,17 @@ export type operations = { /** @enum {string} */ federation: 'all' | 'specified' | 'none'; federationHosts: string[]; + enableLlmTranslator: boolean; + enableLlmTranslatorRedisCache: boolean; + llmTranslatorRedisCacheTtl: number; + llmTranslatorBaseUrl: string | null; + llmTranslatorApiKey: string | null; + llmTranslatorModel: string | null; + llmTranslatorTemperature: number | null; + llmTranslatorTopP: number | null; + llmTranslatorMaxTokens: number | null; + llmTranslatorSysPrompt: string | null; + llmTranslatorUserPrompt: string | null; }; }; }; @@ -11024,6 +11035,17 @@ export type operations = { /** @enum {string} */ federation?: 'all' | 'none' | 'specified'; federationHosts?: string[]; + enableLlmTranslator?: boolean; + enableLlmTranslatorRedisCache?: boolean; + llmTranslatorRedisCacheTtl?: number; + llmTranslatorBaseUrl?: string | null; + llmTranslatorApiKey?: string | null; + llmTranslatorModel?: string | null; + llmTranslatorTemperature?: number | null; + llmTranslatorTopP?: number | null; + llmTranslatorMaxTokens?: number | null; + llmTranslatorSysPrompt?: string | null; + llmTranslatorUserPrompt?: string | null; }; }; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46416c0332..5b84edecf6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -332,6 +332,9 @@ importers: oauth2orize-pkce: specifier: 0.1.2 version: 0.1.2 + openai: + specifier: 4.86.1 + version: 4.86.1(encoding@0.1.13)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)) os-utils: specifier: 0.0.14 version: 0.0.14 @@ -2590,67 +2593,79 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -2937,30 +2952,35 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/canvas-linux-arm64-musl@0.1.68': resolution: {integrity: sha512-IQzts91rCdOALXBWQxLZRCEDrfFTGDtNRJMNu+2SKZ1uT8cmPQkPwVk5rycvFpvgAcmiFiOSCp1aRrlfU8KPpQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/canvas-linux-riscv64-gnu@0.1.68': resolution: {integrity: sha512-e9AS5UttoIKqXSmBzKZdd3NErSVyOEYzJfNOCGtafGk1//gibTwQXGlSXmAKuErqMp09pyk9aqQRSYzm1AQfBw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@napi-rs/canvas-linux-x64-gnu@0.1.68': resolution: {integrity: sha512-Pa/I36VE3j57I3Obhrr+J48KGFfkZk2cJN/2NmW/vCgmoF7kCP6aTVq5n+cGdGWLd/cN9CJ9JvNwEoMRDghu0g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/canvas-linux-x64-musl@0.1.68': resolution: {integrity: sha512-9c6rkc5195wNxuUHJdf4/mmnq433OQey9TNvQ9LspJazvHbfSkTij8wtKjASVQsJyPDva4fkWOeV/OQ7cLw0GQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/canvas-win32-x64-msvc@0.1.68': resolution: {integrity: sha512-Fc5Dez23u0FoSATurT6/w1oMytiRnKWEinHivdMvXpge6nG4YvhrASrtqMk8dGJMVQpHr8QJYF45rOrx2YU2Aw==} @@ -3312,36 +3332,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.0': resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.0': resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.0': resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.0': resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.0': resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.0': resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} @@ -3472,51 +3498,61 @@ packages: resolution: {integrity: sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.36.0': resolution: {integrity: sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.36.0': resolution: {integrity: sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.36.0': resolution: {integrity: sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.36.0': resolution: {integrity: sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.36.0': resolution: {integrity: sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.36.0': resolution: {integrity: sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.36.0': resolution: {integrity: sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.36.0': resolution: {integrity: sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.36.0': resolution: {integrity: sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.36.0': resolution: {integrity: sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==} @@ -4201,24 +4237,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.11.11': resolution: {integrity: sha512-nR2tfdQRRzwqR2XYw9NnBk9Fdvff/b8IiJzDL28gRR2QiJWLaE8LsRovtWrzCOYq6o5Uu9cJ3WbabWthLo4jLw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.11.11': resolution: {integrity: sha512-b4gBp5HA9xNWNC5gsYbdzGBJWx4vKSGybGMGOVWWuF+ynx10+0sA/o4XJGuNHm8TEDuNh9YLKf6QkIO8+GPJ1g==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.11.11': resolution: {integrity: sha512-dEvqmQVswjNvMBwXNb8q5uSvhWrJLdttBSef3s6UC5oDSwOr00t3RQPzyS3n5qmGJ8UMTdPRmsopxmqaODISdg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.11.11': resolution: {integrity: sha512-aZNZznem9WRnw2FbTqVpnclvl8Q2apOBW2B316gZK+qxbe+ktjOUnYaMhdCG3+BYggyIBDOnaJeQrXbKIMmNdw==} @@ -4525,6 +4565,9 @@ packages: '@types/node-fetch@2.6.11': resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + '@types/node@18.19.81': + resolution: {integrity: sha512-7KO9oZ2//ivtSsryp0LQUqq79zyGXzwq1WqfywpC9ucjY7YyltMMmxWgtRFRKCxwa7VPxVBVy4kHf5UC1E8Lug==} + '@types/node@22.13.10': resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==} @@ -5070,6 +5113,10 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -6820,6 +6867,9 @@ packages: forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + form-data-encoder@2.1.4: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} @@ -6832,6 +6882,10 @@ packages: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -7233,6 +7287,9 @@ packages: resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==} engines: {node: '>=18.18.0'} + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -8692,6 +8749,18 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openai@4.86.1: + resolution: {integrity: sha512-x3iCLyaC3yegFVZaxOmrYJjitKxZ9hpVbLi+ZlT5UHuHTMlEQEbKXkGOM78z9qm2T5GF+XRUZCP2/aV4UPFPJQ==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} @@ -9870,24 +9939,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] slacc-linux-arm64-musl@0.0.10: resolution: {integrity: sha512-3lUX7752f6Okn54aONioaA+9M5TvifqXBAart+u2lNXEdWmmh003cVSU2Vcwg7nJ9lLHtju2DkDmKKfJjFuShA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] slacc-linux-x64-gnu@0.0.10: resolution: {integrity: sha512-BxxvylF9zlOLRLCpiyMvKTIUpdLlpetNBJ+DSMDh5+Ggq+AmQz2NUGawmcBJw58F8nMCj9TpWLlGNWc2AuY+JQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] slacc-linux-x64-musl@0.0.10: resolution: {integrity: sha512-TYJi8LOtJiTFcZvka4du7bMjF9Bz1RHRwyLnScr5E5yjjgoLRrsvgSu7bxp87xH+rgJ3CdEwE3w3Ux8EiewHpA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] slacc-win32-arm64-msvc@0.0.10: resolution: {integrity: sha512-1CHPLiDB4exzFyT5ndtJDsRRhBxNg8mGz6I6eJEMjelGkJR2KZPT9LZuby/1bS/bcVOr7zuJvGNfbEGBeHRwPQ==} @@ -10610,6 +10683,9 @@ packages: undefsafe@2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} @@ -10956,6 +11032,10 @@ packages: resolution: {integrity: sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==} engines: {node: '>= 8'} + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -14940,6 +15020,10 @@ snapshots: '@types/node': 22.13.15 form-data: 4.0.2 + '@types/node@18.19.81': + dependencies: + undici-types: 5.26.5 + '@types/node@22.13.10': dependencies: undici-types: 6.20.0 @@ -15667,6 +15751,10 @@ snapshots: agent-base@7.1.3: {} + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -18001,6 +18089,8 @@ snapshots: forever-agent@0.6.1: {} + form-data-encoder@1.7.2: {} + form-data-encoder@2.1.4: {} form-data-encoder@4.0.2: {} @@ -18012,6 +18102,11 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -18470,6 +18565,10 @@ snapshots: human-signals@8.0.0: {} + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -20375,6 +20474,20 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openai@4.86.1(encoding@0.1.13)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@6.0.5)): + dependencies: + '@types/node': 18.19.81 + '@types/node-fetch': 2.6.11 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0(encoding@0.1.13) + optionalDependencies: + ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) + transitivePeerDependencies: + - encoding + openapi-types@12.1.3: {} openapi-typescript@6.7.6: @@ -22389,6 +22502,8 @@ snapshots: undefsafe@2.0.5: {} + undici-types@5.26.5: {} + undici-types@6.20.0: {} undici@5.28.5: @@ -22766,6 +22881,8 @@ snapshots: web-streams-polyfill@4.0.0: optional: true + web-streams-polyfill@4.0.0-beta.3: {} + webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {}