diff --git a/apps/stage-tamagotchi/src/renderer/pages/index.vue b/apps/stage-tamagotchi/src/renderer/pages/index.vue index d489f3deb..a0f083407 100644 --- a/apps/stage-tamagotchi/src/renderer/pages/index.vue +++ b/apps/stage-tamagotchi/src/renderer/pages/index.vue @@ -598,6 +598,18 @@ function getVoiceInputGeneration(metadata?: Record) { const voiceInputSession = useVoiceInputSession(stream, { shouldUseStreamInput, + onLog(level, event, message, details) { + const output = `[Voice Input] ${event}: ${message}` + if (level === 'error') { + console.error(output, details ?? {}) + return + } + if (level === 'warn') { + console.warn(output, details ?? {}) + return + } + console.info(output, details ?? {}) + }, canStartSegment: () => enabled.value && !isVoiceInputSuppressed(), inspectBeforeTranscription: ({ metadata }) => inspectVoiceInputProviderRequestGate(getVoiceInputGeneration(metadata)), inspectAfterTranscription: ({ metadata }) => inspectVoiceInputProviderRequestGate(getVoiceInputGeneration(metadata)), diff --git a/cspell.config.yaml b/cspell.config.yaml index 0716355ec..5afe4cfc5 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -111,6 +111,7 @@ words: - esaxx - eventa - Factorio + - fakemic - feaxios - fflate - Flathub diff --git a/packages/electron-screen-capture/package.json b/packages/electron-screen-capture/package.json index 00611464e..fe5d4428d 100644 --- a/packages/electron-screen-capture/package.json +++ b/packages/electron-screen-capture/package.json @@ -51,7 +51,7 @@ }, "inlinedDependencies": { "@electron-toolkit/preload": "3.0.2", - "@moeru/eventa": "1.0.0-beta.13", + "@moeru/eventa": "1.0.0-beta.15", "async-mutex": "0.5.0", "nanoid": [ "5.1.11", diff --git a/packages/stage-ui/src/composables/audio/voice-input-session.test.ts b/packages/stage-ui/src/composables/audio/voice-input-session.test.ts index 62998b0e7..c107ea0f0 100644 --- a/packages/stage-ui/src/composables/audio/voice-input-session.test.ts +++ b/packages/stage-ui/src/composables/audio/voice-input-session.test.ts @@ -9,6 +9,7 @@ const audioRecorderMock = vi.hoisted(() => ({ })) const vadMock = vi.hoisted(() => ({ + init: vi.fn<() => Promise>(), options: undefined as { onSpeechStart?: () => void onSpeechEnd?: () => void @@ -16,6 +17,7 @@ const vadMock = vi.hoisted(() => ({ onSpeechReady?: (event: { buffer: Float32Array, duration: number }) => void minSilenceDurationMs?: number } | undefined, + start: vi.fn<() => Promise>(), })) const hearingPipelineMock = vi.hoisted(() => ({ @@ -33,9 +35,9 @@ vi.mock('../../stores/ai/models/vad', async () => { useVAD: (_workerUrl: string, options: typeof vadMock.options) => { vadMock.options = options return { - init: vi.fn(), + init: vadMock.init, dispose: vi.fn(), - start: vi.fn(), + start: vadMock.start, loaded: vue.ref(true), isSpeech: vue.ref(false), isSpeechProb: vue.ref(0), @@ -82,6 +84,8 @@ describe('useVoiceInputSession', () => { audioRecorderMock.isRecording.value = false audioRecorderMock.onStopRecordHook = undefined vadMock.options = undefined + vadMock.init.mockReset().mockResolvedValue(undefined) + vadMock.start.mockReset().mockResolvedValue(undefined) vi.useRealTimers() vi.unstubAllGlobals() vi.clearAllMocks() diff --git a/packages/stage-ui/src/composables/audio/voice-input-vad-startup.test.ts b/packages/stage-ui/src/composables/audio/voice-input-vad-startup.test.ts index 0bf418b9a..981fbd236 100644 --- a/packages/stage-ui/src/composables/audio/voice-input-vad-startup.test.ts +++ b/packages/stage-ui/src/composables/audio/voice-input-vad-startup.test.ts @@ -3,6 +3,26 @@ import { describe, expect, it, vi } from 'vitest' import { startVoiceInputVadDetectionSafely } from './voice-input-vad-startup' describe('voice input VAD startup', () => { + it('reports readiness after VAD connects to the microphone stream', async () => { + const log = vi.fn() + const start = vi.fn().mockResolvedValue(undefined) + + await expect(startVoiceInputVadDetectionSafely({ + init: vi.fn().mockResolvedValue(undefined), + loaded: () => true, + start, + stream: {} as MediaStream, + log, + })).resolves.toBe(true) + + expect(start).toHaveBeenCalledOnce() + expect(log).toHaveBeenLastCalledWith( + 'info', + 'vad-ready', + 'VAD is connected to the microphone stream.', + ) + }) + it('returns false and logs when VAD initialization throws', async () => { const init = vi.fn().mockRejectedValue(new Error('vad unavailable')) const start = vi.fn() diff --git a/packages/stage-ui/src/composables/audio/voice-input-vad-startup.ts b/packages/stage-ui/src/composables/audio/voice-input-vad-startup.ts index 03f5e023c..9bd3a9714 100644 --- a/packages/stage-ui/src/composables/audio/voice-input-vad-startup.ts +++ b/packages/stage-ui/src/composables/audio/voice-input-vad-startup.ts @@ -18,6 +18,7 @@ export async function startVoiceInputVadDetectionSafely(options: VoiceInputVadSt stream: options.stream, }) await options.start(options.stream) + options.log?.('info', 'vad-ready', 'VAD is connected to the microphone stream.') return true } diff --git a/packages/testing-audio/.gitignore b/packages/testing-audio/.gitignore new file mode 100644 index 000000000..51511d1f8 --- /dev/null +++ b/packages/testing-audio/.gitignore @@ -0,0 +1 @@ +test-results/ diff --git a/packages/testing-audio/README.md b/packages/testing-audio/README.md new file mode 100644 index 000000000..24b1690bf --- /dev/null +++ b/packages/testing-audio/README.md @@ -0,0 +1,127 @@ +# Testing audio + +This package runs recorded microphone tests through the real AIRI audio pipeline. + +```text +input.wav -> virtual microphone -> VAD -> ASR -> LLM -> TTS -> playback -> UI +``` + +The package exports audio-aware `describe`, `it`, and `expect` APIs. Vitest owns the task tree and result protocol. Each project starts its configured Playwright runtime. + +`src` only owns test scheduling, runtime startup, browser probes, and matchers. Case-specific environment, storage, Provider, route, and UI operations live under `cases/shared`: + +```text +cases/shared/ + configurations/ # preflight callbacks that configure one concern + interactions/ # reusable UI operations selected by a case +``` + +## Configure a case + +The optional `preflight` field is an ordered callback array. The fake-microphone Vitest integration starts the runtime before it invokes these callbacks. Each callback receives: + +- `env`: the process environment for this case +- `runtime`: the clean Playwright runtime +- `skip`: Vitest's case-level skip control + +Every case explicitly selects the configuration it needs. Do not create one shared “complete pipeline” preflight that hides the Provider combination. + +```ts +import { describe, expect, it } from '../../src' +import { configureModuleHearing, configureOnboarding, loadCaseEnvironment } from '../shared/configurations' +import { enableChatMicrophone } from '../shared/interactions' +import { openaiAsr } from '../shared/providers' + +describe('audio input pipeline', () => { + it('transcribes a greeting', { + input: new URL('./input.test.wav', import.meta.url), + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const apiKey = environment.TESTING_AUDIO_ASR_API_KEY + context.skip(!apiKey, 'Set TESTING_AUDIO_ASR_API_KEY to run this ASR case.') + if (!apiKey) + return undefined + + return { + provider: openaiAsr({ + apiKey, + baseUrl: environment.TESTING_AUDIO_ASR_API_BASE_URL ?? 'https://api.openai.com/v1/', + model: environment.TESTING_AUDIO_ASR_MODEL ?? 'whisper-1', + provider: environment.TESTING_AUDIO_ASR_PROVIDER ?? 'openai-compatible-audio-transcription', + }), + captureFormat: 'wav', + } + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio) + await expect(audio).toHaveTranscriptions([ + ['Please say hello.'], + ]) + }) +}) +``` + +A case can independently choose its VAD behavior, ASR, LLM, and TTS configuration. A configuration callback can read its own environment, write local storage, use another persistence mechanism, or deliberately leave onboarding incomplete. + +## Provider environment + +Each case selects its environment variables. `loadCaseEnvironment` uses Vite test mode to read repository, `packages/stage-ui`, and package environment files. Process variables have the highest priority. + +Put local test credentials in `packages/testing-audio/.env.test.local`. Git ignores this file. + +The OpenAI-compatible Provider helpers do not read the environment. Pass the endpoint, API key, model, and voice from the case callback. + +The included cases use these explicit variables: + +```dotenv +TESTING_AUDIO_ASR_PROVIDER=openai-compatible-audio-transcription +TESTING_AUDIO_ASR_MODEL=whisper-1 +TESTING_AUDIO_ASR_API_BASE_URL=https://api.openai.com/v1/ +TESTING_AUDIO_ASR_API_KEY=... + +TESTING_AUDIO_ASR_ALIYUN_NLS_PROVIDER=aliyun-nls-transcription +TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_ID=... +TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_SECRET=... +TESTING_AUDIO_ASR_ALIYUN_NLS_APPKEY=... + +TESTING_AUDIO_LLM_PROVIDER=openai-compatible +TESTING_AUDIO_LLM_MODEL=gpt-4o-mini +TESTING_AUDIO_LLM_API_BASE_URL=https://api.openai.com/v1/ +TESTING_AUDIO_LLM_API_KEY=... + +TESTING_AUDIO_TTS_PROVIDER=openai-compatible-audio-speech +TESTING_AUDIO_TTS_MODEL=tts-1 +TESTING_AUDIO_TTS_VOICE=alloy +TESTING_AUDIO_TTS_API_BASE_URL=https://api.openai.com/v1/ +TESTING_AUDIO_TTS_API_KEY=... +``` + +These tests send audio and text to external Providers. Each run can incur Provider charges. + +## Run the tests + +Build both targets and run all runtime projects: + +```bash +pnpm -F @proj-airi/testing-audio test:run +``` + +Use existing builds: + +```bash +pnpm -F @proj-airi/testing-audio test:existing-builds +``` + +Run one runtime project: + +```bash +pnpm -F @proj-airi/testing-audio exec vitest run --project audio-web +pnpm -F @proj-airi/testing-audio exec vitest run --project audio-electron +``` + +Use `*.audio.web.test.ts` for Web-only cases. Use `*.audio.electron.test.ts` for Electron-only cases. The `*.audio.test.ts` pattern runs in both projects. + +Do not use Vitest Browser Mode for these cases. Each task needs a case-specific Chromium fake-microphone process argument. diff --git a/packages/testing-audio/cases/long-leading-silence/case.audio.test.ts b/packages/testing-audio/cases/long-leading-silence/case.audio.test.ts new file mode 100644 index 000000000..2e74415ed --- /dev/null +++ b/packages/testing-audio/cases/long-leading-silence/case.audio.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, it } from '../../src' +import { configureModuleHearing, configureOnboarding, loadCaseEnvironment } from '../shared/configurations' +import { enableChatMicrophone } from '../shared/interactions' +import { aliyunNlsAsr, openaiAsr } from '../shared/providers' + +describe('audio input pipeline', () => { + // The fixture uses the repository recording at docs/content/en/blog/DevLog-2025.03.20/assets/ashley-pitch-test.mp3. + // It has 20 seconds of leading silence and 4 seconds of trailing silence in mono 16 kHz PCM WAV format. + it('does not preserve the complete phrase after long leading silence', { + input: new URL('./input.test.wav', import.meta.url), + // This regression isolates AIRI's default VAD and one explicit ASR Provider. + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const apiKey = environment.TESTING_AUDIO_ASR_API_KEY + context.skip(!apiKey, 'Set TESTING_AUDIO_ASR_API_KEY to run this ASR case.') + if (!apiKey) + return undefined + + return { + provider: openaiAsr({ + apiKey, + baseUrl: environment.TESTING_AUDIO_ASR_API_BASE_URL ?? 'https://api.openai.com/v1/', + model: environment.TESTING_AUDIO_ASR_MODEL ?? 'whisper-1', + provider: environment.TESTING_AUDIO_ASR_PROVIDER ?? 'openai-compatible-audio-transcription', + }), + captureFormat: 'wav', + } + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio) + + if (audio.transcriptionCaptureFormat) { + await expect(audio).toHaveCapturedTranscriptionAudio({ + count: 1, + minimumBytes: 8000, + }) + } + + // The VAD upload currently drops part of the sentence before it sends the recording to ASR. + await expect(audio).not.toHaveTranscriptions([ + ['There is no meaning to your existence, just let go.'], + ]) + }) + + it('does not preserve the complete phrase with Aliyun NLS', { + input: new URL('./input.test.wav', import.meta.url), + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const provider = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_PROVIDER + const accessKeyId = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_ID + const accessKeySecret = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_SECRET + const appKey = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_APPKEY + context.skip( + !provider || !accessKeyId || !accessKeySecret || !appKey, + 'Set all TESTING_AUDIO_ASR_ALIYUN_NLS_* variables to run this ASR case.', + ) + if (!provider || !accessKeyId || !accessKeySecret || !appKey) + return undefined + + return { + provider: aliyunNlsAsr({ provider, accessKeyId, accessKeySecret, appKey }), + captureFormat: 'pcm', + } + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio, { readiness: 'streaming-transcription' }) + + await expect(audio).toHaveCapturedTranscriptionAudio({ + count: 1, + minimumBytes: 8000, + }) + await expect(audio).not.toHaveTranscriptions([ + ['There is no meaning to your existence, just let go.'], + ]) + }) +}) diff --git a/packages/testing-audio/cases/long-leading-silence/input.test.wav b/packages/testing-audio/cases/long-leading-silence/input.test.wav new file mode 100644 index 000000000..0c4855621 Binary files /dev/null and b/packages/testing-audio/cases/long-leading-silence/input.test.wav differ diff --git a/packages/testing-audio/cases/shared/configurations/active-card.ts b/packages/testing-audio/cases/shared/configurations/active-card.ts new file mode 100644 index 000000000..44c94a3d6 --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/active-card.ts @@ -0,0 +1,35 @@ +import type { AiriCard, AiriExtension } from '@proj-airi/stage-ui/types' + +import type { AudioInputSession } from '../../../src/types' + +type ActiveCardModules = Partial> + +/** Updates Provider selections that the active AIRI Card reapplies during application startup. */ +export async function configureActiveCardModules( + runtime: AudioInputSession, + modules: ActiveCardModules, +): Promise { + await runtime.runtimePage.evaluate(({ configuredModules }) => { + const serializedCards = localStorage.getItem('airi-cards') + if (!serializedCards) + throw new Error('The AIRI Card store is not initialized.') + + const activeCardId = localStorage.getItem('airi-card-active-id') ?? 'default' + const cards = JSON.parse(serializedCards) as Array<[string, AiriCard]> + const activeCard = cards.find(([cardId]) => cardId === activeCardId)?.[1] + if (!activeCard) + throw new Error(`The active AIRI Card "${activeCardId}" does not exist.`) + + const currentModules = activeCard.extensions.airi.modules + activeCard.extensions.airi.modules = { + ...currentModules, + ...(configuredModules.consciousness + ? { consciousness: configuredModules.consciousness } + : {}), + ...(configuredModules.speech + ? { speech: { ...currentModules.speech, ...configuredModules.speech } } + : {}), + } + localStorage.setItem('airi-cards', JSON.stringify(cards)) + }, { configuredModules: modules }) +} diff --git a/packages/testing-audio/cases/shared/configurations/environment.ts b/packages/testing-audio/cases/shared/configurations/environment.ts new file mode 100644 index 000000000..995ab9153 --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/environment.ts @@ -0,0 +1,23 @@ +import type { AudioInputPreflightContext } from '../../../src/types' + +import { resolve } from 'node:path' + +import { findWorkspaceDir } from '@pnpm/find-workspace-dir' +import { loadEnv } from 'vite' + +/** Loads Vite test-mode environment files and applies the environment of the current case. */ +export async function loadCaseEnvironment( + environment: AudioInputPreflightContext['env'], +): Promise> { + const repositoryRoot = await findWorkspaceDir(import.meta.dirname) + if (!repositoryRoot) + throw new Error(`Unable to find the pnpm workspace from ${import.meta.dirname}`) + + const repositoryEnvironment = loadEnv('test', repositoryRoot, '') + // Shared Provider development variables live in stage-ui. These values override repository files. + const stageUiEnvironment = loadEnv('test', resolve(repositoryRoot, 'packages/stage-ui'), '') + // Audio case credentials belong to this package. These values override shared Provider variables. + const testingAudioEnvironment = loadEnv('test', resolve(repositoryRoot, 'packages/testing-audio'), '') + // The case process has the highest priority so that CI and shell values override local files. + return { ...repositoryEnvironment, ...stageUiEnvironment, ...testingAudioEnvironment, ...environment } +} diff --git a/packages/testing-audio/cases/shared/configurations/index.ts b/packages/testing-audio/cases/shared/configurations/index.ts new file mode 100644 index 000000000..cf5ad4c9e --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/index.ts @@ -0,0 +1,9 @@ +export { loadCaseEnvironment } from './environment' +export { configureModuleConsciousness } from './module-consciousness' +export type { ConsciousnessModuleConfiguration } from './module-consciousness' +export { configureModuleHearing } from './module-hearing' +export type { HearingModuleConfiguration } from './module-hearing' +export { configureModuleSpeech } from './module-speech' +export type { SpeechModuleConfiguration } from './module-speech' +export { configureOnboarding } from './onboarding' +export type { OnboardingConfiguration } from './onboarding' diff --git a/packages/testing-audio/cases/shared/configurations/module-consciousness.ts b/packages/testing-audio/cases/shared/configurations/module-consciousness.ts new file mode 100644 index 000000000..546fe23dd --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/module-consciousness.ts @@ -0,0 +1,33 @@ +import type { AudioInputPreflightCallback, AudioInputPreflightContext } from '../../../src/types' +import type { ProviderConfiguration } from './provider' + +import { configureActiveCardModules } from './active-card' +import { configureProvider } from './provider' +import { configureStorage } from './storage' + +export interface ConsciousnessModuleConfiguration { + provider: ProviderConfiguration +} + +type ConsciousnessModuleResolver = (context: AudioInputPreflightContext) => ConsciousnessModuleConfiguration | undefined | Promise + +/** Configures the consciousness module with the LLM Provider selected by one case. */ +export function configureModuleConsciousness(resolve: ConsciousnessModuleResolver): AudioInputPreflightCallback { + return async (context) => { + const configuration = await resolve(context) + if (!configuration) + return + + await configureProvider(context.runtime, configuration.provider) + await configureActiveCardModules(context.runtime, { + consciousness: { + provider: configuration.provider.id, + model: configuration.provider.model, + }, + }) + await configureStorage(context.runtime, { + 'settings/consciousness/active-provider': configuration.provider.id, + 'settings/consciousness/active-model': configuration.provider.model, + }) + } +} diff --git a/packages/testing-audio/cases/shared/configurations/module-hearing.ts b/packages/testing-audio/cases/shared/configurations/module-hearing.ts new file mode 100644 index 000000000..959011820 --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/module-hearing.ts @@ -0,0 +1,46 @@ +import type { AudioCaptureFormat } from '@proj-airi/vitest-plugin-fakemic' + +import type { AudioInputPreflightCallback, AudioInputPreflightContext } from '../../../src/types' +import type { ProviderConfiguration } from './provider' + +import { configureProvider } from './provider' +import { configureStorage } from './storage' + +export interface HearingModuleConfiguration { + /** @default undefined */ + captureFormat?: AudioCaptureFormat + /** @default false */ + microphoneEnabled?: boolean + provider: ProviderConfiguration +} + +type HearingModuleResolver = (context: AudioInputPreflightContext) => HearingModuleConfiguration | undefined | Promise + +/** Configures the hearing module with the ASR Provider selected by one case. */ +export function configureModuleHearing(resolve: HearingModuleResolver): AudioInputPreflightCallback { + return async (context) => { + const configuration = await resolve(context) + if (!configuration) + return + + await configureProvider(context.runtime, configuration.provider) + const settings: Record = { + 'settings/hearing/active-provider': configuration.provider.id, + 'settings/hearing/active-model': configuration.provider.model, + 'settings/audio/input/enabled': String(configuration.microphoneEnabled ?? false), + } + + if (context.runtime.target === 'electron') { + const microphoneInput = await context.runtime.runtimePage.evaluate(async () => { + const devices = await navigator.mediaDevices.enumerateDevices() + return devices.find(device => device.kind === 'audioinput' && device.label.includes('Fake'))?.deviceId + }) + if (!microphoneInput) + throw new Error('Chromium did not expose the file-backed fake microphone.') + settings['settings/audio/input'] = microphoneInput + } + + await configureStorage(context.runtime, settings) + context.runtime.transcriptionCaptureFormat = configuration.captureFormat + } +} diff --git a/packages/testing-audio/cases/shared/configurations/module-speech.ts b/packages/testing-audio/cases/shared/configurations/module-speech.ts new file mode 100644 index 000000000..6f14f2596 --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/module-speech.ts @@ -0,0 +1,39 @@ +import type { AudioInputPreflightCallback, AudioInputPreflightContext } from '../../../src/types' +import type { ProviderConfiguration } from './provider' + +import { configureActiveCardModules } from './active-card' +import { configureProvider } from './provider' +import { configureStorage } from './storage' + +export interface SpeechModuleConfiguration { + /** @default false */ + muted?: boolean + provider: ProviderConfiguration + voice: string +} + +type SpeechModuleResolver = (context: AudioInputPreflightContext) => SpeechModuleConfiguration | undefined | Promise + +/** Configures the speech module with the TTS Provider selected by one case. */ +export function configureModuleSpeech(resolve: SpeechModuleResolver): AudioInputPreflightCallback { + return async (context) => { + const configuration = await resolve(context) + if (!configuration) + return + + await configureProvider(context.runtime, configuration.provider) + await configureActiveCardModules(context.runtime, { + speech: { + provider: configuration.provider.id, + model: configuration.provider.model, + voice_id: configuration.voice, + }, + }) + await configureStorage(context.runtime, { + 'settings/speech/active-provider': configuration.provider.id, + 'settings/speech/active-model': configuration.provider.model, + 'settings/speech/voice': configuration.voice, + 'settings/speech/output-muted': String(configuration.muted ?? false), + }) + } +} diff --git a/packages/testing-audio/cases/shared/configurations/onboarding.ts b/packages/testing-audio/cases/shared/configurations/onboarding.ts new file mode 100644 index 000000000..fee77e2a7 --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/onboarding.ts @@ -0,0 +1,33 @@ +import type { AudioInputPreflightCallback, AudioInputPreflightContext } from '../../../src/types' + +import { configureStorage } from './storage' + +export interface OnboardingConfiguration { + completed: boolean + /** @default false */ + skipped?: boolean +} + +type OnboardingResolver = (context: AudioInputPreflightContext) => OnboardingConfiguration | undefined | Promise + +/** Configures onboarding with values selected by one case. */ +export function configureOnboarding(resolve: OnboardingResolver): AudioInputPreflightCallback { + return async (context) => { + const configuration = await resolve(context) + if (!configuration) + return + + await configureStorage(context.runtime, { + 'onboarding/completed': String(configuration.completed), + 'onboarding/skipped': String(configuration.skipped ?? false), + }) + + if (configuration.completed || configuration.skipped) { + await new Promise(resolveWait => setTimeout(resolveWait, 1_000)) + const onboardingPages = context.runtime.electronApp + ?.windows() + .filter(page => new URL(page.url()).hash.startsWith('#/onboarding')) ?? [] + await Promise.all(onboardingPages.map(page => page.close().catch(() => undefined))) + } + } +} diff --git a/packages/testing-audio/cases/shared/configurations/provider.ts b/packages/testing-audio/cases/shared/configurations/provider.ts new file mode 100644 index 000000000..e2a7db9b7 --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/provider.ts @@ -0,0 +1,31 @@ +import type { AudioInputSession } from '../../../src/types' + +/** Provider values stored by one case preflight callback. */ +export interface ProviderConfiguration { + config: Record + definitionId: string + id: string + model: string +} + +/** Adds one Provider without replacing Providers configured by earlier callbacks. */ +export async function configureProvider(runtime: AudioInputSession, provider: ProviderConfiguration): Promise { + await runtime.page.evaluate(({ configuredProvider }) => { + const credentials = JSON.parse(localStorage.getItem('settings/credentials/providers') ?? '{}') as Record + const configured = JSON.parse(localStorage.getItem('settings/providers/configured') ?? '{}') as Record + const added = JSON.parse(localStorage.getItem('settings/providers/added') ?? '{}') as Record + + credentials[configuredProvider.id] = configuredProvider.config + configured[configuredProvider.id] = { + id: configuredProvider.id, + definitionId: configuredProvider.definitionId, + config: configuredProvider.config, + status: 'configured', + } + added[configuredProvider.id] = true + + localStorage.setItem('settings/credentials/providers', JSON.stringify(credentials)) + localStorage.setItem('settings/providers/configured', JSON.stringify(configured)) + localStorage.setItem('settings/providers/added', JSON.stringify(added)) + }, { configuredProvider: provider }) +} diff --git a/packages/testing-audio/cases/shared/configurations/storage.ts b/packages/testing-audio/cases/shared/configurations/storage.ts new file mode 100644 index 000000000..eaa2648fb --- /dev/null +++ b/packages/testing-audio/cases/shared/configurations/storage.ts @@ -0,0 +1,12 @@ +import type { AudioInputSession } from '../../../src/types' + +/** Writes AIRI settings through the storage owned by the current runtime page. */ +export async function configureStorage( + runtime: AudioInputSession, + settings: Record, +): Promise { + await runtime.runtimePage.evaluate(({ entries }) => { + for (const [key, value] of Object.entries(entries)) + localStorage.setItem(key, value) + }, { entries: settings }) +} diff --git a/packages/testing-audio/cases/shared/interactions/chat.ts b/packages/testing-audio/cases/shared/interactions/chat.ts new file mode 100644 index 000000000..589085f58 --- /dev/null +++ b/packages/testing-audio/cases/shared/interactions/chat.ts @@ -0,0 +1,126 @@ +import type { Locator } from 'playwright' + +import type { AudioInputSession } from '../../../src/types' + +import { captureStreamingTranscription } from './streaming-transcription' + +export interface EnableChatMicrophoneOptions { + /** @default 'vad' */ + readiness?: 'streaming-transcription' | 'vad' +} + +/** Enables the chat microphone through the UI owned by the selected runtime. */ +export async function enableChatMicrophone( + runtime: AudioInputSession, + options: EnableChatMicrophoneOptions = {}, +): Promise { + if (runtime.target === 'electron') { + const app = runtime.electronApp + if (!app) + throw new Error('The Electron audio session does not expose its application.') + + const existingChatPage = app.windows().find(page => page.url().includes('index.html#/chat')) + if (existingChatPage) { + runtime.activatePage(existingChatPage) + } + else { + const chatButton = runtime.runtimePage.locator('button').filter({ + has: runtime.runtimePage.locator('[i-solar\\:chat-line-line-duotone]'), + }).first() + await chatButton.waitFor({ state: 'visible', timeout: 30_000 }) + runtime.activatePage(await openElectronChat(app, chatButton)) + } + } + + const { page } = runtime + await page.locator('textarea').first().waitFor({ state: 'visible', timeout: 60_000 }) + await captureStreamingTranscription(page, 'textarea') + + if (runtime.target === 'electron') { + await runtime.runtimePage.waitForFunction(async () => { + const devices = await navigator.mediaDevices.enumerateDevices() + return devices.some(device => device.kind === 'audioinput' && device.label.includes('Fake')) + }) + + const hearingTrigger = runtime.runtimePage.locator('div[aria-haspopup="dialog"] button').first() + await hearingTrigger.waitFor({ state: 'visible', timeout: 15_000 }) + await hearingTrigger.hover() + await hearingTrigger.click({ force: true }) + await runtime.runtimePage.waitForTimeout(500) + + const enableButton = runtime.runtimePage.locator('button[aria-label="Enable microphone input"]') + await enableButton.waitFor({ state: 'visible', timeout: 15_000 }) + const inputReady = options.readiness === 'streaming-transcription' + ? runtime.waitForStreamingTranscriptionReady() + : runtime.waitForVadReady() + await enableButton.click({ force: true }) + const disableButton = runtime.runtimePage.locator('button[aria-label="Disable microphone input"]') + await disableButton.waitFor({ state: 'visible', timeout: 15_000 }) + await inputReady + return + } + + const microphoneTrigger = page.locator('button').filter({ has: page.locator('.i-ph\\:microphone-slash') }).first() + await microphoneTrigger.click({ force: true }) + + const enableButton = page.locator('button[aria-label="Enable microphone input"]') + await enableButton.waitFor({ state: 'visible' }) + const inputReady = options.readiness === 'streaming-transcription' + ? runtime.waitForStreamingTranscriptionReady() + : runtime.waitForVadReady() + await enableButton.click() + await page.locator('button[aria-label="Disable microphone input"]').waitFor({ state: 'visible' }) + await inputReady +} + +/** Opens the chat page and waits for its input. */ +export async function openChat(runtime: AudioInputSession): Promise { + await runtime.page.evaluate(() => { + window.location.hash = '/chat' + }) + await runtime.page.locator('textarea').first().waitFor({ state: 'visible', timeout: 60_000 }) +} + +/** Returns the assistant messages on the current chat page. */ +export function assistantMessages(runtime: AudioInputSession): Locator { + return runtime.page.locator('[data-chat-message-role="assistant"] .markdown-content') +} + +async function openElectronChat( + app: NonNullable, + chatButton: Locator, +): Promise { + let lastError: unknown + for (let attempt = 0; attempt < 10; attempt++) { + await chatButton.click({ force: true }) + try { + return await waitForElectronPage(app, page => page.url().includes('index.html#/chat'), 3_000) + } + catch (error) { + lastError = error + } + } + + throw lastError +} + +async function waitForElectronPage( + app: NonNullable, + predicate: (page: AudioInputSession['page']) => boolean, + timeoutMs = 60_000, +): Promise { + const deadline = Date.now() + timeoutMs + while (Date.now() < deadline) { + const page = app.windows().find(predicate) + if (page) { + await page.waitForLoadState('domcontentloaded') + await page.bringToFront() + await page.waitForTimeout(750) + return page + } + + await new Promise(resolveWait => setTimeout(resolveWait, 100)) + } + + throw new Error(`Timed out while waiting for the Electron chat window. Open pages: ${app.windows().map(page => page.url()).join(', ')}`) +} diff --git a/packages/testing-audio/cases/shared/interactions/hearing-playground.ts b/packages/testing-audio/cases/shared/interactions/hearing-playground.ts new file mode 100644 index 000000000..9f9ab4607 --- /dev/null +++ b/packages/testing-audio/cases/shared/interactions/hearing-playground.ts @@ -0,0 +1,68 @@ +import type { ElectronApplication, Page } from 'playwright' + +import type { AudioInputSession } from '../../../src/types' + +import { captureStreamingTranscription } from './streaming-transcription' + +/** Opens the Electron hearing playground for a case that selects this input UI. */ +export async function openHearingPlayground(runtime: AudioInputSession): Promise { + const app = runtime.electronApp + if (!app) + throw new Error('The hearing playground interaction requires an Electron runtime') + + const settingsButton = runtime.page.getByRole('button', { name: /Open settings|打开设置/ }).last() + if (!await settingsButton.isVisible().catch(() => false)) { + await runtime.page.getByRole('button', { name: /Expand|展开/ }).last().click({ force: true }) + await settingsButton.waitFor({ state: 'visible', timeout: 15_000 }) + } + + await settingsButton.click({ force: true }) + const settingsPage = await waitForElectronPage(app, page => page.url().includes('index.html#/settings')) + await settingsPage.evaluate(() => { + window.location.hash = '/settings/modules/hearing' + }) + await settingsPage.waitForURL(/#\/settings\/modules\/hearing/) + await settingsPage.getByTestId('hearing-playground-monitor-toggle').waitFor({ state: 'visible', timeout: 60_000 }) + return settingsPage +} + +/** Enables microphone monitoring on an open hearing playground. */ +export async function enableHearingPlaygroundMicrophone(page: Page): Promise { + await captureStreamingTranscription(page, '[data-testid="hearing-playground-current"] p') + + const modelBasedToggle = page.getByRole('switch').last() + if (await modelBasedToggle.isChecked()) + await modelBasedToggle.click() + + const monitorToggle = page.getByTestId('hearing-playground-monitor-toggle') + await monitorToggle.click() +} + +/** Reads the requested number of final hearing playground transcripts. */ +export async function readHearingPlaygroundTranscriptions(page: Page, count: number): Promise { + const transcriptions = page.getByTestId('hearing-playground-transcript') + await transcriptions.nth(count - 1).waitFor({ state: 'visible', timeout: 60_000 }) + const results = (await transcriptions.allTextContents()).toReversed() + await page.evaluate((transcriptionResults) => { + if (window.__airiAudioInputE2E) + window.__airiAudioInputE2E.transcriptionResults = transcriptionResults + }, results) + return results +} + +async function waitForElectronPage( + app: ElectronApplication, + predicate: (page: Page) => boolean, + timeoutMs = 60_000, +): Promise { + const deadline = Date.now() + timeoutMs + while (Date.now() < deadline) { + const page = app.windows().find(predicate) + if (page) { + await page.waitForLoadState('domcontentloaded') + return page + } + await new Promise(resolveWait => setTimeout(resolveWait, 100)) + } + throw new Error('Timed out while waiting for the Electron renderer') +} diff --git a/packages/testing-audio/cases/shared/interactions/index.ts b/packages/testing-audio/cases/shared/interactions/index.ts new file mode 100644 index 000000000..b57841b15 --- /dev/null +++ b/packages/testing-audio/cases/shared/interactions/index.ts @@ -0,0 +1,7 @@ +export { assistantMessages, enableChatMicrophone, openChat } from './chat' +export type { EnableChatMicrophoneOptions } from './chat' +export { + enableHearingPlaygroundMicrophone, + openHearingPlayground, + readHearingPlaygroundTranscriptions, +} from './hearing-playground' diff --git a/packages/testing-audio/cases/shared/interactions/streaming-transcription.ts b/packages/testing-audio/cases/shared/interactions/streaming-transcription.ts new file mode 100644 index 000000000..0cb923e08 --- /dev/null +++ b/packages/testing-audio/cases/shared/interactions/streaming-transcription.ts @@ -0,0 +1,20 @@ +import type { Page } from 'playwright' + +/** Records distinct visible transcription values until the page closes. */ +export async function captureStreamingTranscription(page: Page, selector: string): Promise { + await page.evaluate((captureSelector) => { + let lastUpdate = '' + setInterval(() => { + const element = document.querySelector(captureSelector) + const value = element instanceof HTMLTextAreaElement + ? element.value + : element?.textContent + const update = value?.trim() ?? '' + const updates = window.__airiAudioInputE2E?.streamingTranscriptionUpdates + if (update && update !== lastUpdate && updates) { + lastUpdate = update + updates.push(update) + } + }, 20) + }, selector) +} diff --git a/packages/testing-audio/cases/shared/providers/aliyun-nls.ts b/packages/testing-audio/cases/shared/providers/aliyun-nls.ts new file mode 100644 index 000000000..d6f74270c --- /dev/null +++ b/packages/testing-audio/cases/shared/providers/aliyun-nls.ts @@ -0,0 +1,26 @@ +import type { ProviderConfiguration } from '../configurations/provider' + +/** Credentials and Provider selection for Aliyun NLS transcription. */ +export interface AliyunNlsAsrOptions { + accessKeyId: string + accessKeySecret: string + appKey: string + provider: string +} + +/** Creates an Aliyun NLS realtime ASR Provider configuration. */ +export function aliyunNlsAsr(options: AliyunNlsAsrOptions): ProviderConfiguration { + if (options.provider !== 'aliyun-nls-transcription') + throw new Error('The Aliyun NLS Provider must be "aliyun-nls-transcription".') + + return { + id: options.provider, + definitionId: options.provider, + model: 'aliyun-nls-v1', + config: { + accessKeyId: options.accessKeyId, + accessKeySecret: options.accessKeySecret, + appKey: options.appKey, + }, + } +} diff --git a/packages/testing-audio/cases/shared/providers/index.ts b/packages/testing-audio/cases/shared/providers/index.ts new file mode 100644 index 000000000..99a7d1ff0 --- /dev/null +++ b/packages/testing-audio/cases/shared/providers/index.ts @@ -0,0 +1,4 @@ +export { aliyunNlsAsr } from './aliyun-nls' +export type { AliyunNlsAsrOptions } from './aliyun-nls' +export { openaiAsr, openaiLlm, openaiTts } from './openai' +export type { OpenAIProviderOptions, OpenAISpeechProviderOptions } from './openai' diff --git a/packages/testing-audio/cases/shared/providers/openai.ts b/packages/testing-audio/cases/shared/providers/openai.ts new file mode 100644 index 000000000..c632e9578 --- /dev/null +++ b/packages/testing-audio/cases/shared/providers/openai.ts @@ -0,0 +1,58 @@ +import type { ProviderConfiguration } from '../configurations/provider' + +/** Configuration for an OpenAI-compatible Provider selected by one case. */ +export interface OpenAIProviderOptions { + apiKey: string + baseUrl: string + model: string + provider: string +} + +/** Configuration for an OpenAI-compatible speech Provider selected by one case. */ +export interface OpenAISpeechProviderOptions extends OpenAIProviderOptions { + voice: string +} + +/** Creates an OpenAI-compatible ASR Provider configuration. */ +export function openaiAsr(options: OpenAIProviderOptions): ProviderConfiguration { + return { + id: options.provider, + definitionId: options.provider, + model: options.model, + config: { + apiKey: options.apiKey, + baseUrl: options.baseUrl, + }, + } +} + +/** Creates an OpenAI-compatible LLM Provider configuration. */ +export function openaiLlm(options: OpenAIProviderOptions): ProviderConfiguration { + return { + id: options.provider, + definitionId: options.provider, + model: options.model, + config: { + apiKey: options.apiKey, + baseUrl: options.baseUrl, + }, + } +} + +/** Creates an OpenAI-compatible TTS Provider configuration. */ +export function openaiTts(options: OpenAISpeechProviderOptions): { provider: ProviderConfiguration, voice: string } { + return { + voice: options.voice, + provider: { + id: options.provider, + definitionId: options.provider, + model: options.model, + config: { + apiKey: options.apiKey, + baseUrl: options.baseUrl, + model: options.model, + voice: options.voice, + }, + }, + } +} diff --git a/packages/testing-audio/cases/single-utterance-pipeline/case.audio.test.ts b/packages/testing-audio/cases/single-utterance-pipeline/case.audio.test.ts new file mode 100644 index 000000000..839aff10d --- /dev/null +++ b/packages/testing-audio/cases/single-utterance-pipeline/case.audio.test.ts @@ -0,0 +1,121 @@ +import { describe, expect, it } from '../../src' +import { configureModuleConsciousness, configureModuleHearing, configureModuleSpeech, configureOnboarding, loadCaseEnvironment } from '../shared/configurations' +import { assistantMessages, enableChatMicrophone, openChat } from '../shared/interactions' +import { aliyunNlsAsr, openaiAsr, openaiLlm, openaiTts } from '../shared/providers' + +describe('audio input pipeline', () => { + // An OpenAI-compatible TTS Provider generated the fixture in mono 16 kHz PCM WAV format. + // The fixture contains 14 seconds of leading silence for VAD initialization and 3 seconds of trailing silence. + // Its warm-up phrase gives the VAD time to start. Only "Please say hello." is required in the transcript. + it('runs an OpenAI-compatible request through the complete pipeline', { + input: new URL('./input.test.wav', import.meta.url), + // This case keeps AIRI's default VAD and selects every remote Provider explicitly. + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const apiKey = environment.TESTING_AUDIO_ASR_API_KEY + context.skip(!apiKey, 'Set TESTING_AUDIO_ASR_API_KEY to run this ASR case.') + if (!apiKey) + return undefined + + return { + provider: openaiAsr({ + apiKey, + baseUrl: environment.TESTING_AUDIO_ASR_API_BASE_URL ?? 'https://api.openai.com/v1/', + model: environment.TESTING_AUDIO_ASR_MODEL ?? 'whisper-1', + provider: environment.TESTING_AUDIO_ASR_PROVIDER ?? 'openai-compatible-audio-transcription', + }), + captureFormat: 'wav', + } + }), + configureModuleConsciousness(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const apiKey = environment.TESTING_AUDIO_LLM_API_KEY + context.skip(!apiKey, 'Set TESTING_AUDIO_LLM_API_KEY to run this LLM case.') + if (!apiKey) + return undefined + + return { + provider: openaiLlm({ + apiKey, + baseUrl: environment.TESTING_AUDIO_LLM_API_BASE_URL ?? 'https://api.openai.com/v1/', + model: environment.TESTING_AUDIO_LLM_MODEL ?? 'gpt-4o-mini', + provider: environment.TESTING_AUDIO_LLM_PROVIDER ?? 'openai-compatible', + }), + } + }), + configureModuleSpeech(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const apiKey = environment.TESTING_AUDIO_TTS_API_KEY + context.skip(!apiKey, 'Set TESTING_AUDIO_TTS_API_KEY to run this TTS case.') + if (!apiKey) + return undefined + + return openaiTts({ + apiKey, + baseUrl: environment.TESTING_AUDIO_TTS_API_BASE_URL ?? 'https://api.openai.com/v1/', + model: environment.TESTING_AUDIO_TTS_MODEL ?? 'tts-1', + provider: environment.TESTING_AUDIO_TTS_PROVIDER ?? 'openai-compatible-audio-speech', + voice: environment.TESTING_AUDIO_TTS_VOICE ?? 'alloy', + }) + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio) + + if (audio.transcriptionCaptureFormat) { + await expect(audio).toHaveCapturedTranscriptionAudio({ + count: 1, + minimumBytes: 8000, + }) + } + + await expect(audio).toHaveTranscriptions([ + ['Please say hello.'], + ], { match: 'contains' }) + + await expect.poll(async () => (await audio.completedSpans('LLM inference')).length, { timeout: 60_000 }).toBeGreaterThanOrEqual(1) + await expect.poll(async () => (await audio.completedSpans('TTS synthesis')).length, { timeout: 60_000 }).toBeGreaterThanOrEqual(1) + await expect.poll(async () => (await audio.completedSpans('Audio playback')).length, { timeout: 60_000 }).toBeGreaterThanOrEqual(1) + + await openChat(audio) + const messages = await assistantMessages(audio).allTextContents() + expect(messages.at(-1)).toMatch(/.+/s) + }) + + it('transcribes the greeting with Aliyun NLS', { + input: new URL('./input.test.wav', import.meta.url), + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const provider = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_PROVIDER + const accessKeyId = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_ID + const accessKeySecret = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_SECRET + const appKey = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_APPKEY + context.skip( + !provider || !accessKeyId || !accessKeySecret || !appKey, + 'Set all TESTING_AUDIO_ASR_ALIYUN_NLS_* variables to run this ASR case.', + ) + if (!provider || !accessKeyId || !accessKeySecret || !appKey) + return undefined + + return { + provider: aliyunNlsAsr({ provider, accessKeyId, accessKeySecret, appKey }), + captureFormat: 'pcm', + } + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio, { readiness: 'streaming-transcription' }) + + await expect(audio).toHaveCapturedTranscriptionAudio({ + count: 1, + minimumBytes: 8000, + }) + await expect(audio).toHaveTranscriptions([ + ['Please say hello.'], + ], { match: 'contains' }) + }) +}) diff --git a/packages/testing-audio/cases/single-utterance-pipeline/input.test.wav b/packages/testing-audio/cases/single-utterance-pipeline/input.test.wav new file mode 100644 index 000000000..99e270ffd Binary files /dev/null and b/packages/testing-audio/cases/single-utterance-pipeline/input.test.wav differ diff --git a/packages/testing-audio/cases/two-utterance-streaming/case.audio.test.ts b/packages/testing-audio/cases/two-utterance-streaming/case.audio.test.ts new file mode 100644 index 000000000..b4639e51d --- /dev/null +++ b/packages/testing-audio/cases/two-utterance-streaming/case.audio.test.ts @@ -0,0 +1,105 @@ +import { describe, expect, it } from '../../src' +import { configureModuleHearing, configureOnboarding, loadCaseEnvironment } from '../shared/configurations' +import { enableChatMicrophone } from '../shared/interactions' +import { aliyunNlsAsr, openaiAsr } from '../shared/providers' + +describe('audio input pipeline', () => { + // The fixture has 12 seconds of leading silence so that the browser VAD can load. + // It repeats the greeting after a 2-second pause to catch regressions that drop the second utterance. + it('keeps two utterances in streaming transcription', { + input: new URL('./input.test.wav', import.meta.url), + // This regression isolates AIRI's default VAD and one explicit ASR Provider. + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const apiKey = environment.TESTING_AUDIO_ASR_API_KEY + context.skip(!apiKey, 'Set TESTING_AUDIO_ASR_API_KEY to run this ASR case.') + if (!apiKey) + return undefined + + return { + provider: openaiAsr({ + apiKey, + baseUrl: environment.TESTING_AUDIO_ASR_API_BASE_URL ?? 'https://api.openai.com/v1/', + model: environment.TESTING_AUDIO_ASR_MODEL ?? 'whisper-1', + provider: environment.TESTING_AUDIO_ASR_PROVIDER ?? 'openai-compatible-audio-transcription', + }), + captureFormat: 'wav', + } + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio) + + if (audio.transcriptionCaptureFormat) { + await expect(audio).toHaveCapturedTranscriptionAudio({ + count: 1, + minimumBytes: 8000, + }) + } + + const expectedTranscriptions = [ + [ + 'Microphone warm up, microphone warm up. Hello, AIRI, please say hello.', + 'Microphone warm up, microphone warm up. Hello, Eric, please say hello.', + ], + [ + 'Microphone warm up, microphone warm up. Hello, AIRI, please say hello.', + 'Microphone warm up, microphone warm up. Hello, Eric, please say hello.', + ], + ] + await expect(audio).toHaveTranscriptions(expectedTranscriptions) + + const finalTranscriptions = await audio.transcriptionResults(expectedTranscriptions.length) + const streamingUpdates = await audio.streamingTranscriptionUpdates() + expect(streamingUpdates.some(update => !finalTranscriptions.includes(update))).toBe(true) + }) + + it('keeps two Aliyun NLS utterances in streaming transcription', { + input: new URL('./input.test.wav', import.meta.url), + preflight: [ + configureOnboarding(() => ({ completed: true })), + configureModuleHearing(async (context) => { + const environment = await loadCaseEnvironment(context.env) + const provider = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_PROVIDER + const accessKeyId = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_ID + const accessKeySecret = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_ALIYUN_AK_SECRET + const appKey = environment.TESTING_AUDIO_ASR_ALIYUN_NLS_APPKEY + context.skip( + !provider || !accessKeyId || !accessKeySecret || !appKey, + 'Set all TESTING_AUDIO_ASR_ALIYUN_NLS_* variables to run this ASR case.', + ) + if (!provider || !accessKeyId || !accessKeySecret || !appKey) + return undefined + + return { + provider: aliyunNlsAsr({ provider, accessKeyId, accessKeySecret, appKey }), + captureFormat: 'pcm', + } + }), + ], + }, async ({ audio }) => { + await enableChatMicrophone(audio, { readiness: 'streaming-transcription' }) + + await expect(audio).toHaveCapturedTranscriptionAudio({ + count: 1, + minimumBytes: 8000, + }) + const expectedTranscriptions = [ + [ + 'Microphone warm up, microphone warm up. Hello, AIRI, please say hello.', + 'Microphone warm up, microphone warm up. Hello, Eric, please say hello.', + ], + [ + 'Microphone warm up, microphone warm up. Hello, AIRI, please say hello.', + 'Microphone warm up, microphone warm up. Hello, Eric, please say hello.', + ], + ] + await expect(audio).toHaveTranscriptions(expectedTranscriptions) + + const finalTranscriptions = await audio.transcriptionResults(expectedTranscriptions.length) + const streamingUpdates = await audio.streamingTranscriptionUpdates() + expect(streamingUpdates.some(update => !finalTranscriptions.includes(update))).toBe(true) + }) +}) diff --git a/packages/testing-audio/cases/two-utterance-streaming/input.test.wav b/packages/testing-audio/cases/two-utterance-streaming/input.test.wav new file mode 100644 index 000000000..1affb61a9 Binary files /dev/null and b/packages/testing-audio/cases/two-utterance-streaming/input.test.wav differ diff --git a/packages/testing-audio/package.json b/packages/testing-audio/package.json new file mode 100644 index 000000000..35ef67618 --- /dev/null +++ b/packages/testing-audio/package.json @@ -0,0 +1,34 @@ +{ + "name": "@proj-airi/testing-audio", + "type": "module", + "version": "0.11.3", + "private": true, + "description": "AIRI Web and Electron audio pipeline tests", + "author": { + "name": "Moeru AI Project AIRI Team", + "email": "airi@moeru.ai", + "url": "https://github.com/moeru-ai" + }, + "license": "MIT", + "exports": "./src/index.ts", + "scripts": { + "build:targets": "pnpm -F @proj-airi/stage-web build && pnpm -F @proj-airi/stage-tamagotchi build", + "test": "vitest", + "test:run": "pnpm run build:targets && vitest run", + "test:existing-builds": "vitest run", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@moeru/std": "catalog:", + "@pnpm/find-workspace-dir": "catalog:", + "@proj-airi/stage-shared": "workspace:^", + "@proj-airi/stage-ui": "workspace:^", + "@proj-airi/vitest-plugin-fakemic": "workspace:^", + "playwright": "catalog:", + "vite": "catalog:", + "vitest": "catalog:vitest" + }, + "devDependencies": { + "@types/node": "catalog:" + } +} diff --git a/packages/testing-audio/src/describe.ts b/packages/testing-audio/src/describe.ts new file mode 100644 index 000000000..4e35890c3 --- /dev/null +++ b/packages/testing-audio/src/describe.ts @@ -0,0 +1,76 @@ +import type { AudioTestTask } from '@proj-airi/vitest-plugin-fakemic' + +import type { AudioInputPreflightContext, AudioInputSession, AudioInputTestCase } from './types' + +import { env } from 'node:process' +import { fileURLToPath } from 'node:url' + +import { errorMessageFrom } from '@moeru/std' +import { createAudioTestAPI, createAudioTestTask, runAudioTestSession, startFakemicRuntime } from '@proj-airi/vitest-plugin-fakemic' +import { inject } from 'vitest' + +import { expect, installAudioInputMatchers } from './expect-extend' + +type RunnableAudioInputTest = AudioTestTask + +installAudioInputMatchers() + +const audioTestAPI = createAudioTestAPI< + AudioInputTestCase, + RunnableAudioInputTest, + { audio: AudioInputSession }, + AudioInputPreflightContext +>({ + preflight: definition => definition.preflight, + createPlans(name, testCase) { + const task = createAudioTestTask(name, testCase) + return [{ + name: task.name, + definition: task, + metadata: { + input: fileURLToPath(task.input), + runtime: inject('fakemicRuntime').name, + }, + }] + }, + async execute({ plan, task, invokeHandler, runPreflight }) { + await runAudioTestSession({ + start() { + const microphoneInput = fileURLToPath(plan.definition.input) + return startFakemicRuntime(microphoneInput) + }, + async execute(session) { + await runPreflight({ + env, + runtime: session, + skip: (condition, note) => task.context.skip(Boolean(condition), note), + }) + await session.runtimePage.reload({ waitUntil: 'domcontentloaded' }) + await session.runtimePage.locator('[i-solar\\:alt-arrow-up-line-duotone]').first().waitFor({ state: 'visible', timeout: 30_000 }) + await session.runtimePage.bringToFront() + await session.runtimePage.waitForTimeout(750) + Object.assign(task.context, { audio: session }) + await invokeHandler() + }, + async recordArtifacts(session) { + const snapshot = await session.snapshot().catch(error => ({ + snapshotError: errorMessageFrom(error) ?? 'Unknown snapshot error', + })) + await task.context.annotate('pipeline.json', { + body: `${JSON.stringify(snapshot, null, 2)}\n`, + bodyEncoding: 'utf-8', + contentType: 'application/json', + }) + }, + }) + }, +}) + +/** Groups AIRI audio-input tests in the Vitest task tree. */ +export const describe = audioTestAPI.describe + +/** Defines an AIRI audio-input test for each selected target. */ +export const it = audioTestAPI.it + +/** Vitest expect with AIRI audio-input matchers installed. */ +export { expect } diff --git a/packages/testing-audio/src/expect-extend.test.ts b/packages/testing-audio/src/expect-extend.test.ts new file mode 100644 index 000000000..38e72d812 --- /dev/null +++ b/packages/testing-audio/src/expect-extend.test.ts @@ -0,0 +1,28 @@ +import type { AudioInputObservations } from './types' + +import { describe, it } from 'vitest' + +import { expect, installAudioInputMatchers } from './expect-extend' + +installAudioInputMatchers() + +describe('audio input matchers', () => { + it('normalizes transcription case, width, punctuation, and whitespace', async () => { + const session = createAudioInputSession(['Please, SAY hello!']) + + await expect(session).toHaveTranscriptions([ + ['please say hello'], + ]) + }) +}) + +function createAudioInputSession(transcriptions: string[]): AudioInputObservations { + return { + capturedTranscriptionAudio: async () => [], + streamingTranscriptionUpdates: async () => [], + transcriptionResults: async () => transcriptions, + completedSpans: async () => [], + waitForStreamingTranscriptionReady: async () => {}, + waitForVadReady: async () => {}, + } +} diff --git a/packages/testing-audio/src/expect-extend.ts b/packages/testing-audio/src/expect-extend.ts new file mode 100644 index 000000000..9814f6391 --- /dev/null +++ b/packages/testing-audio/src/expect-extend.ts @@ -0,0 +1,100 @@ +import type { AudioInputObservations } from './types' + +import { expect as vitestExpect } from 'vitest' + +export interface CapturedTranscriptionAudioExpectation { + count: number + minimumBytes: number +} + +export interface TranscriptionExpectationOptions { + /** @default 'exact' */ + match?: 'exact' | 'contains' +} + +declare module 'vitest' { + interface Assertion { + toHaveCapturedTranscriptionAudio: T extends AudioInputObservations + ? (expected: CapturedTranscriptionAudioExpectation) => Promise + : never + toHaveTranscriptions: T extends AudioInputObservations + ? ( + expected: ReadonlyArray>, + options?: TranscriptionExpectationOptions, + ) => Promise + : never + } +} + +/** Vitest expect with AIRI audio-input matcher types. */ +export const expect = vitestExpect + +/** + * Normalizes a transcript for speech-recognition comparison. + * + * @example + * normalizeTranscript(' Hello, AIRI! ') + * // => 'helloairi' + */ +function normalizeTranscript(value: string): string { + return value + .normalize('NFKC') + .toLocaleLowerCase() + .replace(/[^\p{L}\p{N}]+/gu, '') +} + +/** Installs asynchronous matchers for AIRI audio-input observations. */ +export function installAudioInputMatchers(): void { + vitestExpect.extend({ + async toHaveCapturedTranscriptionAudio( + session: AudioInputObservations, + expected: CapturedTranscriptionAudioExpectation, + ) { + const format = session.transcriptionCaptureFormat + if (!format) { + return { + pass: false, + message: () => 'The active transcription Provider does not expose uploaded audio.', + } + } + + const captures = await session.capturedTranscriptionAudio(expected.count) + const invalidCapture = captures.find((capture) => { + if (capture.format !== format || capture.data.byteLength < expected.minimumBytes) + return true + return format === 'wav' && new TextDecoder().decode(capture.data.subarray(0, 4)) !== 'RIFF' + }) + const pass = captures.length === expected.count && !invalidCapture + + return { + pass, + message: () => pass + ? 'Expected the session not to contain valid transcription audio.' + : `Expected ${expected.count} ${format} capture(s) with at least ${expected.minimumBytes} bytes.`, + } + }, + async toHaveTranscriptions( + session: AudioInputObservations, + expected: ReadonlyArray>, + options: TranscriptionExpectationOptions = {}, + ) { + const actual = await session.transcriptionResults(expected.length) + const normalizedActual = actual.map(normalizeTranscript) + const normalizedExpected = expected.map(alternatives => alternatives.map(normalizeTranscript)) + const match = options.match ?? 'exact' + const pass = normalizedActual.length === normalizedExpected.length + && normalizedActual.every((transcript, index) => ( + match === 'contains' + ? normalizedExpected[index].some(candidate => transcript.includes(candidate)) + : normalizedExpected[index].includes(transcript) + )) + + return { + pass, + message: () => pass + ? 'Expected the session not to contain the specified transcriptions.' + : `Expected transcriptions ${JSON.stringify(expected)}, but received ${JSON.stringify(actual)}.`, + } + }, + }) +} diff --git a/packages/testing-audio/src/index.ts b/packages/testing-audio/src/index.ts new file mode 100644 index 000000000..b2619c5eb --- /dev/null +++ b/packages/testing-audio/src/index.ts @@ -0,0 +1,10 @@ +export { describe, expect, it } from './describe' + +export type { + AudioInputObservations, + AudioInputPreflightCallback, + AudioInputPreflightContext, + AudioInputSession, + AudioInputTarget, + AudioInputTestCase, +} from './types' diff --git a/packages/testing-audio/src/runtimes/prepare-electron.ts b/packages/testing-audio/src/runtimes/prepare-electron.ts new file mode 100644 index 000000000..9195d65b5 --- /dev/null +++ b/packages/testing-audio/src/runtimes/prepare-electron.ts @@ -0,0 +1,44 @@ +import type { FakemicElectronPrepareContext } from '@proj-airi/vitest-plugin-fakemic' +import type { Page } from 'playwright' + +import type { AudioInputSession } from '../types' + +import { stubForBrowser } from '../setup/browser-probe' +import { createSession } from '../setup/session' + +/** Adapts a Fakemic Electron process into an AIRI desktop audio session. */ +export default async function prepareElectronRuntime(context: FakemicElectronPrepareContext): Promise { + await context.app.context().addInitScript(stubForBrowser) + const page = await waitForPage(context, (page) => { + const url = new URL(page.url()) + return url.pathname.endsWith('/index.html') && url.hash === '#/' + }) + await page.locator('[i-solar\\:alt-arrow-up-line-duotone]').first().waitFor({ state: 'visible', timeout: 30_000 }) + await page.evaluate(stubForBrowser) + + return createSession({ + electronApp: context.app, + page, + target: 'electron', + close: context.close, + }) +} + +async function waitForPage( + context: FakemicElectronPrepareContext, + predicate: (page: Page) => boolean, + timeoutMs = 60_000, +): Promise { + const deadline = Date.now() + timeoutMs + while (Date.now() < deadline) { + const page = context.app.windows().find(predicate) + if (page) { + await page.waitForLoadState('domcontentloaded') + return page + } + + await new Promise(resolveWait => setTimeout(resolveWait, 100)) + } + + throw new Error('Timed out while waiting for the Electron renderer') +} diff --git a/packages/testing-audio/src/runtimes/prepare-web.ts b/packages/testing-audio/src/runtimes/prepare-web.ts new file mode 100644 index 000000000..b8dea08b0 --- /dev/null +++ b/packages/testing-audio/src/runtimes/prepare-web.ts @@ -0,0 +1,20 @@ +import type { FakemicWebPrepareContext } from '@proj-airi/vitest-plugin-fakemic' + +import type { AudioInputSession } from '../types' + +import { stubForBrowser } from '../setup/browser-probe' +import { createSession } from '../setup/session' + +/** Adapts a Fakemic Chromium process into an AIRI Web audio session. */ +export default async function prepareWebRuntime(context: FakemicWebPrepareContext): Promise { + await context.context.addInitScript(stubForBrowser) + + const page = await context.context.newPage() + await page.goto(context.runtime.url) + + return createSession({ + page, + target: 'web', + close: context.close, + }) +} diff --git a/packages/testing-audio/src/setup/browser-probe.ts b/packages/testing-audio/src/setup/browser-probe.ts new file mode 100644 index 000000000..4dee09346 --- /dev/null +++ b/packages/testing-audio/src/setup/browser-probe.ts @@ -0,0 +1,204 @@ +import type { SerializedIOSpan } from '@proj-airi/stage-shared/types/io-trace' + +/** + * Installs passive browser probes before the application starts. + * + * Triggering workflow: + * + * `BrowserContext.addInitScript` + * -> {@link stubForBrowser} + * -> `window.fetch` + * -> `BroadcastChannel('io-tracer-channel')` + * + * Upstream: + * - `BrowserContext.addInitScript` + * + * Downstream: + * - `window.__airiAudioInputE2E` + */ +export function stubForBrowser() { + const state: BrowserAudioInputState = { spans: [], streamingTranscriptionReady: false, streamingTranscriptionUpdates: [], transcriptionAudio: [], transcriptionResults: [], vadReady: false } + window.__airiAudioInputE2E = state + + const originalConsoleInfo = console.info.bind(console) + console.info = (...values: unknown[]) => { + if (typeof values[0] === 'string' && values[0].startsWith('[Voice Input] vad-ready:')) + state.vadReady = true + originalConsoleInfo(...values) + } + + const originalFetch = window.fetch.bind(window) + + /** + * Copies each ASR upload and response while it forwards the request. + * + * Triggering workflow: + * + * `window.fetch` + * -> `POST /audio/transcriptions` + * -> captureFetch + * + * Upstream: + * - The OpenAI-compatible transcription Provider. + * + * Downstream: + * - `window.__airiAudioInputE2E` + * - The original `window.fetch` function. + */ + const captureFetch: typeof window.fetch = async (input, init) => { + const requestUrl = typeof input === 'string' + ? input + : input instanceof URL + ? input.href + : input.url + + const capturesTranscription = new URL(requestUrl, window.location.href).pathname.endsWith('/audio/transcriptions') + if (capturesTranscription && init?.body instanceof FormData) { + const file = init.body.get('file') + if (file instanceof Blob) { + state.transcriptionAudio.push({ + base64: new Uint8Array(await file.arrayBuffer()).toBase64(), + format: 'wav', + }) + } + } + + const response = await originalFetch(input, init) + if (capturesTranscription && response.ok) { + const payload = await response.clone().json() as { text?: unknown } + if (typeof payload.text === 'string') + state.transcriptionResults.push(payload.text) + } + + return response + } + + window.fetch = captureFetch + + const OriginalWebSocket = window.WebSocket + const audioChunksBySocket = new WeakMap() + const capturesAliyunNlsBySocket = new WeakMap() + const capturedSockets = new WeakSet() + + function capturePcmAudio(socket: WebSocket) { + const audioChunks = audioChunksBySocket.get(socket) + if (!audioChunks || capturedSockets.has(socket) || !audioChunks.length) + return + + const byteLength = audioChunks.reduce((total, chunk) => total + chunk.byteLength, 0) + if (byteLength < 8192) + return + + capturedSockets.add(socket) + const audio = new Uint8Array(byteLength) + let offset = 0 + for (const chunk of audioChunks) { + audio.set(chunk, offset) + offset += chunk.byteLength + } + state.transcriptionAudio.push({ base64: audio.toBase64(), format: 'pcm' }) + } + + class CaptureAliyunNlsWebSocket extends OriginalWebSocket { + constructor(url: string | URL, protocols?: string | string[]) { + super(url, protocols) + const target = new URL(url.toString(), window.location.href) + const capturesAliyunNls = target.hostname.startsWith('nls-gateway-') && target.hostname.endsWith('.aliyuncs.com') + capturesAliyunNlsBySocket.set(this, capturesAliyunNls) + + if (capturesAliyunNls) { + audioChunksBySocket.set(this, []) + this.addEventListener('open', () => { + state.streamingTranscriptionReady = true + }) + this.addEventListener('message', (event) => { + if (typeof event.data !== 'string') + return + + try { + const payload = JSON.parse(event.data) as { header?: { name?: string }, payload?: { result?: unknown } } + if (payload.header?.name === 'SentenceEnd' && typeof payload.payload?.result === 'string') + state.transcriptionResults.push(payload.payload.result) + } + catch { + // NLS can send non-transcription frames. The Provider handles those frames. + } + }) + } + } + + send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void { + const audioChunks = audioChunksBySocket.get(this) + if (capturesAliyunNlsBySocket.get(this) && audioChunks && typeof data !== 'string') { + if (data instanceof Blob) { + void data.arrayBuffer().then((buffer) => { + audioChunks.push(new Uint8Array(buffer)) + }) + } + else if (ArrayBuffer.isView(data)) { + audioChunks.push(new Uint8Array(data.buffer, data.byteOffset, data.byteLength)) + } + else { + audioChunks.push(new Uint8Array(data)) + } + capturePcmAudio(this) + } + + let outboundData: string | Blob | BufferSource + if (typeof data === 'string' || data instanceof Blob || data instanceof ArrayBuffer) { + outboundData = data + } + else if (ArrayBuffer.isView(data)) { + // WebSocket does not accept views backed by SharedArrayBuffer. The copy uses a regular ArrayBuffer. + outboundData = new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice() + } + else { + // ArrayBufferLike also includes SharedArrayBuffer. The copy keeps the original bytes in a supported buffer. + outboundData = new Uint8Array(data).slice() + } + + super.send(outboundData) + } + + close(code?: number, reason?: string): void { + const audioChunks = audioChunksBySocket.get(this) + if (capturesAliyunNlsBySocket.get(this) && audioChunks && !capturedSockets.has(this) && audioChunks.length) { + capturePcmAudio(this) + } + + super.close(code, reason) + } + } + + window.WebSocket = CaptureAliyunNlsWebSocket + + const channel = new BroadcastChannel('io-tracer-channel') + + /** + * Stores completed I/O spans for the case artifact. + * + * Triggering workflow: + * + * `BroadcastChannel('io-tracer-channel')` + * -> `message` + * -> captureSpan + * + * Upstream: + * - The AIRI I/O trace exporter. + * + * Downstream: + * - `window.__airiAudioInputE2E.spans` + */ + const captureSpan = (event: MessageEvent) => { + if (event.data?.type === 'span' && event.data.span?.ended) + state.spans.push(event.data.span as SerializedIOSpan) + } + + channel.addEventListener('message', captureSpan) +} + +/** Returns the completed browser spans that match the optional span name. */ +export function readCompletedSpans(name?: string) { + const spans = window.__airiAudioInputE2E?.spans ?? [] + return name ? spans.filter(span => span.name === name) : spans +} diff --git a/packages/testing-audio/src/setup/session.ts b/packages/testing-audio/src/setup/session.ts new file mode 100644 index 000000000..90481953e --- /dev/null +++ b/packages/testing-audio/src/setup/session.ts @@ -0,0 +1,116 @@ +import type { AudioCapture } from '@proj-airi/vitest-plugin-fakemic' +import type { ElectronApplication, Page } from 'playwright' + +import type { AudioInputSession, AudioInputTarget } from '../types' + +import { Buffer } from 'node:buffer' + +import { readCompletedSpans } from './browser-probe' + +/** Creates the runtime session and records its page diagnostics. */ +export function createSession(options: { + electronApp?: ElectronApplication + page: Page + target: AudioInputTarget + close: () => Promise + transcriptionCaptureFormat?: AudioCapture['format'] +}): AudioInputSession { + const diagnostics: string[] = [] + const observedPages = new WeakSet() + + function observePage(page: Page) { + if (observedPages.has(page)) + return + + observedPages.add(page) + page.on('console', (message) => { + const text = message.text() + const isAudioPipelineInfo = message.type() === 'info' + && (text.includes('[Hearing Pipeline]') || text.includes('[Voice Input]') || text.includes('transcription')) + if (['error', 'warning'].includes(message.type()) || isAudioPipelineInfo) + diagnostics.push(`[console:${message.type()}] ${text}`) + }) + page.on('pageerror', error => diagnostics.push(`[pageerror] ${error.message}`)) + } + + observePage(options.page) + + const session: AudioInputSession = { + electronApp: options.electronApp, + page: options.page, + runtimePage: options.page, + target: options.target, + transcriptionCaptureFormat: options.transcriptionCaptureFormat, + activatePage(page) { + observePage(page) + session.page = page + }, + async capturedTranscriptionAudio(count) { + try { + await options.page.waitForFunction(expectedCount => ( + (window.__airiAudioInputE2E?.transcriptionAudio.length ?? 0) >= expectedCount + ), count, { timeout: 60_000 }) + } + catch (error) { + const runtimeState = await options.page.evaluate(async () => ({ + activeModel: localStorage.getItem('settings/hearing/active-model'), + activeProvider: localStorage.getItem('settings/hearing/active-provider'), + devices: (await navigator.mediaDevices.enumerateDevices()).map(device => ({ + deviceId: device.deviceId, + kind: device.kind, + label: device.label, + })), + microphoneEnabled: localStorage.getItem('settings/audio/input/enabled'), + microphoneInput: localStorage.getItem('settings/audio/input'), + microphoneOffIconVisible: Boolean(document.querySelector('[i-ph\\:microphone-slash]')), + probeInstalled: Boolean(window.__airiAudioInputE2E), + streamingTranscriptionReady: window.__airiAudioInputE2E?.streamingTranscriptionReady ?? false, + url: window.location.href, + vadReady: window.__airiAudioInputE2E?.vadReady ?? false, + })) + throw new Error(`Timed out waiting for captured transcription audio: ${JSON.stringify({ diagnostics, runtimeState })}`, { cause: error }) + } + const capturedAudio = await options.page.evaluate(() => window.__airiAudioInputE2E?.transcriptionAudio ?? []) + return capturedAudio.map(audio => ({ + format: audio.format, + data: Buffer.from(audio.base64, 'base64'), + })) + }, + streamingTranscriptionUpdates: () => session.page.evaluate(() => window.__airiAudioInputE2E?.streamingTranscriptionUpdates ?? []), + async transcriptionResults(count) { + await options.page.waitForFunction(expectedCount => ( + (window.__airiAudioInputE2E?.transcriptionResults.length ?? 0) >= expectedCount + ), count, { timeout: 60_000 }) + return options.page.evaluate(() => window.__airiAudioInputE2E?.transcriptionResults ?? []) + }, + async completedSpans(name) { + const runtimeSpans = await options.page.evaluate(readCompletedSpans, name) + if (session.page === options.page) + return runtimeSpans + + const interactionSpans = await session.page.evaluate(readCompletedSpans, name) + return [...runtimeSpans, ...interactionSpans] + }, + async waitForVadReady() { + await options.page.waitForFunction(() => window.__airiAudioInputE2E?.vadReady === true, undefined, { timeout: 30_000 }) + }, + async waitForStreamingTranscriptionReady() { + await options.page.waitForFunction(() => window.__airiAudioInputE2E?.streamingTranscriptionReady === true, undefined, { timeout: 30_000 }) + }, + async snapshot() { + const runtimeState = await options.page.evaluate(() => window.__airiAudioInputE2E) + const interactionState = session.page === options.page + ? runtimeState + : await session.page.evaluate(() => window.__airiAudioInputE2E) + return { + spans: runtimeState?.spans ?? [], + streamingTranscriptionUpdates: interactionState?.streamingTranscriptionUpdates ?? [], + transcriptionResults: runtimeState?.transcriptionResults ?? [], + diagnostics: [...diagnostics], + } + }, + close: options.close, + } + + return session +} diff --git a/packages/testing-audio/src/types.ts b/packages/testing-audio/src/types.ts new file mode 100644 index 000000000..44ae685ba --- /dev/null +++ b/packages/testing-audio/src/types.ts @@ -0,0 +1,60 @@ +import type { SerializedIOSpan } from '@proj-airi/stage-shared/types/io-trace' +import type { AudioCapture, AudioCaptureFormat, AudioTestCase, AudioTestPreflightCallback, AudioTestSession } from '@proj-airi/vitest-plugin-fakemic' +import type { ElectronApplication, Page } from 'playwright' + +export const audioInputTargets = ['web', 'electron'] as const + +export type AudioInputTarget = (typeof audioInputTargets)[number] + +/** Values available when one case resolves its preflight callbacks. */ +export interface AudioInputPreflightContext { + /** Environment variables loaded for this case. */ + env: Readonly + /** Clean runtime that the configuration callback can prepare. */ + runtime: AudioInputSession + /** Skips this case when its environment does not satisfy a case constraint. */ + skip: (condition: unknown, note?: string) => void +} + +/** One optional case callback that resolves configuration from its environment. */ +export type AudioInputPreflightCallback = AudioTestPreflightCallback + +/** One AIRI audio-input test definition. */ +export type AudioInputTestCase = AudioTestCase + +/** Snapshot of the observable AIRI audio pipeline state. */ +export interface AudioInputSnapshot { + spans: SerializedIOSpan[] + streamingTranscriptionUpdates: string[] + transcriptionResults: string[] + diagnostics: string[] +} + +/** Observable audio values used by AIRI matchers. */ +export interface AudioInputObservations { + /** Capture format used by the active transcription Provider. */ + transcriptionCaptureFormat?: AudioCaptureFormat + capturedTranscriptionAudio: (count: number) => Promise + streamingTranscriptionUpdates: () => Promise + transcriptionResults: (count: number) => Promise + completedSpans: (name?: string) => Promise + /** Waits until the VAD audio graph is connected to the microphone stream. */ + waitForVadReady: () => Promise + /** Waits until a streaming transcription transport accepts microphone audio. */ + waitForStreamingTranscriptionReady: () => Promise +} + +/** Runtime handle for one AIRI audio-input test. */ +export interface AudioInputSession extends AudioInputObservations, AudioTestSession { + /** Electron application for Electron tasks. */ + electronApp?: ElectronApplication + /** Page used by case interactions. */ + page: Page + /** Page that owns the audio-input pipeline. */ + runtimePage: Page + /** Runtime selected for this concrete task. */ + target: AudioInputTarget + /** Selects the page used by subsequent case interactions. */ + activatePage: (page: Page) => void + snapshot: () => Promise +} diff --git a/packages/testing-audio/src/types/browser.d.ts b/packages/testing-audio/src/types/browser.d.ts new file mode 100644 index 000000000..4111bcdaa --- /dev/null +++ b/packages/testing-audio/src/types/browser.d.ts @@ -0,0 +1,30 @@ +import type { SerializedIOSpan } from '@proj-airi/stage-shared/types/io-trace' + +declare global { + interface BrowserAudioInputState { + spans: SerializedIOSpan[] + streamingTranscriptionReady: boolean + streamingTranscriptionUpdates: string[] + transcriptionAudio: Array<{ base64: string, format: 'pcm' | 'wav' }> + transcriptionResults: string[] + vadReady: boolean + } + + interface Window { + __airiAudioInputE2E?: BrowserAudioInputState + } + + // NOTICE: + // TypeScript 5.9 does not declare the Baseline 2025 Uint8Array Base64 methods. + // The test runs in current Playwright and Electron Chromium runtimes that implement this API. + // Source: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64 + // Remove this declaration when the TypeScript standard library includes the method. + interface Uint8Array { + toBase64: (options?: { + alphabet?: 'base64' | 'base64url' + omitPadding?: boolean + }) => string + } +} + +export {} diff --git a/packages/testing-audio/tsconfig.json b/packages/testing-audio/tsconfig.json new file mode 100644 index 000000000..8a4165aa3 --- /dev/null +++ b/packages/testing-audio/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": [ + "ESNext", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "moduleResolution": "Bundler", + "types": [ + "node" + ], + "strict": true, + "noEmit": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true + }, + "include": [ + "cases/**/*.ts", + "src/**/*.ts", + "vitest.config.ts" + ] +} diff --git a/packages/testing-audio/vitest.config.ts b/packages/testing-audio/vitest.config.ts new file mode 100644 index 000000000..755058df2 --- /dev/null +++ b/packages/testing-audio/vitest.config.ts @@ -0,0 +1,48 @@ +import { join } from 'node:path' + +import fakemic, { electron, web } from '@proj-airi/vitest-plugin-fakemic' + +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + projects: [ + fakemic({ + name: 'audio-web', + include: ['cases/**/*.audio.test.ts', 'cases/**/*.audio.web.test.ts'], + runtime: web({ + name: 'web', + prepare: new URL('./src/runtimes/prepare-web.ts', import.meta.url).href, + url: 'http://127.0.0.1:4173/', + context: { permissions: ['microphone'] }, + preview: { + configFile: join(import.meta.dirname, '../../apps/stage-web/vite.config.ts'), + root: join(import.meta.dirname, '../../apps/stage-web'), + }, + }), + }), + fakemic({ + name: 'audio-electron', + include: ['cases/**/*.audio.test.ts', 'cases/**/*.audio.electron.test.ts'], + runtime: electron({ + name: 'electron', + prepare: new URL('./src/runtimes/prepare-electron.ts', import.meta.url).href, + entry: join(import.meta.dirname, '../../apps/stage-tamagotchi/out/main/index.js'), + args: ['--no-sandbox'], + cwd: join(import.meta.dirname, '../..'), + temporaryUserData: { + env: 'APP_USER_DATA_PATH', + prefix: 'airi-testing-audio-', + }, + }), + }), + { + extends: true, + test: { + name: 'unit', + include: ['src/**/*.test.ts'], + }, + }, + ], + }, +}) diff --git a/packages/vitest-plugin-fakemic/README.md b/packages/vitest-plugin-fakemic/README.md new file mode 100644 index 000000000..3fe966db6 --- /dev/null +++ b/packages/vitest-plugin-fakemic/README.md @@ -0,0 +1,32 @@ +# Vitest plugin for fake microphones + +This package supplies fake-microphone Web and Electron runtimes with Vitest project integration. + +Import the Vitest interface from the package root: + +```ts +import fakemic, { + createAudioTestAPI, + electron, + runAudioTestSession, + web, +} from '@proj-airi/vitest-plugin-fakemic' +``` + +`src/index.ts` owns project configuration, runtime launch, task collection, and preflight scheduling. `src/runner.ts` owns task execution. + +Runtime configuration contains only serializable values. A `prepare` module adapts the launched Playwright runtime into an application session. + +```ts +fakemic({ + name: 'audio-web', + include: ['cases/**/*.audio.test.ts', 'cases/**/*.audio.web.test.ts'], + runtime: web({ + name: 'web', + prepare: new URL('./prepare-web.ts', import.meta.url).href, + url: 'http://127.0.0.1:4173/', + }), +}) +``` + +Application packages own selectors, routes, probes, Provider settings, and prepare modules. diff --git a/packages/audio-input-e2e/package.json b/packages/vitest-plugin-fakemic/package.json similarity index 57% rename from packages/audio-input-e2e/package.json rename to packages/vitest-plugin-fakemic/package.json index aa561dd24..d79907289 100644 --- a/packages/audio-input-e2e/package.json +++ b/packages/vitest-plugin-fakemic/package.json @@ -1,22 +1,24 @@ { - "name": "@proj-airi/audio-input-e2e", + "name": "@proj-airi/vitest-plugin-fakemic", "type": "module", "version": "0.11.3", "private": true, - "description": "End-to-end audio input contracts for AIRI Web and Electron", + "description": "Fake microphone test runtime and Vitest integration", "author": { "name": "Moeru AI Project AIRI Team", "email": "airi@moeru.ai", "url": "https://github.com/moeru-ai" }, "license": "MIT", + "exports": "./src/index.ts", "scripts": { + "test": "vitest run", + "typecheck": "tsc --noEmit" }, "dependencies": { - "@pnpm/find-workspace-dir": "catalog:", - "@proj-airi/stage-shared": "workspace:^", "playwright": "catalog:", - "valibot": "catalog:" + "vite": "catalog:", + "vitest": "catalog:vitest" }, "devDependencies": { "@types/node": "catalog:" diff --git a/packages/vitest-plugin-fakemic/src/index.test.ts b/packages/vitest-plugin-fakemic/src/index.test.ts new file mode 100644 index 000000000..de7f9974c --- /dev/null +++ b/packages/vitest-plugin-fakemic/src/index.test.ts @@ -0,0 +1,91 @@ +import { + createAudioTestAPI, + createAudioTestTask, + runAudioTestSession, +} from '@proj-airi/vitest-plugin-fakemic' +import { describe, expect, it, vi } from 'vitest' + +const calls: string[] = [] +const audio = createAudioTestAPI< + { value: string, preflight?: readonly ((context: { value: string }) => void)[] }, + { value: string }, + { capturedValue: string }, + { value: string } +>({ + createPlans: (name, definition) => [{ + name: `mock: ${name}`, + definition, + metadata: { + input: '/fixtures/input.wav', + runtime: 'mock', + }, + }], + preflight: definition => definition.preflight, + async execute({ plan, task, invokeHandler, runPreflight }) { + await runPreflight({ value: 'preflight' }) + Object.assign(task.context, { + capturedValue: plan.definition.value, + }) + await invokeHandler() + }, +}) + +audio.describe('createAudioTestAPI', () => { + audio.it('runs preflight before a registered task', { + value: 'captured', + preflight: [({ value }) => calls.push(value)], + }, ({ capturedValue }) => { + expect(calls).toEqual(['preflight']) + expect(capturedValue).toBe('captured') + }) +}) + +describe('audio test tasks', () => { + it('creates one task for the current runtime project', () => { + const input = new URL('file:///audio/input.wav') + const task = createAudioTestTask('captures speech', { input }) + + expect(task).toEqual({ name: 'captures speech', input }) + }) + + it('records artifacts before it closes the session', async () => { + const calls: string[] = [] + const session = { + close: vi.fn(async () => { + calls.push('close') + }), + } + + await runAudioTestSession({ + start: async () => session, + execute: async () => { + calls.push('execute') + }, + recordArtifacts: async () => { + calls.push('record') + }, + }) + + expect(calls).toEqual(['execute', 'record', 'close']) + }) + + it('closes the session and keeps execution and cleanup failures', async () => { + const executionError = new Error('execution failed') + const closeError = new Error('close failed') + + const result = runAudioTestSession({ + start: async () => ({ + close: async () => { + throw closeError + }, + }), + execute: async () => { + throw executionError + }, + }) + + await expect(result).rejects.toMatchObject({ + errors: [executionError, closeError], + }) + }) +}) diff --git a/packages/vitest-plugin-fakemic/src/index.ts b/packages/vitest-plugin-fakemic/src/index.ts new file mode 100644 index 000000000..e6117a742 --- /dev/null +++ b/packages/vitest-plugin-fakemic/src/index.ts @@ -0,0 +1,420 @@ +import type { Browser, BrowserContext, ElectronApplication } from 'playwright' +import type { RunnerTestCase, TestAPI, TestContext } from 'vitest' +import type { UserWorkspaceConfig } from 'vitest/config' + +import { mkdtemp, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { env } from 'node:process' +import { fileURLToPath } from 'node:url' + +import { chromium, _electron as playwrightElectron } from 'playwright' +import { preview } from 'vite' +import { describe, inject, TestRunner } from 'vitest' + +/** Supported encodings for captured audio. */ +export type AudioCaptureFormat = 'pcm' | 'wav' + +/** One audio payload captured from a tested runtime. */ +export interface AudioCapture { + format: AudioCaptureFormat + data: Uint8Array +} + +/** A session that owns one audio test runtime. */ +export interface AudioTestSession { + /** Releases the runtime and all resources that belong to the session. */ + close: () => Promise +} + +/** One callback that runs after a runtime starts and before its test handler. */ +export type AudioTestPreflightCallback = (context: Context) => void | Promise + +/** A runner-neutral audio test definition. */ +export interface AudioTestCase { + /** File-backed microphone input for the test. */ + input: URL + /** @default [] */ + preflight?: readonly AudioTestPreflightCallback[] +} + +/** One runnable task derived from an audio test case. */ +export interface AudioTestTask { + name: string + input: URL +} + +/** Lifecycle operations for one audio test session. */ +export interface RunAudioTestSessionOptions { + start: () => Promise + execute: (session: Session) => Promise + recordArtifacts?: (session: Session) => Promise +} + +/** Metadata that identifies an audio task in Vitest reports. */ +export interface AudioVitestTaskMetadata { + input: string + runtime: string +} + +declare module 'vitest' { + interface TaskMeta { + audioTest?: AudioVitestTaskMetadata + } +} + +/** + * One concrete audio task that the custom runner can execute. + * + * @param Definition - The concrete definition stored for this task. + */ +export interface AudioVitestPlan { + name: string + definition: Definition + metadata: AudioVitestTaskMetadata +} + +/** + * Test context exposed to an audio test callback. + * + * @param Context - Fields added by the concrete audio framework. + */ +export type AudioVitestTaskContext = TestContext & Context + +/** + * Callback for an audio task. + * + * @param Context - Fields added by the concrete audio framework. + */ +export type AudioTestHandler = ( + context: AudioVitestTaskContext, +) => void | Promise + +/** + * A Vitest-like test function that accepts an audio definition. + * + * @param Definition - The definition supplied by each test. + * @param Context - Fields exposed to the test callback. + */ +export interface AudioTestAPI { + (name: string, definition: Definition, handler: AudioTestHandler): void + only: AudioTestAPI + skip: AudioTestAPI + todo: AudioTestAPI + fails: AudioTestAPI +} + +/** + * Configuration for a package-owned audio test interface. + * + * @param Definition - The definition supplied by each test. + * @param Plan - One concrete task produced from that definition. + */ +export interface CreateAudioTestAPIOptions { + createPlans: (name: string, definition: Definition) => Array> + execute: (options: { + plan: AudioVitestPlan + task: RunnerTestCase + invokeHandler: () => Promise + runPreflight: (context: PreflightContext) => Promise + }) => Promise + preflight?: (definition: Definition) => readonly AudioTestPreflightCallback[] | undefined +} + +/** Serializable Web runtime configuration. */ +export interface FakemicWebRuntime { + kind: 'web' + name: string + prepare: string + url: string + launch?: Parameters[0] + context?: Parameters[0] + preview?: { + configFile: string + root: string + host?: string + port?: number + } +} + +/** Serializable Electron runtime configuration. */ +export interface FakemicElectronRuntime { + kind: 'electron' + name: string + prepare: string + entry: string + args?: string[] + cwd?: string + env?: Record + temporaryUserData?: { + env: string + prefix?: string + } +} + +/** Runtime selected by one Fakemic Vitest project. */ +export type FakemicRuntime = FakemicElectronRuntime | FakemicWebRuntime + +/** Context supplied to a Web prepare module. */ +export interface FakemicWebPrepareContext { + browser: Browser + context: BrowserContext + close: () => Promise + runtime: FakemicWebRuntime +} + +/** Context supplied to an Electron prepare module. */ +export interface FakemicElectronPrepareContext { + app: ElectronApplication + close: () => Promise + runtime: FakemicElectronRuntime +} + +/** Module that adapts a launched runtime into the application session. */ +export interface FakemicPrepareModule { + default: (context: Context) => Promise +} + +/** Configuration for one Fakemic Vitest project. */ +export interface FakemicPluginOptions { + include: string[] + name: string + runtime: FakemicRuntime + /** @default 180000 */ + testTimeout?: number + /** @default 120000 */ + hookTimeout?: number +} + +declare module 'vitest' { + interface ProvidedContext { + fakemicRuntime: FakemicRuntime + } +} + +interface FakemicTaskExecution { + run: (task: RunnerTestCase, invokeHandler: () => Promise) => Promise +} + +const registryKey = Symbol.for('airi.vitest-plugin-fakemic.executions') +const registryHost = globalThis as typeof globalThis & Record | undefined> + +// NOTICE: +// Vitest can load the runner and collected test modules through different module IDs. +// The global symbol gives both module instances access to the same task registry. +// Source: the Vitest ModuleRunner seam between the runner and collected test files. +// Remove this registry when Vitest provides a public task execution registry. +const fakemicTaskExecutions = registryHost[registryKey] ??= new WeakMap() + +/** Creates package-owned `describe` and `it` functions for an audio framework. */ +export function createAudioTestAPI( + options: CreateAudioTestAPIOptions, +): { + describe: typeof describe + it: AudioTestAPI +} { + const collector = TestRunner.createTaskCollector(function ( + this: object, + name: string, + definition: Definition, + handler: AudioTestHandler, + ) { + const plans = options.createPlans(name, definition) + const preflight = options.preflight?.(definition) ?? [] + + for (const plan of plans) { + const task = TestRunner.getCurrentSuite().task(plan.name, { + ...this, + meta: { + audioTest: plan.metadata, + }, + handler: async (context) => { + await handler(context as AudioVitestTaskContext) + }, + }) + + fakemicTaskExecutions.set(task, { + run: (runnerTask, invokeHandler) => options.execute({ + plan, + task: runnerTask, + invokeHandler, + async runPreflight(context) { + for (const callback of preflight) + await callback(context) + }, + }), + }) + } + }) + + return { + describe, + it: collector as TestAPI as AudioTestAPI, + } +} + +/** Creates a Web runtime descriptor for one Fakemic project. */ +export function web(options: Omit): FakemicWebRuntime { + return { kind: 'web', ...options } +} + +/** Creates an Electron runtime descriptor for one Fakemic project. */ +export function electron(options: Omit): FakemicElectronRuntime { + return { kind: 'electron', ...options } +} + +/** Configures a serial Node Vitest project for package-owned audio tests. */ +export default function fakemic(options: FakemicPluginOptions): UserWorkspaceConfig { + return { + test: { + name: options.name, + include: options.include, + environment: 'node', + runner: fileURLToPath(new URL('./runner.ts', import.meta.url)), + fileParallelism: false, + maxWorkers: 1, + testTimeout: options.testTimeout ?? 180_000, + hookTimeout: options.hookTimeout ?? 120_000, + provide: { + fakemicRuntime: options.runtime, + }, + }, + } +} + +/** Creates Chromium arguments for a non-looping file-backed microphone. */ +export function createChromiumFileMicrophoneArguments(microphoneInput: string): string[] { + return [ + '--use-fake-ui-for-media-stream', + '--use-fake-device-for-media-stream', + `--use-file-for-fake-audio-capture=${microphoneInput}%noloop`, + '--autoplay-policy=no-user-gesture-required', + ] +} + +/** + * Creates one runnable task from an audio case. + * + * @example + * createAudioTestTask('greets the user', { input }) + * // => { name: 'greets the user', input } + */ +export function createAudioTestTask( + name: string, + testCase: AudioTestCase, +): AudioTestTask { + return { + name, + input: testCase.input, + } +} + +/** Launches the runtime selected by the current Vitest project. */ +export async function startFakemicRuntime(microphoneInput: string): Promise { + const runtime = inject('fakemicRuntime') + if (runtime.kind === 'electron') + return startElectronFakemicRuntime(runtime, microphoneInput) + return startWebFakemicRuntime(runtime, microphoneInput) +} + +async function startWebFakemicRuntime(runtime: FakemicWebRuntime, microphoneInput: string): Promise { + const server = runtime.preview + ? await preview({ + configFile: runtime.preview.configFile, + root: runtime.preview.root, + preview: { + host: runtime.preview.host ?? '127.0.0.1', + port: runtime.preview.port ?? 4173, + strictPort: true, + }, + }) + : undefined + let browser: Browser | undefined + const close = async () => { + await browser?.close() + await server?.close() + } + + try { + browser = await chromium.launch({ + ...runtime.launch, + args: [...(runtime.launch?.args ?? []), ...createChromiumFileMicrophoneArguments(microphoneInput)], + }) + const context = await browser.newContext(runtime.context) + const module = await import(runtime.prepare) as FakemicPrepareModule + return await module.default({ browser, context, close, runtime }) + } + catch (error) { + await close() + throw error + } +} + +async function startElectronFakemicRuntime(runtime: FakemicElectronRuntime, microphoneInput: string): Promise { + const temporaryUserData = runtime.temporaryUserData + const userDataPath = temporaryUserData + ? await mkdtemp(join(tmpdir(), temporaryUserData.prefix ?? 'fakemic-electron-')) + : undefined + let app: ElectronApplication | undefined + const close = async () => { + await app?.close() + if (userDataPath) + await rm(userDataPath, { recursive: true, force: true }) + } + + try { + const launchEnvironment = Object.fromEntries( + Object.entries({ ...env, ...runtime.env }) + .filter((entry): entry is [string, string] => entry[1] !== undefined), + ) + if (temporaryUserData && userDataPath) + launchEnvironment[temporaryUserData.env] = userDataPath + + app = await playwrightElectron.launch({ + args: [runtime.entry, ...(runtime.args ?? []), ...createChromiumFileMicrophoneArguments(microphoneInput)], + cwd: runtime.cwd, + env: launchEnvironment, + }) + const launchedApp = app + const module = await import(runtime.prepare) as FakemicPrepareModule + return await module.default({ app: launchedApp, close, runtime }) + } + catch (error) { + await close() + throw error + } +} + +/** Runs one audio session and preserves execution and cleanup failures. */ +export async function runAudioTestSession( + options: RunAudioTestSessionOptions, +): Promise { + const session = await options.start() + const errors: unknown[] = [] + + try { + await options.execute(session) + } + catch (error) { + errors.push(error) + } + + try { + await options.recordArtifacts?.(session) + } + catch (error) { + errors.push(error) + } + + try { + await session.close() + } + catch (error) { + errors.push(error) + } + + if (errors.length === 1) + throw errors[0] + if (errors.length > 1) + throw new AggregateError(errors, 'The audio test and its cleanup produced multiple errors') +} diff --git a/packages/vitest-plugin-fakemic/src/runner.ts b/packages/vitest-plugin-fakemic/src/runner.ts new file mode 100644 index 000000000..41f46111e --- /dev/null +++ b/packages/vitest-plugin-fakemic/src/runner.ts @@ -0,0 +1,38 @@ +import type { RunnerTestCase } from 'vitest' + +import { TestRunner } from 'vitest' + +interface FakemicTaskExecution { + run: (task: RunnerTestCase, invokeHandler: () => Promise) => Promise +} + +const registryKey = Symbol.for('airi.vitest-plugin-fakemic.executions') +const registryHost = globalThis as typeof globalThis & Record | undefined> +const fakemicTaskExecutions = registryHost[registryKey] ??= new WeakMap() + +/** + * Runs package-owned audio tasks and delegates normal tasks to Vitest. + * + * Call stack: + * + * FakemicVitestRunner.runTask + * -> fakemic task execution + * -> {@link TestRunner.getTestFn} + */ +export default class FakemicVitestRunner extends TestRunner { + async runTask(task: RunnerTestCase): Promise { + const handler = TestRunner.getTestFn(task) + if (!handler) + throw new Error(`Vitest did not collect a handler for "${task.name}"`) + + const execution = fakemicTaskExecutions.get(task) + if (!execution) { + await handler() + return + } + + await execution.run(task, async () => { + await handler() + }) + } +} diff --git a/packages/vitest-plugin-fakemic/tsconfig.json b/packages/vitest-plugin-fakemic/tsconfig.json new file mode 100644 index 000000000..0f9b062fe --- /dev/null +++ b/packages/vitest-plugin-fakemic/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": [ + "ESNext" + ], + "rootDir": ".", + "module": "ESNext", + "moduleResolution": "Bundler", + "types": [ + "node" + ], + "strict": true, + "noEmit": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "vitest.config.ts" + ] +} diff --git a/packages/vitest-plugin-fakemic/vitest.config.ts b/packages/vitest-plugin-fakemic/vitest.config.ts new file mode 100644 index 000000000..cff5a5890 --- /dev/null +++ b/packages/vitest-plugin-fakemic/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['src/**/*.test.ts'], + runner: './src/runner.ts', + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9fe382b0..aafa2343a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -244,8 +244,8 @@ catalogs: specifier: 0.1.0-beta.19 version: 0.1.0-beta.19 '@moeru/eventa': - specifier: 1.0.0-beta.13 - version: 1.0.0-beta.13 + specifier: 1.0.0-beta.15 + version: 1.0.0-beta.15 '@moeru/std': specifier: 0.1.0-beta.17 version: 0.1.0-beta.17 @@ -1450,7 +1450,7 @@ importers: version: 3.8.1 '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -1801,6 +1801,33 @@ importers: specifier: 'catalog:' version: 3.2.6(typescript@5.9.3) + apps/stage-pocket/ios/DerivedData/C7F38B99-FA7A-44C4-A739-DFE441C9AD8B/SourcePackages/checkouts/OSBarcodeLib-iOS: + devDependencies: + '@semantic-release/changelog': + specifier: ^6.0.0 + version: 6.0.3(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/commit-analyzer': + specifier: ^13.0.0 + version: 13.0.1(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/exec': + specifier: ^7.0.0 + version: 7.1.0(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/git': + specifier: ^10.0.0 + version: 10.0.1(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/github': + specifier: ^12.0.0 + version: 12.0.9(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/npm': + specifier: ^13.0.0 + version: 13.1.5(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/release-notes-generator': + specifier: ^14.0.0 + version: 14.1.1(semantic-release@25.0.9(typescript@5.9.3)) + semantic-release: + specifier: ^25.0.0 + version: 25.0.9(typescript@5.9.3) + apps/stage-tamagotchi: dependencies: '@date-fns/utc': @@ -1853,7 +1880,7 @@ importers: version: 11.3.2 '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)))(hono@4.12.2)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)))(hono@4.12.2)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -2124,7 +2151,7 @@ importers: version: 3.0.2(electron@41.2.1) '@electron-toolkit/tsconfig': specifier: 'catalog:' - version: 2.0.0(@types/node@24.12.2) + version: 2.0.0(@types/node@25.6.0) '@electron-toolkit/utils': specifier: 'catalog:' version: 4.0.0(electron@41.2.1) @@ -2163,7 +2190,7 @@ importers: version: 3.1.0 '@intlify/unplugin-vue-i18n': specifier: 'catalog:' - version: 11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.7.0))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + version: 11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.7.0))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) '@modelcontextprotocol/sdk': specifier: 'catalog:' version: 1.30.0(@cfworker/json-schema@4.1.1)(zod@4.4.3) @@ -2199,10 +2226,10 @@ importers: version: link:../../packages/ui-transitions '@proj-airi/unplugin-fetch': specifier: 'catalog:' - version: 0.2.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 0.2.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@proj-airi/unplugin-live2d-sdk': specifier: 'catalog:' - version: 0.1.7(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@types/audioworklet': specifier: 'catalog:' version: 0.0.97 @@ -2229,7 +2256,7 @@ importers: version: 2.10.3 '@vitejs/plugin-vue': specifier: 'catalog:' - version: 6.0.6(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) + version: 6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) '@vue-macros/volar': specifier: 'catalog:' version: 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) @@ -2262,7 +2289,7 @@ importers: version: 6.8.3 electron-vite: specifier: 'catalog:' - version: 5.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 5.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) get-port-please: specifier: 'catalog:' version: 3.2.0 @@ -2283,31 +2310,31 @@ importers: version: 2.2.6 unocss-preset-scrollbar: specifier: 'catalog:' - version: 4.0.0(unocss@66.6.8(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 4.0.0(unocss@66.6.8(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) unplugin-info: specifier: 'catalog:' - version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) unplugin-yaml: specifier: 'catalog:' - version: 4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite: specifier: 'catalog:' - version: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-bundle-visualizer: specifier: 'catalog:' version: 1.2.1(rolldown@1.0.0-rc.16)(rollup@4.60.1) vite-plugin-mkcert: specifier: 'catalog:' - version: 2.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 2.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plugin-vue-devtools: specifier: 'catalog:' - version: 8.1.1(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) + version: 8.1.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) vite-plugin-vue-layouts: specifier: 'catalog:' - version: 0.11.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + version: 0.11.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) vue-macros: specifier: 'catalog:' - version: 3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) + version: 3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) vue-tsc: specifier: 'catalog:' version: 3.2.6(typescript@5.9.3) @@ -2334,7 +2361,7 @@ importers: version: 3.8.1 '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -2719,7 +2746,7 @@ importers: version: 3.8.1 '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -3440,25 +3467,6 @@ importers: specifier: 'catalog:' version: 0.0.97 - packages/audio-input-e2e: - dependencies: - '@pnpm/find-workspace-dir': - specifier: 'catalog:' - version: 1000.1.5 - '@proj-airi/stage-shared': - specifier: workspace:^ - version: link:../stage-shared - playwright: - specifier: 'catalog:' - version: 1.60.0 - valibot: - specifier: 'catalog:' - version: 1.4.2(typescript@5.9.3) - devDependencies: - '@types/node': - specifier: 'catalog:' - version: 24.12.2 - packages/audio-pipelines-transcribe: dependencies: '@moeru/std': @@ -3475,7 +3483,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)))(hono@4.12.2)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)))(hono@4.12.2)(web-worker@1.5.0) crossws: specifier: 'catalog:' version: 0.4.5(srvx@0.11.22) @@ -3611,7 +3619,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@40.8.5)(h3@2.0.1-rc.25)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@40.8.5)(h3@2.0.1-rc.25)(web-worker@1.5.0) builder-util-runtime: specifier: 'catalog:' version: 9.5.1 @@ -3639,7 +3647,7 @@ importers: version: 3.0.2(electron@41.2.1) '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -3657,7 +3665,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@40.8.5)(h3@2.0.1-rc.25)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@40.8.5)(h3@2.0.1-rc.25)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -3764,7 +3772,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -3776,7 +3784,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@xsai/shared-chat': specifier: 'catalog:' version: 0.5.0-beta.8 @@ -3785,7 +3793,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -3807,7 +3815,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@proj-airi/plugin-sdk': specifier: workspace:* version: link:../plugin-sdk @@ -3943,7 +3951,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) packages/server-shared: dependencies: @@ -3955,7 +3963,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -4070,7 +4078,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -4219,7 +4227,7 @@ importers: version: 3.0.2(electron@41.2.1) '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@nekopaw/tempora': specifier: 'catalog:' version: 0.4.0-alpha.1 @@ -4246,7 +4254,7 @@ importers: version: 3.8.1 '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -4944,7 +4952,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@pixiv/three-vrm': specifier: 'catalog:' version: 3.5.2(@types/three@0.184.0)(three@0.184.0) @@ -5009,6 +5017,37 @@ importers: packages/stream-kit: {} + packages/testing-audio: + dependencies: + '@moeru/std': + specifier: 'catalog:' + version: 0.1.0-beta.17 + '@pnpm/find-workspace-dir': + specifier: 'catalog:' + version: 1000.1.5 + '@proj-airi/stage-shared': + specifier: workspace:^ + version: link:../stage-shared + '@proj-airi/stage-ui': + specifier: workspace:^ + version: link:../stage-ui + '@proj-airi/vitest-plugin-fakemic': + specifier: workspace:^ + version: link:../vitest-plugin-fakemic + playwright: + specifier: 'catalog:' + version: 1.60.0 + vite: + specifier: 'catalog:' + version: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vitest: + specifier: catalog:vitest + version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.1.1(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + devDependencies: + '@types/node': + specifier: 'catalog:' + version: 24.12.2 + packages/ui: dependencies: '@moeru/std': @@ -5126,6 +5165,22 @@ importers: specifier: '>=66' version: 66.6.8 + packages/vitest-plugin-fakemic: + dependencies: + playwright: + specifier: 'catalog:' + version: 1.60.0 + vite: + specifier: 'catalog:' + version: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vitest: + specifier: catalog:vitest + version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.1.1(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + devDependencies: + '@types/node': + specifier: 'catalog:' + version: 24.12.2 + plugins/airi-plugin-bilibili-laplace: dependencies: '@guiiai/logg': @@ -5176,7 +5231,7 @@ importers: dependencies: '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -5273,7 +5328,7 @@ importers: version: 1.2.4 '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -5333,7 +5388,7 @@ importers: version: 5.4.0(@opentelemetry/api@1.9.1) '@moeru/eventa': specifier: 'catalog:' - version: 1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) + version: 1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0) '@moeru/std': specifier: 'catalog:' version: 0.1.0-beta.17 @@ -5634,6 +5689,18 @@ packages: '@acemir/cssom@0.9.31': resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + '@actions/core@3.0.1': + resolution: {integrity: sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==} + + '@actions/exec@3.0.0': + resolution: {integrity: sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==} + + '@actions/http-client@4.0.1': + resolution: {integrity: sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==} + + '@actions/io@3.0.2': + resolution: {integrity: sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==} + '@agentclientprotocol/sdk@1.3.0': resolution: {integrity: sha512-i3h/efaeuMUFAO1HSfo97QZQnnvMd7wWBYtBsdL6UMZg3a78sk3Ffya5Xu7C7tYsXomXoDXJBAzQF2PcFKAhIQ==} peerDependencies: @@ -6664,6 +6731,10 @@ packages: '@codemirror/view@6.39.7': resolution: {integrity: sha512-3Vif9hnNHJnl2YgOtkR/wzGzhYcQ8gy3LGdUhkLUU8xSBbgsTxrE8he/CMTpeINm5TgxLe2FmzvF6IYQL/BSAg==} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@cryptography/aes@0.1.1': resolution: {integrity: sha512-PcYz4FDGblO6tM2kSC+VzhhK62vml6k6/YAkiWtyPvrgJVfnDRoHGDtKn5UiaRRUrvUTTocBpvc2rRgTCqxjsg==} @@ -8203,8 +8274,8 @@ packages: web-worker: optional: true - '@moeru/eventa@1.0.0-beta.13': - resolution: {integrity: sha512-zar2haIEkttvDJkBMSv4nEjo3OMhePDwr65nOBJFb6rXLbUjZQ+El6OuPDQZMbuxA+pcKwZhOT6AvamNXxjHfQ==} + '@moeru/eventa@1.0.0-beta.15': + resolution: {integrity: sha512-isjbOHeQuZJmlYJAQ6C28awXa4lpSdSEi/YPHrMuZQADHKDDu6O2R2oUclBiLVWM0Ut8R4WJFY8uLRuZP6Hq6g==} peerDependencies: '@tauri-apps/api': '>=2' electron: '>=39' @@ -8426,6 +8497,60 @@ packages: '@nxg-org/mineflayer-util-plugin@1.8.4': resolution: {integrity: sha512-hPaCZxU0Aq+gUSi/l6x7n32hUG6bnDugAMoQXD2dFE/gyNkmRSpmgH5+Y6G41w3H8P3Nl++upGCOlaxvZ7RuoA==} + '@octokit/auth-token@6.0.0': + resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} + engines: {node: '>= 20'} + + '@octokit/core@7.0.7': + resolution: {integrity: sha512-DcB0M3KFgr9ECI328lhBMVsyFT2DnmNucSBTqEN3exyNKUzkkpUSCHmTRcunF41Eou2TIQKW4seewri8ON9bSA==} + engines: {node: '>= 20'} + + '@octokit/endpoint@11.0.4': + resolution: {integrity: sha512-f1cOWoHPmxryJFknxbtDdjODWfV8A9tc8Aae6ermXPNgHFZ/x91AtHIz4gicEjL8hkJiip+u21QHJORfBv/qiA==} + engines: {node: '>= 20'} + + '@octokit/graphql@9.0.4': + resolution: {integrity: sha512-5s15CCiY8XXQ+FG+b1YQcl6Z2FA++nwAz/tg2VUrTmnMncP+2nnGUEYANImdnxsA2Fnq+Mbl7hDjUTw7cFAwcg==} + engines: {node: '>= 20'} + + '@octokit/openapi-types@27.0.0': + resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} + + '@octokit/openapi-types@28.0.0': + resolution: {integrity: sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==} + + '@octokit/plugin-paginate-rest@14.0.0': + resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-retry@8.1.1': + resolution: {integrity: sha512-VCVvZ/R1+u3WuiBWpNavZ0mY4aaJNAsENrpBP9aLSR2QyOpQgd7DhM5j4AW7z4MQpnJYgwBPf0XqPQoNBRdQwg==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=7' + + '@octokit/plugin-throttling@11.0.5': + resolution: {integrity: sha512-LIdrkrUv+DWbKeg/49rGuFJ3SU0d3hUS+B4MhNZLepBoNUFXms8Ic9edJjrlx+zycqJHjrMRudVpVb/bAXM2Lw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': ^7.0.0 + + '@octokit/request-error@7.1.1': + resolution: {integrity: sha512-+eaY7G2VVpSf2pc5Gn1+mph837V/d/TYTJAgWL9Tb0ogGYcpN3IlAVFgjL+Vv93F/sevrxkvsYCedtpLdcFLzA==} + engines: {node: '>= 20'} + + '@octokit/request@10.0.13': + resolution: {integrity: sha512-v2269YxL9Yf+x3d+gRI63FP0vFQEiWgLyBzxe/Y+0yFDg2B/Tzf5dhh9VNfccVAQnfcfwQWyk/y6Bn7rUXXs7A==} + engines: {node: '>= 20'} + + '@octokit/types@16.0.0': + resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} + + '@octokit/types@17.0.0': + resolution: {integrity: sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==} + '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} @@ -10676,6 +10801,59 @@ packages: resolution: {integrity: sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@semantic-release/changelog@6.0.3': + resolution: {integrity: sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + + '@semantic-release/commit-analyzer@13.0.1': + resolution: {integrity: sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=20.1.0' + + '@semantic-release/error@3.0.0': + resolution: {integrity: sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==} + engines: {node: '>=14.17'} + + '@semantic-release/error@4.0.0': + resolution: {integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==} + engines: {node: '>=18'} + + '@semantic-release/exec@7.1.0': + resolution: {integrity: sha512-4ycZ2atgEUutspPZ2hxO6z8JoQt4+y/kkHvfZ1cZxgl9WKJId1xPj+UadwInj+gMn2Gsv+fLnbrZ4s+6tK2TFQ==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=24.1.0' + + '@semantic-release/git@10.0.1': + resolution: {integrity: sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + + '@semantic-release/github@12.0.9': + resolution: {integrity: sha512-ODIqb0V3QqndipryEEiaBxUQCFjvv7Oese5Dt4omMGa60YRNEW0Sx3K+zri0uac2Y6S9nOlMehciWIzvvRCTGQ==} + engines: {node: ^22.14.0 || >= 24.10.0} + peerDependencies: + semantic-release: '>=24.1.0' + + '@semantic-release/npm@13.1.5': + resolution: {integrity: sha512-Hq5UxzoatN3LHiq2rTsWS54nCdqJHlsssGERCo8WlvdfFA9LoN0vO+OuKVSjtNapIc/S8C2LBj206wKLHg62mg==} + engines: {node: ^22.14.0 || >= 24.10.0} + peerDependencies: + semantic-release: '>=20.1.0' + + '@semantic-release/release-notes-generator@14.1.1': + resolution: {integrity: sha512-Pbd2e2XRMUD0OxehHpgd5/YghsE76cddkRHSoDvKLK+OCy4Ewxn49rWR631MEUU01lgwF/uyVXvbnVuu6+Z6VA==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=20.1.0' + '@shikijs/core@3.23.0': resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} @@ -10751,6 +10929,10 @@ packages: resolution: {integrity: sha512-sUKOu2lb5vGIWADNNLpscyj07DAeQZU3KLbnE2Tj53tW6BbDQKMly2CCfnR4oYzqtRELCPWfwaPg+Q0T8qfKBg==} deprecated: Contains a breaking change that should be a major version bump + '@simple-libs/stream-utils@1.2.0': + resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==} + engines: {node: '>=18'} + '@sindresorhus/base62@1.0.0': resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} engines: {node: '>=18'} @@ -10763,6 +10945,10 @@ packages: resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@snazzah/davey-android-arm-eabi@0.1.11': resolution: {integrity: sha512-T1RYbNYKN6tLOcGIDKJd8OI6FBSEemwL7DOYdTMmhqfhhMr3YVN8WOhfoxGg63OcnpTN2e2c5tdY2bAx25RmQQ==} engines: {node: '>= 10'} @@ -11271,6 +11457,9 @@ packages: '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/nprogress@0.2.3': resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} @@ -12335,6 +12524,18 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + agent-base@9.0.0: + resolution: {integrity: sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==} + engines: {node: '>= 20'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + aggregate-error@5.0.0: + resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} + engines: {node: '>=18'} + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -12389,6 +12590,10 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -12445,6 +12650,9 @@ packages: args-tokenizer@0.3.0: resolution: {integrity: sha512-xXAd7G2Mll5W8uo37GETpQ2VrE84M181Z7ugHFGQnJZ50M2mbOv0osSZ9VsSgPfJQ+LVG0prSi0th+ELMsno7Q==} + argv-formatter@1.0.0: + resolution: {integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==} + aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} @@ -12465,6 +12673,9 @@ packages: resolution: {integrity: sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + array-union@1.0.2: resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} engines: {node: '>=0.10.0'} @@ -12647,6 +12858,9 @@ packages: bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + before-after-hook@4.0.0: + resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + best-effort-json-parser@1.4.0: resolution: {integrity: sha512-gYmXQicIXaaspBdCLqok3t0JXYdi3Cr9oIgYh2+9rEWiNhLvi/89cguCWXZJWp0FgBR6YoEE9YkbZEfqKdqs+Q==} @@ -12840,6 +13054,9 @@ packages: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + boxen@8.0.1: resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} engines: {node: '>=18'} @@ -12970,6 +13187,10 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + camelcase@4.1.0: resolution: {integrity: sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==} engines: {node: '>=4'} @@ -13009,6 +13230,10 @@ packages: resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} engines: {node: '>=12'} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -13020,6 +13245,10 @@ packages: change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -13082,6 +13311,14 @@ packages: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + clean-stack@5.3.0: + resolution: {integrity: sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg==} + engines: {node: '>=14.16'} + cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} @@ -13094,6 +13331,11 @@ packages: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -13102,6 +13344,10 @@ packages: resolution: {integrity: sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==} engines: {node: '>=18.20'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} @@ -13113,10 +13359,17 @@ packages: cliss@0.0.2: resolution: {integrity: sha512-6rj9pgdukjT994Md13JCUAgTk91abAKrygL9sAvmHY4F6AKMOV8ccGaxhUUfcBuyg3sundWnn3JE0Mc9W6ZYqw==} + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} @@ -13132,10 +13385,16 @@ packages: resolution: {integrity: sha512-Zvxo5inxwvoGMI0R+cXV+5nVbl/Gw7zYV1Msn9mn7loC6CK941CjvsBplgClJV83T4UXID+SXhtfVulfaBat5w==} engines: {node: '>=22.10.0'} + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -13234,6 +13493,9 @@ packages: commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + compare-version@0.1.2: resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} engines: {node: '>=0.10.0'} @@ -13286,6 +13548,32 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + conventional-changelog-angular@8.3.1: + resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} + engines: {node: '>=18'} + + conventional-changelog-writer@8.4.0: + resolution: {integrity: sha512-HHBFkk1EECxxmCi4CTu091iuDpQv5/OavuCUAuZmrkWpmYfyD816nom1CvtfXJ/uYfAAjavgHvXHX291tSLK8g==} + engines: {node: '>=18'} + hasBin: true + + conventional-commits-filter@5.0.0: + resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} + engines: {node: '>=18'} + + conventional-commits-parser@6.4.0: + resolution: {integrity: sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==} + engines: {node: '>=18'} + hasBin: true + + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -13327,6 +13615,15 @@ packages: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} + cosmiconfig@9.0.2: + resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + crc@3.8.0: resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} @@ -13355,6 +13652,10 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} + crypto-random-string@4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + css-line-break@2.1.0: resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} @@ -13686,6 +13987,10 @@ packages: dir-compare@4.2.0: resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + direction@2.0.1: resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} hasBin: true @@ -13735,6 +14040,10 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dot-prop@9.0.0: resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} engines: {node: '>=18'} @@ -13965,6 +14274,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -14079,6 +14391,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -14134,6 +14449,10 @@ packages: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} + env-ci@11.2.0: + resolution: {integrity: sha512-D5kWfzkmaOQDioPmiviWAVtKmpPT4/iJmMVQxWxMPJTFyTkdc5JQUfc5iXEeWxcOdsYTKSAiA/Age4NUOqKsRA==} + engines: {node: ^18.17 || >=20.6.1} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -14521,6 +14840,14 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + exif-parser@0.1.12: resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} @@ -14647,6 +14974,14 @@ packages: fflate@0.8.3: resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + figures@2.0.0: + resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} + engines: {node: '>=4'} + + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -14722,6 +15057,10 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + find-versions@6.0.0: + resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==} + engines: {node: '>=18'} + firefox-profile@4.7.0: resolution: {integrity: sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ==} engines: {node: '>=18'} @@ -14877,6 +15216,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@1.0.2: + resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} + engines: {node: '>=18'} + functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} @@ -14941,6 +15284,14 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} @@ -14959,6 +15310,9 @@ packages: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true + git-log-parser@1.2.1: + resolution: {integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==} + git-up@8.1.1: resolution: {integrity: sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==} @@ -15114,6 +15468,11 @@ packages: crossws: optional: true + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + har-schema@2.0.0: resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} engines: {node: '>=4'} @@ -15123,6 +15482,10 @@ packages: engines: {node: '>=6'} deprecated: this library is no longer supported + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -15210,6 +15573,9 @@ packages: resolution: {integrity: sha512-MXaWVJVeAgNzLoEAjbsu+cwcN9XhvgURDLJqmDUXXEYO7DUV6eK8LK3Fy6mLgfP73GdtVjTtZan6gj7xhPUrLA==} hasBin: true + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + histoire@1.0.0-beta.1: resolution: {integrity: sha512-hzhFiqlL9Ko1B2APCamGIchM3Bjng5+CTX7kLL1q/NB2Lp4Uqpe4ZZicc7RU4CTCe4Vj7Q/Eb3UE/IacL1Ta5g==} hasBin: true @@ -15233,6 +15599,10 @@ packages: resolution: {integrity: sha512-gJnaDHXKDayjt8ue0n8Gs0A007yKXj4Xzb8+cNjZeYsSzzwKc0Lr+OZgYwVfB0pHfUs17EPoLvrOsEaJ9mj+Tg==} engines: {node: '>=16.9.0'} + hook-std@4.0.0: + resolution: {integrity: sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==} + engines: {node: '>=20'} + hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -15243,6 +15613,14 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -15283,6 +15661,10 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} + http-proxy-agent@9.1.0: + resolution: {integrity: sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==} + engines: {node: '>= 20'} + http-signature@1.2.0: resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} engines: {node: '>=0.8', npm: '>=1.3.7'} @@ -15295,10 +15677,22 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + https-proxy-agent@9.1.0: + resolution: {integrity: sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==} + engines: {node: '>= 20'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + iconv-corefoundation@1.1.7: resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} engines: {node: ^8.11.2 || >=10} @@ -15348,10 +15742,18 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + import-from-esm@1.3.4: resolution: {integrity: sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg==} engines: {node: '>=16.20'} + import-from-esm@2.0.0: + resolution: {integrity: sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==} + engines: {node: '>=18.20'} + import-in-the-middle@3.0.0: resolution: {integrity: sha512-OnGy+eYT7wVejH2XWgLRgbmzujhhVIATQH0ztIeRilwHBjTeG3pD+XnH3PKX0r9gJ0BuJmJ68q/oh9qgXnNDQg==} engines: {node: '>=18'} @@ -15367,10 +15769,18 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -15533,6 +15943,10 @@ packages: resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} engines: {node: '>=0.10.0'} + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + is-path-inside@4.0.0: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} @@ -15574,6 +15988,14 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -15581,6 +16003,10 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} @@ -15629,6 +16055,10 @@ packages: isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + issue-parser@7.0.2: + resolution: {integrity: sha512-7atWPjhGEIX3JEtMrOYd8TKzboYlq+5sNbdl9POiLYOI14G5HZiQbZP0Xj5EZdrufQVXfJlpTV0hys0CuxwxZw==} + engines: {node: ^18.17 || >=20.6.1} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -15653,6 +16083,10 @@ packages: engines: {node: '>=10'} hasBin: true + java-properties@1.0.2: + resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} + engines: {node: '>= 0.6.0'} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true @@ -15733,6 +16167,12 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-parse-even-better-errors@3.0.2: resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -15755,6 +16195,9 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + json-with-bigint@3.5.10: + resolution: {integrity: sha512-Vcx+JVNEBts/xfcoCS69sKrOhOk/3TVlvlT+XzUOefVKnnrbYSCKpDCm10pohsJFtsJVYnwa/cXRZ4eElzaM6w==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -16000,6 +16443,10 @@ packages: resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} + load-json-file@4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} + local-pkg@1.1.2: resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} engines: {node: '>=14'} @@ -16019,9 +16466,15 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.capitalize@4.2.1: + resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -16077,6 +16530,9 @@ packages: lodash.truncate@4.4.2: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + lodash.uniqby@4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -16140,6 +16596,10 @@ packages: magicli@0.0.8: resolution: {integrity: sha512-x/eBenweAHF+DsYy172sK4doRxZl0yrJnfxhLJiN7H6hPM3Ya0PfI6uBZshZ3ScFFSQD7HXgBqMdbnXKEZsO1g==} + make-asynchronous@1.1.0: + resolution: {integrity: sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==} + engines: {node: '>=18'} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -16187,6 +16647,17 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked-terminal@7.3.0: + resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <16' + + marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true + marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} @@ -16257,6 +16728,10 @@ packages: mediabunny@1.40.1: resolution: {integrity: sha512-HU/stGzAkdWaJIly6ypbUVgAUvT9kt39DIg0IaErR7/1fwtTmgUYs4i8uEPYcgcjPjbB9gtBmUXOLnXi6J2LDw==} + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + meow@14.1.0: resolution: {integrity: sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==} engines: {node: '>=20'} @@ -16410,10 +16885,19 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -16657,6 +17141,12 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + nerf-dart@1.0.0: + resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} + neverthrow@8.2.0: resolution: {integrity: sha512-kOCT/1MCPAxY5iUV3wytNFUMUolzuwd/VF/1KCx7kf6CutrOsTie+84zTGTpgQycjvfLdBBdvBvFLqFD2c0wkQ==} engines: {node: '>=18'} @@ -16689,6 +17179,10 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + node-emoji@2.2.0: + resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} + engines: {node: '>=18'} + node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} @@ -16747,6 +17241,14 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + + normalize-package-data@8.0.0: + resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==} + engines: {node: ^20.17.0 || >=22.9.0} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -16755,10 +17257,93 @@ packages: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} + normalize-url@9.0.1: + resolution: {integrity: sha512-ARftfC5HdUNu9jJeL8pHj8debUIHA2b91FizCoMzY4lG6dDX13jdvTK0TBe24IBDRf2HvJSzzwEPvmbkQWHRSg==} + engines: {node: '>=20'} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + + npm@11.19.0: + resolution: {integrity: sha512-SDd/hHg3KqHE5Ht2NHWxNYNtqCQ2pXAPLl6OtQhPyED5PHsRfrOtO199MZTIG2cQoQ1ZRI9t28shrD+2cr3AAw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/metavuln-calculator' + - '@npmcli/package-json' + - '@npmcli/promise-spawn' + - '@npmcli/redact' + - '@npmcli/run-script' + - '@sigstore/tuf' + - abbrev + - archy + - cacache + - chalk + - ci-info + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - ms + - node-gyp + - nopt + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - semver + - spdx-expression-parse + - ssri + - supports-color + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + nprogress@0.2.0: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} @@ -16831,6 +17416,10 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + onetime@7.0.0: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} @@ -16919,6 +17508,18 @@ packages: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} + p-each-series@3.0.0: + resolution: {integrity: sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==} + engines: {node: '>=12'} + + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + + p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} + engines: {node: '>=18'} + p-limit@1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -16951,6 +17552,18 @@ packages: resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} + p-reduce@2.1.0: + resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==} + engines: {node: '>=8'} + + p-reduce@3.0.0: + resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==} + engines: {node: '>=12'} + + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + p-try@1.0.0: resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} engines: {node: '>=4'} @@ -16975,6 +17588,10 @@ packages: pako@2.1.0: resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + parse-gitignore@2.0.0: resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==} engines: {node: '>=14'} @@ -16982,10 +17599,26 @@ packages: parse-imports-exports@0.2.4: resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + parse-json@4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + parse-json@7.1.1: resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} engines: {node: '>=16'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + parse-node-version@1.0.1: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} @@ -17000,6 +17633,15 @@ packages: resolution: {integrity: sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==} engines: {node: '>=14.13.0'} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -17032,6 +17674,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -17049,6 +17695,10 @@ packages: path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + path-type@6.0.0: resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} engines: {node: '>=18'} @@ -17131,6 +17781,10 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -17196,6 +17850,10 @@ packages: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} + pkg-conf@2.1.0: + resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} + engines: {node: '>=4'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -17354,6 +18012,10 @@ packages: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + prism-media@1.3.5: resolution: {integrity: sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==} peerDependencies: @@ -17495,6 +18157,15 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent-negotiate@1.1.0: + resolution: {integrity: sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==} + engines: {node: '>= 20'} + peerDependencies: + kerberos: ^2.0.0 + peerDependenciesMeta: + kerberos: + optional: true + prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -17599,6 +18270,22 @@ packages: resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} hasBin: true + read-package-up@11.0.0: + resolution: {integrity: sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==} + engines: {node: '>=18'} + + read-package-up@12.0.0: + resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==} + engines: {node: '>=20'} + + read-pkg@10.1.0: + resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==} + engines: {node: '>=20'} + + read-pkg@9.0.1: + resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} + engines: {node: '>=18'} + readable-stream@1.0.34: resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} @@ -17777,6 +18464,14 @@ packages: resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -17955,9 +18650,18 @@ packages: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} engines: {node: '>=4'} + semantic-release@25.0.9: + resolution: {integrity: sha512-bxve7csK0/Txr++CkfrmV+X1r4jqiSOw2WsSad9E2S68R+ZfLBwDn8IceM8WfiOmKQIHgsQc1cNA8Dzg7U75pg==} + engines: {node: ^22.14.0 || >= 24.10.0} + hasBin: true + semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + semver-regex@4.0.5: + resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==} + engines: {node: '>=12'} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -18053,6 +18757,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + signale@1.4.0: + resolution: {integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==} + engines: {node: '>=6'} + simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -18080,6 +18788,10 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + slash@5.1.0: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} @@ -18168,12 +18880,21 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spawn-error-forwarder@1.0.0: + resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} + spawn-sync@1.0.15: resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==} + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + spdx-exceptions@2.5.0: resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + spdx-expression-parse@4.0.0: resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} @@ -18190,6 +18911,9 @@ packages: split-skip@0.0.2: resolution: {integrity: sha512-weHOi8BolsDnGIwhhWHbA+wKSuSpvWwjRrdj8SdbIIis2vSwOE37CQP8x3EleuzxanUr3AK8BdUy4MkiOULPZg==} + split2@1.0.0: + resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -18273,6 +18997,9 @@ packages: store2@2.14.4: resolution: {integrity: sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw==} + stream-combiner2@1.1.1: + resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} + streamx@2.28.0: resolution: {integrity: sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==} @@ -18288,6 +19015,10 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string-width@8.2.2: + resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==} + engines: {node: '>=20'} + string_decoder@0.10.31: resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} @@ -18324,6 +19055,10 @@ packages: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} engines: {node: '>=0.10.0'} + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-bom@5.0.0: resolution: {integrity: sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==} engines: {node: '>=12'} @@ -18336,6 +19071,14 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-indent@4.1.1: resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} @@ -18396,6 +19139,10 @@ packages: resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} engines: {node: '>= 8.0'} + super-regex@1.1.0: + resolution: {integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==} + engines: {node: '>=18'} + superjson@2.2.6: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} @@ -18404,10 +19151,18 @@ packages: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -18440,6 +19195,10 @@ packages: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -18473,6 +19232,10 @@ packages: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} + temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} @@ -18484,6 +19247,10 @@ packages: resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} engines: {node: '>=10'} + tempy@3.2.0: + resolution: {integrity: sha512-d79HhZya5Djd7am0q+W4RTsSU+D/aJzM+4Y4AGJGuGlgM2L6sx5ZvOYTmZjqPhrDrV6xJTtRSm1JCLj6V6LHLQ==} + engines: {node: '>=14.16'} + terser@5.46.1: resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} engines: {node: '>=10'} @@ -18539,12 +19306,19 @@ packages: through2@0.6.5: resolution: {integrity: sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==} + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + timm@1.7.1: resolution: {integrity: sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==} @@ -18628,6 +19402,10 @@ packages: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} + traverse@0.6.8: + resolution: {integrity: sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==} + engines: {node: '>= 0.4'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -18714,6 +19492,10 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + turbo@2.9.6: resolution: {integrity: sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg==} hasBin: true @@ -18733,6 +19515,14 @@ packages: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} + type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + type-fest@3.13.1: resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} engines: {node: '>=14.16'} @@ -18741,6 +19531,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-fest@5.8.0: + resolution: {integrity: sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==} + engines: {node: '>=20'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -18806,6 +19600,11 @@ packages: ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} @@ -18860,6 +19659,10 @@ packages: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + unicode-match-property-ecmascript@2.0.0: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} @@ -18872,10 +19675,18 @@ packages: resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} engines: {node: '>=4'} + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -18895,6 +19706,10 @@ packages: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} + unique-string@3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + unist-builder@4.0.0: resolution: {integrity: sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==} @@ -18922,6 +19737,9 @@ packages: unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universal-user-agent@7.0.3: + resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -19194,6 +20012,10 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-join@5.0.0: + resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + url@0.11.4: resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} engines: {node: '>= 0.4'} @@ -19248,6 +20070,9 @@ packages: typescript: optional: true + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + validate-npm-package-name@5.0.1: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -19796,6 +20621,9 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + wordwrapjs@3.0.0: resolution: {integrity: sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==} engines: {node: '>=4.0.0'} @@ -20012,17 +20840,33 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs-parser@7.0.0: resolution: {integrity: sha512-WhzC+xgstid9MbVUktco/bf+KJG+Uu6vMX0LN1sLJvwmbCQVxb4D8LzogobonKycNasCZLdOzTAk1SK7+K7swg==} + yargs@16.2.2: + resolution: {integrity: sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==} + engines: {node: '>=10'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.1.0: + resolution: {integrity: sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} @@ -20078,6 +20922,22 @@ snapshots: '@acemir/cssom@0.9.31': {} + '@actions/core@3.0.1': + dependencies: + '@actions/exec': 3.0.0 + '@actions/http-client': 4.0.1 + + '@actions/exec@3.0.0': + dependencies: + '@actions/io': 3.0.2 + + '@actions/http-client@4.0.1': + dependencies: + tunnel: 0.0.6 + undici: 6.24.1 + + '@actions/io@3.0.2': {} + '@agentclientprotocol/sdk@1.3.0(zod@4.4.3)': dependencies: zod: 4.4.3 @@ -21507,6 +22367,9 @@ snapshots: style-mod: 4.1.3 w3c-keyname: 2.2.8 + '@colors/colors@1.5.0': + optional: true + '@cryptography/aes@0.1.1': {} '@csstools/color-helpers@5.1.0': {} @@ -21700,9 +22563,9 @@ snapshots: dependencies: electron: 41.2.1 - '@electron-toolkit/tsconfig@2.0.0(@types/node@24.12.2)': + '@electron-toolkit/tsconfig@2.0.0(@types/node@25.6.0)': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@electron-toolkit/utils@4.0.0(electron@41.2.1)': dependencies: @@ -22639,31 +23502,6 @@ snapshots: - supports-color - typescript - '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.7.0))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3))': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.7.0)) - '@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3))) - '@intlify/shared': 11.3.2 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.3.2)(@vue/compiler-dom@3.5.32)(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.60.1) - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - debug: 4.4.3(supports-color@10.2.2) - fast-glob: 3.3.3 - pathe: 2.0.3 - picocolors: 1.1.1 - unplugin: 2.3.11 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vue: 3.5.32(typescript@5.9.3) - optionalDependencies: - vue-i18n: 11.3.2(vue@3.5.32(typescript@5.9.3)) - transitivePeerDependencies: - - '@vue/compiler-dom' - - eslint - - rollup - - supports-color - - typescript - '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.7.0))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.7.0)) @@ -23060,7 +23898,7 @@ snapshots: h3: 2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)) web-worker: 1.5.0 - '@moeru/eventa@1.0.0-beta.13(electron@40.8.5)(h3@2.0.1-rc.25)(web-worker@1.5.0)': + '@moeru/eventa@1.0.0-beta.15(electron@40.8.5)(h3@2.0.1-rc.25)(web-worker@1.5.0)': dependencies: nanoid: 6.0.1 picomatch: 4.0.4 @@ -23069,7 +23907,7 @@ snapshots: h3: 2.0.1-rc.25 web-worker: 1.5.0 - '@moeru/eventa@1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)))(hono@4.12.2)(web-worker@1.5.0)': + '@moeru/eventa@1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.20(crossws@0.4.5(srvx@0.11.22)))(hono@4.12.2)(web-worker@1.5.0)': dependencies: nanoid: 6.0.1 picomatch: 4.0.4 @@ -23079,7 +23917,7 @@ snapshots: hono: 4.12.2 web-worker: 1.5.0 - '@moeru/eventa@1.0.0-beta.13(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0)': + '@moeru/eventa@1.0.0-beta.15(electron@41.2.1)(h3@2.0.1-rc.25)(hono@4.11.3)(web-worker@1.5.0)': dependencies: nanoid: 6.0.1 picomatch: 4.0.4 @@ -23285,6 +24123,72 @@ snapshots: '@nxg-org/mineflayer-util-plugin@1.8.4': {} + '@octokit/auth-token@6.0.0': {} + + '@octokit/core@7.0.7': + dependencies: + '@octokit/auth-token': 6.0.0 + '@octokit/graphql': 9.0.4 + '@octokit/request': 10.0.13 + '@octokit/request-error': 7.1.1 + '@octokit/types': 17.0.0 + before-after-hook: 4.0.0 + universal-user-agent: 7.0.3 + + '@octokit/endpoint@11.0.4': + dependencies: + '@octokit/types': 17.0.0 + universal-user-agent: 7.0.3 + + '@octokit/graphql@9.0.4': + dependencies: + '@octokit/request': 10.0.13 + '@octokit/types': 17.0.0 + universal-user-agent: 7.0.3 + + '@octokit/openapi-types@27.0.0': {} + + '@octokit/openapi-types@28.0.0': {} + + '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.7)': + dependencies: + '@octokit/core': 7.0.7 + '@octokit/types': 16.0.0 + + '@octokit/plugin-retry@8.1.1(@octokit/core@7.0.7)': + dependencies: + '@octokit/core': 7.0.7 + '@octokit/request-error': 7.1.1 + '@octokit/types': 17.0.0 + bottleneck: 2.19.5 + + '@octokit/plugin-throttling@11.0.5(@octokit/core@7.0.7)': + dependencies: + '@octokit/core': 7.0.7 + '@octokit/types': 17.0.0 + bottleneck: 2.19.5 + + '@octokit/request-error@7.1.1': + dependencies: + '@octokit/types': 17.0.0 + + '@octokit/request@10.0.13': + dependencies: + '@octokit/endpoint': 11.0.4 + '@octokit/request-error': 7.1.1 + '@octokit/types': 17.0.0 + content-type: 2.0.0 + json-with-bigint: 3.5.10 + universal-user-agent: 7.0.3 + + '@octokit/types@16.0.0': + dependencies: + '@octokit/openapi-types': 27.0.0 + + '@octokit/types@17.0.0': + dependencies: + '@octokit/openapi-types': 28.0.0 + '@one-ini/wasm@0.1.1': {} '@opentelemetry/api-logs@0.215.0': @@ -24807,35 +25711,11 @@ snapshots: transitivePeerDependencies: - magicast - '@proj-airi/unplugin-fetch@0.2.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - ofetch: 1.5.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@proj-airi/unplugin-fetch@0.2.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: ofetch: 1.5.1 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@proj-airi/unplugin-live2d-sdk@0.1.7(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)': - dependencies: - ofetch: 1.5.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - yauzl: 3.3.0 - transitivePeerDependencies: - - '@types/node' - - '@vitejs/devtools' - - esbuild - - jiti - - less - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - '@proj-airi/unplugin-live2d-sdk@0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)': dependencies: ofetch: 1.5.1 @@ -25190,6 +26070,117 @@ snapshots: '@sapphire/snowflake@3.5.5': {} + '@sec-ant/readable-stream@0.4.1': {} + + '@semantic-release/changelog@6.0.3(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + fs-extra: 11.3.4 + lodash: 4.17.21 + semantic-release: 25.0.9(typescript@5.9.3) + + '@semantic-release/commit-analyzer@13.0.1(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + conventional-changelog-angular: 8.3.1 + conventional-changelog-writer: 8.4.0 + conventional-commits-filter: 5.0.0 + conventional-commits-parser: 6.4.0 + debug: 4.4.3(supports-color@10.2.2) + import-from-esm: 2.0.0 + lodash-es: 4.18.1 + micromatch: 4.0.8 + semantic-release: 25.0.9(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@semantic-release/error@3.0.0': {} + + '@semantic-release/error@4.0.0': {} + + '@semantic-release/exec@7.1.0(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + '@semantic-release/error': 4.0.0 + aggregate-error: 3.1.0 + debug: 4.4.3(supports-color@10.2.2) + execa: 9.6.1 + lodash-es: 4.18.1 + parse-json: 8.3.0 + semantic-release: 25.0.9(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@semantic-release/git@10.0.1(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + debug: 4.4.3(supports-color@10.2.2) + dir-glob: 3.0.1 + execa: 5.1.1 + lodash: 4.17.21 + micromatch: 4.0.8 + p-reduce: 2.1.0 + semantic-release: 25.0.9(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@semantic-release/github@12.0.9(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + '@octokit/core': 7.0.7 + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.7) + '@octokit/plugin-retry': 8.1.1(@octokit/core@7.0.7) + '@octokit/plugin-throttling': 11.0.5(@octokit/core@7.0.7) + '@semantic-release/error': 4.0.0 + aggregate-error: 5.0.0 + debug: 4.4.3(supports-color@10.2.2) + dir-glob: 3.0.1 + http-proxy-agent: 9.1.0 + https-proxy-agent: 9.1.0 + issue-parser: 7.0.2 + lodash-es: 4.18.1 + mime: 4.1.0 + p-filter: 4.1.0 + semantic-release: 25.0.9(typescript@5.9.3) + tinyglobby: 0.2.17 + undici: 7.25.0 + url-join: 5.0.0 + transitivePeerDependencies: + - kerberos + - supports-color + + '@semantic-release/npm@13.1.5(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + '@actions/core': 3.0.1 + '@semantic-release/error': 4.0.0 + aggregate-error: 5.0.0 + env-ci: 11.2.0 + execa: 9.6.1 + fs-extra: 11.3.4 + lodash-es: 4.18.1 + nerf-dart: 1.0.0 + normalize-url: 9.0.1 + npm: 11.19.0 + rc: 1.2.8 + read-pkg: 10.1.0 + registry-auth-token: 5.1.0 + semantic-release: 25.0.9(typescript@5.9.3) + semver: 7.7.4 + tempy: 3.2.0 + + '@semantic-release/release-notes-generator@14.1.1(semantic-release@25.0.9(typescript@5.9.3))': + dependencies: + conventional-changelog-angular: 8.3.1 + conventional-changelog-writer: 8.4.0 + conventional-commits-filter: 5.0.0 + conventional-commits-parser: 6.4.0 + debug: 4.4.3(supports-color@10.2.2) + import-from-esm: 2.0.0 + lodash-es: 4.18.1 + read-package-up: 11.0.0 + semantic-release: 25.0.9(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + '@shikijs/core@3.23.0': dependencies: '@shikijs/types': 3.23.0 @@ -25288,12 +26279,16 @@ snapshots: dependencies: '@simple-git/args-pathspec': 1.0.3 + '@simple-libs/stream-utils@1.2.0': {} + '@sindresorhus/base62@1.0.0': {} '@sindresorhus/is@4.6.0': {} '@sindresorhus/merge-streams@2.3.0': {} + '@sindresorhus/merge-streams@4.0.0': {} + '@snazzah/davey-android-arm-eabi@0.1.11': optional: true @@ -25789,6 +26784,8 @@ snapshots: dependencies: undici-types: 7.19.2 + '@types/normalize-package-data@2.4.4': {} + '@types/nprogress@0.2.3': {} '@types/offscreencanvas@2019.7.3': {} @@ -26566,12 +27563,6 @@ snapshots: transitivePeerDependencies: - typescript - '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3))': - dependencies: - '@rolldown/pluginutils': 1.0.0-rc.13 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vue: 3.5.32(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.13 @@ -26847,15 +27838,6 @@ snapshots: transitivePeerDependencies: - vue - '@vue-macros/devtools@3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - sirv: 3.0.2 - vue: 3.5.32(typescript@5.9.3) - optionalDependencies: - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - typescript - '@vue-macros/devtools@3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: sirv: 3.0.2 @@ -27446,6 +28428,18 @@ snapshots: agent-base@7.1.4: {} + agent-base@9.0.0: {} + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + aggregate-error@5.0.0: + dependencies: + clean-stack: 5.3.0 + indent-string: 5.0.0 + ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: ajv: 8.18.0 @@ -27494,6 +28488,10 @@ snapshots: ansi-regex@6.2.2: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -27605,6 +28603,8 @@ snapshots: args-tokenizer@0.3.0: {} + argv-formatter@1.0.0: {} + aria-hidden@1.2.6: dependencies: tslib: 2.8.1 @@ -27619,6 +28619,8 @@ snapshots: array-differ@4.0.0: {} + array-ify@1.0.0: {} + array-union@1.0.2: dependencies: array-uniq: 1.0.3 @@ -27774,6 +28776,8 @@ snapshots: dependencies: tweetnacl: 0.14.5 + before-after-hook@4.0.0: {} + best-effort-json-parser@1.4.0: {} better-auth@1.4.22(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.41.0(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.29.4)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)): @@ -27918,6 +28922,8 @@ snapshots: boolean@3.2.0: {} + bottleneck@2.19.5: {} + boxen@8.0.1: dependencies: ansi-align: 3.0.1 @@ -28098,6 +29104,8 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + callsites@3.1.0: {} + camelcase@4.1.0: {} camelcase@8.0.0: {} @@ -28127,6 +29135,12 @@ snapshots: dependencies: chalk: 4.1.2 + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -28136,6 +29150,8 @@ snapshots: change-case@5.4.4: {} + char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} @@ -28194,6 +29210,12 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + clean-stack@2.2.0: {} + + clean-stack@5.3.0: + dependencies: + escape-string-regexp: 5.0.0 + cli-boxes@3.0.0: {} cli-cursor@3.1.0: @@ -28204,10 +29226,25 @@ snapshots: dependencies: restore-cursor: 5.1.0 + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.2 + cli-spinners@2.9.2: {} cli-spinners@3.4.0: {} + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@2.1.0: dependencies: slice-ansi: 3.0.0 @@ -28230,12 +29267,24 @@ snapshots: strip-ansi: 4.0.0 yargs-parser: 7.0.0 + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + clone-response@1.0.3: dependencies: mimic-response: 1.0.1 @@ -28246,10 +29295,16 @@ snapshots: clustr@1.0.2: {} + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} color-string@1.9.1: @@ -28330,6 +29385,11 @@ snapshots: commondir@1.0.1: {} + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + compare-version@0.1.2: {} compressible@2.0.18: @@ -28392,6 +29452,29 @@ snapshots: content-type@1.0.5: {} + content-type@2.0.0: {} + + conventional-changelog-angular@8.3.1: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-writer@8.4.0: + dependencies: + '@simple-libs/stream-utils': 1.2.0 + conventional-commits-filter: 5.0.0 + handlebars: 4.7.9 + meow: 13.2.0 + semver: 7.7.4 + + conventional-commits-filter@5.0.0: {} + + conventional-commits-parser@6.4.0: + dependencies: + '@simple-libs/stream-utils': 1.2.0 + meow: 13.2.0 + + convert-hrtime@5.0.0: {} + convert-source-map@2.0.0: {} cookie-es@1.2.3: {} @@ -28425,6 +29508,15 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cosmiconfig@9.0.2(typescript@5.9.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.9.3 + crc@3.8.0: dependencies: buffer: 5.7.1 @@ -28451,6 +29543,10 @@ snapshots: crypto-random-string@2.0.0: {} + crypto-random-string@4.0.0: + dependencies: + type-fest: 1.4.0 + css-line-break@2.1.0: dependencies: utrie: 1.0.2 @@ -28768,6 +29864,10 @@ snapshots: minimatch: 3.1.5 p-limit: 3.1.0 + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + direction@2.0.1: {} discontinuous-range@1.0.0: {} @@ -28856,6 +29956,10 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + dot-prop@9.0.0: dependencies: type-fest: 4.41.0 @@ -28920,6 +30024,10 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + duplexer@0.1.2: {} earcut@2.2.4: {} @@ -29010,7 +30118,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-vite@5.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + electron-vite@5.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) @@ -29018,7 +30126,7 @@ snapshots: esbuild: 0.25.12 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -29080,6 +30188,8 @@ snapshots: emoji-regex@9.2.2: {} + emojilib@2.4.0: {} + empathic@2.0.0: {} encodeurl@1.0.2: {} @@ -29142,6 +30252,11 @@ snapshots: entities@8.0.0: {} + env-ci@11.2.0: + dependencies: + execa: 8.0.1 + java-properties: 1.0.2 + env-paths@2.2.1: {} environment@1.1.0: {} @@ -29685,6 +30800,33 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 + exif-parser@0.1.12: {} expand-template@2.0.3: {} @@ -29860,6 +31002,14 @@ snapshots: fflate@0.8.3: {} + figures@2.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -29953,6 +31103,11 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + find-versions@6.0.0: + dependencies: + semver-regex: 4.0.5 + super-regex: 1.1.0 + firefox-profile@4.7.0: dependencies: adm-zip: 0.5.16 @@ -30107,6 +31262,8 @@ snapshots: function-bind@1.1.2: {} + function-timeout@1.0.2: {} + functional-red-black-tree@1.0.1: {} fuse.js@7.1.0: {} @@ -30177,6 +31334,13 @@ snapshots: get-stream@6.0.1: {} + get-stream@8.0.1: {} + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 @@ -30209,6 +31373,15 @@ snapshots: nypm: 0.6.5 pathe: 2.0.3 + git-log-parser@1.2.1: + dependencies: + argv-formatter: 1.0.0 + spawn-error-forwarder: 1.0.0 + split2: 1.0.0 + stream-combiner2: 1.1.1 + through2: 2.0.5 + traverse: 0.6.8 + git-up@8.1.1: dependencies: is-ssh: 1.4.1 @@ -30398,6 +31571,15 @@ snapshots: rou3: 0.9.1 srvx: 0.11.22 + handlebars@4.7.9: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + har-schema@2.0.0: {} har-validator@5.1.5: @@ -30405,6 +31587,8 @@ snapshots: ajv: 6.14.0 har-schema: 2.0.0 + has-flag@3.0.0: {} + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -30577,6 +31761,8 @@ snapshots: gray-matter: 4.0.3 unplugin: 3.0.0 + highlight.js@10.7.3: {} + histoire@1.0.0-beta.1(@noble/hashes@2.0.1)(@types/node@25.6.0)(bufferutil@4.1.0)(canvas@3.2.3)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@akryum/tinypool': 0.3.1 @@ -30636,6 +31822,8 @@ snapshots: hono@4.12.2: {} + hook-std@4.0.0: {} + hookable@5.5.3: {} hookable@6.1.1: {} @@ -30644,6 +31832,14 @@ snapshots: dependencies: lru-cache: 6.0.0 + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.3.5 + html-encoding-sniffer@6.0.0(@noble/hashes@2.0.1): dependencies: '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) @@ -30696,6 +31892,15 @@ snapshots: transitivePeerDependencies: - supports-color + http-proxy-agent@9.1.0: + dependencies: + agent-base: 9.0.0 + debug: 4.4.3(supports-color@10.2.2) + proxy-agent-negotiate: 1.1.0 + transitivePeerDependencies: + - kerberos + - supports-color + http-signature@1.2.0: dependencies: assert-plus: 1.0.0 @@ -30714,8 +31919,21 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@9.1.0: + dependencies: + agent-base: 9.0.0 + debug: 4.4.3(supports-color@10.2.2) + proxy-agent-negotiate: 1.1.0 + transitivePeerDependencies: + - kerberos + - supports-color + human-signals@2.1.0: {} + human-signals@5.0.0: {} + + human-signals@8.0.1: {} + iconv-corefoundation@1.1.7: dependencies: cli-truncate: 2.1.0 @@ -30760,6 +31978,11 @@ snapshots: immediate@3.0.6: {} + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + import-from-esm@1.3.4: dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -30767,6 +31990,13 @@ snapshots: transitivePeerDependencies: - supports-color + import-from-esm@2.0.0: + dependencies: + debug: 4.4.3(supports-color@10.2.2) + import-meta-resolve: 4.2.0 + transitivePeerDependencies: + - supports-color + import-in-the-middle@3.0.0: dependencies: acorn: 8.16.0 @@ -30780,8 +32010,12 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + indent-string@5.0.0: {} + index-to-position@1.2.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -30930,6 +32164,8 @@ snapshots: is-obj@1.0.1: {} + is-obj@2.0.0: {} + is-path-inside@4.0.0: {} is-plain-obj@4.1.0: {} @@ -30956,10 +32192,16 @@ snapshots: is-stream@2.0.1: {} + is-stream@3.0.0: {} + + is-stream@4.0.1: {} + is-typedarray@1.0.0: {} is-unicode-supported@0.1.0: {} + is-unicode-supported@2.1.0: {} + is-what@4.1.16: {} is-what@5.5.0: {} @@ -30997,6 +32239,14 @@ snapshots: isstream@0.1.2: {} + issue-parser@7.0.2: + dependencies: + lodash.capitalize: 4.2.1 + lodash.escaperegexp: 4.1.2 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.uniqby: 4.7.0 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -31026,6 +32276,8 @@ snapshots: filelist: 1.0.4 picocolors: 1.1.1 + java-properties@1.0.2: {} + jiti@2.7.0: {} jose@6.2.2: {} @@ -31131,6 +32383,10 @@ snapshots: json-buffer@3.0.1: {} + json-parse-better-errors@1.0.2: {} + + json-parse-even-better-errors@2.3.1: {} + json-parse-even-better-errors@3.0.2: {} json-schema-traverse@0.4.1: {} @@ -31145,6 +32401,8 @@ snapshots: json-stringify-safe@5.0.1: {} + json-with-bigint@3.5.10: {} + json5@2.2.3: {} jsonc-eslint-parser@2.4.2: @@ -31409,6 +32667,13 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.2 + load-json-file@4.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + local-pkg@1.1.2: dependencies: mlly: 1.8.0 @@ -31432,8 +32697,12 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.18.1: {} + lodash.camelcase@4.3.0: {} + lodash.capitalize@4.2.1: {} + lodash.debounce@4.0.8: {} lodash.defaults@4.2.0: {} @@ -31470,6 +32739,8 @@ snapshots: lodash.truncate@4.4.2: {} + lodash.uniqby@4.7.0: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -31549,6 +32820,12 @@ snapshots: for-each-property: 0.0.4 inspect-property: 0.0.6 + make-asynchronous@1.1.0: + dependencies: + p-event: 6.0.1 + type-fest: 4.41.0 + web-worker: 1.5.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -31607,6 +32884,19 @@ snapshots: markdown-table@3.0.4: {} + marked-terminal@7.3.0(marked@15.0.12): + dependencies: + ansi-escapes: 7.2.0 + ansi-regex: 6.2.2 + chalk: 5.6.2 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 15.0.12 + node-emoji: 2.2.0 + supports-hyperlinks: 3.2.0 + + marked@15.0.12: {} + marky@1.3.0: {} matcher@3.0.0: @@ -31765,6 +33055,8 @@ snapshots: '@types/dom-mediacapture-transform': 0.1.11 '@types/dom-webcodecs': 0.1.13 + meow@13.2.0: {} + meow@14.1.0: {} merge-descriptors@1.0.3: {} @@ -32012,8 +33304,12 @@ snapshots: mime@3.0.0: {} + mime@4.1.0: {} + mimic-fn@2.1.0: {} + mimic-fn@4.0.0: {} + mimic-function@5.0.1: {} mimic-response@1.0.1: {} @@ -32342,6 +33638,10 @@ snapshots: negotiator@1.0.0: {} + neo-async@2.6.2: {} + + nerf-dart@1.0.0: {} + neverthrow@8.2.0: optionalDependencies: '@rollup/rollup-linux-x64-gnu': 4.60.1 @@ -32369,6 +33669,13 @@ snapshots: node-domexception@1.0.0: {} + node-emoji@2.2.0: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + node-fetch-native@1.6.7: {} node-fetch@2.7.0(encoding@0.1.13): @@ -32442,14 +33749,39 @@ snapshots: dependencies: abbrev: 3.0.1 + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + + normalize-package-data@8.0.0: + dependencies: + hosted-git-info: 9.0.3 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} normalize-url@6.1.0: {} + normalize-url@9.0.1: {} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + npm@11.19.0: {} + nprogress@0.2.0: {} nth-check@2.1.1: @@ -32514,6 +33846,10 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + onetime@7.0.0: dependencies: mimic-function: 5.0.1 @@ -32751,6 +34087,16 @@ snapshots: p-cancelable@2.1.1: {} + p-each-series@3.0.0: {} + + p-event@6.0.1: + dependencies: + p-timeout: 6.1.4 + + p-filter@4.1.0: + dependencies: + p-map: 7.0.4 + p-limit@1.3.0: dependencies: p-try: 1.0.0 @@ -32781,6 +34127,12 @@ snapshots: p-map@7.0.4: {} + p-reduce@2.1.0: {} + + p-reduce@3.0.0: {} + + p-timeout@6.1.4: {} + p-try@1.0.0: {} p-try@2.2.0: {} @@ -32800,12 +34152,28 @@ snapshots: pako@2.1.0: {} + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + parse-gitignore@2.0.0: {} parse-imports-exports@0.2.4: dependencies: parse-statements: 1.0.11 + parse-json@4.0.0: + dependencies: + error-ex: 1.3.4 + json-parse-better-errors: 1.0.2 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parse-json@7.1.1: dependencies: '@babel/code-frame': 7.29.0 @@ -32814,6 +34182,14 @@ snapshots: lines-and-columns: 2.0.4 type-fest: 3.13.1 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + index-to-position: 1.2.0 + type-fest: 4.41.0 + + parse-ms@4.0.0: {} + parse-node-version@1.0.1: {} parse-path@7.1.0: @@ -32827,6 +34203,14 @@ snapshots: '@types/parse-path': 7.1.0 parse-path: 7.1.0 + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -32849,6 +34233,8 @@ snapshots: path-key@3.1.1: {} + path-key@4.0.0: {} + path-parse@1.0.7: {} path-scurry@1.11.1: @@ -32865,6 +34251,8 @@ snapshots: path-to-regexp@8.3.0: {} + path-type@4.0.0: {} + path-type@6.0.0: {} pathe@1.1.2: {} @@ -32928,6 +34316,8 @@ snapshots: pify@2.3.0: {} + pify@3.0.0: {} + pify@4.0.1: optional: true @@ -33035,6 +34425,11 @@ snapshots: pkce-challenge@5.0.1: {} + pkg-conf@2.1.0: + dependencies: + find-up: 2.1.0 + load-json-file: 4.0.0 + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -33176,6 +34571,10 @@ snapshots: pretty-bytes@6.1.1: {} + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + prism-media@1.3.5(opusscript@0.1.1): optionalDependencies: opusscript: 0.1.1 @@ -33401,6 +34800,8 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent-negotiate@1.1.0: {} + prr@1.0.1: optional: true @@ -33514,6 +34915,34 @@ snapshots: transitivePeerDependencies: - supports-color + read-package-up@11.0.0: + dependencies: + find-up-simple: 1.0.1 + read-pkg: 9.0.1 + type-fest: 4.41.0 + + read-package-up@12.0.0: + dependencies: + find-up-simple: 1.0.1 + read-pkg: 10.1.0 + type-fest: 5.8.0 + + read-pkg@10.1.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 8.0.0 + parse-json: 8.3.0 + type-fest: 5.8.0 + unicorn-magic: 0.4.0 + + read-pkg@9.0.1: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 6.0.2 + parse-json: 8.3.0 + type-fest: 4.41.0 + unicorn-magic: 0.1.0 + readable-stream@1.0.34: dependencies: core-util-is: 1.0.3 @@ -33761,6 +35190,10 @@ snapshots: resolve-alpn@1.2.1: {} + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} resolve.exports@2.0.3: {} @@ -34017,8 +35450,45 @@ snapshots: extend-shallow: 2.0.1 kind-of: 6.0.3 + semantic-release@25.0.9(typescript@5.9.3): + dependencies: + '@semantic-release/commit-analyzer': 13.0.1(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/error': 4.0.0 + '@semantic-release/github': 12.0.9(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/npm': 13.1.5(semantic-release@25.0.9(typescript@5.9.3)) + '@semantic-release/release-notes-generator': 14.1.1(semantic-release@25.0.9(typescript@5.9.3)) + aggregate-error: 5.0.0 + cosmiconfig: 9.0.2(typescript@5.9.3) + debug: 4.4.3(supports-color@10.2.2) + env-ci: 11.2.0 + execa: 9.6.1 + figures: 6.1.0 + find-versions: 6.0.0 + get-stream: 6.0.1 + git-log-parser: 1.2.1 + hook-std: 4.0.0 + hosted-git-info: 9.0.3 + import-from-esm: 2.0.0 + lodash-es: 4.18.1 + marked: 15.0.12 + marked-terminal: 7.3.0(marked@15.0.12) + micromatch: 4.0.8 + p-each-series: 3.0.0 + p-reduce: 3.0.0 + read-package-up: 12.0.0 + resolve-from: 5.0.0 + semver: 7.7.4 + signale: 1.4.0 + yargs: 18.1.0 + transitivePeerDependencies: + - kerberos + - supports-color + - typescript + semver-compare@1.0.0: {} + semver-regex@4.0.5: {} + semver@5.7.2: {} semver@6.3.1: {} @@ -34180,6 +35650,12 @@ snapshots: signal-exit@4.1.0: {} + signale@1.4.0: + dependencies: + chalk: 2.4.2 + figures: 2.0.0 + pkg-conf: 2.1.0 + simple-concat@1.0.1: {} simple-get@4.0.1: @@ -34216,6 +35692,10 @@ snapshots: sisteransi@1.0.5: {} + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + slash@5.1.0: {} slice-ansi@3.0.0: @@ -34326,13 +35806,25 @@ snapshots: space-separated-tokens@2.0.2: {} + spawn-error-forwarder@1.0.0: {} + spawn-sync@1.0.15: dependencies: concat-stream: 1.6.2 os-shim: 0.1.3 + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.22 + spdx-exceptions@2.5.0: {} + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + spdx-expression-parse@4.0.0: dependencies: spdx-exceptions: 2.5.0 @@ -34346,6 +35838,10 @@ snapshots: split-skip@0.0.2: {} + split2@1.0.0: + dependencies: + through2: 2.0.5 + split2@4.2.0: {} split@1.0.1: @@ -34426,6 +35922,11 @@ snapshots: store2@2.14.4: {} + stream-combiner2@1.1.1: + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + streamx@2.28.0: dependencies: events-universal: 1.0.1 @@ -34453,6 +35954,11 @@ snapshots: get-east-asian-width: 1.5.0 strip-ansi: 7.1.2 + string-width@8.2.2: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.1.2 + string_decoder@0.10.31: {} string_decoder@1.1.1: @@ -34493,12 +35999,18 @@ snapshots: strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} + strip-bom@5.0.0: {} strip-comments@2.0.1: {} strip-final-newline@2.0.0: {} + strip-final-newline@3.0.0: {} + + strip-final-newline@4.0.0: {} + strip-indent@4.1.1: {} strip-json-comments@2.0.1: {} @@ -34555,16 +36067,31 @@ snapshots: transitivePeerDependencies: - supports-color + super-regex@1.1.0: + dependencies: + function-timeout: 1.0.2 + make-asynchronous: 1.1.0 + time-span: 5.1.0 + superjson@2.2.6: dependencies: copy-anything: 4.0.5 supports-color@10.2.2: {} + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} svix@1.90.0: @@ -34603,6 +36130,8 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + tagged-tag@1.0.0: {} + tapable@2.3.0: {} tar-fs@2.1.4: @@ -34686,6 +36215,8 @@ snapshots: temp-dir@2.0.0: {} + temp-dir@3.0.0: {} + temp-file@3.4.0: dependencies: async-exit-hook: 2.0.1 @@ -34703,6 +36234,13 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 + tempy@3.2.0: + dependencies: + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 + terser@5.46.1: dependencies: '@jridgewell/source-map': 0.3.11 @@ -34767,12 +36305,21 @@ snapshots: readable-stream: 1.0.34 xtend: 4.0.2 + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + through2@4.0.2: dependencies: readable-stream: 3.6.2 through@2.3.8: {} + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + timm@1.7.1: {} tiny-async-pool@1.3.0: @@ -34847,6 +36394,8 @@ snapshots: dependencies: punycode: 2.3.1 + traverse@0.6.8: {} + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -34928,6 +36477,8 @@ snapshots: dependencies: safe-buffer: '@nolyfill/safe-buffer@1.0.44' + tunnel@0.0.6: {} + turbo@2.9.6: optionalDependencies: '@turbo/darwin-64': 2.9.6 @@ -34947,10 +36498,18 @@ snapshots: type-fest@0.16.0: {} + type-fest@1.4.0: {} + + type-fest@2.19.0: {} + type-fest@3.13.1: {} type-fest@4.41.0: {} + type-fest@5.8.0: + dependencies: + tagged-tag: 1.0.0 + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -35005,6 +36564,9 @@ snapshots: ufo@1.6.3: {} + uglify-js@3.19.3: + optional: true + uhyphen@0.2.0: {} uint4@0.1.2: {} @@ -35054,6 +36616,8 @@ snapshots: unicode-canonical-property-names-ecmascript@2.0.1: {} + unicode-emoji-modifier-base@1.0.0: {} + unicode-match-property-ecmascript@2.0.0: dependencies: unicode-canonical-property-names-ecmascript: 2.0.1 @@ -35063,8 +36627,12 @@ snapshots: unicode-property-aliases-ecmascript@2.2.0: {} + unicorn-magic@0.1.0: {} + unicorn-magic@0.3.0: {} + unicorn-magic@0.4.0: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -35104,6 +36672,10 @@ snapshots: dependencies: crypto-random-string: 2.0.0 + unique-string@3.0.0: + dependencies: + crypto-random-string: 4.0.0 + unist-builder@4.0.0: dependencies: '@types/unist': 3.0.3 @@ -35147,6 +36719,8 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 + universal-user-agent@7.0.3: {} + universalify@0.1.2: {} universalify@2.0.1: {} @@ -35156,6 +36730,11 @@ snapshots: '@unocss/preset-mini': 66.6.8 unocss: 66.6.8(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + unocss-preset-scrollbar@4.0.0(unocss@66.6.8(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))): + dependencies: + '@unocss/preset-mini': 66.6.8 + unocss: 66.6.8(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + unocss@66.6.8(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@unocss/cli': 66.6.8 @@ -35222,14 +36801,6 @@ snapshots: unplugin: 2.3.11 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - optionalDependencies: - esbuild: 0.27.2 - rolldown: 1.0.0-rc.16 - rollup: 4.60.1 - unplugin: 2.3.11 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): optionalDependencies: esbuild: 0.27.2 @@ -35251,19 +36822,6 @@ snapshots: transitivePeerDependencies: - supports-color - unplugin-info@1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - ci-info: 4.4.0 - git-url-parse: 16.1.0 - simple-git: 3.36.0 - unplugin: 2.3.11 - optionalDependencies: - esbuild: 0.27.2 - rollup: 4.60.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color - unplugin-info@1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: ci-info: 4.4.0 @@ -35357,17 +36915,6 @@ snapshots: rollup: 2.80.0 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-yaml@4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.60.1) - unplugin: 3.0.0 - yaml: 2.8.3 - optionalDependencies: - esbuild: 0.27.2 - rolldown: 1.0.0-rc.16 - rollup: 4.60.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - unplugin-yaml@4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.1) @@ -35456,6 +37003,8 @@ snapshots: dependencies: punycode: 2.3.1 + url-join@5.0.0: {} + url@0.11.4: dependencies: punycode: 1.4.1 @@ -35495,6 +37044,11 @@ snapshots: optionalDependencies: typescript: 5.9.3 + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + validate-npm-package-name@5.0.1: {} vary@1.1.2: {} @@ -35606,22 +37160,12 @@ snapshots: - rollup - supports-color - vite-dev-rpc@1.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - birpc: 2.9.0 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-hot-client: 2.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-dev-rpc@1.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: birpc: 2.9.0 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-hot-client: 2.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-hot-client@2.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-hot-client@2.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) @@ -35667,21 +37211,6 @@ snapshots: - tsx - yaml - vite-plugin-inspect@11.3.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - ansis: 4.2.0 - debug: 4.4.3(supports-color@10.2.2) - error-stack-parser-es: 1.0.5 - ohash: 2.0.11 - open: 10.2.0 - perfect-debounce: 2.1.0 - sirv: 3.0.2 - unplugin-utils: 0.3.1 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-dev-rpc: 1.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - transitivePeerDependencies: - - supports-color - vite-plugin-inspect@11.3.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: ansis: 4.2.0 @@ -35713,13 +37242,6 @@ snapshots: - typescript - ws - vite-plugin-mkcert@2.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - supports-color: 10.2.2 - undici: 8.1.0 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-mkcert@2.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -35738,20 +37260,6 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-devtools@8.1.1(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)): - dependencies: - '@vue/devtools-core': 8.1.1(vue@3.5.32(typescript@5.9.3)) - '@vue/devtools-kit': 8.1.1 - '@vue/devtools-shared': 8.1.1 - sirv: 3.0.2 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-inspect: 11.3.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-plugin-vue-inspector: 5.3.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - transitivePeerDependencies: - - '@nuxt/kit' - - supports-color - - vue - vite-plugin-vue-devtools@8.1.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.1.1(vue@3.5.32(typescript@5.9.3)) @@ -35766,21 +37274,6 @@ snapshots: - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.29.0) - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) - '@vue/compiler-dom': 3.5.32 - kolorist: 1.8.0 - magic-string: 0.30.21 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color - vite-plugin-vue-inspector@5.3.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.29.0 @@ -35796,16 +37289,6 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-vue-layouts@0.11.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)): - dependencies: - debug: 4.4.3(supports-color@10.2.2) - fast-glob: 3.3.3 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vue: 3.5.32(typescript@5.9.3) - vue-router: 5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - transitivePeerDependencies: - - supports-color - vite-plugin-vue-layouts@0.11.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)): dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -36090,54 +37573,6 @@ snapshots: - vue-tsc - webpack - vue-macros@3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)): - dependencies: - '@vue-macros/better-define': 3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/boolean-prop': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/chain-call': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/common': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/config': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-emit': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-models': 3.1.2(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-prop': 3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-props': 3.1.2(@vue-macros/reactivity-transform@3.1.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-props-refs': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-render': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-slots': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/define-stylex': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/devtools': 3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vue-macros/export-expose': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/export-props': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/export-render': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/hoist-static': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/jsx-directive': 3.1.2(typescript@5.9.3) - '@vue-macros/named-template': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/reactivity-transform': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/script-lang': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/setup-block': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/setup-component': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/setup-sfc': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/short-bind': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/short-emits': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/short-vmodel': 3.1.2(vue@3.5.32(typescript@5.9.3)) - '@vue-macros/volar': 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) - unplugin: 2.3.11 - unplugin-combine: 2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - unplugin-vue-define-options: 3.1.2(vue@3.5.32(typescript@5.9.3)) - vue: 3.5.32(typescript@5.9.3) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - '@rspack/core' - - '@vueuse/core' - - esbuild - - rolldown - - rollup - - typescript - - vite - - vue-tsc - - webpack - vue-macros@3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.7.0)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue-macros/better-define': 3.1.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(vue@3.5.32(typescript@5.9.3)) @@ -36295,8 +37730,7 @@ snapshots: web-vitals@4.2.4: {} - web-worker@1.5.0: - optional: true + web-worker@1.5.0: {} webidl-conversions@3.0.1: {} @@ -36387,6 +37821,8 @@ snapshots: word-wrap@1.2.5: {} + wordwrap@1.0.0: {} + wordwrapjs@3.0.0: dependencies: reduce-flatten: 1.0.1 @@ -36682,12 +38118,26 @@ snapshots: yaml@2.8.3: {} + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs-parser@7.0.0: dependencies: camelcase: 4.1.0 + yargs@16.2.2: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -36698,6 +38148,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.1.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 8.2.2 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yauzl@2.10.0: dependencies: buffer-crc32: 0.2.13 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 13836400d..3051c9c8e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -115,7 +115,7 @@ catalog: '@mediapipe/tasks-vision': ^0.10.34 '@modelcontextprotocol/sdk': ^1.29.0 '@moeru/eslint-config': 0.1.0-beta.19 - '@moeru/eventa': 1.0.0-beta.13 + '@moeru/eventa': 1.0.0-beta.15 '@moeru/std': 0.1.0-beta.17 '@moeru/three-mmd': 0.1.0-beta.7 '@moeru/three-mmd-physics-ammo': 0.1.0-beta.7 diff --git a/vitest.config.ts b/vitest.config.ts index 0547c9922..112cd5a37 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -19,6 +19,7 @@ export default defineConfig({ 'packages/server-runtime', 'packages/server-sdk', 'packages/stage-shared', + 'packages/vitest-plugin-fakemic', ], }, })