From 0bcb5cea6eb469ddb25a07e55b51d3c61923a2d0 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:21:32 +0300 Subject: [PATCH 01/13] core: add A-law stream data transformation helpers Add A-law encode/decode utilities and generic transformData helpers for converting between core sample formats and stream formats. Also export stream data type metadata and add tests for A-law compression and transformData conversions --- packages/core/src/common/defines.ts | 3 +- packages/core/src/common/index.ts | 4 +- packages/core/src/common/types.ts | 24 ++++ .../src/tests/transform/compressors.test.ts | 63 +++++++++ .../src/tests/transform/transformdata.test.ts | 58 ++++++++ packages/core/src/transform/compressors.ts | 58 ++++++++ packages/core/src/transform/index.ts | 11 +- packages/core/src/transform/transformdata.ts | 127 ++++++++++++++++++ 8 files changed, 344 insertions(+), 4 deletions(-) create mode 100644 packages/core/src/tests/transform/compressors.test.ts create mode 100644 packages/core/src/tests/transform/transformdata.test.ts create mode 100644 packages/core/src/transform/compressors.ts create mode 100644 packages/core/src/transform/transformdata.ts diff --git a/packages/core/src/common/defines.ts b/packages/core/src/common/defines.ts index bd68f5f..9dea775 100644 --- a/packages/core/src/common/defines.ts +++ b/packages/core/src/common/defines.ts @@ -3,4 +3,5 @@ export const CHUNK_SIZE = 8192; export const FLOAT_SIZE = Float32Array.BYTES_PER_ELEMENT; export const COMPLEX_FLOAT_SIZE = 2 * FLOAT_SIZE; export const INT16_SIZE = Int16Array.BYTES_PER_ELEMENT; -export const COMPLEX_INT16_SIZE = 2 * INT16_SIZE; \ No newline at end of file +export const COMPLEX_INT16_SIZE = 2 * INT16_SIZE; +export const INT8_SIZE = Int8Array.BYTES_PER_ELEMENT; \ No newline at end of file diff --git a/packages/core/src/common/index.ts b/packages/core/src/common/index.ts index 4bad98d..645e221 100644 --- a/packages/core/src/common/index.ts +++ b/packages/core/src/common/index.ts @@ -1,5 +1,5 @@ // Re-exporting all common types and definitions -export { DataType } from './types'; +export { DataType, DataTypeNames, StreamDataType, StreamDataTypeNames } from './types'; export { - CHUNK_SIZE, FLOAT_SIZE, COMPLEX_FLOAT_SIZE, INT16_SIZE, COMPLEX_INT16_SIZE + CHUNK_SIZE, FLOAT_SIZE, COMPLEX_FLOAT_SIZE, INT16_SIZE, COMPLEX_INT16_SIZE, INT8_SIZE } from './defines'; \ No newline at end of file diff --git a/packages/core/src/common/types.ts b/packages/core/src/common/types.ts index 710bf37..b478350 100644 --- a/packages/core/src/common/types.ts +++ b/packages/core/src/common/types.ts @@ -5,3 +5,27 @@ export enum DataType { i16 = 'i16', i8 = 'i8', } + +export const DataTypeNames: Record = { + [DataType.cf32]: 'Complex Float 32', + [DataType.ci16]: 'Complex Int 16', + [DataType.f32]: 'Float 32', + [DataType.i16]: 'Int 16', + [DataType.i8]: 'Int 8', +} + +export enum StreamDataType { + cf32 = 'cf32', + ci16 = 'ci16', + f32 = 'f32', + i16 = 'i16', + alaw = 'alaw', +} + +export const StreamDataTypeNames: Record = { + [StreamDataType.cf32]: 'Complex Float 32', + [StreamDataType.ci16]: 'Complex Int 16', + [StreamDataType.f32]: 'Float 32', + [StreamDataType.i16]: 'Int 16', + [StreamDataType.alaw]: 'A-Law', +} diff --git a/packages/core/src/tests/transform/compressors.test.ts b/packages/core/src/tests/transform/compressors.test.ts new file mode 100644 index 0000000..682221a --- /dev/null +++ b/packages/core/src/tests/transform/compressors.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from 'vitest'; +import { + alawEncodeBuffer, + alawDecodeBuffer, + alawEncodeBufferF32, + alawDecodeBufferF32, + alawEncode, + alawDecode, +} from '@/transform/compressors'; + +describe('A-law compressors', () => { + test('Int16Array roundtrip is exact', () => { + const input = Int16Array.from([0, 1, 15, 31, 127, 1023, -1, -32768, 12345, -12345]); + const encoded = alawEncodeBuffer(input); + expect(encoded).toBeInstanceOf(Uint8Array); + const decoded = alawDecodeBuffer(encoded); + expect(decoded.length).toBe(input.length); + for (let i = 0; i < input.length; ++i) { + const expected = alawDecode(alawEncode(input[i]!)); + expect(decoded[i]).toBe(expected); + } + }); + + test('Float32Array roundtrip is approximately equal', () => { + const input = Float32Array.from([0, 0.1, -0.5, 0.99, -0.99, 0.1234, -0.2345]); + const encoded = alawEncodeBufferF32(input); + expect(encoded).toBeInstanceOf(Uint8Array); + const decoded = alawDecodeBufferF32(encoded); + expect(decoded.length).toBe(input.length); + for (let i = 0; i < input.length; ++i) { + const expected = alawDecode(alawEncode(input[i]! * 0x7000)) / 0x8000; + expect(decoded[i]).toBeCloseTo(expected, 6); + } + }); + + test('A-law matches encode/decode', () => { + const code_test_data: Array<{ input: number, output: number, output2: number }> = [ + { input: 0b0000000000000000, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000000001, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000000011, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000000111, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000001111, output: 0b00000000, output2: 0b0000000000000000 }, + { input: 0b0000000000011111, output: 0b00000001, output2: 0b0000000000010000 }, + { input: 0b0000000000111111, output: 0b00000011, output2: 0b0000000000110000 }, + { input: 0b0000000001111111, output: 0b00000111, output2: 0b0000000001110000 }, + { input: 0b0000000011111111, output: 0b00001111, output2: 0b0000000011110000 }, + { input: 0b0000000111111111, output: 0b00011111, output2: 0b0000000111110000 }, + { input: 0b0000001111111111, output: 0b00101111, output2: 0b0000001111100000 }, + { input: 0b0000011111111111, output: 0b00111111, output2: 0b0000011111000000 }, + { input: 0b0000111111111111, output: 0b01001111, output2: 0b0000111110000000 }, + { input: 0b0001111111111111, output: 0b01011111, output2: 0b0001111100000000 }, + { input: 0b0011111111111111, output: 0b01101111, output2: 0b0011111000000000 }, + { input: 0b0111111111111111, output: 0b01111111, output2: 0b0111110000000000 }, + ]; + + code_test_data.forEach(v => { + const o = alawEncode(v.input); + expect(o).toBe(v.output); + const o2 = alawDecode(o); + expect(o2).toBe(v.output2); + }); + }); +}); diff --git a/packages/core/src/tests/transform/transformdata.test.ts b/packages/core/src/tests/transform/transformdata.test.ts new file mode 100644 index 0000000..b098b44 --- /dev/null +++ b/packages/core/src/tests/transform/transformdata.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, test } from 'vitest'; +import { + transformData, + getSampleByteLength, + getElementsPerSample, + getSamplesCount, + getElementsCount, + getDataView, + createTypedArray, +} from '@/transform/transformdata'; +import { DataType, StreamDataType } from '@/common/types'; +import { alawEncode, alawDecode } from '@/transform/compressors'; + +describe('transformdata utilities', () => { + test('createTypedArray and element/sample helpers', () => { + const arr = createTypedArray(DataType.cf32, 4); + expect(arr).toBeInstanceOf(Float32Array); + expect(arr.length).toBe(4 * getElementsPerSample(DataType.cf32)); + + const byteLen = getSampleByteLength(DataType.f32) * 10; + expect(getSamplesCount(DataType.f32, byteLen)).toBe(10); + expect(getElementsCount(DataType.f32, byteLen)).toBe(Math.floor(byteLen / getElementsPerSample(DataType.f32) / getSampleByteLength(DataType.f32) * getElementsPerSample(DataType.f32)) || 10); + }); + + test('getDataView returns correct typed views and same-type copy in transformData', () => { + const inArr = new Float32Array([1.5, -2.5, 3.25]); + const outArr = new Float32Array(inArr.length); + transformData( + { type: DataType.f32, buffer: inArr.buffer, offset: 0, length: inArr.length }, + { type: DataType.f32, buffer: outArr.buffer, offset: 0, length: outArr.length } + ); + expect(Array.from(outArr)).toEqual(Array.from(inArr)); + + const view = getDataView({ type: DataType.f32, buffer: inArr.buffer, offset: 0, length: inArr.length }); + expect(view).toBeInstanceOf(Float32Array); + }); + + test('f32 -> alaw -> f32 roundtrip (quantized) via transformData', () => { + const input = new Float32Array([0, 0.1, -0.2, 0.9, -0.9]); + const alawBuf = new Uint8Array(input.length); + + transformData( + { type: DataType.f32, buffer: input.buffer, offset: 0, length: input.length }, + { type: StreamDataType.alaw, buffer: alawBuf.buffer, offset: 0, length: alawBuf.length } + ); + + const out = new Float32Array(input.length); + transformData( + { type: StreamDataType.alaw, buffer: alawBuf.buffer, offset: 0, length: alawBuf.length }, + { type: DataType.f32, buffer: out.buffer, offset: 0, length: out.length } + ); + + for (let i = 0; i < input.length; ++i) { + const expected = alawDecode(alawEncode(input[i]! * 0x7000)) / 0x8000; + expect(out[i]).toBeCloseTo(expected, 6); + } + }); +}); diff --git a/packages/core/src/transform/compressors.ts b/packages/core/src/transform/compressors.ts new file mode 100644 index 0000000..4709b5f --- /dev/null +++ b/packages/core/src/transform/compressors.ts @@ -0,0 +1,58 @@ +export function alawEncode(input: number): number { + let mask = 0x8000; + const sign = (input & mask) >> 8; + if (sign) input = ~input; + let shift = 0b111; + for (; shift > 0; --shift) { + if (input & mask) break; + mask >>= 1; + } + input >>= 4 + shift; + const output = sign + (shift << 4) + input; + + return output; +} + +export function alawDecode(input: number): number { + const sign = input & 0x80; + const shift = (input >> 4) & 0x7; + let output = ((shift ? 0x10 : 0) | (input & 0x0f)) << (shift + (shift ? 3 : 4)); + if (sign) output = ~output; + return output; +} + +export function alawEncodeBuffer(input: Int16Array, outbuf?: Uint8Array): Uint8Array { + const output = outbuf ? outbuf : new Uint8Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawEncode(input[i]!); + } + return output; +} + +export function alawDecodeBuffer(input: Uint8Array, outbuf?: Int16Array): Int16Array { + const output = outbuf ? outbuf : new Int16Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawDecode(input[i]!); + } + return output; +} + +export function alawEncodeBufferF32(input: Float32Array, outbuf?: Uint8Array): Uint8Array { + const output = outbuf ? outbuf : new Uint8Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawEncode(input[i]! * 0x7000); + } + return output; +} + +export function alawDecodeBufferF32(input: Uint8Array, outbuf?: Float32Array): Float32Array { + const output = outbuf ? outbuf : new Float32Array(input.length); + const len = Math.min(input.length, output.length); + for (let i = 0; i < len; ++i) { + output[i] = alawDecode(input[i]!) / 0x8000; + } + return output; +} diff --git a/packages/core/src/transform/index.ts b/packages/core/src/transform/index.ts index 826515c..ff95c36 100644 --- a/packages/core/src/transform/index.ts +++ b/packages/core/src/transform/index.ts @@ -1,3 +1,12 @@ // Re-exporting converter functions -export { bufferF32ToI16, bufferI16ToF32, clipF32Buffer } from './converters'; export { base64ToUint8Array, uint8ArrayToBase64 } from './base64'; +export { + alawEncodeBuffer, alawDecodeBuffer, alawEncodeBufferF32, alawDecodeBufferF32, + alawEncode, alawDecode, +} from './compressors'; +export { bufferF32ToI16, bufferI16ToF32, clipF32Buffer } from './converters'; +export { + transformData, getSampleByteLength, getElementByteLength, getElementsPerSample, + getSamplesCount, getElementsCount, getDataView, createTypedArray +} from './transformdata'; +export type { TransformDataType, TransformArrayType, BufferParams } from './transformdata'; diff --git a/packages/core/src/transform/transformdata.ts b/packages/core/src/transform/transformdata.ts new file mode 100644 index 0000000..d1d3bb5 --- /dev/null +++ b/packages/core/src/transform/transformdata.ts @@ -0,0 +1,127 @@ +import { DataType, StreamDataType } from "@/common/types"; +import { bufferF32ToI16, bufferI16ToF32 } from "./converters"; +import { COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE, FLOAT_SIZE, INT16_SIZE, INT8_SIZE } from "@/common/defines"; +import { alawDecodeBuffer, alawDecodeBufferF32, alawEncodeBuffer, alawEncodeBufferF32 } from "@/transform/compressors"; + +export type TransformDataType = DataType | StreamDataType; +export type TransformArrayType = Float32Array | Int16Array | Int8Array | Uint8Array; + +export interface BufferParams { + type: TransformDataType, // DataType or StreamDataType + buffer: ArrayBufferLike, // ArrayBuffer or SharedArrayBuffer + offset?: number, // byte offset + length?: number, // samples count +} + +export function transformData(inBuffer: BufferParams, outBuffer: BufferParams) { + // console.log('transformData: inBuffer =', inBuffer, ', outBuffer =', outBuffer); + const inBufView = getDataView(inBuffer); + const outBufView = getDataView(outBuffer); + if (inBuffer.type === outBuffer.type) { + outBufView.set(inBufView); + } else if ((inBuffer.type === DataType.cf32 || inBuffer.type === DataType.f32) && (outBuffer.type === DataType.ci16 || outBuffer.type === DataType.i16)) { + bufferF32ToI16(inBufView as Float32Array, outBufView as Int16Array); + } else if ((inBuffer.type === DataType.ci16 || inBuffer.type === DataType.i16) && (outBuffer.type === DataType.cf32 || outBuffer.type === DataType.f32)) { + bufferI16ToF32(inBufView as Int16Array, outBufView as Float32Array); + } else if ((inBuffer.type === DataType.cf32 || inBuffer.type === DataType.f32) && outBuffer.type === StreamDataType.alaw) { + alawEncodeBufferF32(inBufView as Float32Array, outBufView as Uint8Array); + } else if (inBuffer.type === StreamDataType.alaw && (outBuffer.type === DataType.cf32 || outBuffer.type === DataType.f32)) { + alawDecodeBufferF32(inBufView as Uint8Array, outBufView as Float32Array); + } else if ((inBuffer.type === DataType.ci16 || inBuffer.type === DataType.i16) && outBuffer.type === StreamDataType.alaw) { + alawEncodeBuffer(inBufView as Int16Array, outBufView as Uint8Array); + } else if (inBuffer.type === StreamDataType.alaw && (outBuffer.type === DataType.ci16 || outBuffer.type === DataType.i16)) { + alawDecodeBuffer(inBufView as Uint8Array, outBufView as Int16Array); + } else { + throw new Error(`transformData: unsupported data type combination: input type ${inBuffer.type}, output type ${outBuffer.type}`); + } +} + +export function getSampleByteLength(datatype: TransformDataType): number { + switch (datatype) { + case DataType.cf32: + return COMPLEX_FLOAT_SIZE; + case DataType.ci16: + return COMPLEX_INT16_SIZE; + case DataType.f32: + return FLOAT_SIZE; + case DataType.i16: + return INT16_SIZE; + case DataType.i8: + return INT8_SIZE; + case StreamDataType.alaw: + return INT8_SIZE; + } + throw new Error(`getSampleByteLength: unsupported data type ${datatype}`) +} + +export function getElementByteLength(datatype: TransformDataType): number { + switch (datatype) { + case DataType.cf32: + case DataType.f32: + return FLOAT_SIZE; + case DataType.ci16: + case DataType.i16: + return INT16_SIZE; + case DataType.i8: + case StreamDataType.alaw: + return INT8_SIZE; + } + throw new Error(`getSampleByteLength: unsupported data type ${datatype}`) +} + +export function getElementsPerSample(datatype: TransformDataType): number { + switch (datatype) { + case DataType.cf32: + case DataType.ci16: + return 2; + case DataType.f32: + case DataType.i16: + case DataType.i8: + case StreamDataType.alaw: + return 1; + } + throw new Error(`getElementsPerSample: unsupported data type ${datatype}`) +} + +export function getSamplesCount(datatype: TransformDataType, byteLength: number): number { + return Math.floor(byteLength / getSampleByteLength(datatype)); +} + +export function getElementsCount(datatype: TransformDataType, byteLength: number): number { + return Math.floor(byteLength / getElementByteLength(datatype)); +} + +export function getDataView(bufferParams: BufferParams): TransformArrayType { + // console.log('getDataView', bufferParams) + switch (bufferParams.type) { + case DataType.cf32: + return new Float32Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.f32: + return new Float32Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.ci16: + return new Int16Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.i16: + return new Int16Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case DataType.i8: + return new Int8Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + case StreamDataType.alaw: + return new Uint8Array(bufferParams.buffer, bufferParams.offset, bufferParams.length); + } + throw new Error(`getDataView: unsupported data type ${bufferParams.type}`) +} + +export function createTypedArray(datatype: TransformDataType, samples: number): TransformArrayType { + switch (datatype) { + case DataType.cf32: + case DataType.f32: + return new Float32Array(samples * getElementsPerSample(datatype)); + case DataType.ci16: + case DataType.i16: + return new Int16Array(samples * getElementsPerSample(datatype)); + case DataType.i8: + return new Int8Array(samples * getElementsPerSample(datatype)); + case StreamDataType.alaw: + return new Uint8Array(samples * getElementsPerSample(datatype)); + } + throw new Error(`createTypedArray: unsupported data type ${datatype}`) +} \ No newline at end of file From 060bd8785cb1fad8d944c9802b4b21a653259dbc Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:27:02 +0300 Subject: [PATCH 02/13] core: add allocator and data slicer utilities Add an Emscripten heap allocator wrapper for creating typed array views over WASM memory, and introduce DataSlicer for buffering typed sample data. Also extend boolean conversion helpers, export new utilities, and add unit tests for allocator, DataSlicer, and conversion behavior. --- .../core/src/tests/utils/allocator.test.ts | 69 ++++++++ .../core/src/tests/utils/convUtils.test.ts | 71 +++++---- .../core/src/tests/utils/dataSlicer.test.ts | 23 +++ packages/core/src/utils/allocator.ts | 63 ++++++++ packages/core/src/utils/convUtils.ts | 50 +++--- packages/core/src/utils/dataSlicer.ts | 148 ++++++++++++++++++ packages/core/src/utils/index.ts | 6 +- packages/core/src/utils/stringUtils.ts | 9 +- 8 files changed, 384 insertions(+), 55 deletions(-) create mode 100644 packages/core/src/tests/utils/allocator.test.ts create mode 100644 packages/core/src/tests/utils/dataSlicer.test.ts create mode 100644 packages/core/src/utils/allocator.ts create mode 100644 packages/core/src/utils/dataSlicer.ts diff --git a/packages/core/src/tests/utils/allocator.test.ts b/packages/core/src/tests/utils/allocator.test.ts new file mode 100644 index 0000000..df6d6e7 --- /dev/null +++ b/packages/core/src/tests/utils/allocator.test.ts @@ -0,0 +1,69 @@ +import { describe, it, expect, vi } from 'vitest'; +import { Allocator } from '@/utils/allocator'; + +function createMockModule() { + let nextPtr = 1000; // start of free memory + const buf = new ArrayBuffer(4096); + const mod = { + HEAPU8: new Uint8Array(buf), + HEAP8: new Int8Array(buf), + HEAPU16: new Uint16Array(buf), + HEAP16: new Int16Array(buf), + HEAPU32: new Uint32Array(buf), + HEAP32: new Int32Array(buf), + HEAPF32: new Float32Array(buf), + _malloc: vi.fn((size: number) => { + const p = nextPtr; + nextPtr += size; + return p; + }), + _free: vi.fn((p: number) => { + // noop + }) + } as unknown as EmscriptenModule; + return mod; +} + +describe('Allocator', () => { + const cases: Array<[string, any, number]> = [ + ['allocUint8Buffer', Uint8Array, Uint8Array.BYTES_PER_ELEMENT], + ['allocInt8Buffer', Int8Array, Int8Array.BYTES_PER_ELEMENT], + ['allocUint16Buffer', Uint16Array, Uint16Array.BYTES_PER_ELEMENT], + ['allocInt16Buffer', Int16Array, Int16Array.BYTES_PER_ELEMENT], + ['allocUint32Buffer', Uint32Array, Uint32Array.BYTES_PER_ELEMENT], + ['allocInt32Buffer', Int32Array, Int32Array.BYTES_PER_ELEMENT], + ['allocFloat32Buffer', Float32Array, Float32Array.BYTES_PER_ELEMENT] + ]; + + for (const [method, ctor, bytes] of cases) { + it(`${method} returns correct typed array view`, () => { + const mod = createMockModule(); + const a = new Allocator(mod); + const size = 64; // bytes + // call specific allocator method + // @ts-ignore - dynamic call of method + const view = (a as any)[method](size); + + expect(view).toBeInstanceOf(ctor); + expect(view.length).toBe(size / bytes); + expect(view.buffer).toBe(mod.HEAPU8.buffer); + // ensure malloc was called + expect(mod._malloc).toHaveBeenCalled(); + }); + } + + it('alloc and dealloc call malloc/free with same pointer', () => { + const mod = createMockModule(); + const a = new Allocator(mod); + const size = 32; + const ptr = a.alloc(size); + expect(mod._malloc).toHaveBeenCalledWith(size); + a.dealloc(); + expect(mod._free).toHaveBeenCalledWith(ptr); + }); + + it('alloc throws if module is undefined', () => { + const a = new Allocator(undefined as any); + expect(() => a.alloc(8)).toThrow(); + }); +}); diff --git a/packages/core/src/tests/utils/convUtils.test.ts b/packages/core/src/tests/utils/convUtils.test.ts index 2e31835..8064e3d 100644 --- a/packages/core/src/tests/utils/convUtils.test.ts +++ b/packages/core/src/tests/utils/convUtils.test.ts @@ -1,45 +1,54 @@ -import { describe, it, expect, vi, beforeEach } from "vitest"; -import { stringToBoolean } from "@/utils/convUtils"; - -describe("stringToBoolean", () => { - beforeEach(() => { - vi.restoreAllMocks(); - }); +import { describe, it, expect } from "vitest"; +import { stringToBoolean, toBoolean } from "@/utils/convUtils"; +describe("toBoolean", () => { it("returns true for truthy textual values (case-insensitive, trimmed)", () => { - expect(stringToBoolean("true")).toBe(true); - expect(stringToBoolean(" TrUe ")).toBe(true); - expect(stringToBoolean("yes")).toBe(true); - expect(stringToBoolean(" YES")).toBe(true); - expect(stringToBoolean("1")).toBe(true); + expect(toBoolean("true")).toBe(true); + expect(toBoolean(" TrUe ")).toBe(true); + expect(toBoolean("yes")).toBe(true); + expect(toBoolean(" YES")).toBe(true); + expect(toBoolean("1")).toBe(true); + expect(toBoolean("on")).toBe(true); }); it("returns false for explicit falsey textual values", () => { - expect(stringToBoolean("false")).toBe(false); - expect(stringToBoolean("No")).toBe(false); - expect(stringToBoolean("0")).toBe(false); - expect(stringToBoolean("")).toBe(false); + expect(toBoolean("false")).toBe(false); + expect(toBoolean("No")).toBe(false); + expect(toBoolean("0")).toBe(false); + expect(toBoolean("off")).toBe(false); + expect(toBoolean("")).toBe(false); + }); + + it("returns false for null-like values", () => { + expect(toBoolean("null")).toBe(false); + expect(toBoolean("undefined")).toBe(false); + expect(toBoolean(null)).toBe(false); + expect(toBoolean(undefined)).toBe(false); }); - it("parses JSON for other strings (e.g. \"null\" -> null)", () => { - expect(stringToBoolean("null")).toBe(false); + it("passes boolean values through", () => { + expect(toBoolean(true)).toBe(true); + expect(toBoolean(false)).toBe(false); }); - it("returns false and logs an error for invalid JSON strings", () => { - const spy = vi.spyOn(console, "error").mockImplementation(() => { }); - expect(stringToBoolean("not a json")).toBe(false); - expect(spy).toHaveBeenCalled(); - spy.mockRestore(); + it("converts number values using JavaScript boolean semantics", () => { + expect(toBoolean(1)).toBe(true); + expect(toBoolean(-1)).toBe(true); + expect(toBoolean(0)).toBe(false); + expect(toBoolean(NaN)).toBe(false); }); - it("handles actual null and undefined inputs by returning false and logging an error", () => { - const spy = vi.spyOn(console, "error").mockImplementation(() => { }); + it("returns false for unsupported values", () => { + expect(toBoolean({ value: "true" })).toBe(false); + }); - // call with values that violate the declared type to exercise runtime behavior - expect(stringToBoolean('asd')).toBe(false); + it("returns false for unknown strings", () => { + expect(toBoolean("not a json")).toBe(false); + expect(toBoolean('asd')).toBe(false); + }); - // console.error should have been called at least once for the thrown JSON.parse or type error - expect(spy).toHaveBeenCalled(); - spy.mockRestore(); + it("keeps stringToBoolean as a backwards-compatible alias", () => { + expect(stringToBoolean).toBe(toBoolean); + expect(stringToBoolean("true")).toBe(true); }); -}); \ No newline at end of file +}); diff --git a/packages/core/src/tests/utils/dataSlicer.test.ts b/packages/core/src/tests/utils/dataSlicer.test.ts new file mode 100644 index 0000000..1334d31 --- /dev/null +++ b/packages/core/src/tests/utils/dataSlicer.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from 'vitest'; +import { DataSlicer } from '@/utils/dataSlicer'; +import type { DataSlicerParams } from '@/utils/dataSlicer'; +import { DataType } from '@/common/types'; + +describe('DataSlicer', () => { + test('reinitialize and basic pushBack behavior', () => { + const params: DataSlicerParams = { datatype: DataType.i16, bufferSamplesSize: 8, buffersCount: 2 }; + const slicer = new DataSlicer(params); + expect(slicer.capacity()).toBe(2); + expect(slicer.size()).toBe(0); + + const input = new Int16Array([10, 20, 30]); + slicer.pushBack(input.buffer, 0, input.length * Int16Array.BYTES_PER_ELEMENT, 0, 0n); + + const front = slicer.front(); + expect(front).toBeDefined(); + expect(front!.bufferFilled).toBe(input.length); + + const view = new Int16Array(front!.buffer); + expect(Array.from(view.slice(0, input.length))).toEqual(Array.from(input)); + }); +}); diff --git a/packages/core/src/utils/allocator.ts b/packages/core/src/utils/allocator.ts new file mode 100644 index 0000000..cee4f1e --- /dev/null +++ b/packages/core/src/utils/allocator.ts @@ -0,0 +1,63 @@ +export class Allocator { + private pointer: number = 0; + private module: EmscriptenModule | undefined; + + constructor(module: EmscriptenModule | undefined) { + this.module = module; + } + + alloc(sizeOfBuffer: number): number { + if (!this.module) throw new Error('Module with malloc is undefined'); + this.pointer = this.module._malloc(sizeOfBuffer); + return this.pointer; + } + + allocFloat32Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Float32Array(this.module.HEAPF32.buffer, pointer, sizeOfBuffer / Float32Array.BYTES_PER_ELEMENT); + } + + allocUint32Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Uint32Array(this.module.HEAPU32.buffer, pointer, sizeOfBuffer / Uint32Array.BYTES_PER_ELEMENT); + } + + allocInt32Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Int32Array(this.module.HEAP32.buffer, pointer, sizeOfBuffer / Int32Array.BYTES_PER_ELEMENT); + } + + allocUint16Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Uint16Array(this.module.HEAPU16.buffer, pointer, sizeOfBuffer / Uint16Array.BYTES_PER_ELEMENT); + } + + allocInt16Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Int16Array(this.module.HEAP16.buffer, pointer, sizeOfBuffer / Int16Array.BYTES_PER_ELEMENT); + } + + allocUint8Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Uint8Array(this.module.HEAPU8.buffer, pointer, sizeOfBuffer / Uint8Array.BYTES_PER_ELEMENT); + } + + allocInt8Buffer(sizeOfBuffer: number) { + if (!this.module) throw new Error('Module with malloc is undefined'); + const pointer = this.alloc(sizeOfBuffer); + return new Int8Array(this.module.HEAP8.buffer, pointer, sizeOfBuffer / Int8Array.BYTES_PER_ELEMENT); + } + + dealloc() { + if (!this.pointer) return; + if (!this.module) throw new Error('Module with malloc is undefined'); + this.module._free(this.pointer); + this.pointer = 0; + } +} diff --git a/packages/core/src/utils/convUtils.ts b/packages/core/src/utils/convUtils.ts index 129c7bc..8ddb293 100644 --- a/packages/core/src/utils/convUtils.ts +++ b/packages/core/src/utils/convUtils.ts @@ -1,26 +1,34 @@ -export function stringToBoolean(str: string | null | undefined): boolean { - try { - switch (str?.toLowerCase()?.trim()) { - case "true": - case "yes": - case "1": - return true; +export function toBoolean(value: unknown): boolean { + if (typeof value === "boolean") { + return value; + } - case "false": - case "no": - case "0": - case "": - case "null": - case "undefined": - case null: - case undefined: - return false; + if (typeof value === "number") { + return Boolean(value); + } - default: - throw new Error("Invalid input"); - } - } catch (err) { - console.error("stringToBoolean: error converting ", str, " to boolean"); + if (typeof value !== "string") { + return false; } + + switch (value.toLowerCase().trim()) { + case "true": + case "yes": + case "1": + case "on": + return true; + + case "false": + case "no": + case "0": + case "off": + case "": + case "null": + case "undefined": + return false; + } + return false; } + +export const stringToBoolean = toBoolean; diff --git a/packages/core/src/utils/dataSlicer.ts b/packages/core/src/utils/dataSlicer.ts new file mode 100644 index 0000000..50721b0 --- /dev/null +++ b/packages/core/src/utils/dataSlicer.ts @@ -0,0 +1,148 @@ +import { getDataView, getElementByteLength, getElementsPerSample, getSampleByteLength } from "@/transform/transformdata"; +import { DataType } from "@/common/types"; + +const debugDataSlicer = false; + +interface DataItem { + buffer: SharedArrayBuffer, + bufferFilled: number, + overrun: number, + timestamp: bigint, +} + +export class DataSlicer { + protected _firstTimeStamp: bigint | undefined = undefined; + protected _datatype: DataType = DataType.ci16; + protected _sampleSize: number = 0; + protected _elementSize: number = 0; + protected _elementsPerSample: number = 0; + protected _buffer: Array = []; + protected _bufferLen: number = 0; + protected _bufferHead: number = 0; + protected _bufferTail: number = 0; + onChangeSize: () => void = () => void {}; + + constructor(parms?: DataSlicerParams) { + this.reinitialize(parms); + } + + protected _clearBuffer(idx: number) { + if (idx < 0 || idx >= this._buffer.length) return; + const item = this._buffer[idx]!; + item.bufferFilled = 0; + item.overrun = 0; + item.timestamp = 0n; + } + + get datatype() { + return this._datatype; + } + + reinitialize(parms?: DataSlicerParams) { + if (debugDataSlicer) console.log('DataSlicer.reinitialize', parms); + if (!parms) return; + this._datatype = parms.datatype; + this._bufferLen = parms.buffersCount; + this._buffer = this._bufferLen > 0 ? new Array(this._bufferLen) : []; + this._sampleSize = getSampleByteLength(this._datatype); + this._elementSize = getElementByteLength(this._datatype); + this._elementsPerSample = getElementsPerSample(this._datatype); + const bufferSize = parms.bufferSamplesSize * this._sampleSize; + for (let i = 0; i < this._bufferLen; ++i) { + this._buffer[i] = { + buffer: new SharedArrayBuffer(bufferSize), + bufferFilled: 0, + overrun: 0, + timestamp: -1n, + } + } + } + + clear() { + this._bufferHead = 0; + this._bufferTail = 0; + this.onChangeSize(); + } + + capacity() { + return this._bufferLen; + } + + size() { + if (this._bufferHead <= this._bufferTail) + return this._bufferTail - this._bufferHead; + return this._bufferTail + this._bufferLen - this._bufferHead; + } + + pushBack(iqBuf: ArrayBufferLike, iqBufOffset: number, iqBufByteLength: number | undefined, overrun: number, timestamp: bigint) { + if (debugDataSlicer) console.log('DataSlicer.pushBack: iqBuf =', iqBuf, ', iqBufOffset =', iqBufOffset, ', iqBufByteLength =', iqBufByteLength, ', overrun =', overrun, ', timestamp =', timestamp); + const outItem = this._buffer[this._bufferTail]!; + let outView = getDataView({ type: this._datatype, buffer: outItem.buffer }); + let inView = getDataView({ type: this._datatype, buffer: iqBuf, offset: iqBufOffset, length: iqBufByteLength !== undefined ? Math.ceil(iqBufByteLength / this._elementSize) : undefined }); + + if (this._firstTimeStamp === undefined) + this._firstTimeStamp = timestamp; + + let outBufFree = outView.length - outItem.bufferFilled; + //console.log('0 outBufFree =', outBufFree) + + if (outItem.bufferFilled === 0) { + outItem.overrun = overrun; + outItem.timestamp = timestamp; + } else { + const ourTimestamp = outItem.timestamp + BigInt(outItem.bufferFilled / this._elementsPerSample); + // console.log('outItem.timestamp =', outItem.timestamp, ', outItem.bufferFilled =', outItem.bufferFilled, ', timestamp =', timestamp); + if (ourTimestamp === timestamp) { + if (debugDataSlicer) console.log('Timestamp is good'); + } else if (timestamp > ourTimestamp) { + if (debugDataSlicer) console.log('Timestamp is bad, were overruns'); + const fillLen = Math.min(outBufFree, Math.max(0, Number(timestamp - ourTimestamp) * this._elementsPerSample)); + // console.log('fill from =', outItem.bufferFilled, ', len =', fillLen); + outView.fill(0, outItem.bufferFilled, fillLen); + outItem.bufferFilled += fillLen; + outBufFree -= fillLen; + // console.log('1 outBufFree =', outBufFree) + } + } + + const len = Math.min(inView.length, outBufFree); + if (len > 0) { + outView.set(inView.subarray(0, len), outItem.bufferFilled); + outItem.bufferFilled += len; + outBufFree -= len; + // console.log('2 outBufFree =', outBufFree) + } + if (outBufFree === 0) { + this._bufferTail = (this._bufferTail + 1) % this._bufferLen; + if (this._bufferHead === this._bufferTail) + this._bufferHead = (this._bufferHead + 1) % this._bufferLen; + this._clearBuffer(this._bufferTail); + if (inView.length > len) { + const offset = len * inView.BYTES_PER_ELEMENT + this.pushBack(iqBuf, iqBufOffset + offset, iqBufByteLength !== undefined ? iqBufByteLength - offset : undefined, + 0, timestamp + BigInt(len >> 1)); + } + this.onChangeSize(); + } + } + + front() { + return this._buffer[this._bufferHead]; + } + + pop_front(cnt: number = 1) { + if (cnt < 1) return; + const cntBiggerSize = (cnt >= this.size()); + this._bufferHead = (this._bufferHead + cnt) % this._bufferLen; + if (cntBiggerSize) + this._bufferTail = this._bufferHead; + this.onChangeSize(); + } +} + +export interface DataSlicerParams { + datatype: DataType, + bufferSamplesSize: number, + buffersCount: number, +} + diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 6ca32bc..52956de 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -6,5 +6,7 @@ export { JournalLogLevel } from './journal'; export type { JournalLogLevelKeys, JournalLogItem } from './journal'; export { SimpleLogger, LogLevels as LOG_LEVELS } from './logger'; export type { LoggerInterface, LogLevel } from './logger'; -export { stringToBoolean } from './convUtils'; -export { containsAnySubstr } from './stringUtils'; +export { toBoolean, stringToBoolean } from './convUtils'; +export { containsAnySubstr, printBin } from './stringUtils'; +export { DataSlicer } from './dataSlicer'; +export { Allocator } from './allocator'; diff --git a/packages/core/src/utils/stringUtils.ts b/packages/core/src/utils/stringUtils.ts index 3132438..01cf10c 100644 --- a/packages/core/src/utils/stringUtils.ts +++ b/packages/core/src/utils/stringUtils.ts @@ -9,4 +9,11 @@ export function containsAnySubstr(str: string | undefined | null, substrs: strin if (text.includes(substrConv)) return true; } return false; -} \ No newline at end of file +} +export function printBin(v: number, d = 8) { + let ret = ''; + for (let mask = 1 << (d - 1); mask > 0; mask >>= 1) { + ret += (v & mask) ? '1' : '0'; + } + return ret; +} From f762d05ae12e5fcfe7814846cd0a3b940003a098 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:28:33 +0300 Subject: [PATCH 03/13] core: document new transform and utility APIs Expand the core package README with API reference sections for sample conversions, A-law companding, transform helpers, DataSlicer, and utility functions. Also bump @websdr/core to 0.6.0. --- packages/core/README.md | 320 ++++++++++++++++++++++++++++++++++-- packages/core/package.json | 5 +- packages/core/tsconfig.json | 9 +- 3 files changed, 318 insertions(+), 16 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index 867c86f..48d51f6 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -5,7 +5,7 @@ Core TypeScript utilities for the WebSDR ecosystem: shared types/constants, smal **What’s inside** - **Common:** shared types + size/format constants. - **Utils:** circular buffer, timing helpers, logging, promise helper, string helpers, journal types. -- **Transform:** PCM buffer converters used by DSP pipelines. +- **Transform:** sample format converters used by DSP pipelines. ## Install @@ -37,10 +37,30 @@ import { bufferI16ToF32 } from '@websdr/core/transform'; import { CHUNK_SIZE, DataType } from '@websdr/core/common'; ``` -## Examples +## API reference and examples ### CircularBuffer +Files: `packages/core/src/utils/circularbuffer.ts` + +Provides a fixed-capacity deque for low-allocation queues, rolling windows, and +producer/consumer buffers. It keeps logical order even when the internal array +wraps around, so `get(0)` is always the oldest/front item and `get(size() - 1)` +is the newest/back item. + +- `new CircularBuffer(len)` — create a buffer with fixed capacity. +- `push_back(value)` / `push_front(value)` — append/prepend an item; when full, + discard one item from the opposite side. +- `pop_front(count?)` / `pop_back(count?)` — remove one or more items. +- `front()` / `back()` — read the first/last logical item. +- `get(index)` / `set(index, value)` — read/write by logical index from the + front. +- `alloc_front(count?)` / `alloc_back(count?)` — reserve logical slots without + writing values. +- `capacity()`, `size()`, `isEmpty()`, `isFull()` — inspect buffer state. +- `clear()` — reset to an empty state. +- `waitForChangeSize()` / `onChangeSize` — react to size-changing operations. + ```ts import { CircularBuffer } from '@websdr/core/utils'; @@ -53,8 +73,43 @@ console.log(buf.front()); // 1 console.log(buf.back()); // 2 ``` +When the buffer is full, adding an item drops one item from the opposite side: +`push_back()` drops the oldest/front item, and `push_front()` drops the +newest/back item. + +```ts +const buf = new CircularBuffer(3); + +buf.push_back(1); +buf.push_back(2); +buf.push_back(3); +buf.push_back(4); + +console.log(buf.size()); // 3 +console.log([buf.get(0), buf.get(1), buf.get(2)]); // [2, 3, 4] +``` + +Notes + +- `front()` and `back()` return `undefined` when the buffer is empty. +- Counts larger than the current size clear the buffer; zero or negative counts + are ignored. +- `get(index)` and `set(index, value)` throw if the index is outside the active + range. + ### Timing helpers +Files: `packages/core/src/utils/time.ts` + +Provides small timing helpers for async delays, monotonic elapsed-time +measurements, and journal/log timestamp formatting. + +- `sleep(seconds): Promise` — wait for a number of seconds. +- `usleep(milliseconds): Promise` — wait for a number of milliseconds. +- `now(): number` — return `performance.now()` for elapsed-time measurements. +- `timestampToTimeString(timestamp): string` — format a wall-clock timestamp as + `HH:mm:ss.SSS`. + ```ts import { now, sleep, usleep } from '@websdr/core/utils'; @@ -64,7 +119,28 @@ await sleep(0.05); // seconds console.log('elapsed', now() - t0); ``` -### PCM conversions +Use `Date.now()` when you need a wall-clock timestamp. Use `now()` when you need +to measure duration without being affected by system clock changes. + +### Float/Int16 sample conversions + +Files: `packages/core/src/transform/converters.ts` + +Provides fast typed-array conversions between normalized `Float32` samples in +the `[-1.0, 1.0]` range and signed 16-bit integer samples. These helpers are +useful for audio, IQ, and other DSP data paths, and can reuse caller-provided +output buffers to avoid allocations. + +- `bufferF32ToI16(input, outbuf?): Int16Array` — convert normalized float + samples to signed 16-bit integer samples. +- `bufferI16ToF32(input, outbuf?): Float32Array` — convert signed 16-bit + integer samples to normalized float samples. +- `clipF32Buffer(buffer, outbuf?): void` — clip float samples to the + `[-1.0, 1.0]` range. + +If an output buffer is provided, conversion runs for +`min(input.length, outbuf.length)` elements and the same `outbuf` instance is +returned. ```ts import { bufferF32ToI16, bufferI16ToF32, clipF32Buffer } from '@websdr/core/transform'; @@ -78,6 +154,15 @@ const i16 = bufferF32ToI16(f32); const f32roundtrip = bufferI16ToF32(i16); ``` +Scaling rules: + +- `bufferI16ToF32()` divides samples by `0x8000`, so `-32768` becomes `-1.0` + and `32767` becomes about `0.99997`. +- `bufferF32ToI16()` multiplies samples by `0x7fff`. It does not clamp + out-of-range floats for speed, so clip first if your upstream can produce + values outside `[-1.0, 1.0]`. +- `clipF32Buffer(buffer)` clips in place. `NaN` values are left unchanged. + If you want to avoid allocations in a hot path, reuse an output buffer: ```ts @@ -92,8 +177,34 @@ function onAudioFrame(frame: Float32Array) { } ``` +For an out-of-place clip, initialize or copy the output first. The current +`clipF32Buffer(input, out)` implementation only writes values that need +clipping; in-range values in `out` are left as they were. + +```ts +const input = new Float32Array([1.2, 0.25, -1.5]); +const clipped = new Float32Array(input); + +clipF32Buffer(input, clipped); +console.log([...clipped]); // [1, 0.25, -1] +``` + ### Common constants and types +Files: `packages/core/src/common/types.ts`, `packages/core/src/common/defines.ts` + +Provides shared data-type enums, readable names, and byte-size constants used by +streaming and transform code. + +- `DataType` — internal buffer/sample formats: `cf32`, `ci16`, `f32`, `i16`, + `i8`. +- `StreamDataType` — stream-level formats: `cf32`, `ci16`, `f32`, `i16`, + `alaw`. +- `DataTypeNames` / `StreamDataTypeNames` — display names for data types. +- `CHUNK_SIZE` — default stream chunk size, currently `8192` samples. +- `FLOAT_SIZE`, `COMPLEX_FLOAT_SIZE`, `INT16_SIZE`, `COMPLEX_INT16_SIZE`, + `INT8_SIZE` — byte-size constants for sample calculations. + ```ts import { CHUNK_SIZE, COMPLEX_FLOAT_SIZE, DataType } from '@websdr/core/common'; @@ -104,6 +215,17 @@ console.log({ streamType, bytesPerChunk }); ### Logging +Files: `packages/core/src/utils/logger.ts` + +Provides a small console-backed logger and shared logger types for components +that should accept any compatible logging implementation. + +- `SimpleLogger(context?)` — prefixes messages with an optional context and + writes to the browser/Node console. +- `LoggerInterface` — common logger contract with `log`, `warn`, `error`, and + optional `debug`, `verbose`, `fatal` methods. +- `LOG_LEVELS` / `LogLevel` — supported log-level values. + ```ts import { SimpleLogger } from '@websdr/core/utils'; @@ -115,7 +237,18 @@ logger.error('something bad'); ### PromiseHelper (request/response correlation) -Useful when you send requests that later resolve from an event handler. +Files: `packages/core/src/utils/promiseHelper.ts` + +Provides a small request/response correlation helper. It creates numbered +promises that can be resolved or rejected later from an event handler. + +- `createPromise(): [number, Promise]` — allocate the next numeric id and + store the promise callbacks. +- `getPromise(id)` — retrieve the stored callbacks for an id. +- `deletePromise(id)` — remove an id from the map. +- `promiseResolve(entry, value?)` / `promiseReject(entry, reason?)` — settle a + stored promise entry. +- `clear()` — remove all pending entries and reset id generation. ```ts import { PromiseHelper } from '@websdr/core/utils'; @@ -139,16 +272,41 @@ transport.on('message', (msg: { id: number; result?: unknown; error?: unknown }) ### Filtering helpers +Files: `packages/core/src/utils/convUtils.ts`, `packages/core/src/utils/stringUtils.ts` + +Provides lightweight string conversion and filtering helpers for config parsing, +log filtering, and diagnostics. + +- `toBoolean(value): boolean` — convert booleans, numbers, and common boolean + strings such as `true`, `yes`, `1`, `on`, `false`, `no`, `0`, and `off`; + unsupported values return `false`. +- `stringToBoolean(value): boolean` — backwards-compatible alias for + `toBoolean`. +- `containsAnySubstr(text, substrs, caseSensitive?)` — check whether a string + contains any non-empty substring from a string or string array. +- `printBin(value, digits?)` — format a number as a binary string with fixed + width. + ```ts -import { containsAnySubstr, stringToBoolean } from '@websdr/core/utils'; +import { containsAnySubstr, toBoolean } from '@websdr/core/utils'; -const enabled = stringToBoolean(process.env.DEBUG); +const enabled = toBoolean(process.env.DEBUG); const allow = containsAnySubstr('usb:device connected', ['usb:', 'webusb'], false); console.log({ enabled, allow }); ``` ### Journal log items +Files: `packages/core/src/utils/journal.ts` + +Provides serializable journal/log item types used by components that collect or +transport structured logs. + +- `JournalLogLevel` — enum with `DEBUG`, `INFO`, `WARNING`, `ERROR`, `FATAL`. +- `JournalLogLevelKeys` — TypeScript union of journal level keys. +- `JournalLogItem` — timestamped log item shape with subsystem, level, and + message. + ```ts import { JournalLogLevel, timestampToTimeString } from '@websdr/core/utils'; import type { JournalLogItem } from '@websdr/core/utils'; @@ -163,18 +321,160 @@ const item: JournalLogItem = { console.log(`[${timestampToTimeString(item.timestamp)}] ${item.subSystem}: ${item.message}`); ``` +### A-law companding + +Files: `packages/core/src/transform/compressors.ts` + +Provides functions to encode/decode A-law companded sample data and buffer +helpers for batch conversions. + +- `alawEncode(input: number): number` — encode a signed 16-bit linear sample to + 8-bit A-law. +- `alawDecode(input: number): number` — decode 8-bit A-law to a signed 16-bit + linear sample. +- `alawEncodeBuffer(input, outbuf?): Uint8Array` — encode an `Int16Array` into + a `Uint8Array`. +- `alawDecodeBuffer(input, outbuf?): Int16Array` — decode a `Uint8Array` into an + `Int16Array`. +- `alawEncodeBufferF32(input, outbuf?): Uint8Array` — encode normalized + `Float32Array` samples to A-law. +- `alawDecodeBufferF32(input, outbuf?): Float32Array` — decode A-law samples to + normalized `Float32Array` samples. + +```ts +import { alawEncodeBufferF32, alawDecodeBufferF32 } from '@websdr/core/transform'; + +const f32 = new Float32Array([0.0, 0.5, -0.5]); +const alaw = alawEncodeBufferF32(f32); // Uint8Array +const roundtrip = alawDecodeBufferF32(alaw); // Float32Array (approx) +``` + +Notes + +- The A-law helpers operate on linear sample ranges expected by the package: + `Int16Array` uses signed 16-bit values; `Float32Array` helpers scale to/from + that range internally. +- Buffer helpers convert up to `min(input.length, outbuf.length)` when an output + buffer is provided. + +### Base64 helpers + +Files: `packages/core/src/transform/base64.ts` + +Provides conversion helpers for moving binary data through text-only channels. + +- `uint8ArrayToBase64(bytes): string` — encode bytes into a base64 string. +- `base64ToUint8Array(base64): Uint8Array` — decode a base64 string into bytes. + +```ts +import { base64ToUint8Array, uint8ArrayToBase64 } from '@websdr/core/transform'; + +const bytes = new Uint8Array([1, 2, 3]); +const encoded = uint8ArrayToBase64(bytes); +const decoded = base64ToUint8Array(encoded); +``` + +### Transform helpers + +Files: `packages/core/src/transform/transformdata.ts` + +Provides high-level helpers for converting between supported data +representations and for calculating typed-array sizes/views. + +- `transformData(inBuffer, outBuffer): void` — convert data between supported + input/output types. +- `createTypedArray(datatype, samples)` — allocate a typed array for a data + type and sample count. +- `getDataView(bufferParams)` — create the matching typed-array view over an + existing buffer. +- `getSampleByteLength(datatype)` — return bytes per logical sample. +- `getElementByteLength(datatype)` — return bytes per typed-array element. +- `getElementsPerSample(datatype)` — return element count per logical sample. +- `getSamplesCount(datatype, byteLength)` — convert byte length to sample count. +- `getElementsCount(datatype, byteLength)` — convert byte length to element + count. +- `TransformDataType`, `TransformArrayType`, `BufferParams` — TypeScript helper + types for transform buffers. + +```ts +import { transformData, createTypedArray } from '@websdr/core/transform'; +import { DataType, StreamDataType } from '@websdr/core/common'; + +const inF32 = new Float32Array([0.1, -0.2, 0.3]); +const outAlaw = createTypedArray(StreamDataType.alaw, inF32.length); + +transformData( + { type: DataType.f32, buffer: inF32.buffer, length: inF32.length }, + { type: StreamDataType.alaw, buffer: outAlaw.buffer, length: outAlaw.length } +); +``` + +Notes + +- `transformData()` throws on unsupported input/output combinations. +- Prefer pre-allocated output arrays with `createTypedArray()` in hot paths. + +### DataSlicer + +Files: `packages/core/src/utils/DataSlicer.ts` + +Provides a fixed-capacity frame assembler that collects incoming sample chunks +into `SharedArrayBuffer` slots, tracks overruns/timestamps, and exposes a small +consumer queue API. + +- `new DataSlicer(params?)` — create a slicer and optionally initialize buffer + slots. +- `reinitialize(params)` — recreate slots for a datatype, samples-per-buffer, + and buffer count. +- `pushBack(buffer, offset, byteLength, overrun, timestamp)` — append incoming + sample bytes into the current output slot. +- `front()` — read the current filled slot. +- `pop_front(count?)` — release one or more filled slots. +- `capacity()`, `size()`, `clear()` — inspect or reset the queue. +- `datatype` — read the current data type. +- `onChangeSize` — callback invoked when filled slots are produced or removed. + +```ts +import { DataSlicer } from '@websdr/core/utils'; +import { DataType } from '@websdr/core/common'; + +const slicer = new DataSlicer({ + datatype: DataType.ci16, + bufferSamplesSize: 1024, + buffersCount: 4, +}); + +slicer.pushBack(iqBuf, 0, iqBuf.byteLength, 0, BigInt(timestamp)); + +const item = slicer.front(); +if (item && item.bufferFilled > 0) { + const samples = new Int16Array(item.buffer, 0, item.bufferFilled); + slicer.pop_front(); +} +``` + ## Public API (summary) -- **`@websdr/core/common`**: `DataType`, `CHUNK_SIZE`, `FLOAT_SIZE`, `COMPLEX_FLOAT_SIZE`, `INT16_SIZE`, `COMPLEX_INT16_SIZE`. +- **`@websdr/core/common`**: `DataType`, `DataTypeNames`, `StreamDataType`, + `StreamDataTypeNames`, `CHUNK_SIZE`, `FLOAT_SIZE`, `COMPLEX_FLOAT_SIZE`, + `INT16_SIZE`, `COMPLEX_INT16_SIZE`, `INT8_SIZE`. - **`@websdr/core/utils`**: - `CircularBuffer` - `sleep`, `usleep`, `now`, `timestampToTimeString` - `PromiseHelper` - `JournalLogLevel`, `JournalLogLevelKeys`, `JournalLogItem` - `SimpleLogger`, `LOG_LEVELS`, `LoggerInterface`, `LogLevel` - - `stringToBoolean`, `containsAnySubstr` -- **`@websdr/core/transform`**: `bufferF32ToI16`, `bufferI16ToF32`. -- **`@websdr/core/transform`**: `bufferF32ToI16`, `bufferI16ToF32`, `clipF32Buffer`. + - `toBoolean`, `stringToBoolean`, `containsAnySubstr`, `printBin` + - `DataSlicer` +- **`@websdr/core/transform`**: + - `bufferF32ToI16`, `bufferI16ToF32`, `clipF32Buffer` + - `alawEncode`, `alawDecode`, `alawEncodeBuffer`, `alawDecodeBuffer`, + `alawEncodeBufferF32`, `alawDecodeBufferF32` + - `base64ToUint8Array`, `uint8ArrayToBase64` + - `transformData`, `createTypedArray`, `getDataView` + - `getSampleByteLength`, `getElementByteLength`, `getElementsPerSample`, + `getSamplesCount`, `getElementsCount` + - `TransformDataType`, `TransformArrayType`, `BufferParams` ## Compatibility notes diff --git a/packages/core/package.json b/packages/core/package.json index fe336b5..b1bcb70 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/core", - "version": "0.5.3", + "version": "0.6.0", "description": "This is the core package for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -32,7 +32,8 @@ "postpack": "rm -f ./LICENSE" }, "devDependencies": { - "@types/node": "^25.2.3" + "@types/emscripten": "^1.41.5", + "@types/node": "^25.9.1" }, "exports": { ".": { diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 1c732b9..98d68a6 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,10 +4,9 @@ "rootDir": "src", "outDir": "dist", // Path Mapping - "baseUrl": ".", "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" @@ -18,7 +17,8 @@ "target": "esnext", "moduleResolution": "bundler", "types": [ - "vitest/globals" + "vitest/globals", + "emscripten" ], // Other Outputs "sourceMap": false, @@ -46,7 +46,8 @@ "skipLibCheck": true, }, "include": [ - "src/**/*" + "src/**/*", + "node_modules/@types/" ], "exclude": [ "node_modules", From 36eafdb33dc32155fbedd1e7b880b40a43b2fd09 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:35:17 +0300 Subject: [PATCH 04/13] frontend-core: add environment and debug configuration helpers Introduce environment access utilities for import.meta and process.env, and extend debug handling with runtime configuration helpers and assertion support. Also add configurable debug mode detection shared across browser, Node.js, and test environments. --- packages/frontend-core/src/common/debug.ts | 73 ++++++++++++++++++---- packages/frontend-core/src/common/env.ts | 40 ++++++++++++ packages/frontend-core/src/common/index.ts | 5 +- 3 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 packages/frontend-core/src/common/env.ts diff --git a/packages/frontend-core/src/common/debug.ts b/packages/frontend-core/src/common/debug.ts index 6a0f54d..194ae85 100644 --- a/packages/frontend-core/src/common/debug.ts +++ b/packages/frontend-core/src/common/debug.ts @@ -1,22 +1,71 @@ +import { toBoolean } from "@websdr/core/utils"; +import { getEnvValue } from "./env"; + declare global { - var debug_mode: boolean; + var debug_mode: boolean | undefined; +} + +type DebugEnv = { + VITE_DEBUG?: string; + DEBUG?: string; + MODE?: string; + NODE_ENV?: string; +}; + +type DebugOptions = { + debug?: boolean; +}; + +function parseBoolean(value: unknown): boolean | undefined { + if (typeof value === 'boolean') return value; + if (typeof value !== 'string') return undefined; - interface ImportMeta { - readonly env?: ImportMetaEnv; + return toBoolean(value); +} + +function readDebugMode(): boolean { + if (typeof globalThis.debug_mode === 'boolean') { + return globalThis.debug_mode; } + + return parseBoolean(getEnvValue(["VITE_DEBUG", "DEBUG"])) + ?? false; } -interface ImportMetaEnv { - readonly VITE_DEBUG?: string; +function readMode(): string | undefined { + const mode = getEnvValue(["MODE", "NODE_ENV"]); + return mode === undefined ? undefined : String(mode); } -// compute once and assign -const _debug_mode = ((import.meta.env?.VITE_DEBUG) ?? (typeof process !== 'undefined' ? process.env?.VITE_DEBUG : undefined)) === 'true'; +export let debug_mode = readDebugMode(); -// only set if not already set to avoid overwriting other code during tests if (typeof globalThis.debug_mode !== 'boolean') { - globalThis.debug_mode = _debug_mode; -} else { - // keep existing value (no-op) + globalThis.debug_mode = debug_mode; +} + +export function setDebugMode(value: boolean) { + debug_mode = value; + globalThis.debug_mode = value; +} + +export function configureDebug(options: DebugOptions) { + if (typeof options.debug === 'boolean') { + setDebugMode(options.debug); + } +} + +export function isDebugMode(): boolean { + return globalThis.debug_mode ?? debug_mode; +} + +function shouldThrowAssertions(): boolean { + return readMode() === 'test' || isDebugMode(); +} + +export function assert(value: any, ...rest: any[]): asserts value { + console.assert(value, ...rest) + if (shouldThrowAssertions() && !value) { + const [msg, ..._] = rest + throw new Error(msg ? 'Assertion failed: ' + msg : 'Assertion failed') + } } -export const debug_mode = globalThis.debug_mode; diff --git a/packages/frontend-core/src/common/env.ts b/packages/frontend-core/src/common/env.ts new file mode 100644 index 0000000..f30a1e8 --- /dev/null +++ b/packages/frontend-core/src/common/env.ts @@ -0,0 +1,40 @@ +export type EnvValue = string | boolean | number | undefined; +export type EnvRecord = Record; +export type EnvSource = "process" | "importMeta"; + +export function getImportMetaEnv(): TEnv | undefined { + return (import.meta as ImportMeta & { env?: TEnv }).env; +} + +export function getProcessEnv(): TEnv | undefined { + const proc = (globalThis as typeof globalThis & { process?: { env?: TEnv } }).process; + return proc?.env; +} + +export function getEnv( + sources: EnvSource[] = ["process", "importMeta"], +): TEnv | undefined { + for (const source of sources) { + const env = source === "process" ? getProcessEnv() : getImportMetaEnv(); + if (env) return env; + } + + return undefined; +} + +export function getEnvValue( + keys: (keyof TEnv & string)[], + sources: EnvSource[] = ["process", "importMeta"], +): EnvValue { + for (const source of sources) { + const env = source === "process" ? getProcessEnv() : getImportMetaEnv(); + if (!env) continue; + + for (const key of keys) { + const value = env[key]; + if (value !== undefined && value !== "") return value; + } + } + + return undefined; +} diff --git a/packages/frontend-core/src/common/index.ts b/packages/frontend-core/src/common/index.ts index 73e4927..b021901 100644 --- a/packages/frontend-core/src/common/index.ts +++ b/packages/frontend-core/src/common/index.ts @@ -1,4 +1,5 @@ // Re-exporting all common functionalities -export { debug_mode } from "./debug"; -export { Protocol, NngWebSocket } from "./nngWebSocket"; +export { debug_mode, setDebugMode, configureDebug, isDebugMode, assert } from "./debug"; +export { getImportMetaEnv, getProcessEnv, getEnv, getEnvValue } from "./env"; +export type { EnvRecord, EnvSource, EnvValue } from "./env"; export { WASMErrno } from "./wasmErrno"; From 7cbf9e6fc709a4878b80118e3057c6ccea489d4a Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:37:40 +0300 Subject: [PATCH 05/13] frontend-core: move NngWebSocket to transport module Move NngWebSocket into a dedicated transport namespace and improve event dispatching by creating fresh public events instead of reusing internal WebSocket events. Also switch debug checks to isDebugMode(), broaden send() buffer types, and extend tests for public event dispatch behavior. --- .../nngWebSocket.test.ts | 18 ++++- packages/frontend-core/src/transport/index.ts | 2 + .../src/{common => transport}/nngWebSocket.ts | 74 ++++++++++++++++--- 3 files changed, 81 insertions(+), 13 deletions(-) rename packages/frontend-core/src/tests/{common => transport}/nngWebSocket.test.ts (90%) create mode 100644 packages/frontend-core/src/transport/index.ts rename packages/frontend-core/src/{common => transport}/nngWebSocket.ts (85%) diff --git a/packages/frontend-core/src/tests/common/nngWebSocket.test.ts b/packages/frontend-core/src/tests/transport/nngWebSocket.test.ts similarity index 90% rename from packages/frontend-core/src/tests/common/nngWebSocket.test.ts rename to packages/frontend-core/src/tests/transport/nngWebSocket.test.ts index 0c776f2..a3fb3ce 100644 --- a/packages/frontend-core/src/tests/common/nngWebSocket.test.ts +++ b/packages/frontend-core/src/tests/transport/nngWebSocket.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import { NngWebSocket, Protocol } from '@/common/nngWebSocket' +import { NngWebSocket, Protocol } from '@/transport/nngWebSocket' /** * Re-declare a minimal FakeWebSocket for these additional tests so they can run standalone. @@ -159,6 +159,22 @@ describe('NngWebSocket additional tests', () => { expect(got.messageCount).toBeGreaterThanOrEqual(1) }) + it('dispatches a fresh public open event instead of reusing the WebSocket event', async () => { + const nng = new NngWebSocket({ url: 'ws://open-event-clone', protocol: Protocol.SUB }) + const original = new Event('open') + let publicEvent: Event | undefined + + nng.addEventListener('open', (event) => { + publicEvent = event + }) + + await (nng as any).onWsOpen(original) + + expect(publicEvent).toBeInstanceOf(Event) + expect(publicEvent).not.toBe(original) + expect(publicEvent?.type).toBe('open') + }) + it('non-REQ send after close rejects as not connected', async () => { const nng = new NngWebSocket({ url: 'ws://after-close', protocol: Protocol.SUB, binaryType: NngWebSocket.ARRAYBUFFER }) const p = nng.open() diff --git a/packages/frontend-core/src/transport/index.ts b/packages/frontend-core/src/transport/index.ts new file mode 100644 index 0000000..687d777 --- /dev/null +++ b/packages/frontend-core/src/transport/index.ts @@ -0,0 +1,2 @@ +// Re-exporting all common functionalities +export { Protocol, NngWebSocket } from "./nngWebSocket"; diff --git a/packages/frontend-core/src/common/nngWebSocket.ts b/packages/frontend-core/src/transport/nngWebSocket.ts similarity index 85% rename from packages/frontend-core/src/common/nngWebSocket.ts rename to packages/frontend-core/src/transport/nngWebSocket.ts index a8cb138..4c39818 100644 --- a/packages/frontend-core/src/common/nngWebSocket.ts +++ b/packages/frontend-core/src/transport/nngWebSocket.ts @@ -1,3 +1,4 @@ +import { isDebugMode } from '@/common/debug'; import { sleep } from '@websdr/core/utils'; const nngVerbose = false; @@ -91,6 +92,55 @@ export class NngWebSocket extends EventTarget { return this._binaryType === NngWebSocket.BLOB ? 'blob' : 'arraybuffer'; } + protected createPublicEvent(event: Event): Event { + if (event instanceof MessageEvent) { + return new MessageEvent(event.type, { + data: event.data, + origin: event.origin, + lastEventId: event.lastEventId, + source: event.source, + ports: Array.from(event.ports), + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + } + + if (event instanceof CloseEvent) { + return new CloseEvent(event.type, { + wasClean: event.wasClean, + code: event.code, + reason: event.reason, + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + } + + if (typeof ErrorEvent !== 'undefined' && event instanceof ErrorEvent) { + return new ErrorEvent(event.type, { + message: event.message, + filename: event.filename, + lineno: event.lineno, + colno: event.colno, + error: event.error, + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + } + + const publicEvent = new Event(event.type, { + bubbles: event.bubbles, + cancelable: event.cancelable, + composed: event.composed, + }); + if ((event as any).data !== undefined) { + (publicEvent as any).data = (event as any).data; + } + return publicEvent; + } + async open(url = undefined, binaryType = undefined, protocol = undefined) { if (url !== undefined) this._url = url if (binaryType !== undefined) this._binaryType = binaryType @@ -135,7 +185,7 @@ export class NngWebSocket extends EventTarget { } async close() { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log(`NngWebSocket: close connection to url ${this._url}`); this._closing = true if (this._websocket !== undefined) { @@ -175,7 +225,7 @@ export class NngWebSocket extends EventTarget { this._reqId = (this._reqId + 1) % REQ_ID_MOD; } - async send(data: string | ArrayBuffer | Uint8Array | Blob, timeoutMs = DEFAULT_SEND_TIMEOUT_MS): Promise { + async send(data: string | Blob | BufferSource, timeoutMs = DEFAULT_SEND_TIMEOUT_MS): Promise { if (!this.isConnected()) { return Promise.reject(`NngWebSocket: cannot send data, websocket to url ${this._url} is not connected`) } @@ -276,7 +326,7 @@ export class NngWebSocket extends EventTarget { buf = event.data; } - if (globalThis.debug_mode || nngVerbose) { + if (isDebugMode() || nngVerbose) { let len = -1; if (buf != null) { if (typeof buf === 'string') { @@ -305,7 +355,7 @@ export class NngWebSocket extends EventTarget { } async onWsOpen(event: Event) { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log(`NngWebSocket: connection to url ${this._url} established`); if (this._open_promise) { if (this._open_promise.resolve) @@ -313,19 +363,19 @@ export class NngWebSocket extends EventTarget { this._open_promise = undefined; } - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } async onWsClose(event: CloseEvent) { if (event.wasClean && this._closing) { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log(`NngWebSocket: connection to url ${this._url} has been closed`); } else { const err_str = `NngWebSocket: connection to url ${this._url} has been droped... reopening`; if (this._open_promise) { this._open_promise.reject?.(err_str); this._open_promise = undefined; - } else if (globalThis.debug_mode || nngVerbose) console.error(err_str); + } else if (isDebugMode() || nngVerbose) console.error(err_str); if (this._reconnectTime !== -1) { await sleep(this._reconnectTime); @@ -334,11 +384,11 @@ export class NngWebSocket extends EventTarget { } // dispatch the actual CloseEvent so listeners get reason/code/etc. - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } async onWsMessage(event: MessageEvent) { - if (globalThis.debug_mode || nngVerbose) + if (isDebugMode() || nngVerbose) console.log('NngWebSocket: receive event', event); // if we received a Blob, convert it to ArrayBuffer first so receive() can parse header if (typeof Blob !== 'undefined' && event.data instanceof Blob) { @@ -351,7 +401,7 @@ export class NngWebSocket extends EventTarget { } const buf = this.receive(event); if (buf) this.dispatchEvent(new CustomEvent('data', { detail: { data: buf } })); - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } async onWsError(event: Event) { @@ -368,7 +418,7 @@ export class NngWebSocket extends EventTarget { } } const err_str = `NngWebSocket: connection to url ${this._url}: an error has occurred: ` + detailStr; - if (globalThis.debug_mode || nngVerbose) console.error(err_str, event); + if (isDebugMode() || nngVerbose) console.error(err_str, event); if (this._open_promise) { this._open_promise.reject?.(err_str); @@ -379,6 +429,6 @@ export class NngWebSocket extends EventTarget { this._send_promises[Number(k)]!.reject?.(err_str); delete this._send_promises[Number(k)]; } - this.dispatchEvent(event); + this.dispatchEvent(this.createPublicEvent(event)); } } From c3aa19eefc703dd396ea000fcaa0035803222310 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:41:27 +0300 Subject: [PATCH 06/13] frontend-core: add stream telemetry utilities Add StreamMeter telemetry helper for tracking stream state, counters, and buffer statistics with listener-based notifications. Also export telemetry and transport modules from the frontend-core entry point, improve API URL environment handling, and add a browser file download utility with unit tests for StreamMeter behavior. --- packages/frontend-core/src/index.ts | 2 + packages/frontend-core/src/services/api.ts | 25 +- packages/frontend-core/src/telemetry/index.ts | 4 + .../src/telemetry/streamMeter.ts | 241 ++++++++++++++++++ .../src/tests/telemetry/streamMeter.test.ts | 53 ++++ .../frontend-core/src/utils/downloadFile.ts | 7 + packages/frontend-core/src/utils/index.ts | 2 + 7 files changed, 321 insertions(+), 13 deletions(-) create mode 100644 packages/frontend-core/src/telemetry/index.ts create mode 100644 packages/frontend-core/src/telemetry/streamMeter.ts create mode 100644 packages/frontend-core/src/tests/telemetry/streamMeter.test.ts create mode 100644 packages/frontend-core/src/utils/downloadFile.ts create mode 100644 packages/frontend-core/src/utils/index.ts diff --git a/packages/frontend-core/src/index.ts b/packages/frontend-core/src/index.ts index 092ad0c..ae3cdbb 100644 --- a/packages/frontend-core/src/index.ts +++ b/packages/frontend-core/src/index.ts @@ -1,4 +1,6 @@ // Re-exporting all frontend core functionalities export * from "./common"; export * from "./services"; +export * from "./telemetry"; +export * from "./transport"; export * from "./webusb"; diff --git a/packages/frontend-core/src/services/api.ts b/packages/frontend-core/src/services/api.ts index 1f928c6..a1128ca 100644 --- a/packages/frontend-core/src/services/api.ts +++ b/packages/frontend-core/src/services/api.ts @@ -1,8 +1,15 @@ +import { getEnvValue } from "@/common/env"; + // Minimal API helper for the frontend -// Use import.meta.env.VITE_API_URL for absolute API base, or rely on the dev proxy (/api) +// Use VITE_API_URL/API_URL for an absolute API base, or rely on the dev proxy (/api) let apiBase: string | undefined = undefined; +type ApiEnv = { + VITE_API_URL?: string; + API_URL?: string; +}; + /** * Set the API base URL dynamically (call from your app initialization). * Example: setApiBase('http://localhost:3000') @@ -13,24 +20,16 @@ export function setApiBase(base?: string) { /** Determine the API base URL by checking multiple locations (manual -> global -> env for SSR). */ function getEnvApiBase(): string | undefined { - const g = globalThis as any; + const g = globalThis as { __API_BASE__?: unknown }; // 1) Explicit global variable (can be set from index.html) if (typeof g.__API_BASE__ === 'string' && g.__API_BASE__) { return g.__API_BASE__; } - // 2) process.env (SSR / Node). In browsers globalThis.process is usually undefined. - const proc = g.process as any | undefined; - if (proc && proc.env) { - if (proc.env.VITE_API_URL) return proc.env.VITE_API_URL; - if (proc.env.API_URL) return proc.env.API_URL; - } - - // 3) We do not read import.meta.env directly here to stay environment-agnostic. - // If import.meta.env is required, call setApiBase(import.meta.env.VITE_API_URL) at build/runtime. - - return undefined; + // 2) process.env (SSR / Node), then import.meta.env (Vite / bundler builds). + const envApiBase = getEnvValue(["VITE_API_URL", "API_URL"]); + return envApiBase === undefined ? undefined : String(envApiBase); } /** Return the current API base URL (manual -> env -> fallback '/'). */ diff --git a/packages/frontend-core/src/telemetry/index.ts b/packages/frontend-core/src/telemetry/index.ts new file mode 100644 index 0000000..50c6bb8 --- /dev/null +++ b/packages/frontend-core/src/telemetry/index.ts @@ -0,0 +1,4 @@ +export { StreamMeter } from "./streamMeter"; +export type { + StreamMeterState, StreamMeterListener, StreamMeterParams, StreamMeterConfig +} from "./streamMeter"; \ No newline at end of file diff --git a/packages/frontend-core/src/telemetry/streamMeter.ts b/packages/frontend-core/src/telemetry/streamMeter.ts new file mode 100644 index 0000000..f786217 --- /dev/null +++ b/packages/frontend-core/src/telemetry/streamMeter.ts @@ -0,0 +1,241 @@ +export interface StreamMeterState { + is_up: boolean; + cloud_is_up: boolean; + downloaded: number; + processed: number; + overrun: number; + wr_ahead_avg: number; + lastSend: number; + uploaded: number; + dropped: number; + skipped: number; + realigned: number; + errors: number; +} + +export type StreamMeterListener = (state: Readonly, meter: StreamMeter) => void; + +const StreamMeterInitialState: StreamMeterState = { + is_up: false, + cloud_is_up: false, + downloaded: 0, + processed: 0, + overrun: 0, + wr_ahead_avg: 0, + lastSend: 0, + uploaded: 0, + dropped: 0, + skipped: 0, + realigned: 0, + errors: 0, +}; + +export class StreamMeter { + //config + config: StreamMeterConfig = { ...StreamMeterInitialConfig }; + notifyIntervalMs: number; + + private _state: StreamMeterState = { ...StreamMeterInitialState }; + private _listeners: Set = new Set(); + private _notifyTimer: ReturnType | undefined = undefined; + private _dirty = false; + + constructor(params: StreamMeterParams = {}) { + this.notifyIntervalMs = params.notifyIntervalMs ?? 100; + this.configure(params.config); + } + + configure(config?: StreamMeterConfig) { + this.config.show_cloud_link = (config && config.show_cloud_link) ?? StreamMeterInitialConfig.show_cloud_link; + } + + subscribe(listener: StreamMeterListener, emitCurrent = true) { + this._listeners.add(listener); + if (emitCurrent) listener(this.snapshot(), this); + return () => this.unsubscribe(listener); + } + + unsubscribe(listener: StreamMeterListener) { + this._listeners.delete(listener); + } + + snapshot(): StreamMeterState { + return { ...this._state }; + } + + update(patch: Partial) { + let changed = false; + const nextState: StreamMeterState = { ...this._state }; + for (const key of Object.keys(patch) as Array) { + const value = patch[key]; + if (value !== undefined && nextState[key] !== value) { + (nextState as Record)[key] = value; + changed = true; + } + } + if (!changed) return; + this._state = nextState; + this.scheduleNotify(); + } + + flush() { + if (this._notifyTimer !== undefined) { + clearTimeout(this._notifyTimer); + this._notifyTimer = undefined; + } + this.notify(); + } + + reset() { + this.update(StreamMeterInitialState); + } + + up() { + this.is_up = true; + } + + down() { + this.is_up = false; + } + + cloud_up() { + this.cloud_is_up = true; + } + + cloud_down() { + this.cloud_is_up = false; + } + + resetDownload() { + this.update({ downloaded: 0, processed: 0, overrun: 0 }); + } + + resetUpload() { + this.update({ uploaded: 0, dropped: 0, skipped: 0, realigned: 0, errors: 0 }); + } + + resetErrors() { + this.update({ dropped: 0, skipped: 0, overrun: 0, realigned: 0, errors: 0 }); + } + + get is_up() { + return this._state.is_up; + } + set is_up(value: boolean) { + this.setStateValue("is_up", value); + } + + get cloud_is_up() { + return this._state.cloud_is_up; + } + set cloud_is_up(value: boolean) { + this.setStateValue("cloud_is_up", value); + } + + get downloaded() { + return this._state.downloaded; + } + set downloaded(value: number) { + this.setStateValue("downloaded", value); + } + + get processed() { + return this._state.processed; + } + set processed(value: number) { + this.setStateValue("processed", value); + } + + get overrun() { + return this._state.overrun; + } + set overrun(value: number) { + this.setStateValue("overrun", value); + } + + get wr_ahead_avg() { + return this._state.wr_ahead_avg; + } + set wr_ahead_avg(value: number) { + this.setStateValue("wr_ahead_avg", value); + } + + get lastSend() { + return this._state.lastSend; + } + set lastSend(value: number) { + this.setStateValue("lastSend", value); + } + + get uploaded() { + return this._state.uploaded; + } + set uploaded(value: number) { + this.setStateValue("uploaded", value); + } + + get dropped() { + return this._state.dropped; + } + set dropped(value: number) { + this.setStateValue("dropped", value); + } + + get skipped() { + return this._state.skipped; + } + set skipped(value: number) { + this.setStateValue("skipped", value); + } + + get realigned() { + return this._state.realigned; + } + set realigned(value: number) { + this.setStateValue("realigned", value); + } + + get errors() { + return this._state.errors; + } + set errors(value: number) { + this.setStateValue("errors", value); + } + + private setStateValue(key: K, value: StreamMeterState[K]) { + if (this._state[key] === value) return; + this._state[key] = value; + this.scheduleNotify(); + } + + private scheduleNotify() { + if (this._listeners.size === 0) return; + + this._dirty = true; + if (this._notifyTimer !== undefined) return; + this._notifyTimer = setTimeout(() => { + this._notifyTimer = undefined; + this.notify(); + }, this.notifyIntervalMs); + } + + private notify() { + if (!this._dirty) return; + this._dirty = false; + const state = this.snapshot(); + this._listeners.forEach(listener => listener(state, this)); + } +} + +export interface StreamMeterParams { + config?: StreamMeterConfig; + notifyIntervalMs?: number; +} + +export interface StreamMeterConfig { + show_cloud_link?: boolean; +} + +const StreamMeterInitialConfig: StreamMeterConfig = { + show_cloud_link: false, +} diff --git a/packages/frontend-core/src/tests/telemetry/streamMeter.test.ts b/packages/frontend-core/src/tests/telemetry/streamMeter.test.ts new file mode 100644 index 0000000..9a0c822 --- /dev/null +++ b/packages/frontend-core/src/tests/telemetry/streamMeter.test.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from 'vitest'; +import { StreamMeter } from '@/telemetry/streamMeter'; +import type { StreamMeterState } from '@/telemetry/streamMeter'; + +describe('StreamMeter', () => { + it('has correct initial state', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1 }); + const s = meter.snapshot(); + expect(s.is_up).toBe(false); + expect(s.cloud_is_up).toBe(false); + expect(s.downloaded).toBe(0); + expect(s.processed).toBe(0); + expect(s.overrun).toBe(0); + expect(s.wr_ahead_avg).toBe(0); + expect(s.lastSend).toBe(0); + expect(s.uploaded).toBe(0); + expect(s.dropped).toBe(0); + expect(s.skipped).toBe(0); + expect(s.realigned).toBe(0); + expect(s.errors).toBe(0); + }); + + it('notifies listeners on property set and flushes immediately', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1000 }); + const received: StreamMeterState[] = []; + meter.subscribe((s) => received.push(s), false); + meter.downloaded = 5; + meter.flush(); + expect(received.length).toBe(1); + expect(received[0]!.downloaded).toBe(5); + }); + + it('update patch changes multiple fields and notifies once', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1000 }); + const received: StreamMeterState[] = []; + meter.subscribe((s) => received.push(s), false); + meter.update({ uploaded: 10, dropped: 2 }); + meter.flush(); + expect(received.length).toBe(1); + expect(received[0]!.uploaded).toBe(10); + expect(received[0]!.dropped).toBe(2); + }); + + it('reset brings counters to zero', () => { + const meter = new StreamMeter({ notifyIntervalMs: 1 }); + meter.downloaded = 7; + meter.uploaded = 3; + meter.reset(); + const s = meter.snapshot(); + expect(s.downloaded).toBe(0); + expect(s.uploaded).toBe(0); + }); +}); diff --git a/packages/frontend-core/src/utils/downloadFile.ts b/packages/frontend-core/src/utils/downloadFile.ts new file mode 100644 index 0000000..743fca2 --- /dev/null +++ b/packages/frontend-core/src/utils/downloadFile.ts @@ -0,0 +1,7 @@ +export function downloadFile(buf: any, fname: string) { + let a = document.createElement('a'); + const buffer = Buffer.from(buf); + a.href = "data:application/octet-stream;base64," + buffer.toString('base64'); + a.download = fname; + a.click(); +} diff --git a/packages/frontend-core/src/utils/index.ts b/packages/frontend-core/src/utils/index.ts new file mode 100644 index 0000000..f10973b --- /dev/null +++ b/packages/frontend-core/src/utils/index.ts @@ -0,0 +1,2 @@ +// Re-exporting all common functionalities +export { downloadFile } from "./downloadFile"; \ No newline at end of file From 2b1f385aeca19089c3687c693988ff8a32ffa915 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:44:49 +0300 Subject: [PATCH 07/13] frontend-core: add WebUSB device control base and source sink Introduce WebUsbDeviceControlBase for validated SDR parameters, streaming setup, and shared control-layer integration. Add WebUsbSourceSink for RX/TX streaming with DataSlicer buffering and StreamMeter counters, and expose the new WebUSB streaming helpers and types. Also add streaming parameter flags, expand channel masks, switch WebUSB debug logging to isDebugMode(), and add tests for control parameter validation and streaming command generation. --- .../src/tests/webusb/controlWebUsb.test.ts | 35 +- .../webusb/webUsbDeviceControlBase.test.ts | 252 +++++++++++ .../frontend-core/src/webusb/controlWebUsb.ts | 124 +++-- packages/frontend-core/src/webusb/index.ts | 27 +- .../src/webusb/streaming/webUsbSourceSink.ts | 229 ++++++++++ .../frontend-core/src/webusb/webUsb.worker.ts | 3 +- .../frontend-core/src/webusb/webUsbBase.ts | 18 +- .../src/webusb/webUsbControlApi.ts | 20 +- .../src/webusb/webUsbDeviceControlBase.ts | 427 ++++++++++++++++++ .../frontend-core/src/webusb/webUsbLimeSdr.ts | 9 +- .../frontend-core/src/webusb/webUsbManager.ts | 4 +- .../frontend-core/src/webusb/webUsbWsdr.ts | 23 +- 12 files changed, 1092 insertions(+), 79 deletions(-) create mode 100644 packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts create mode 100644 packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts create mode 100644 packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts diff --git a/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts b/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts index 079c106..8a0f357 100644 --- a/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts +++ b/packages/frontend-core/src/tests/webusb/controlWebUsb.test.ts @@ -1,5 +1,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { ControlWebUsb } from '@/webusb/controlWebUsb'; +import { + buildWebUsbStreamingParam, + ControlWebUsb, + WebUsbStreamingParamFlag, + WebUsbStreamingParamSpecial, + WebUsbStreamingSync, +} from '@/webusb/controlWebUsb'; import { WebUsbManagerMode } from '@/webusb/webUsbManager'; import { DataType } from '@websdr/core/common'; @@ -36,6 +42,28 @@ describe('ControlWebUsb', () => { delete (globalThis as any).Worker; }); + describe('buildWebUsbStreamingParam', () => { + it('should build the default start param', () => { + expect(buildWebUsbStreamingParam()).toBe(WebUsbStreamingSync.DONT_CHANGE); + }); + + it('should encode sync, stop and restart bits', () => { + expect(buildWebUsbStreamingParam({ + sync: WebUsbStreamingSync.NONE, + start: false, + restart: true, + })).toBe(WebUsbStreamingSync.NONE | WebUsbStreamingParamFlag.DO_NOT_START | WebUsbStreamingParamFlag.RESTART); + }); + + it('should return the special timestamp value as is', () => { + expect(buildWebUsbStreamingParam({ + special: WebUsbStreamingParamSpecial.DONT_TOUCH_TIMESTAMP, + sync: WebUsbStreamingSync.RX, + restart: true, + })).toBe(42); + }); + }); + describe('constructor', () => { it('should create instance with default parameters', () => { const ctrl = new ControlWebUsb(); @@ -44,9 +72,6 @@ describe('ControlWebUsb', () => { it('should create instance with custom parameters', () => { const ctrl = new ControlWebUsb({ - control_ep: 1, - control_rep_ep: 2, - notification_ep: 3, type: DataType.ci16, mode: WebUsbManagerMode.WORKER, }); @@ -263,4 +288,4 @@ describe('ControlWebUsb', () => { expect(status).toBe('STARTED'); }); }); -}); \ No newline at end of file +}); diff --git a/packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts b/packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts new file mode 100644 index 0000000..8b8b4b6 --- /dev/null +++ b/packages/frontend-core/src/tests/webusb/webUsbDeviceControlBase.test.ts @@ -0,0 +1,252 @@ +import { describe, expect, it } from 'vitest'; +import { DataType } from '@websdr/core/common'; +import { WebUsbDeviceControlBase } from '@/webusb/webUsbDeviceControlBase'; +import type { RequestKeys } from '@/webusb/controlWebUsb'; +import type { DeviceParameterKey } from '@/webusb/webUsbDeviceControlBase'; +import { DeviceStreamType, WebUsbDirection } from '@/webusb/deviceParameters'; +import type { DeviceConfiguration } from '@/webusb/deviceParameters'; + +const makeConfiguration = (operationModes: WebUsbDirection): DeviceConfiguration => ({ + operationModes, + defaultSamplesCount: 1024, + rxFrequencyRange: { min: 100, max: 200 }, + txFrequencyRange: { min: 300, max: 400 }, + bandwidthRange: { min: 10, max: 20 }, + rateRange: { min: 1000, max: 2000 }, + streamTypes: { [DeviceStreamType.raw]: { dataTypes: [DataType.ci16] } }, + txRxDelay: 0, + warmupPackets: 0, +}); + +describe('WebUsbDeviceControlBase', () => { + it('validates RX parameters against device ranges', () => { + const params = new WebUsbDeviceControlBase({}, makeConfiguration(WebUsbDirection.RX)); + + params.setRxFrequency(150); + params.setRxBandwidth(15); + params.rate = 1500; + + expect(params.rx.frequency).toBe(150); + expect(params.rx.bandwidth).toBe(15); + expect(params.rate).toBe(1500); + expect(params.state.rx).toEqual({ frequency: 150, bandwidth: 15, gain: 15 }); + expect(() => params.setRxFrequency(250)).toThrow(/RX frequency/); + }); + + it('rejects TX parameters for RX-only devices', () => { + const params = new WebUsbDeviceControlBase({}, makeConfiguration(WebUsbDirection.RX)); + + expect(params.getSupportedStreamingMode(WebUsbDirection.RX_TX)).toBe(WebUsbDirection.RX); + expect(() => params.setTxFrequency(350)).toThrow(/not supported/); + expect(() => params.ensureDirection(WebUsbDirection.TX, 'TX data')).toThrow(/not supported/); + }); + + it('validates only directions used for streaming', () => { + const params = new WebUsbDeviceControlBase({ + rate: 1500, + rx: { + frequency: 150, + bandwidth: 15, + }, + tx: { + frequency: 0, + bandwidth: 0, + }, + }, makeConfiguration(WebUsbDirection.RX)); + + expect(() => params.validateForStreaming(WebUsbDirection.RX)).not.toThrow(); + }); + + it('accepts nested direction initial params', () => { + const params = new WebUsbDeviceControlBase({ + rx: { + frequency: 150, + bandwidth: 15, + gain: 7, + }, + }, makeConfiguration(WebUsbDirection.RX)); + + expect(params.state.rx).toEqual({ frequency: 150, bandwidth: 15, gain: 7 }); + }); + + it('calls change hook after successful parameter updates', () => { + class HookedConfigurator extends WebUsbDeviceControlBase { + changes: Array<{ parameter: DeviceParameterKey; value: number }> = []; + + protected onParameterChanged(parameter: DeviceParameterKey, value: number) { + this.changes.push({ parameter, value }); + } + } + + const params = new HookedConfigurator({}, makeConfiguration(WebUsbDirection.RX_TX)); + + params.setRxFrequency(150); + params.setTxGain(4); + + expect(params.changes).toEqual([ + { parameter: 'rx.frequency', value: 150 }, + { parameter: 'tx.gain', value: 4 }, + ]); + }); + + it('syncs changed device parameters through the control layer when open', () => { + class ControlBackedConfigurator extends WebUsbDeviceControlBase { + parameters: Array<{ parameter: RequestKeys; args: Record; now: boolean }> = []; + + protected isControlOpen() { + return true; + } + + protected async setControlParameter( + parameter: RequestKeys, + args: (() => Record) | Record, + now = false, + ) { + this.parameters.push({ + parameter, + args: (typeof args === 'function' ? args() : args) as Record, + now, + }); + } + } + + const params = new ControlBackedConfigurator({}, makeConfiguration(WebUsbDirection.RX_TX)); + + params.setRxFrequency(150); + params.setTxBandwidth(15); + params.rate = 1500; + + expect(params.parameters).toEqual([ + { parameter: 'SET_RX_FREQUENCY', args: { frequency: 150 }, now: true }, + { parameter: 'SET_TX_BANDWIDTH', args: { frequency: 15 }, now: true }, + ]); + }); + + it('starts and stops device streaming through the control layer', async () => { + class StreamingConfigurator extends WebUsbDeviceControlBase { + commands: Array<{ command: RequestKeys; args: Record }> = []; + parameters: Array<{ parameter: RequestKeys; args: Record; now: boolean }> = []; + + async prepare() { + return this.prepareDeviceStreaming(); + } + + async start() { + return this.startDeviceStreaming(); + } + + async startPrepared() { + await this.startPreparedDeviceStreaming(); + } + + async stop() { + await this.stopDeviceStreaming(); + } + + protected async sendControlCommand(command: RequestKeys, args = {}) { + this.commands.push({ command, args }); + return {}; + } + + protected async getDeviceRxSamplesCount(samples: number): Promise { + return samples * 2; + } + + protected async setControlParameter( + parameter: RequestKeys, + args: (() => Record) | Record, + now = false, + ) { + this.parameters.push({ + parameter, + args: (typeof args === 'function' ? args() : args) as Record, + now, + }); + } + } + + const params = new StreamingConfigurator({ + rate: 1500, + throttleon: 10, + rx: { frequency: 150, bandwidth: 15, gain: 3 }, + tx: { frequency: 350, bandwidth: 16, gain: 4 }, + }, makeConfiguration(WebUsbDirection.RX_TX)); + + await expect(params.prepare()).resolves.toEqual({ + mode: WebUsbDirection.RX_TX, + packetSize: 2048, + }); + await params.startPrepared(); + await params.stop(); + + expect(params.commands).toEqual([ + { + command: 'START_STREAMING', + args: { + samplerate: 1500, + packetsize: 2048, + throttleon: 10, + param: 31, + mode: WebUsbDirection.RX_TX, + }, + }, + { command: 'CONTROL_STREAMING', args: { samplerate: 0, throttleon: 0, param: 0 } }, + { command: 'STOP_STREAMING', args: {} }, + ]); + expect(params.parameters).toEqual([ + { parameter: 'SET_RX_FREQUENCY', args: { frequency: 150 }, now: true }, + { parameter: 'SET_RX_BANDWIDTH', args: { frequency: 15 }, now: true }, + { parameter: 'SET_RX_GAIN', args: { gain: 3 }, now: true }, + { parameter: 'SET_TX_FREQUENCY', args: { frequency: 350 }, now: true }, + { parameter: 'SET_TX_BANDWIDTH', args: { frequency: 16 }, now: true }, + { parameter: 'SET_TX_GAIN', args: { gain: 4 }, now: true }, + ]); + }); + + it('starts device streaming immediately when using start helper', async () => { + class StreamingConfigurator extends WebUsbDeviceControlBase { + commands: Array<{ command: RequestKeys; args: Record }> = []; + + async start() { + return this.startDeviceStreaming(); + } + + protected async sendControlCommand(command: RequestKeys, args = {}) { + this.commands.push({ command, args }); + return {}; + } + + protected async getDeviceRxSamplesCount(samples: number): Promise { + return samples * 2; + } + + protected async setControlParameter() { + } + } + + const params = new StreamingConfigurator({ + rate: 1500, + throttleon: 10, + rx: { frequency: 150, bandwidth: 15 }, + tx: { frequency: 350, bandwidth: 16 }, + }, makeConfiguration(WebUsbDirection.RX_TX)); + + await expect(params.start()).resolves.toEqual({ + mode: WebUsbDirection.RX_TX, + packetSize: 2048, + }); + + expect(params.commands).toEqual([ + { + command: 'START_STREAMING', + args: { + samplerate: 1500, + packetsize: 2048, + throttleon: 10, + param: 23, + mode: WebUsbDirection.RX_TX, + }, + }, + ]); + }); +}); diff --git a/packages/frontend-core/src/webusb/controlWebUsb.ts b/packages/frontend-core/src/webusb/controlWebUsb.ts index c563821..7e04925 100644 --- a/packages/frontend-core/src/webusb/controlWebUsb.ts +++ b/packages/frontend-core/src/webusb/controlWebUsb.ts @@ -1,14 +1,13 @@ import { DataType, CHUNK_SIZE } from '@websdr/core/common'; -// import { Buffer } from 'buffer'; import { base64ToUint8Array, uint8ArrayToBase64 } from '@websdr/core/transform'; import { sleep } from '@websdr/core/utils'; -import { NngWebSocket, Protocol } from '@/common/nngWebSocket'; +import { NngWebSocket, Protocol } from '@/transport/nngWebSocket'; import { getWebUsbManagerInstance, WebUsbManager, WebUsbManagerMode } from './webUsbManager'; import { WebUsbDirection } from './deviceParameters'; -import { WebUsbEndpoints } from './webUsbBase' import type { StreamStatus } from './webUsbBase' +import { isDebugMode } from '@/common/debug'; const debug_control = false; @@ -29,7 +28,68 @@ interface DeferredParameter { export enum WebUsbChannels { CHAN1 = 1 << 0, CHAN2 = 1 << 1, - ALL_CHANS = CHAN1 | CHAN2, + CHAN3 = 1 << 2, + CHAN4 = 1 << 3, + CHAN5 = 1 << 4, + CHAN6 = 1 << 5, + CHAN7 = 1 << 6, + CHAN8 = 1 << 7, + ALL_CHANS = CHAN1 | CHAN2 | CHAN3 | CHAN4 | CHAN5 | CHAN6 | CHAN7 | CHAN8, +} + +export enum WebUsbStreamingSync { + /* Don't change the current synchronization state */ + DONT_CHANGE = 0, + /* Synchronize streaming to an external 1PPS signal. + * Device will attempt to align the start of streaming to the rising edge of the 1PPS signal, + * and maintain alignment throughout streaming session. + * If synchronization is lost (e.g. due to weak 1PPS signal), + * device will attempt to resynchronize on the next 1PPS edge. + */ + PPS1 = 1, + /* Synchronize streaming by RX signal */ + RX = 2, + /* Synchronize streaming by TX signal */ + TX = 3, + /* Synchronize streaming by any (1PPS, RX or TX signals) */ + ANY = 5, + /* Streaming without synchronization */ + NONE = 7, +} + +export enum WebUsbStreamingParamFlag { + /* For START_STREAMING: if set, streaming will not start until a separate + * START_STREAMING command with this flag cleared is sent + */ + DO_NOT_START = 0x8, + /* For START_STREAMING: if set, streaming will restart (stop and start again) + * if already started + */ + RESTART = 0x10, +} + +export enum WebUsbStreamingParamSpecial { + /* Special streaming parameter value which can be used with CONTROL_STREAMING + * command to indicate that the timestamp should not be modified + */ + DONT_TOUCH_TIMESTAMP = 42, +} + +export interface WebUsbStreamingParamOptions { + sync?: WebUsbStreamingSync; + start?: boolean; + restart?: boolean; + special?: WebUsbStreamingParamSpecial; +} + +export function buildWebUsbStreamingParam(options: WebUsbStreamingParamOptions = {}): number { + if (options.special !== undefined) return options.special; + + let param = options.sync ?? WebUsbStreamingSync.DONT_CHANGE; + if (options.start === false) param |= WebUsbStreamingParamFlag.DO_NOT_START; + if (options.restart === true) param |= WebUsbStreamingParamFlag.RESTART; + + return param; } export class ControlWebUsb extends EventTarget { @@ -111,7 +171,6 @@ export class ControlWebUsb extends EventTarget { param: 0, mode: WebUsbDirection.RX_TX, dataformat: DataType.ci16, - // stream_type: ControlStreamType.raw, //right now just for behemoth daemon }, }, STOP_STREAMING: { @@ -122,7 +181,7 @@ export class ControlWebUsb extends EventTarget { req_params: { samplerate: 1e6, throttleon: 10e6, - param: 42, + param: WebUsbStreamingParamSpecial.DONT_TOUCH_TIMESTAMP, }, }, GET_SENSOR: { @@ -188,9 +247,6 @@ export class ControlWebUsb extends EventTarget { }; private fd: number = -1; - protected control_ep: number; - protected control_rep_ep: number; - protected notification_ep: number; protected type: DataType; protected commands: Record = {}; protected parameters: Record = {}; @@ -210,14 +266,9 @@ export class ControlWebUsb extends EventTarget { constructor(params: ControlWebUsbParams = ControlWebUsbInitialParams) { super() - this.control_ep = params.control_ep !== undefined ? params.control_ep : ControlWebUsbInitialParams.control_ep!; - this.control_rep_ep = params.control_rep_ep !== undefined ? params.control_rep_ep : ControlWebUsbInitialParams.control_rep_ep!; - this.notification_ep = params.notification_ep !== undefined ? params.notification_ep : ControlWebUsbInitialParams.notification_ep!; this.type = params.type !== undefined ? params.type : ControlWebUsbInitialParams.type!; this._debugServer = params.debugServer !== undefined ? params.debugServer : ControlWebUsbInitialParams.debugServer!; this._mode = params.mode !== undefined ? params.mode : ControlWebUsbInitialParams.mode!; - if (this._mode !== WebUsbManagerMode.UNKNOWN) - this._webUsbManager = getWebUsbManagerInstance(this._mode); this._onControlOpen = this.onControlOpen.bind(this) this._onDebugWSMessage = this.onDebugWSMessage.bind(this) this._onDebugWSOpen = this.onDebugWSOpen.bind(this) @@ -229,9 +280,15 @@ export class ControlWebUsb extends EventTarget { this._webUsbManager = webUsbManager; } + protected getWebUsbManager(): WebUsbManager | undefined { + if (!this._webUsbManager && this._mode !== WebUsbManagerMode.UNKNOWN) { + this._webUsbManager = getWebUsbManagerInstance(this._mode); + } + return this._webUsbManager; + } + getRequest(req: Record, args = {}, ext_args = {}) { let ret = req - // ret.id = '12345'; if (ret.req_params) Object.assign(ret.req_params, args) Object.assign(ret, ext_args) @@ -249,7 +306,7 @@ export class ControlWebUsb extends EventTarget { } async setParameter(parm: RequestKeys, args: (() => Record) | Record, now = false) { - if (globalThis.debug_mode || debug_control) + if (isDebugMode() || debug_control) console.log('ControlWebUsb.setParameter(', parm, ', ', args, '): ') if (now) { await this.setParameterNow(parm, args); @@ -283,7 +340,7 @@ export class ControlWebUsb extends EventTarget { } async setSdrParameter(path: string, value: string | bigint | number | undefined): Promise { - if (globalThis.debug_mode || debug_control) + if (isDebugMode() || debug_control) console.log('ControlWebUsb.setSdrParameter(', path, ', ', value, '): ') const data = await this.sendCommand('SET_PARAMETER', { path, value }); if (!data || data.result !== 0) { @@ -292,7 +349,7 @@ export class ControlWebUsb extends EventTarget { } async getSdrParameter(path: string): Promise { - if (globalThis.debug_mode || debug_control) + if (isDebugMode() || debug_control) console.log('ControlWebUsb.getSdrParameter(', path, '): ') const data = await this.sendCommand('GET_PARAMETER', { path }); if (data && data.result === 0 && data.details?.path === path) { @@ -300,11 +357,11 @@ export class ControlWebUsb extends EventTarget { } else { throw new Error(`ControlWebUsb.getSdrParameter: Error getting parameter ${path}`); } - // return undefined; //??? } async sendRawCommand(req: Record): Promise> { - return this._webUsbManager ? await this._webUsbManager.sendCommand(this.fd, req) : {}; + const webUsbManager = this.getWebUsbManager(); + return webUsbManager ? await webUsbManager.sendCommand(this.fd, req) : {}; } async sendCommand(cmd: RequestKeys, args = {}, ext_args = {}) { @@ -331,13 +388,13 @@ export class ControlWebUsb extends EventTarget { } const req = this.getRequest(ControlWebUsb.Requests[cmd], args, ext_args); // console.log('REQUEST', req); - if (globalThis.debug_mode || debug_control) { + if (isDebugMode() || debug_control) { this._start_ms = Date.now(); console.log('1. ControlWebUsb.sendCommand(', cmd, ', ', args, ', ', ext_args, '): req =', req); } const data = await this.sendRawCommand(req); // console.log('DATA', data); - if (globalThis.debug_mode || debug_control) { + if (isDebugMode() || debug_control) { this._end_ms = Date.now(); console.log('2. ControlWebUsb.sendCommand(', cmd, ', ', args, ', ', ext_args, '): data =', data, 'duration', this._end_ms - this._start_ms); } @@ -521,20 +578,23 @@ export class ControlWebUsb extends EventTarget { } async getStreamStatus(): Promise { - if (this.fd < 0 || !this._webUsbManager) return 'INVALID' - return await this._webUsbManager.getStreamStatus(this.fd); + const webUsbManager = this.getWebUsbManager(); + if (this.fd < 0 || !webUsbManager) return 'INVALID' + return await webUsbManager.getStreamStatus(this.fd); } async setStreamStatus(status: StreamStatus) { - if (this.fd < 0 || !this._webUsbManager) return; - await this._webUsbManager.setStreamStatus(this.fd, status); + const webUsbManager = this.getWebUsbManager(); + if (this.fd < 0 || !webUsbManager) return; + await webUsbManager.setStreamStatus(this.fd, status); } async onDebugWSMessage(event: Event) { - if (this._webUsbManager) { + const webUsbManager = this.getWebUsbManager(); + if (webUsbManager) { const data = (event as MessageEvent).data; console.warn('Received debug command:', data); - const res = await this._webUsbManager.sendDebugCommand(this.fd, data); + const res = await webUsbManager.sendDebugCommand(this.fd, data); console.warn('Reply to debug command:', res); await this._debugWS?.send(res); } @@ -556,19 +616,13 @@ export class ControlWebUsb extends EventTarget { } export interface ControlWebUsbParams { - control_ep?: number, - control_rep_ep?: number, - notification_ep?: number, type?: DataType, debugServer?: string, mode?: WebUsbManagerMode; } export const ControlWebUsbInitialParams: ControlWebUsbParams = { - control_ep: WebUsbEndpoints.CONTROL_EP, - control_rep_ep: WebUsbEndpoints.CONTROL_EP, - notification_ep: WebUsbEndpoints.NOTIFY_EP, type: DataType.cf32, debugServer: '', mode: WebUsbManagerMode.WORKER, -} \ No newline at end of file +} diff --git a/packages/frontend-core/src/webusb/index.ts b/packages/frontend-core/src/webusb/index.ts index a276265..998a0d3 100644 --- a/packages/frontend-core/src/webusb/index.ts +++ b/packages/frontend-core/src/webusb/index.ts @@ -4,9 +4,20 @@ import './webUsbDevices.autogen'; // Re-exporting all types from WebUsb module export { - WebUsbChannels, ControlWebUsb, ControlWebUsbInitialParams + buildWebUsbStreamingParam, + ControlWebUsb, + ControlWebUsbInitialParams, + WebUsbChannels, + WebUsbStreamingParamFlag, + WebUsbStreamingParamSpecial, + WebUsbStreamingSync, +} from './controlWebUsb'; +export type { + ControlWebUsbParams, + RequestKeys, + WebUsbDeviceInfo, + WebUsbStreamingParamOptions, } from './controlWebUsb'; -export type { WebUsbDeviceInfo, RequestKeys, ControlWebUsbParams } from './controlWebUsb'; export { SDRDevicesIds, getDeviceHash, registerWebUsbInstance, getWebUsbInstance @@ -20,6 +31,16 @@ export type { DeviceParamRange, DeviceStreamParameters, DeviceStreamTypes, DeviceDataTypes, DeviceConfiguration } from './deviceParameters'; +export { WebUsbDeviceControlBase } from './webUsbDeviceControlBase'; +export type { + DeviceDirectionParameterState, + DeviceParameterInitialState, + DeviceParameterKey, + DeviceParameterState, + DeviceStreamingStartOptions, + DeviceStreamingStartResult, + WebUsbDeviceControlBaseParams, +} from './webUsbDeviceControlBase'; export { CommandQueue } from './commandQueue'; export type { CommandRequest } from './commandQueue'; export { WebUsbEndpoints, WebUsb } from './webUsbBase'; @@ -32,3 +53,5 @@ export type { WebUsbManagerParams } from './webUsbDeviceManager'; export { WebUsbManagerMode, getWebUsbManagerInstance, WebUsbManager } from './webUsbManager'; export type { RequestDeviceInfo } from './webUsbManager'; export { ensureWebUsb } from './ensureWebUsb'; +export { WebUsbSourceSink } from './streaming/webUsbSourceSink'; +export type { WebUsbSourceSinkParams } from './streaming/webUsbSourceSink'; \ No newline at end of file diff --git a/packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts b/packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts new file mode 100644 index 0000000..4b80eab --- /dev/null +++ b/packages/frontend-core/src/webusb/streaming/webUsbSourceSink.ts @@ -0,0 +1,229 @@ +import { WebUsbDirection } from '@/webusb/deviceParameters'; +import { WebUsbManagerMode } from '@/webusb/webUsbManager'; +import { StreamMeter } from '@/telemetry/streamMeter'; +import { DefaultDeviceConfiguration } from '@/webusb/deviceParameters'; +import { WebUsbDeviceControlBase, WebUsbDeviceControlBaseInitialParams } from '@/webusb/webUsbDeviceControlBase'; +import type { WebUsbDeviceControlBaseParams } from '@/webusb/webUsbDeviceControlBase'; +import type { RXBuffer, RXDecoderOptions, TXResult } from '@/webusb/webUsbBase'; +import { DataType } from '@websdr/core/common'; +import { DataSlicer } from '@websdr/core/utils'; + + +export class WebUsbSourceSink extends WebUsbDeviceControlBase { + static MAX_IN_STREAM = 256;//128; + protected _dataSlicer: DataSlicer = new DataSlicer(); + protected _in_stream = 0; + protected _max_in_stream = 0; + protected _stream_started = false; + protected _onData: (buf: SharedArrayBuffer, overrun: number, timestamp: bigint) => void; + protected _onReceiveData: (data: RXBuffer) => Promise; + protected _onReceiveError: (err: any) => void; + protected _onTransmitData: (res: TXResult) => void; + protected _onTransmitError: (err: any) => void; + protected _debugTimer: string | number | NodeJS.Timeout | undefined = undefined; + protected _discard_timestamp: boolean = false; + protected _firstTimestamp: bigint | undefined = undefined; + protected _streamMeterData: StreamMeter | undefined = undefined; + protected _streamingPacketSize: number = 0; + protected _warmupCounter = 0; + + constructor(params: WebUsbSourceSinkParams = WebUsbSourceSinkInitialParams) { + super({ ...params, mode: WebUsbManagerMode.SINGLE }, DefaultDeviceConfiguration); + this._streamMeterData = params.streamMeterData; + this._onData = params.onData !== undefined ? params.onData : WebUsbSourceSinkInitialParams.onData!; + this._onReceiveData = this.onReceiveData.bind(this); + this._onReceiveError = this.onReceiveError.bind(this); + this._onTransmitData = this.onTransmitData.bind(this); + this._onTransmitError = this.onTransmitError.bind(this); + this.resetStreamMeter(); + this._dataSlicer = new DataSlicer({ datatype: DataType.ci16, bufferSamplesSize: this.packet_size, buffersCount: WebUsbSourceSink.MAX_IN_STREAM << 1 }) + } + + get rx_frequency() { + return this.rx.frequency; + } + + set rx_frequency(value: number) { + this.setRxFrequency(value); + } + + get tx_frequency() { + return this.tx.frequency; + } + + set tx_frequency(value: number) { + this.setTxFrequency(value); + } + + get rx_bandwidth() { + return this.rx.bandwidth; + } + + set rx_bandwidth(value: number) { + this.setRxBandwidth(value); + } + + get tx_bandwidth() { + return this.tx.bandwidth; + } + + set tx_bandwidth(value: number) { + this.setTxBandwidth(value); + } + + get rx_gain() { + return this.rx.gain; + } + + set rx_gain(value: number) { + this.setRxGain(value); + } + + get tx_gain() { + return this.tx.gain; + } + + set tx_gain(value: number) { + this.setTxGain(value); + } + + resetStreamMeter() { + this._streamMeterData?.reset(); + } + + async open(fd: number) { + await this.openDevice(fd); + this._streamMeterData?.up(); + } + + close() { + void this.closeDevice(); + this._streamMeterData?.down(); + } + + async start() { + const { packetSize } = await this.prepareDeviceStreaming(); + this._streamingPacketSize = packetSize; + } + + async stop() { + this.stopStream(); + } + + async startStream() { + if (this._stream_started) return; + this._stream_started = true; + this._in_stream = 0; + this._warmupCounter = this.configuration.warmupPackets; + this._firstTimestamp = undefined; + this._max_in_stream = WebUsbSourceSink.MAX_IN_STREAM; + // console.log(`START STREAMING AT ${Date.now()}`) + + // await this.sendControlCommand('CALIBRATE', { param: 15 }); + await this.startDataPoll(); + this.schedulePreparedDeviceStreamingStart(1000); + // this._debugTimer = setInterval(() => {this.sendControlCommand('DEBUG_DUMP')}, 10) + } + + async stopStream() { + if (!this._stream_started) return; + this._stream_started = false; + clearInterval(this._debugTimer); + this._debugTimer = undefined; + this._in_stream = 0; + this._max_in_stream = 0; + await this.stopDeviceStreaming(); + } + + async startDataPoll() { + if (!this.hasOpenDevice || !this._stream_started) { + console.error('startDataPoll: fd', this.fd, 'stream_started', this._stream_started) + return; + } + const opts: RXDecoderOptions = { datatype: DataType.ci16 }; + while (this._in_stream < this._max_in_stream) { + this.submitDeviceRxPacket(this._streamingPacketSize, opts) + .then(this._onReceiveData) + .catch(this._onReceiveError) + ++this._in_stream; + } + } + + async sendData(buf: SharedArrayBuffer, offset: number, byteLength: number, datatype: DataType, timestamp?: bigint, sliceSamples?: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX data'); + // console.log('sendData', timestamp) + return this.sendDeviceTxPacket( + { + data: buf, + byteOffset: offset, + byteLength: byteLength, + datatype: datatype, + discard_timestamp: this._discard_timestamp, + timestamp: (timestamp || BigInt(0n)) - BigInt(this.configuration.txRxDelay) + (this._firstTimestamp || BigInt(0)) + }, + { sliceSamples: sliceSamples }) + .then(this._onTransmitData) + .catch(this._onTransmitError) + } + + async onReceiveData(data: RXBuffer) { + if (this._warmupCounter > 0) { + --this._warmupCounter; + if (this._in_stream > 0) --this._in_stream; + if (this._stream_started) this.startDataPoll(); + return; + } + if (this._firstTimestamp === undefined) { + console.warn('Starting accepting messages...') + this._firstTimestamp = data.timestamp; + } + // console.log('RECEIVED DATA', data) + if (this._streamMeterData) { + this._streamMeterData.downloaded += data.recvsize; + this._streamMeterData.overrun += data.overrun; + this._streamMeterData.realigned = data.realigned; + this._streamMeterData.dropped = data.dropped; + } + this._dataSlicer.pushBack(data.data, 0, undefined, data.overrun, data.timestamp - this._firstTimestamp/* this._timestamp */); + while (this._dataSlicer.size() > 0) { + const dataItem = this._dataSlicer.front(); + if (this._onData && dataItem) this._onData(dataItem.buffer, dataItem.overrun, dataItem.timestamp); + this._dataSlicer.pop_front(); + } + if (this._in_stream > 0) --this._in_stream; + if (this._stream_started) this.startDataPoll(); + } + + async onReceiveError(err: any) { + if (this._in_stream > 0) --this._in_stream; + if (this._stream_started) { + console.error('WebUsbSourceSink.receiveData error:', err) + this.startDataPoll(); + } + } + + onTransmitData(res: TXResult) { + if (res !== undefined && res.usbOutTransferResult !== undefined + && res.usbOutTransferResult.status === 'ok' && res.usbOutTransferResult.bytesWritten !== undefined) { + if (this._streamMeterData) this._streamMeterData.uploaded += res.usbOutTransferResult.bytesWritten; + } + } + + onTransmitError(err: any) { + if (this._stream_started) { + // console.error('WebUsbSourceSink.sendData error:', err) + if (this._streamMeterData) ++this._streamMeterData.errors; + } + } +} + +export interface WebUsbSourceSinkParams extends WebUsbDeviceControlBaseParams { + streamMeterData?: StreamMeter; + onData?: (buf: SharedArrayBuffer, overrun: number, timestamp: bigint) => void; +} + +export const WebUsbSourceSinkInitialParams: WebUsbSourceSinkParams = { + ...WebUsbDeviceControlBaseInitialParams, + streamMeterData: undefined, + onData: () => { }, +} diff --git a/packages/frontend-core/src/webusb/webUsb.worker.ts b/packages/frontend-core/src/webusb/webUsb.worker.ts index d137cbf..f75ffa2 100644 --- a/packages/frontend-core/src/webusb/webUsb.worker.ts +++ b/packages/frontend-core/src/webusb/webUsb.worker.ts @@ -5,6 +5,7 @@ import type { WebUsbWorkerResponse, WebUsbRequestType, } from './webUsb.worker.types'; +import { isDebugMode } from '@/common/debug'; // hoist reusable sets to module scope to avoid recreating them per message const NON_MANAGER_TYPES: ReadonlySet = new Set([ @@ -37,7 +38,7 @@ self.onmessage = async (event: MessageEvent) => { } try { - if (globalThis.debug_mode) console.log('Message from WebUsb', msg); + if (isDebugMode()) console.log('Message from WebUsb', msg); let dev: WebUsb | undefined = undefined; let ret: any; diff --git a/packages/frontend-core/src/webusb/webUsbBase.ts b/packages/frontend-core/src/webusb/webUsbBase.ts index 664b0b5..bb756b5 100644 --- a/packages/frontend-core/src/webusb/webUsbBase.ts +++ b/packages/frontend-core/src/webusb/webUsbBase.ts @@ -7,6 +7,7 @@ import { DataType } from '@websdr/core/common'; import { COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE } from '@websdr/core/common'; import { bufferF32ToI16, bufferI16ToF32 } from '@websdr/core/transform'; import { sleep } from '@websdr/core/utils'; +import { isDebugMode } from '@/common/debug'; const debug_webusb = false; @@ -46,7 +47,6 @@ export interface RXBuffer { * Optional parameters passed to `decodeRxData` to control decoding. */ export interface RXDecoderOptions { - extra_meta?: boolean, // If true, driver should include extra metadata datatype?: DataType, // Hint/override for expected incoming data type data?: ArrayBufferLike, // Optional pre-fetched data buffer to decode id?: number, // Optional id propagated for debugging/traceability @@ -248,7 +248,7 @@ export abstract class WebUsb extends EventTarget { * configuration (control transfers etc.). */ async open(device?: USBDevice): Promise { - if (debug_webusb) console.log('WebUsbBase.open()') + if (isDebugMode() || debug_webusb) console.log('WebUsbBase.open()') navigator.usb.removeEventListener("connect", this._onConnect); navigator.usb.removeEventListener("disconnect", this._onDisconnect); navigator.usb.addEventListener("connect", this._onConnect); @@ -256,17 +256,17 @@ export abstract class WebUsb extends EventTarget { this.device = device; if (!this.device) { const devices = await navigator.usb.getDevices(); - if (debug_webusb) console.log('DEVICES', devices) + if (isDebugMode() || debug_webusb) console.log('DEVICES', devices) for (let device of devices) { - if (debug_webusb) console.log('DEVICE', device, this.vid, this.pid) + if (isDebugMode() || debug_webusb) console.log('DEVICE', device, this.vid, this.pid) if (device.vendorId === this.vid && device.productId === this.pid) { this.device = device; - if (debug_webusb) console.log('FOUND DEVICE', device) + if (isDebugMode() || debug_webusb) console.log('FOUND DEVICE', device) break; } } } - if (globalThis.debug_mode || debug_webusb) console.log('WebUsbBase.device', this.device) + if (isDebugMode() || debug_webusb) console.log('WebUsbBase.device', this.device) // Ensure TX manager is usable after open (recreate if it was closed) if (this._txManager?.isClosed()) { this._initTxManager(); @@ -287,7 +287,7 @@ export abstract class WebUsb extends EventTarget { * commands and release resources held by the control module. */ async close() { - if (debug_webusb) console.log('WebUsbBase.close()') + if (isDebugMode() || debug_webusb) console.log('WebUsbBase.close()') navigator.usb.removeEventListener("connect", this._onConnect); navigator.usb.removeEventListener("disconnect", this._onDisconnect); this._commandQueue.clear(); @@ -540,7 +540,7 @@ export abstract class WebUsb extends EventTarget { * simply logs in debug mode. */ async onConnect(usb: USB, event: USBConnectionEvent) { - if (globalThis.debug_mode) + if (isDebugMode()) console.log(`WebUsb: connection to device ${this.device?.vendorId}:${this.device?.productId} established`); this.dispatchEvent(new Event('connect', event)); } @@ -550,7 +550,7 @@ export abstract class WebUsb extends EventTarget { * logs the event; drivers should perform cleanup when appropriate. */ async onDisconnect(usb: USB, event: USBConnectionEvent) { - if (globalThis.debug_mode) + if (isDebugMode()) console.log(`WebUsb: connection to device ${this.device?.vendorId}:${this.device?.productId} has been closed`); this.dispatchEvent(new Event('disconnect', event)); } diff --git a/packages/frontend-core/src/webusb/webUsbControlApi.ts b/packages/frontend-core/src/webusb/webUsbControlApi.ts index 0448f34..8cb44b0 100644 --- a/packages/frontend-core/src/webusb/webUsbControlApi.ts +++ b/packages/frontend-core/src/webusb/webUsbControlApi.ts @@ -1,12 +1,12 @@ +import { isDebugMode } from "@/common/debug"; import { WebUsbEndpoints } from "./webUsbBase"; -// import { WASMErrno } from "@/common/wasmErrno"; const debug_ep_log = false; const debug_write_log = false; export async function write_ep1(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`write_ep1(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.write) { @@ -14,7 +14,7 @@ export async function write_ep1(fd: number, data: number, len: number): Promise< return 0; } const buf = new Uint8Array(dev.module.HEAPU8.buffer, ((data) >> 0), len); - if (globalThis.debug_mode) console.log(buf.subarray(0, 10)) + if (isDebugMode()) console.log(buf.subarray(0, 10)) dev.write(WebUsbEndpoints.CONTROL_EP, buf as BufferSource); // const end = Date.now(); // console.log(`write_ep1(${fd}, ${data}, ${len}): duration = ${end - start}`) @@ -23,7 +23,7 @@ export async function write_ep1(fd: number, data: number, len: number): Promise< export async function write_ep2(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`write_ep2(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.write) { @@ -31,7 +31,7 @@ export async function write_ep2(fd: number, data: number, len: number): Promise< return 0; } const buf = new Uint8Array(dev.module.HEAPU8.buffer, ((data) >> 0), len); - if (globalThis.debug_mode) console.log(buf.subarray(0, 10)) + if (isDebugMode()) console.log(buf.subarray(0, 10)) dev.write(WebUsbEndpoints.NOTIFY_EP, buf as BufferSource); // const end = Date.now(); // console.log(`write_ep2(${fd}, ${data}, ${len}): duration = ${end - start}`) @@ -40,7 +40,7 @@ export async function write_ep2(fd: number, data: number, len: number): Promise< export async function read_ep1(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`read_ep1(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.read) { @@ -55,7 +55,7 @@ export async function read_ep1(fd: number, data: number, len: number): Promise> 0), len); const readbackvalue = new Uint8Array(result.data.buffer); buf.set(readbackvalue); - if (globalThis.debug_mode) + if (isDebugMode()) console.log(` => rb ${readbackvalue}`); return readbackvalue.length; } @@ -64,7 +64,7 @@ export async function read_ep1(fd: number, data: number, len: number): Promise { // const start = Date.now(); - if (globalThis.debug_mode || debug_ep_log) + if (isDebugMode() || debug_ep_log) console.log(`read_ep2(${fd}, ${data}, ${len}): `/* start = ${start}` */) const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module || !dev.read) { @@ -79,7 +79,7 @@ export async function read_ep2(fd: number, data: number, len: number): Promise> 0), len); const readbackvalue = new Uint8Array(result.data.buffer); buf.set(readbackvalue); - if (globalThis.debug_mode) + if (isDebugMode()) console.log(` => ntfy ${readbackvalue}`); return readbackvalue.length; } @@ -87,7 +87,7 @@ export async function read_ep2(fd: number, data: number, len: number): Promise { - if (globalThis.debug_mode || debug_write_log) { + if (isDebugMode() || debug_write_log) { const dev = globalThis.webUsbDeviceManager?.getDevice(fd); if (!dev || !dev.module) return 0; var s = dev.module.AsciiToString(str); diff --git a/packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts b/packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts new file mode 100644 index 0000000..4ef2b22 --- /dev/null +++ b/packages/frontend-core/src/webusb/webUsbDeviceControlBase.ts @@ -0,0 +1,427 @@ +import { CHUNK_SIZE, DataType } from '@websdr/core/common'; +import { + buildWebUsbStreamingParam, + ControlWebUsb, + ControlWebUsbInitialParams, + WebUsbStreamingSync, + type ControlWebUsbParams, + type RequestKeys, +} from './controlWebUsb'; +import { + DefaultDeviceConfiguration, + WebUsbDirection, +} from './deviceParameters'; +import { getWebUsbManagerInstance, WebUsbManager, WebUsbManagerMode } from './webUsbManager'; +import type { + RXBuffer, + RXDecoderOptions, + TXBuffer, + TXEncoderOptions, + TXResult, +} from './webUsbBase'; +import type { + DeviceConfiguration, + DeviceParamRange, +} from './deviceParameters'; + +export interface DeviceDirectionParameterState { + frequency: number; + bandwidth: number; + gain: number; +} + +export interface DeviceParameterState { + rate: number; + packet_size: number; + throttleon: number; + rx: DeviceDirectionParameterState; + tx: DeviceDirectionParameterState; +} + +export type DeviceParameterInitialState = Partial> & { + rx?: Partial; + tx?: Partial; +}; + +export type WebUsbDeviceControlBaseParams = ControlWebUsbParams & DeviceParameterInitialState; + +export const WebUsbDeviceControlBaseInitialParams: WebUsbDeviceControlBaseParams = { + ...ControlWebUsbInitialParams, + rate: 1e6, + packet_size: CHUNK_SIZE, + throttleon: 10e6, + rx: { + frequency: 1e9, + bandwidth: 1e6, + gain: 15, + }, + tx: { + frequency: 1e9, + bandwidth: 1e6, + gain: 15, + }, +}; + +export type DeviceParameterKey = + | 'rate' + | 'packet_size' + | 'throttleon' + | 'rx.frequency' + | 'rx.bandwidth' + | 'rx.gain' + | 'tx.frequency' + | 'tx.bandwidth' + | 'tx.gain'; + +export interface DeviceStreamingStartResult { + mode: WebUsbDirection; + packetSize: number; +} + +export interface DeviceStreamingStartOptions { + requestedMode?: WebUsbDirection; + start?: boolean; + restart?: boolean; + sync?: WebUsbStreamingSync; +} + +export class WebUsbDeviceControlBase { + protected _fd: number = -1; + protected _type: DataType; + protected _mode: WebUsbManagerMode; + protected _webUsbManager: WebUsbManager | undefined; + protected _configuration: DeviceConfiguration; + protected _state: DeviceParameterState; + protected _control: ControlWebUsb; + + constructor( + params: WebUsbDeviceControlBaseParams = {}, + configuration: DeviceConfiguration = DefaultDeviceConfiguration, + ) { + this._configuration = configuration; + this._type = params.type ?? WebUsbDeviceControlBaseInitialParams.type!; + this._mode = params.mode ?? WebUsbDeviceControlBaseInitialParams.mode!; + this._state = { + rate: params.rate ?? WebUsbDeviceControlBaseInitialParams.rate!, + packet_size: params.packet_size ?? configuration.defaultSamplesCount ?? WebUsbDeviceControlBaseInitialParams.packet_size!, + throttleon: params.throttleon ?? WebUsbDeviceControlBaseInitialParams.throttleon!, + rx: { + frequency: params.rx?.frequency ?? WebUsbDeviceControlBaseInitialParams.rx!.frequency!, + bandwidth: params.rx?.bandwidth ?? WebUsbDeviceControlBaseInitialParams.rx!.bandwidth!, + gain: params.rx?.gain ?? WebUsbDeviceControlBaseInitialParams.rx!.gain!, + }, + tx: { + frequency: params.tx?.frequency ?? WebUsbDeviceControlBaseInitialParams.tx!.frequency!, + bandwidth: params.tx?.bandwidth ?? WebUsbDeviceControlBaseInitialParams.tx!.bandwidth!, + gain: params.tx?.gain ?? WebUsbDeviceControlBaseInitialParams.tx!.gain!, + }, + }; + this._control = new ControlWebUsb({ + type: this._type, + mode: this._mode, + }); + } + + get configuration(): DeviceConfiguration { + return this._configuration; + } + + setConfiguration(configuration: DeviceConfiguration) { + this._configuration = configuration; + if (this._state.packet_size <= 0) { + this._state.packet_size = configuration.defaultSamplesCount; + this.onParameterChanged('packet_size', this._state.packet_size); + } + } + + get state(): DeviceParameterState { + return { + ...this._state, + rx: { ...this._state.rx }, + tx: { ...this._state.tx }, + }; + } + + get rx(): DeviceDirectionParameterState { + return { ...this._state.rx }; + } + + get tx(): DeviceDirectionParameterState { + return { ...this._state.tx }; + } + + get rate() { + return this._state.rate; + } + + set rate(value: number) { + this._state.rate = this.validateRange('Sample rate', value, this._configuration.rateRange); + this.onParameterChanged('rate', this._state.rate); + } + + get packet_size() { + return this._state.packet_size; + } + + set packet_size(value: number) { + if (!Number.isFinite(value) || value <= 0) { + throw new Error(`Packet size must be a positive finite number, got ${value}`); + } + this._state.packet_size = value; + this.onParameterChanged('packet_size', this._state.packet_size); + } + + get throttleon() { + return this._state.throttleon; + } + + set throttleon(value: number) { + this._state.throttleon = this.validateFinite('Throttle', value); + this.onParameterChanged('throttleon', this._state.throttleon); + } + + supportsDirection(direction: WebUsbDirection): boolean { + return (this._configuration.operationModes & direction) === direction; + } + + ensureDirection(direction: WebUsbDirection, parameterName: string) { + if (!this.supportsDirection(direction)) { + throw new Error(`${parameterName} is not supported by this SDR`); + } + } + + getSupportedStreamingMode(requestedMode: WebUsbDirection = WebUsbDirection.RX_TX): WebUsbDirection { + const mode = requestedMode & this._configuration.operationModes; + if (mode === 0) { + throw new Error(`Requested streaming mode ${requestedMode} is not supported by this SDR`); + } + return mode; + } + + setRxFrequency(frequency: number) { + this.ensureDirection(WebUsbDirection.RX, 'RX frequency'); + this._state.rx.frequency = this.validateRange('RX frequency', frequency, this._configuration.rxFrequencyRange); + this.onParameterChanged('rx.frequency', this._state.rx.frequency); + } + + setTxFrequency(frequency: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX frequency'); + this._state.tx.frequency = this.validateRange('TX frequency', frequency, this._configuration.txFrequencyRange); + this.onParameterChanged('tx.frequency', this._state.tx.frequency); + } + + setRxBandwidth(bandwidth: number) { + this.ensureDirection(WebUsbDirection.RX, 'RX bandwidth'); + this._state.rx.bandwidth = this.validateRange('RX bandwidth', bandwidth, this._configuration.bandwidthRange); + this.onParameterChanged('rx.bandwidth', this._state.rx.bandwidth); + } + + setTxBandwidth(bandwidth: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX bandwidth'); + this._state.tx.bandwidth = this.validateRange('TX bandwidth', bandwidth, this._configuration.bandwidthRange); + this.onParameterChanged('tx.bandwidth', this._state.tx.bandwidth); + } + + setRxGain(gain: number) { + this.ensureDirection(WebUsbDirection.RX, 'RX gain'); + this._state.rx.gain = this.validateFinite('RX gain', gain); + this.onParameterChanged('rx.gain', this._state.rx.gain); + } + + setTxGain(gain: number) { + this.ensureDirection(WebUsbDirection.TX, 'TX gain'); + this._state.tx.gain = this.validateFinite('TX gain', gain); + this.onParameterChanged('tx.gain', this._state.tx.gain); + } + + validateForStreaming(mode: WebUsbDirection) { + if ((mode & WebUsbDirection.RX) !== 0) { + this.validateRange('RX frequency', this._state.rx.frequency, this._configuration.rxFrequencyRange); + this.validateRange('RX bandwidth', this._state.rx.bandwidth, this._configuration.bandwidthRange); + } + if ((mode & WebUsbDirection.TX) !== 0) { + this.validateRange('TX frequency', this._state.tx.frequency, this._configuration.txFrequencyRange); + this.validateRange('TX bandwidth', this._state.tx.bandwidth, this._configuration.bandwidthRange); + } + this.validateRange('Sample rate', this._state.rate, this._configuration.rateRange); + } + + protected async prepareDeviceStreaming( + options: DeviceStreamingStartOptions = {}, + ): Promise { + const { + requestedMode = WebUsbDirection.RX_TX, + start = false, + restart = true, + sync = WebUsbStreamingSync.NONE, + } = options; + const streamingMode = this.getSupportedStreamingMode(requestedMode); + this.validateForStreaming(streamingMode); + const streamingPacketSize = await this.getDeviceRxSamplesCount(this.packet_size); + await this.sendControlCommand('START_STREAMING', { + samplerate: Math.floor(this.rate), + packetsize: streamingPacketSize, + throttleon: Math.floor(this.throttleon), + param: buildWebUsbStreamingParam({ + sync, + start, + restart, + }), + mode: streamingMode, + }); + + if ((streamingMode & WebUsbDirection.RX) !== 0) { + await this.setControlParameter('SET_RX_FREQUENCY', { frequency: Math.floor(this._state.rx.frequency) }, true); + await this.setControlParameter('SET_RX_BANDWIDTH', { frequency: Math.floor(this._state.rx.bandwidth) }, true); + await this.setControlParameter('SET_RX_GAIN', { gain: Math.floor(this._state.rx.gain) }, true); + } + if ((streamingMode & WebUsbDirection.TX) !== 0) { + await this.setControlParameter('SET_TX_FREQUENCY', { frequency: Math.floor(this._state.tx.frequency) }, true); + await this.setControlParameter('SET_TX_BANDWIDTH', { frequency: Math.floor(this._state.tx.bandwidth) }, true); + await this.setControlParameter('SET_TX_GAIN', { gain: Math.floor(this._state.tx.gain) }, true); + } + + return { + mode: streamingMode, + packetSize: streamingPacketSize, + }; + } + + protected async startPreparedDeviceStreaming() { + await this.sendControlCommand('CONTROL_STREAMING', { samplerate: 0, throttleon: 0, param: 0 }); + } + + protected schedulePreparedDeviceStreamingStart(delayMs = 0) { + setTimeout(() => { + void this.startPreparedDeviceStreaming().catch((err) => { + console.error('WebUsbDeviceControlBase.startPreparedDeviceStreaming:', err); + }); + }, delayMs); + } + + protected async startDeviceStreaming( + options: DeviceStreamingStartOptions = {}, + ): Promise { + return await this.prepareDeviceStreaming({...options, start: true }); + } + + protected async stopDeviceStreaming() { + await this.sendControlCommand('STOP_STREAMING'); + } + + protected async openDevice(fd: number) { + if (this._fd !== fd) await this.closeDevice(); + this._fd = fd; + await this.openControl(fd); + try { + this.setConfiguration(await this.getDeviceConfiguration()); + } catch { + this.setConfiguration(DefaultDeviceConfiguration); + } + } + + protected async closeDevice() { + await this.closeControl(); + if (this._fd >= 0) { + await this.getWebUsbManager().close(this._fd); + } + this._fd = -1; + } + + protected async getDeviceRxSamplesCount(samples: number): Promise { + return this.getWebUsbManager().getRXSamplesCount(this._fd, samples); + } + + protected async submitDeviceRxPacket(samples: number, opts?: RXDecoderOptions): Promise { + return this.getWebUsbManager().submitRxPacket(this._fd, samples, opts); + } + + protected async sendDeviceTxPacket(data: TXBuffer, opts?: TXEncoderOptions): Promise { + return this.getWebUsbManager().sendTxPacket(this._fd, data, opts); + } + + protected get hasOpenDevice(): boolean { + return this._fd >= 0; + } + + protected get fd(): number { + return this._fd; + } + + private getWebUsbManager(): WebUsbManager { + if (!this._webUsbManager && this._mode !== WebUsbManagerMode.UNKNOWN) { + this._webUsbManager = getWebUsbManagerInstance(this._mode); + } + if (!this._webUsbManager) { + throw new Error('WebUsbDeviceControlBase: WebUsbManager is not configured'); + } + return this._webUsbManager; + } + + private async getDeviceConfiguration(): Promise { + return this.getWebUsbManager().getConfiguration(this._fd); + } + + protected validateRange(name: string, value: number, range: DeviceParamRange): number { + this.validateFinite(name, value); + if (value < range.min || value > range.max) { + throw new Error(`${name} ${value} is out of supported range [${range.min}, ${range.max}]`); + } + return value; + } + + protected validateFinite(name: string, value: number): number { + if (!Number.isFinite(value)) { + throw new Error(`${name} must be a finite number, got ${value}`); + } + return value; + } + + protected async openControl(fd: number) { + await this._control.open(fd); + } + + protected async closeControl() { + await this._control.close(); + } + + protected isControlOpen(): boolean { + return this._control.isOpen(); + } + + protected async sendControlCommand(command: RequestKeys, args = {}, extArgs = {}) { + return this._control.sendCommand(command, args, extArgs); + } + + protected async setControlParameter( + parameter: RequestKeys, + args: (() => Record) | Record, + now = false, + ) { + await this._control.setParameter(parameter, args, now); + } + + protected onParameterChanged(parameter: DeviceParameterKey, value: number) { + if (!this.isControlOpen()) return; + switch (parameter) { + case 'rx.frequency': + void this.setControlParameter('SET_RX_FREQUENCY', { frequency: value }, true); + break; + case 'tx.frequency': + void this.setControlParameter('SET_TX_FREQUENCY', { frequency: value }, true); + break; + case 'rx.bandwidth': + void this.setControlParameter('SET_RX_BANDWIDTH', { frequency: value }, true); + break; + case 'tx.bandwidth': + void this.setControlParameter('SET_TX_BANDWIDTH', { frequency: value }, true); + break; + case 'rx.gain': + void this.setControlParameter('SET_RX_GAIN', { gain: value }, true); + break; + case 'tx.gain': + void this.setControlParameter('SET_TX_GAIN', { gain: value }, true); + break; + } + } +} diff --git a/packages/frontend-core/src/webusb/webUsbLimeSdr.ts b/packages/frontend-core/src/webusb/webUsbLimeSdr.ts index efb2bdf..c2d9884 100644 --- a/packages/frontend-core/src/webusb/webUsbLimeSdr.ts +++ b/packages/frontend-core/src/webusb/webUsbLimeSdr.ts @@ -8,6 +8,7 @@ import { DataType, COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE } from '@websdr/core/common'; import { registerWebUsbInstance } from './webUsb'; +import { isDebugMode } from '@/common/debug'; const debug_usb_log = false; @@ -26,7 +27,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { constructor(parms: WebUsbParams) { super(parms) - if (globalThis.debug_mode || debug_usb_log) console.log('Created WebUsbLimeSdr') + if (isDebugMode() || debug_usb_log) console.log('Created WebUsbLimeSdr') } getConfiguration(): DeviceConfiguration { @@ -94,7 +95,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { } async decodeRxData(data: DataView, samples: number, opts?: RXDecoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) console.log('RECEIVED DATA', data) + if (isDebugMode() || debug_usb_log) console.log('RECEIVED DATA', data) const id = opts !== undefined && opts.id !== undefined ? opts.id : -1; const packetCnt = (data.byteLength / WebUsbLimeSdr.PACKET_SIZE) >> 0; const dataSize = data.byteLength - WebUsbLimeSdr.HEADER_SIZE * packetCnt; @@ -131,7 +132,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { } } - if (globalThis.debug_mode || debug_usb_log) console.log('RECEIVE timestamp', timestamp - this._lastRecvTimestamp, timestamp, this._lastRecvTimestamp, 'output', output.byteLength); + if (isDebugMode() || debug_usb_log) console.log('RECEIVE timestamp', timestamp - this._lastRecvTimestamp, timestamp, this._lastRecvTimestamp, 'output', output.byteLength); const ret: RXBuffer = { data: output, datatype: datatype, @@ -150,7 +151,7 @@ export class WebUsbLimeSdr extends WebUsbWasm { } async encodeTxData(data: TXBuffer, opts?: TXEncoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) console.log('DATA TO SEND', data, data.data.slice(0, 10)); + if (isDebugMode() || debug_usb_log) console.log('DATA TO SEND', data, data.data.slice(0, 10)); // console.log('SEND TIMESTAMP', data.timestamp, data.byteLength /* , data.data.slice(0, 10), data.data.slice(data.size - 10, data.size) */); // const viewin = new Int16Array(data.data, data.byteOffset, data.byteLength); // console.log('VIEWIN', viewin.length, viewin); diff --git a/packages/frontend-core/src/webusb/webUsbManager.ts b/packages/frontend-core/src/webusb/webUsbManager.ts index 608cad8..ee92b13 100644 --- a/packages/frontend-core/src/webusb/webUsbManager.ts +++ b/packages/frontend-core/src/webusb/webUsbManager.ts @@ -7,6 +7,7 @@ import type { import { SDRDevicesIds } from './webUsb'; import { PromiseHelper } from '@websdr/core/utils'; import type { WebUsbWorkerResponse } from './webUsb.worker.types'; +import { isDebugMode } from '@/common/debug'; let webUsbManager: Array = [undefined, undefined, undefined, undefined]; @@ -118,6 +119,7 @@ class WebUsbSingleManager extends WebUsbManager { } async getRXSamplesCount(fd: number, samples: number): Promise { + console.log(`WebUsbSingleManager.getRXSamplesCount: fd ${fd}, requested samples ${samples}`); return globalThis.webUsbDeviceManager?.getDevice(fd)?.getRXSamplesCount(samples) || 0; } @@ -337,7 +339,7 @@ class WebUsbWorkerManager extends WebUsbManager { protected onWorkerMessage(event: MessageEvent) { const msg = event.data as WebUsbWorkerResponse; - if (globalThis.debug_mode) console.log('Message from WebUsbWorker', msg) + if (isDebugMode()) console.log('Message from WebUsbWorker', msg) let promise = undefined; if (typeof msg.id === 'number') promise = this._promiseHelper.getPromise(msg.id); diff --git a/packages/frontend-core/src/webusb/webUsbWsdr.ts b/packages/frontend-core/src/webusb/webUsbWsdr.ts index 7beb913..d2f12f8 100644 --- a/packages/frontend-core/src/webusb/webUsbWsdr.ts +++ b/packages/frontend-core/src/webusb/webUsbWsdr.ts @@ -8,6 +8,7 @@ import { WebUsbWasm } from './webUsbWasm'; import { DataType, CHUNK_SIZE, COMPLEX_FLOAT_SIZE, COMPLEX_INT16_SIZE } from '@websdr/core/common'; +import { isDebugMode } from '@/common/debug'; const debug_usb_log = false; @@ -74,11 +75,10 @@ export abstract class WebUsbWsdr extends WebUsbWasm { } async decodeRxData(data: DataView, samples: number, opts?: RXDecoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('RECEIVED DATA', data) const id = opts !== undefined && opts.id !== undefined ? opts.id : -1; - const extraMeta = true; // now it's always extra meta (old condition: opts?.extra_meta === true;) - const trailerSize = WebUsbWsdr.TRAILER_SIZE + (extraMeta ? WebUsbWsdr.TRAILER_EXTRA_SIZE : 0); + const trailerSize = WebUsbWsdr.TRAILER_SIZE + WebUsbWsdr.TRAILER_EXTRA_SIZE; const dataSize = data.byteLength - trailerSize; const samplesRecv = (dataSize / COMPLEX_INT16_SIZE) >> 0; if (samples !== samplesRecv) { @@ -88,11 +88,10 @@ export abstract class WebUsbWsdr extends WebUsbWasm { const overrun = Number(ts & BigInt(0x0000000000ffffff)); let realigned = 0; let dropped = 0; - if (extraMeta) { - const extra = data.getBigUint64(dataSize + WebUsbWsdr.TRAILER_SIZE, true); - realigned = Number(extra >> BigInt(64 - 20)) - dropped = Number(extra & BigInt(0xffff)) - } + + const extra = data.getBigUint64(dataSize + WebUsbWsdr.TRAILER_SIZE, true); + realigned = Number(extra >> BigInt(64 - 20)) + dropped = Number(extra & BigInt(0xffff)) const datatype = opts?.datatype || DataType.ci16; const elementSize = (datatype === DataType.cf32 || datatype === DataType.f32) ? COMPLEX_FLOAT_SIZE : COMPLEX_INT16_SIZE; @@ -102,7 +101,7 @@ export abstract class WebUsbWsdr extends WebUsbWasm { this._timestamp += BigInt(overrun * samplesRecv); // console.log('RECEIVED TIMESTAMP', this._timestamp); - if (globalThis.debug_mode || debug_usb_log) console.log('RECEIVE timestamp', this._timestamp, overrun, 'output', output.byteLength); + if (isDebugMode() || debug_usb_log) console.log('RECEIVE timestamp', this._timestamp, overrun, 'output', output.byteLength); const ret: RXBuffer = { data: output, @@ -121,7 +120,7 @@ export abstract class WebUsbWsdr extends WebUsbWasm { } async encodeTxData(data: TXBuffer, opts?: TXEncoderOptions): Promise { - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('DATA TO SEND', data, data.datatype, data.byteOffset, data.byteLength); // console.log('SEND TIMESTAMP', data.timestamp, data.byteLength); // const viewin = new Int16Array(data.data, data.byteOffset, data.byteLength); @@ -190,7 +189,7 @@ export class WebUsbXsdr extends WebUsbWsdr { constructor(parms: WebUsbParams) { super(parms) - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('Created WebUsbXsdr') } @@ -215,7 +214,7 @@ export class WebUsbUsdr extends WebUsbWsdr { constructor(parms: WebUsbParams) { super(parms) - if (globalThis.debug_mode || debug_usb_log) + if (isDebugMode() || debug_usb_log) console.log('Created WebUsbUsdr') } From cf16deb4b187bc56a3bbc5989ff853285b737ab6 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:46:46 +0300 Subject: [PATCH 08/13] frontend-core: document new public APIs and bump to 0.6.0 Update README examples and API summary for debug/env helpers, transport, telemetry, utils, and the revised WebUSB API. Also bump @websdr/frontend-core to 0.6.0, depend on @websdr/core 0.6.0, and add package exports for telemetry, transport, and utils. --- packages/frontend-core/README.md | 41 +++++++++++++++++++++++----- packages/frontend-core/package.json | 23 +++++++++++++--- packages/frontend-core/tsconfig.json | 3 +- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/packages/frontend-core/README.md b/packages/frontend-core/README.md index 7fd92b5..0cf7a52 100644 --- a/packages/frontend-core/README.md +++ b/packages/frontend-core/README.md @@ -3,7 +3,7 @@ Frontend-focused TypeScript core for the WebSDR ecosystem. This package provides: -- Small **frontend common** helpers (debug flag, NNG-over-WebSocket client, WASM errno enum). +- Small **frontend common** helpers (debug flag, env helpers, WASM errno enum). - Minimal **HTTP API helpers** for browser apps. - A **WebUSB control + streaming layer** used by WebSDR-compatible devices. @@ -34,7 +34,8 @@ import { apiFetch, setApiBase, ensureWebUsb } from '@websdr/frontend-core'; Or use subpath exports: ```ts -import { debug_mode, NngWebSocket, Protocol } from '@websdr/frontend-core/common'; +import { configureDebug, debug_mode, getEnvValue } from '@websdr/frontend-core/common'; +import { NngWebSocket, Protocol } from '@websdr/frontend-core/transport'; import { apiFetch, setApiBase } from '@websdr/frontend-core/services'; import { ensureWebUsb, WebUsbManagerMode, getWebUsbManagerInstance } from '@websdr/frontend-core/webusb'; ``` @@ -54,6 +55,8 @@ type Profile = { id: string; username: string }; const profile = await apiFetch('/api/auth/profile'); ``` +If `setApiBase()` is not called, the helper tries `globalThis.__API_BASE__`, then `process.env.VITE_API_URL` / `process.env.API_URL`, then `import.meta.env.VITE_API_URL` / `import.meta.env.API_URL`, and finally falls back to `/`. + You can also set the API base via a global variable (useful for `index.html` deployments): ```ts @@ -77,10 +80,29 @@ try { } ``` +### Debug and env helpers + +`debug_mode` is initialized from `process.env.VITE_DEBUG` / `process.env.DEBUG`, then `import.meta.env.VITE_DEBUG` / `import.meta.env.DEBUG`. You can also configure it explicitly: + +```ts +import { configureDebug, isDebugMode } from '@websdr/frontend-core/common'; + +configureDebug({ debug: import.meta.env.DEV }); +console.log(isDebugMode()); +``` + +Common env access is available through `getEnvValue()`, which checks `process.env` before `import.meta.env` by default: + +```ts +import { getEnvValue } from '@websdr/frontend-core/common'; + +const apiUrl = getEnvValue(['VITE_API_URL', 'API_URL']); +``` + ### NNG-over-WebSocket (REQ/SUB) ```ts -import { NngWebSocket, Protocol } from '@websdr/frontend-core/common'; +import { NngWebSocket, Protocol } from '@websdr/frontend-core/transport'; const ws = new NngWebSocket({ url: 'ws://localhost:8000/ws', @@ -96,7 +118,7 @@ ws.addEventListener('message', (ev) => { REQ example (request/response). The `send()` promise resolves when a reply with the same request id arrives: ```ts -import { NngWebSocket, Protocol } from '@websdr/frontend-core/common'; +import { NngWebSocket, Protocol } from '@websdr/frontend-core/transport'; const ws = new NngWebSocket({ url: 'ws://localhost:8000/rpc', @@ -219,7 +241,6 @@ const samples = await mgr.getRXSamplesCount(fd, cfg.defaultSamplesCount); const rx = await mgr.submitRxPacket(fd, samples, { datatype: DataType.ci16, - extra_meta: true, id: 1, }); @@ -324,12 +345,16 @@ export default defineConfig({ ## Public API (summary) - **`@websdr/frontend-core/common`**: - - `debug_mode` - - `Protocol`, `NngWebSocket` + - `debug_mode`, `setDebugMode`, `configureDebug`, `isDebugMode`, `assert` + - `getImportMetaEnv`, `getProcessEnv`, `getEnv`, `getEnvValue` - `WASMErrno` - **`@websdr/frontend-core/services`**: - `setApiBase`, `getApiBase`, `apiUrl`, `apiFetch` - `login`, `logout`, `getProfile` +- **`@websdr/frontend-core/transport`**: + - `Protocol`, `NngWebSocket` +- **`@websdr/frontend-core/utils`**: + - `downloadFile` - **`@websdr/frontend-core/webusb`** (high level): - `ensureWebUsb` - `ControlWebUsb`, `WebUsbChannels`, `ControlWebUsbInitialParams` @@ -372,6 +397,8 @@ This package publishes `dist/` to npm. Source is available in the GitHub reposit - Entry point: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/index.ts - Common exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/common/index.ts - Services exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/services/index.ts +- Transport exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/transport/index.ts +- Utils exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/utils/index.ts - WebUSB exports: https://github.com/wavelet-lab/websdr/blob/main/packages/frontend-core/src/webusb/index.ts Package folder (GitHub): diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 8626fed..75f6f28 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/frontend-core", - "version": "0.5.3", + "version": "0.6.0", "description": "This is the core frontend package for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -37,13 +37,13 @@ "postpack": "rm -f ./LICENSE" }, "dependencies": { - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "usb": "^2.17.0" }, "devDependencies": { "@types/emscripten": "^1.41.5", - "@types/node": "^25.2.3", - "@types/w3c-web-usb": "^1.0.13" + "@types/node": "^25.6.0", + "@types/w3c-web-usb": "^1.0.14" }, "exports": { ".": { @@ -66,6 +66,21 @@ "import": "./dist/services/index.js", "require": "./dist/services/index.js" }, + "./telemetry": { + "types": "./dist/telemetry/index.d.ts", + "import": "./dist/telemetry/index.js", + "require": "./dist/telemetry/index.js" + }, + "./transport": { + "types": "./dist/transport/index.d.ts", + "import": "./dist/transport/index.js", + "require": "./dist/transport/index.js" + }, + "./utils": { + "types": "./dist/utils/index.d.ts", + "import": "./dist/utils/index.js", + "require": "./dist/utils/index.js" + }, "./webusb": { "types": "./dist/webusb/index.d.ts", "import": "./dist/webusb/index.js", diff --git a/packages/frontend-core/tsconfig.json b/packages/frontend-core/tsconfig.json index 7f53d55..d96d961 100644 --- a/packages/frontend-core/tsconfig.json +++ b/packages/frontend-core/tsconfig.json @@ -4,10 +4,9 @@ "rootDir": "src", "outDir": "dist", // Path Mapping - "baseUrl": ".", "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" From 7b8c80521433e821d844e10a5192925952cb0e7d Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:48:32 +0300 Subject: [PATCH 09/13] nestjs-microservice: update package dependencies for 0.6.0 Bump @websdr/nestjs-microservice to 0.6.0 and update its @websdr/core dependency. Move NestJS packages to peer dependencies and keep testing/types packages as dev dependencies. Also improve context logger formatting for optional parameters and error traces. --- packages/nestjs-microservice/package.json | 25 +++++++++++-------- .../src/common/logging.module.ts | 22 +++++++++------- packages/nestjs-microservice/tsconfig.json | 3 +-- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/nestjs-microservice/package.json b/packages/nestjs-microservice/package.json index 687b6df..c4eb5d2 100644 --- a/packages/nestjs-microservice/package.json +++ b/packages/nestjs-microservice/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/nestjs-microservice", - "version": "0.5.3", + "version": "0.6.0", "description": "This is a NestJS microservice for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -33,24 +33,27 @@ "postpack": "rm -f ./LICENSE" }, "dependencies": { - "@nestjs/common": "^11.1.16", - "@nestjs/config": "^4.0.3", - "@nestjs/jwt": "^11.0.2", - "@nestjs/microservices": "^11.1.16", - "@nestjs/passport": "^11.0.5", - "@nestjs/testing": "^11.1.16", - "@nestjs/websockets": "^11.1.16", - "@types/node": "^25.3.5", - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.15.1", "passport-jwt": "^4.0.1", - "ws": "^8.19.0" + "ws": "^8.21.0" }, "devDependencies": { + "@nestjs/testing": "^11.1.24", + "@types/node": "^25.3.5", "@types/passport-jwt": "^4.0.1", "@types/ws": "^8.18.1" }, + "peerDependencies": { + "@nestjs/common": "^11.1.24", + "@nestjs/config": "^4.0.4", + "@nestjs/core": "^11.1.24", + "@nestjs/jwt": "^11.0.2", + "@nestjs/microservices": "^11.1.24", + "@nestjs/passport": "^11.0.5", + "@nestjs/websockets": "^11.1.24" + }, "exports": { ".": { "types": "./dist/index.d.ts", diff --git a/packages/nestjs-microservice/src/common/logging.module.ts b/packages/nestjs-microservice/src/common/logging.module.ts index 500e9c2..f0a1052 100644 --- a/packages/nestjs-microservice/src/common/logging.module.ts +++ b/packages/nestjs-microservice/src/common/logging.module.ts @@ -1,5 +1,6 @@ import { Module, Global } from '@nestjs/common'; import type { DynamicModule, LoggerService } from '@nestjs/common'; +import { format } from 'util'; import { LOGGER } from './tokens'; export function createContextLogger(base: any, context: string): LoggerService { @@ -7,21 +8,24 @@ export function createContextLogger(base: any, context: string): LoggerService { const fn = base?.[method] ?? base?.log; if (!fn) return; if (method === 'error' || method === 'fatal') { - const [message, trace] = args; - fn.call(base, message, trace ?? undefined, context); + const [message, ...optionalParams] = args; + const traceParam = optionalParams.length === 1 ? optionalParams[0] : undefined; + const trace = traceParam instanceof Error ? traceParam.stack : traceParam; + fn.call(base, message, trace, context); } else { - const [message] = args; - fn.call(base, message, context); + const [message, ...optionalParams] = args; + const formattedMessage = optionalParams.length > 0 ? format(message, ...optionalParams) : message; + fn.call(base, formattedMessage, context); } }; return { - log: (msg: any) => call('log', msg), + log: (msg: any, ...optionalParams: any[]) => call('log', msg, ...optionalParams), error: (msg: any, trace?: string) => call('error', msg, trace), fatal: (msg: any, trace?: string) => call('fatal', msg, trace), - warn: (msg: any) => call('warn', msg), - debug: (msg: any) => call('debug', msg), - verbose: (msg: any) => call('verbose', msg), + warn: (msg: any, ...optionalParams: any[]) => call('warn', msg, ...optionalParams), + debug: (msg: any, ...optionalParams: any[]) => call('debug', msg, ...optionalParams), + verbose: (msg: any, ...optionalParams: any[]) => call('verbose', msg, ...optionalParams), }; } @@ -41,4 +45,4 @@ export class LoggingModule { exports: [LOGGER], }; } -} \ No newline at end of file +} diff --git a/packages/nestjs-microservice/tsconfig.json b/packages/nestjs-microservice/tsconfig.json index 15e2558..828c6f0 100644 --- a/packages/nestjs-microservice/tsconfig.json +++ b/packages/nestjs-microservice/tsconfig.json @@ -4,10 +4,9 @@ "rootDir": "src", "outDir": "dist", // Path Mapping - "baseUrl": ".", "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" From 88a1fa07bbfd268c9c5973e84412c8f9fbd472a2 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:50:38 +0300 Subject: [PATCH 10/13] vue3-components: improve WebUSB UX and update dependencies Bump @websdr/vue3-components to 0.6.0 and update @websdr/core and @websdr/frontend-core dependencies. Move Vue to peerDependencies, refresh development dependencies, and improve SdrInput handling for browsers without WebUSB support by showing a friendly error message and avoiding unsupported requests. --- packages/vue3-components/package.json | 21 ++++++----- .../src/components/SdrInput.vue | 31 +++++++++++++--- .../src/tests/SdrInput.test.ts | 35 +++++++++++++++++-- packages/vue3-components/tsconfig.json | 4 +-- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/packages/vue3-components/package.json b/packages/vue3-components/package.json index b47d0d7..6a5028b 100644 --- a/packages/vue3-components/package.json +++ b/packages/vue3-components/package.json @@ -1,6 +1,6 @@ { "name": "@websdr/vue3-components", - "version": "0.5.3", + "version": "0.6.0", "description": "This is a Vue 3 components package for WebSDR", "author": "Timur Davydov ", "license": "MIT", @@ -37,18 +37,21 @@ "postpack": "rm -f ./LICENSE" }, "dependencies": { - "@websdr/core": "^0.5.3", - "@websdr/frontend-core": "^0.5.3", - "vue": "^3.5.30" + "@websdr/core": "^0.6.0", + "@websdr/frontend-core": "^0.6.0" }, "devDependencies": { - "@vitejs/plugin-vue": "^6.0.4", + "@vitejs/plugin-vue": "^6.0.7", "@vue/cli-plugin-typescript": "^5.0.9", "@vue/cli-service": "^5.0.9", - "@vue/test-utils": "^2.4.6", - "happy-dom": "^20.8.3", - "sass": "^1.97.3", - "vue-tsc": "^3.2.5" + "@vue/test-utils": "^2.4.10", + "happy-dom": "^20.9.0", + "sass": "^1.100.0", + "vue": "^3.5.35", + "vue-tsc": "^3.3.2" + }, + "peerDependencies": { + "vue": "^3.5.0" }, "sideEffects": [ "**/*.css", diff --git a/packages/vue3-components/src/components/SdrInput.vue b/packages/vue3-components/src/components/SdrInput.vue index 1e04155..ef4bd7a 100644 --- a/packages/vue3-components/src/components/SdrInput.vue +++ b/packages/vue3-components/src/components/SdrInput.vue @@ -13,6 +13,7 @@ export interface SdrInputProps { device?: RequestDeviceInfo; // Currently selected SDR device mode?: 'single' | 'worker'; // Mode of WebUsb manager operation placeholder?: string; // Placeholder text for the input + unsupportedMessage?: string; // Message shown when WebUSB is not available size?: SizeType; // Size of the input disabled?: boolean; // Whether the input is disabled } @@ -20,7 +21,7 @@ export interface SdrInputProps { @@ -85,7 +108,7 @@ const dropdownStatus = computed((): StatusType => { diff --git a/packages/vue3-components/src/tests/SdrInput.test.ts b/packages/vue3-components/src/tests/SdrInput.test.ts index 23b5af4..61fa285 100644 --- a/packages/vue3-components/src/tests/SdrInput.test.ts +++ b/packages/vue3-components/src/tests/SdrInput.test.ts @@ -23,7 +23,13 @@ describe('SdrInput.vue', () => { vi.clearAllMocks() }) + afterEach(() => { + vi.unstubAllGlobals() + }) + it('renders placeholder when no device provided', async () => { + vi.stubGlobal('navigator', { usb: { requestDevice: vi.fn() } }) + const wrapper = mount(SdrInput, { props: { device: { devName: '', vendorId: 0, productId: 0 } }, // provide empty device to satisfy required prop global: { stubs: { Dropdown: DropdownStub } } @@ -36,6 +42,8 @@ describe('SdrInput.vue', () => { }) it('shows device name and status=success when device prop provided', async () => { + vi.stubGlobal('navigator', { usb: { requestDevice: vi.fn() } }) + const device = { devName: 'SDR-One', vendorId: 123, productId: 456 } const wrapper = mount(SdrInput, { props: { device }, @@ -49,6 +57,8 @@ describe('SdrInput.vue', () => { }) it('calls WebUsb manager and emits update::device on open', async () => { + vi.stubGlobal('navigator', { usb: { requestDevice: vi.fn() } }) + const device = { devName: 'USB-Device', vendorId: 1, productId: 2 } const mockManager = { requestDevice: vi.fn().mockResolvedValue(device) } ; (getWebUsbManagerInstance as any).mockReturnValue(mockManager) @@ -58,7 +68,7 @@ describe('SdrInput.vue', () => { global: { stubs: { Dropdown: DropdownStub } } }) - const dropdown = wrapper.findComponent(DropdownStub) + const dropdown = wrapper.findComponent(DropdownStub) // simulate open event -> component should call requestUsb -> selectUsb -> emit update::device await dropdown.vm.$emit('open') // wait for promise resolution and next ticks @@ -74,4 +84,25 @@ describe('SdrInput.vue', () => { expect((emitted![0] as any)[0]).toBeDefined() expect((emitted![0] as any)[0].devName).toBe('USB-Device') }) -}) \ No newline at end of file + + it('shows a friendly message immediately when WebUSB is not supported', async () => { + vi.stubGlobal('navigator', {}) + + const wrapper = mount(SdrInput, { + props: { device: { devName: '', vendorId: 0, productId: 0 } }, + global: { stubs: { Dropdown: DropdownStub } } + }) + + expect(wrapper.text()).toContain('❗ WebUSB is not supported in this browser') + expect(wrapper.find('.dd-status').text()).toBe('error') + + const dropdown = wrapper.findComponent(DropdownStub) + await dropdown.vm.$emit('open') + await nextTick() + + expect(getWebUsbManagerInstance).not.toHaveBeenCalled() + expect(wrapper.text()).toContain('❗ WebUSB is not supported in this browser') + expect(wrapper.find('.dd-status').text()).toBe('error') + expect(wrapper.emitted()['update:device']).toBeFalsy() + }) +}) diff --git a/packages/vue3-components/tsconfig.json b/packages/vue3-components/tsconfig.json index 8ea9b57..e59ff03 100644 --- a/packages/vue3-components/tsconfig.json +++ b/packages/vue3-components/tsconfig.json @@ -3,10 +3,10 @@ // File Layout "rootDir": "src", "outDir": "dist", - "baseUrl": ".", + // Path Mapping "paths": { "@/*": [ - "src/*" + "./src/*" ], "vitest": [ "../../node_modules/vitest" From 5ea5a9de509894303d66552a4e9f3a933f2f7415 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 00:52:10 +0300 Subject: [PATCH 11/13] build: update workspace development dependencies Refresh shared development tooling versions across the monorepo, including TypeScript 6, Vite 8, Vitest 4.1, Mermaid CLI, coverage tooling, and tsc-alias. --- package-lock.json | 4340 +++++++++++++++++++++++---------------------- package.json | 14 +- 2 files changed, 2215 insertions(+), 2139 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0098b3b..50c2a66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,13 +13,13 @@ "./packages/vue3-components" ], "devDependencies": { - "@mermaid-js/mermaid-cli": "^11.12.0", - "@vitest/coverage-v8": "^4.0.18", - "tsc-alias": "^1.8.16", + "@mermaid-js/mermaid-cli": "^11.15.0", + "@vitest/coverage-v8": "^4.1.7", + "tsc-alias": "^1.8.17", "tsc-esm-fix": "^3.1.2", - "typescript": "^5.9.3", - "vite": "^7.3.1", - "vitest": "^4.0.18" + "typescript": "^6.0.3", + "vite": "^8.0.14", + "vitest": "^4.1.7" } }, "node_modules/@achrinza/node-ipc": { @@ -65,13 +65,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -87,9 +87,9 @@ "license": "MIT" }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -97,21 +97,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -138,14 +138,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -155,14 +155,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -199,9 +199,9 @@ "license": "ISC" }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -209,29 +209,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -241,27 +241,29 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -269,26 +271,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -298,33 +301,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -332,13 +335,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -355,10 +359,11 @@ } }, "node_modules/@borewit/text-codec": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", - "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/Borewit" @@ -371,47 +376,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.1.tgz", - "integrity": "sha512-fRHyv6/f542qQqiRGalrfJl/evD39mAvbJLCekPazhiextEatq1Jx1K/i9gSd5NNO0ds03ek0Cbo/4uVKmOBcw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "11.1.1", - "@chevrotain/types": "11.1.1", - "lodash-es": "4.17.23" - } - }, - "node_modules/@chevrotain/gast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.1.tgz", - "integrity": "sha512-Ko/5vPEYy1vn5CbCjjvnSO4U7GgxyGm+dfUZZJIWTlQFkXkyym0jFYrWEU10hyCjrA7rQtiHtBr0EaZqvHFZvg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "11.1.1", - "lodash-es": "4.17.23" - } - }, - "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.1.tgz", - "integrity": "sha512-ctRw1OKSXkOrR8VTvOxrQ5USEc4sNrfwXHa1NuTcR7wre4YbjPcKw+82C2uylg/TEwFRgwLmbhlln4qkmDyteg==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/@chevrotain/types": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.1.tgz", - "integrity": "sha512-wb2ToxG8LkgPYnKe9FH8oGn3TMCBdnwiuNC5l5y+CtlaVRbCytU0kbVsk6CGrqTL4ZN4ksJa0TXOYbxpbthtqw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/utils": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.1.tgz", - "integrity": "sha512-71eTYMzYXYSFPrbg/ZwftSaSDld7UYlS8OQa3lNnn9jzNtpFbaReRRyghzqS7rI3CDaorqpPJJcXGHK+FE1TVQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "dev": true, "license": "Apache-2.0" }, @@ -425,824 +393,790 @@ "node": ">=10.0.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], + "node_modules/@floating-ui/react": { + "version": "0.27.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.19.tgz", + "integrity": "sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], + "node_modules/@fortawesome/fontawesome-free": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.2.0.tgz", + "integrity": "sha512-3DguDv/oUE+7vjMeTSOjCSG+KeawgVQOHrKRnvUuqYh1mfArrh7s+s8hXW3e4RerBA1+Wh+hBqf8sJNpqNrBWg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "BSD-3-Clause" }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], + "node_modules/@headlessui/react": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.10.tgz", + "integrity": "sha512-5pVLNK9wlpxTUTy9GpgbX/SdcRh+HBnPktjM2wbiLTH4p+2EPHBO1aoSryUCuKUIItdDWO9ITlhUL8UnUN/oIA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.20.2", + "@react-aria/interactions": "^3.25.0", + "@tanstack/react-virtual": "^3.13.9", + "use-sync-external-store": "^1.5.0" + }, "engines": { - "node": ">=18" + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], + "node_modules/@headlessui/react/node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], + "node_modules/@headlessui/tailwindcss": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", + "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=10" + }, + "peerDependencies": { + "tailwindcss": "^3.0 || ^4.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], + "node_modules/@iconify/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], + "node_modules/@internationalized/date": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.1.tgz", + "integrity": "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], + "node_modules/@internationalized/number": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.6.tgz", + "integrity": "sha512-iFgmQaXHE0vytNfpLZWOC2mEJCBRzcUxt53Xf/yCXG93lRvqas237i3r7X4RKMwO3txiyZD4mQjKAByFv6UGSQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], + "node_modules/@internationalized/string": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.8.tgz", + "integrity": "sha512-NdbMQUSfXLYIQol5VyMtinm9pZDciiMfN7RtmSuSB78io1hqwJ0naYfxyW6vgxWBkzWymQa/3uLDlbfmshtCaA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "ansi-regex": "^6.2.2" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", - "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", - "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.4", - "@floating-ui/utils": "^0.2.10" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@floating-ui/react": { - "version": "0.27.18", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.18.tgz", - "integrity": "sha512-xJWJxvmy3a05j643gQt+pRbht5XnTlGpsEsAPnMi5F5YTOEEJymA90uZKBD8OvIv5XvZ1qi4GcccSlqT3Bq44Q==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.1.7", - "@floating-ui/utils": "^0.2.10", - "tabbable": "^6.0.0" - }, - "peerDependencies": { - "react": ">=17.0.0", - "react-dom": ">=17.0.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", - "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.5" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^9.0.0" + "license": "MIT" + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" } }, - "node_modules/@headlessui/react": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.9.tgz", - "integrity": "sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==", + "node_modules/@mermaid-js/layout-elk": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.2.1.tgz", + "integrity": "sha512-MX9jwhMyd5zDcFsYcl3duDUkKhjVRUCGEQrdCeNV5hCIR6+3FuDDbRbFmvVbAu15K1+juzsYGG+K8MDvCY1Amg==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/react": "^0.26.16", - "@react-aria/focus": "^3.20.2", - "@react-aria/interactions": "^3.25.0", - "@tanstack/react-virtual": "^3.13.9", - "use-sync-external-store": "^1.5.0" - }, - "engines": { - "node": ">=10" + "d3": "^7.9.0", + "elkjs": "^0.9.3" }, "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "react-dom": "^18 || ^19 || ^19.0.0-rc" + "mermaid": "^11.0.2" } }, - "node_modules/@headlessui/react/node_modules/@floating-ui/react": { - "version": "0.26.28", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", - "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "node_modules/@mermaid-js/layout-tidy-tree": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mermaid-js/layout-tidy-tree/-/layout-tidy-tree-0.2.2.tgz", + "integrity": "sha512-8RmjDXjKJBxqTS1mICStm8zWRM45fSzs0SOrkp28+KsOGS2YEMFMVTwwRU8CsC6M1L+pDYZVjf1m9AC1c9Wndg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@floating-ui/react-dom": "^2.1.2", - "@floating-ui/utils": "^0.2.8", - "tabbable": "^6.0.0" + "d3": "^7.9.0" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "mermaid": "^11.0.2" } }, - "node_modules/@headlessui/tailwindcss": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", - "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", + "node_modules/@mermaid-js/mermaid-cli": { + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-11.15.0.tgz", + "integrity": "sha512-rmz9ELKtmKQvRcYJGI2e509FK9yCBvmEVfHeRSYkleGqo6qqh8LFooxRPCqq04uVx3JHMp9g/vmM85gi/QFFlQ==", "dev": true, "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-free": "^6.0.0 || ^7.0.1", + "@mermaid-js/layout-elk": "^0.1.5 || ^0.2.0", + "@mermaid-js/mermaid-zenuml": "^0.2.0", + "chalk": "^5.0.1", + "commander": "^13.1.0", + "import-meta-resolve": "^4.1.0", + "katex": "^0.16.25", + "mermaid": "^11.14.0", + "p-limit": "^6.2.0" + }, + "bin": { + "mmdc": "src/cli.js" + }, "engines": { - "node": ">=10" + "node": "^18.19 || >=20.0" + }, + "optionalDependencies": { + "@mermaid-js/layout-tidy-tree": "^0.2.1" }, "peerDependencies": { - "tailwindcss": "^3.0 || ^4.0" + "puppeteer": "^23 || ^24" } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@iconify/utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", - "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "node_modules/@mermaid-js/mermaid-zenuml": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-zenuml/-/mermaid-zenuml-0.2.3.tgz", + "integrity": "sha512-RGBtgL6fc+5Y2Jm9odOH9HRJ80BP4l6atBYnAK5bBzEowF0PU3UtvZRRcbFxImPGPuLIzqZq31ur8lVO0AoF3Q==", "dev": true, "license": "MIT", "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "mlly": "^1.8.0" + "@zenuml/core": "^3.47.0" + }, + "peerDependencies": { + "mermaid": "^10 || ^11" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@mermaid-js/parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" + "@chevrotain/types": "~11.1.1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@napi-rs/canvas": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.100.tgz", + "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", "dev": true, "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.100", + "@napi-rs/canvas-darwin-arm64": "0.1.100", + "@napi-rs/canvas-darwin-x64": "0.1.100", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", + "@napi-rs/canvas-linux-arm64-musl": "0.1.100", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-musl": "0.1.100", + "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", + "@napi-rs/canvas-win32-x64-msvc": "0.1.100" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", + "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", + "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", + "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", + "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 10" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", + "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", + "cpu": [ + "arm64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", + "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", + "cpu": [ + "arm64" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", + "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", + "cpu": [ + "riscv64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", + "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", + "cpu": [ + "x64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", + "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", + "cpu": [ + "x64" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "node_modules/@napi-rs/canvas-win32-arm64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", + "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/@lukeed/csprng": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", - "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@mermaid-js/mermaid-cli": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-11.12.0.tgz", - "integrity": "sha512-a0swOS6PByXKi0dZnLQQIhbtUEu7ubc6bojmIqXqvUPq7mIJukCNEvVBTv6IAbuEWqB3Ti8QntupoGdz3ej+kg==", + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", + "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@mermaid-js/mermaid-zenuml": "^0.2.0", - "chalk": "^5.0.1", - "commander": "^14.0.0", - "import-meta-resolve": "^4.1.0", - "mermaid": "^11.0.2" - }, - "bin": { - "mmdc": "src/cli.js" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.19 || >=20.0" + "node": ">= 10" }, - "peerDependencies": { - "puppeteer": "^23" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" } }, - "node_modules/@mermaid-js/mermaid-zenuml": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-zenuml/-/mermaid-zenuml-0.2.2.tgz", - "integrity": "sha512-sUjwk4NWUpy9uaHypYSIGJDks10ZaZo5CHH9lx9xcmyqv9w7yvd4vecUmlUQxmlHStYO+aqSkYKX5/gFjDfypw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@zenuml/core": "^3.35.2" + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "mermaid": "^10 || ^11" - } - }, - "node_modules/@mermaid-js/parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", - "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "langium": "^4.0.0" + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@nestjs/common": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.16.tgz", - "integrity": "sha512-JSIeW+USuMJkkcNbiOdcPkVCeI3TSnXstIVEPpp3HiaKnPRuSbUUKm9TY9o/XpIcPHWUOQItAtC5BiAwFdVITQ==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.24.tgz", + "integrity": "sha512-9zHxaDDM+oXW9As6UsP5yYB+UqczBmpeSCIFWdPEtEukMnZhxODG1BBjaUcdBB8Sc1uzojSJSJlp3yFp853t1g==", "license": "MIT", + "peer": true, "dependencies": { - "file-type": "21.3.0", + "file-type": "21.3.4", "iterare": "1.2.1", "load-esm": "1.0.3", "tslib": "2.8.1", @@ -1268,14 +1202,15 @@ } }, "node_modules/@nestjs/config": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.3.tgz", - "integrity": "sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.4.tgz", + "integrity": "sha512-CJPjNitr0bAufSEnRe2N+JbnVmMmDoo6hvKCPzXgZoGwJSmp/dZPk9f/RMbuD/+Q1ZJPjwsRpq0vxna++Knwow==", "license": "MIT", + "peer": true, "dependencies": { - "dotenv": "17.2.3", + "dotenv": "17.4.1", "dotenv-expand": "12.0.3", - "lodash": "4.17.23" + "lodash": "4.18.1" }, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", @@ -1283,9 +1218,9 @@ } }, "node_modules/@nestjs/core": { - "version": "11.1.14", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.14.tgz", - "integrity": "sha512-7OXPPMoDr6z+5NkoQKu4hOhfjz/YYqM3bNilPqv1WVFWrzSmuNXxvhbX69YMmNmRYascPXiwESqf5jJdjKXEww==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.24.tgz", + "integrity": "sha512-K4bzT+lEdd0Hhcsw3jtk56QAW6s6skK3ViN7hIROSN0kUf4ROwWEAKopJID6yhPQxB45kDtP2wEcjzE8171J3g==", "hasInstallScript": true, "license": "MIT", "peer": true, @@ -1293,7 +1228,7 @@ "@nuxt/opencollective": "0.4.1", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "path-to-regexp": "8.3.0", + "path-to-regexp": "8.4.2", "tslib": "2.8.1", "uid": "2.0.2" }, @@ -1329,6 +1264,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.2.tgz", "integrity": "sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==", "license": "MIT", + "peer": true, "dependencies": { "@types/jsonwebtoken": "9.0.10", "jsonwebtoken": "9.0.3" @@ -1338,10 +1274,11 @@ } }, "node_modules/@nestjs/microservices": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/microservices/-/microservices-11.1.16.tgz", - "integrity": "sha512-eG/ArIq0UJyR3i/GTYuApA4OZylhuLGacVaVT9mMxQgT7ZTpp5CZgOwLNdcUUdOS6qypK3waG1m2AC54xzdf0Q==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/microservices/-/microservices-11.1.24.tgz", + "integrity": "sha512-ALu/7qk3obFlw7KVSPRz+BjuyWPLmv9isknhLG8UYXkjx3aPhJGp52i3qiTqucM1jKtoBgPa3+SK4e9fVvglGA==", "license": "MIT", + "peer": true, "dependencies": { "iterare": "1.2.1", "tslib": "2.8.1" @@ -1400,15 +1337,17 @@ "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", "integrity": "sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==", "license": "MIT", + "peer": true, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", "passport": "^0.5.0 || ^0.6.0 || ^0.7.0" } }, "node_modules/@nestjs/testing": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.16.tgz", - "integrity": "sha512-E7/aUCxzeMSJV80L5GWGIuiMyR/1ncS7uOIetAImfbS4ATE1/h2GBafk0qpk+vjFtPIbtoh9BWDGICzUEU5jDA==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.24.tgz", + "integrity": "sha512-+4M4UAnhtprBQN0J2uI6IP0wDqhy9aH8XCMu5SO8oCi0oB04YXA4a4PAEkxmsPn7gHW4dj1u4GFteNQOWgvTJw==", + "dev": true, "license": "MIT", "dependencies": { "tslib": "2.8.1" @@ -1433,10 +1372,11 @@ } }, "node_modules/@nestjs/websockets": { - "version": "11.1.16", - "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.1.16.tgz", - "integrity": "sha512-kfLhCFsq6139JVFCQpbFB6LOEjZzdpE7JzXsZtRbVjqmsgTKVSIh8gKRgzpcq27rbLNqHhhZavboOltOfSxZow==", + "version": "11.1.24", + "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.1.24.tgz", + "integrity": "sha512-37Z/QYzZ4nPHcGyGGjhjoKVOcpSPMhmRQj5DS1l0RKlRYgq8S0cmgaZ6kQ8PI3259PdchLx41oQibXh22iEUiA==", "license": "MIT", + "peer": true, "dependencies": { "iterare": "1.2.1", "object-hash": "3.0.0", @@ -1530,6 +1470,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@oxc-project/types": { + "version": "0.132.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", + "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@parcel/watcher": { "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", @@ -1659,6 +1609,9 @@ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1680,6 +1633,9 @@ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1701,6 +1657,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1722,6 +1681,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1743,6 +1705,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1764,6 +1729,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1841,9 +1809,9 @@ } }, "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "optional": true, @@ -1873,20 +1841,19 @@ "license": "MIT" }, "node_modules/@puppeteer/browsers": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.6.1.tgz", - "integrity": "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==", + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz", + "integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "debug": "^4.4.0", + "debug": "^4.4.3", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", - "semver": "^7.6.3", - "tar-fs": "^3.0.6", - "unbzip2-stream": "^1.4.3", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", "yargs": "^17.7.2" }, "bin": { @@ -1897,134 +1864,50 @@ } }, "node_modules/@react-aria/focus": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.4.tgz", - "integrity": "sha512-6gz+j9ip0/vFRTKJMl3R30MHopn4i19HqqLfSQfElxJD+r9hBnYG1Q6Wd/kl/WRR1+CALn2F+rn06jUnf5sT8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@react-aria/interactions": "^3.27.0", - "@react-aria/utils": "^3.33.0", - "@react-types/shared": "^3.33.0", - "@swc/helpers": "^0.5.0", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/interactions": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.0.tgz", - "integrity": "sha512-D27pOy+0jIfHK60BB26AgqjjRFOYdvVSkwC31b2LicIzRCSPOSP06V4gMHuGmkhNTF4+YWDi1HHYjxIvMeiSlA==", + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.22.0.tgz", + "integrity": "sha512-ZfDOVuVhqDsM9mkNji3QUZ/d40JhlVgXrDkrfXylM1035QCrcTHN7m2DpbE95sU2A8EQb4wikvt5jM6K/73BPg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@react-aria/ssr": "^3.9.10", - "@react-aria/utils": "^3.33.0", - "@react-stately/flags": "^3.1.2", - "@react-types/shared": "^3.33.0", - "@swc/helpers": "^0.5.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/ssr": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", - "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-aria/utils": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.33.0.tgz", - "integrity": "sha512-yvz7CMH8d2VjwbSa5nGXqjU031tYhD8ddax95VzJsHSPyqHDEGfxul8RkhGV6oO7bVqZxVs6xY66NIgae+FHjw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@react-aria/ssr": "^3.9.10", - "@react-stately/flags": "^3.1.2", - "@react-stately/utils": "^3.11.0", - "@react-types/shared": "^3.33.0", "@swc/helpers": "^0.5.0", - "clsx": "^2.0.0" + "react-aria": "3.48.0" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@react-stately/flags": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.2.tgz", - "integrity": "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/@react-stately/utils": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.11.0.tgz", - "integrity": "sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw==", + "node_modules/@react-aria/interactions": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.28.0.tgz", + "integrity": "sha512-OXwdU1EWFdMxmr/K1CXNGJzmNlCClByb+PuCaqUyzBymHPCGVhawirLIon/CrIN5psh3AiWpHSh4H0WeJdVpng==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@swc/helpers": "^0.5.0" + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "react-aria": "3.48.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@react-types/shared": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.33.0.tgz", - "integrity": "sha512-xuUpP6MyuPmJtzNOqF5pzFUIHH2YogyOQfUQHag54PRmWB7AbjuGWBUv0l1UDmz6+AbzAYGmDVAzcRDOu2PFpw==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.34.0.tgz", + "integrity": "sha512-gp6xo/s2lX54AlTjOiqwDnxA7UW79BNvI9dB9pr3LZTzRKCd1ZA+ZbgKw/ReIiWuvvVw/8QFJpnqeeFyLocMcQ==", "dev": true, "license": "Apache-2.0", "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", - "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", + "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", "cpu": [ "arm64" ], @@ -2033,12 +1916,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", "cpu": [ "arm64" ], @@ -2047,12 +1933,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", + "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", "cpu": [ "x64" ], @@ -2061,26 +1950,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", + "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", "cpu": [ "x64" ], @@ -2089,26 +1967,15 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", - "cpu": [ - "arm" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", "cpu": [ "arm" ], @@ -2117,180 +1984,135 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", - "cpu": [ - "loong64" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", - "cpu": [ - "loong64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", + "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", - "cpu": [ - "riscv64" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", - "cpu": [ - "riscv64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", + "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", + "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", + "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", "cpu": [ "arm64" ], @@ -2299,40 +2121,51 @@ "optional": true, "os": [ "openharmony" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", + "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", "cpu": [ - "arm64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", "cpu": [ "x64" ], @@ -2341,21 +2174,17 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", - "cpu": [ - "x64" ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, "node_modules/@sideway/address": { "version": "4.1.5", @@ -2429,9 +2258,9 @@ "license": "MIT" }, "node_modules/@swc/helpers": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", - "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==", + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2439,13 +2268,13 @@ } }, "node_modules/@tanstack/react-virtual": { - "version": "3.13.18", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.18.tgz", - "integrity": "sha512-dZkhyfahpvlaV0rIKnvQiVoWPyURppl6w4m9IwMDpuIjcJ1sD9YGWrt0wISvgU7ewACXx2Ct46WPgI6qAD4v6A==", + "version": "3.13.26", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.26.tgz", + "integrity": "sha512-DosdgjOxCLahkn0o+ilmZYwEjo1glfMGuRT/j3PQ18yr5XqA8N/BCaL9IJ3B5TRl+nnzyK2IOFgAILwzN3a9xQ==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.13.18" + "@tanstack/virtual-core": "3.16.0" }, "funding": { "type": "github", @@ -2457,9 +2286,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.13.18", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.18.tgz", - "integrity": "sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==", + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.16.0.tgz", + "integrity": "sha512-Er2N7q3WOiH6y2JLxsxNX+u2/sLqSsL0bxFgDjuiPiA7vKhZRm+IzcS17vRee3GNXr64UsesA5CAp9yTiIYw9A==", "dev": true, "license": "MIT", "funding": { @@ -2472,6 +2301,7 @@ "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" @@ -2488,7 +2318,8 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", @@ -2499,23 +2330,24 @@ "peer": true }, "node_modules/@topoconfig/extends": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@topoconfig/extends/-/extends-0.16.2.tgz", - "integrity": "sha512-sTF+qpWakr5jf1Hn/kkFSi833xPW15s/loMAiKSYSSVv4vDonxf6hwCGzMXjLq+7HZoaK6BgaV72wXr1eY7FcQ==", + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@topoconfig/extends/-/extends-0.16.5.tgz", + "integrity": "sha512-JuBgOuFAK28D3+SsRKw6wVmACKHdxhBvVlAcf2ReRXYw5ftW8pTuTkv5T91xTiRtHcUWMC9XNQksUlQAc/yZ7A==", "dev": true, "license": "MIT", "bin": { "xtends": "target/esm/cli.mjs" } }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10.13.0" + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@types/body-parser": { @@ -2869,32 +2701,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -3006,12 +2816,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.3.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.5.tgz", - "integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/node-forge": { @@ -3071,9 +2881,9 @@ } }, "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "dev": true, "license": "MIT" }, @@ -3159,9 +2969,9 @@ "license": "MIT" }, "node_modules/@types/w3c-web-usb": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.13.tgz", - "integrity": "sha512-N2nSl3Xsx8mRHZBvMSdNGtzMyeleTvtlEw+ujujgXalPqOjIA6UtrqcB6OzyUjkTbDm3J7P1RNK1lgoO7jxtsw==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.14.tgz", + "integrity": "sha512-Qu3Nn6JFuF4+sHKYl+IcX9vYiI40ogleXzFFSxoE1W94rG98o/kXs8uJ0QSfFzuwBCZWlGfUGpPkgwuuX4PchA==", "license": "MIT" }, "node_modules/@types/webpack-env": { @@ -3200,47 +3010,58 @@ "@types/node": "*" } }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", - "integrity": "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.2" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.7.tgz", + "integrity": "sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", + "@vitest/utils": "4.1.7", + "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "obug": "^2.1.1", - "std-env": "^3.10.0", - "tinyrainbow": "^3.0.3" + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.0.18", - "vitest": "4.0.18" + "@vitest/browser": "4.1.7", + "vitest": "4.1.7" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -3249,31 +3070,31 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.7.tgz", + "integrity": "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.7.tgz", + "integrity": "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.18", + "@vitest/spy": "4.1.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3282,7 +3103,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -3294,26 +3115,26 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.7.tgz", + "integrity": "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.7.tgz", + "integrity": "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.18", + "@vitest/utils": "4.1.7", "pathe": "^2.0.3" }, "funding": { @@ -3321,13 +3142,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.7.tgz", + "integrity": "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.7", + "@vitest/utils": "4.1.7", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3336,9 +3158,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.7.tgz", + "integrity": "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==", "dev": true, "license": "MIT", "funding": { @@ -3346,14 +3168,15 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.7.tgz", + "integrity": "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" + "@vitest/pretty-format": "4.1.7", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -3648,13 +3471,14 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", - "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", + "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.35", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -3664,32 +3488,35 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", - "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", + "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-core": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", - "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz", + "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.30", - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.35", + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.15", "source-map-js": "^1.2.1" } }, @@ -3697,16 +3524,18 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, "license": "MIT" }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", - "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz", + "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/component-compiler-utils": { @@ -3780,25 +3609,25 @@ "license": "ISC" }, "node_modules/@vue/language-core": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.5.tgz", - "integrity": "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.2.tgz", + "integrity": "sha512-CLwjSfHlPLhjd2qhuS3tTFtnOIWHXAM5u4X1DxmzlQ8j5bmOYlKCsSusOP7jCRJnlVg0mCTQtHU3vwFvopZGoQ==", "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", - "alien-signals": "^3.0.0", + "alien-signals": "^3.2.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", - "picomatch": "^4.0.2" + "picomatch": "^4.0.4" } }, "node_modules/@vue/language-core/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -3809,64 +3638,79 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", - "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz", + "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.30" + "@vue/shared": "3.5.35" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", - "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz", + "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/reactivity": "3.5.35", + "@vue/shared": "3.5.35" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", - "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz", + "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/runtime-core": "3.5.30", - "@vue/shared": "3.5.30", + "@vue/reactivity": "3.5.35", + "@vue/runtime-core": "3.5.35", + "@vue/shared": "3.5.35", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", - "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz", + "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-ssr": "3.5.35", + "@vue/shared": "3.5.35" }, "peerDependencies": { - "vue": "3.5.30" + "vue": "3.5.35" } }, "node_modules/@vue/shared": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", - "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", + "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", + "dev": true, "license": "MIT" }, "node_modules/@vue/test-utils": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", - "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.10.tgz", + "integrity": "sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA==", "dev": true, "license": "MIT", "dependencies": { "js-beautify": "^1.14.9", - "vue-component-type-helpers": "^2.0.0" + "vue-component-type-helpers": "^3.0.0" + }, + "peerDependencies": { + "@vue/compiler-dom": "3.x", + "@vue/server-renderer": "3.x", + "vue": "3.x" + }, + "peerDependenciesMeta": { + "@vue/server-renderer": { + "optional": true + } } }, "node_modules/@vue/vue-loader-v15": { @@ -4105,9 +3949,9 @@ "license": "Apache-2.0" }, "node_modules/@zenuml/core": { - "version": "3.45.4", - "resolved": "https://registry.npmjs.org/@zenuml/core/-/core-3.45.4.tgz", - "integrity": "sha512-y2s6F0urvcnzB/Rx5oPVLUn9zlq+cnwTMXAlEH46tdItQtqU8fTRYqrGGOuJVIKZcbZwgtpFzpSzzcC0YtjLqQ==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/@zenuml/core/-/core-3.49.0.tgz", + "integrity": "sha512-15hZEYfZYtuJXYK3JVR7cwy95uRfLYn+nlJgJOALDM6Q/xsRqpP+npHoBnfQ3ZmERFjn71Icwuh5B7I3FR6vPA==", "dev": true, "license": "MIT", "dependencies": { @@ -4119,7 +3963,7 @@ "clsx": "^2.1.1", "color-string": "^2.1.4", "dompurify": "^3.3.1", - "highlight.js": "^10.7.3", + "highlight.js": "^11.10.0", "html-to-image": "^1.11.13", "immer": "^10.2.0", "jotai": "^2.16.1", @@ -4127,15 +3971,27 @@ "marked": "^4.3.0", "pako": "^2.1.0", "pino": "^8.21.0", - "radash": "^12.1.1", - "ramda": "^0.28.0", "react": "^19.2.3", "react-dom": "^19.2.3", "tailwind-merge": "^3.4.0", "tailwindcss": "^3.4.19" }, - "engines": { - "node": ">=20" + "bin": { + "zenuml": "dist/cli/zenuml.mjs" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.97" + }, + "peerDependencies": { + "playwright-core": "^1.59.1" + }, + "peerDependenciesMeta": { + "playwright-core": { + "optional": true + } } }, "node_modules/abbrev": { @@ -4186,9 +4042,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -4212,9 +4068,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, "license": "MIT", "dependencies": { @@ -4246,9 +4102,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4281,9 +4137,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -4315,9 +4171,9 @@ } }, "node_modules/alien-signals": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.2.tgz", - "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", "dev": true, "license": "MIT" }, @@ -4437,6 +4293,19 @@ "license": "Python-2.0", "peer": true }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4479,9 +4348,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", - "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.2.tgz", + "integrity": "sha512-dKmJxJsGItLmc5CYZKuEjuG6GnBs6PG4gohMhyFOWKaNQoYCuRZJDECaBlHmcG0lv2wc2E0uU8lESmBEumC3DQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4518,9 +4387,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.24", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", - "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -4538,8 +4407,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001766", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -4555,9 +4424,9 @@ } }, "node_modules/b4a": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.5.tgz", - "integrity": "sha512-iEsKNwDh1wiWTps1/hdkNdmBgDlDVZP5U57ZVOlt+dNFqpc/lpPouCIxZw+DYBgc4P9NDfIZMPNR4CHNhzwLIA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -4639,9 +4508,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", + "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -4655,12 +4524,11 @@ } }, "node_modules/bare-fs": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.4.tgz", - "integrity": "sha512-POK4oplfA7P7gqvetNmCs4CNtm9fNsx+IAh7jH7GgU0OJdge2rso0R20TNWVq6VoWcCvsTdlNDaleLHGaKx8CA==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { "bare-events": "^2.5.4", @@ -4682,12 +4550,11 @@ } }, "node_modules/bare-os": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", - "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "engines": { "bare": ">=1.14.0" @@ -4699,29 +4566,31 @@ "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { "bare-os": "^3.0.1" } }, "node_modules/bare-stream": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", - "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { - "streamx": "^2.21.0", + "streamx": "^2.25.0", "teex": "^1.0.1" }, "peerDependencies": { + "bare-abort-controller": "*", "bare-buffer": "*", "bare-events": "*" }, "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, "bare-buffer": { "optional": true }, @@ -4731,12 +4600,11 @@ } }, "node_modules/bare-url": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", - "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "peer": true, "dependencies": { "bare-path": "^3.0.0" @@ -4764,19 +4632,22 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", - "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/basic-ftp": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", - "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", "dev": true, "license": "MIT", "peer": true, @@ -4874,9 +4745,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "dev": true, "license": "MIT", "dependencies": { @@ -4888,7 +4759,7 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", - "qs": "~6.14.0", + "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" @@ -4929,9 +4800,9 @@ "license": "MIT" }, "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", + "integrity": "sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==", "dev": true, "license": "MIT", "dependencies": { @@ -4947,9 +4818,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -4971,9 +4842,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -4991,11 +4862,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -5139,9 +5010,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001770", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", - "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -5192,34 +5063,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chevrotain": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", - "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/cst-dts-gen": "11.1.1", - "@chevrotain/gast": "11.1.1", - "@chevrotain/regexp-to-ast": "11.1.1", - "@chevrotain/types": "11.1.1", - "@chevrotain/utils": "11.1.1", - "lodash-es": "4.17.23" - } - }, - "node_modules/chevrotain-allstar": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash-es": "^4.17.21" - }, - "peerDependencies": { - "chevrotain": "^11.0.0" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -5269,15 +5112,15 @@ } }, "node_modules/chromium-bidi": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.11.0.tgz", - "integrity": "sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "mitt": "3.0.1", - "zod": "3.23.8" + "mitt": "^3.0.1", + "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" @@ -5390,6 +5233,16 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/cli-highlight/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/cli-highlight/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -5556,13 +5409,13 @@ "license": "MIT" }, "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, "license": "MIT", "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/commondir": { @@ -5628,13 +5481,6 @@ "dev": true, "license": "MIT" }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", @@ -5789,9 +5635,9 @@ } }, "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", "dev": true, "license": "MIT", "peer": true, @@ -5932,9 +5778,9 @@ } }, "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -6135,9 +5981,9 @@ } }, "node_modules/cssnano/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -6161,12 +6007,13 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, "license": "MIT" }, "node_modules/cytoscape": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", - "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "version": "3.33.4", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.4.tgz", + "integrity": "sha512-HIN5Pmd9MrX9BkV7tDwnOcEJCSFvCpc8X97h3f508J6I5FsqAY65wKOCvgH2CuP42CaahWaz4tuh32SOOIH7ww==", "dev": true, "license": "MIT", "engines": { @@ -6704,9 +6551,9 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", "dev": true, "license": "MIT", "dependencies": { @@ -6726,9 +6573,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", "dev": true, "license": "MIT" }, @@ -6946,9 +6793,9 @@ } }, "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", "dev": true, "license": "ISC", "dependencies": { @@ -6966,9 +6813,9 @@ } }, "node_modules/depseek": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/depseek/-/depseek-0.4.3.tgz", - "integrity": "sha512-0Ex/Uoz9Y9oipbqvgSc7FoV2q4GTDGORkg8TGgM9Pd3RyvRzrDYScKplWiqHU7WqckbKN5kukqD0opEayu2bXg==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/depseek/-/depseek-0.4.6.tgz", + "integrity": "sha512-bWgCO97Q18pAlNdmYef1XMWUFCzZ3zoPzh67mIlrrPF2iVzqUT0/1ZsynfCMpWjBxcwY8JjjFHk9FNqgptFrlg==", "dev": true, "license": "MIT" }, @@ -6989,7 +6836,6 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -7002,9 +6848,9 @@ "license": "MIT" }, "node_modules/devtools-protocol": { - "version": "0.0.1367902", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", - "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==", + "version": "0.0.1608973", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1608973.tgz", + "integrity": "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==", "dev": true, "license": "BSD-3-Clause", "peer": true @@ -7114,9 +6960,9 @@ } }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz", + "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==", "dev": true, "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { @@ -7150,10 +6996,11 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz", + "integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==", "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=12" }, @@ -7166,6 +7013,7 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "dotenv": "^16.4.5" }, @@ -7181,6 +7029,7 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=12" }, @@ -7237,15 +7086,15 @@ } }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -7256,9 +7105,9 @@ } }, "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -7276,13 +7125,13 @@ } }, "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7299,12 +7148,19 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.286", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", - "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "version": "1.5.362", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.362.tgz", + "integrity": "sha512-PUY2DrLvkjkUuWqq+KPL2iWshrJsZOcIojzRQ7eXFacc9dWga7MGMJAa15VbiejSZB1PAXaRLAiKgruHP8LB1w==", "dev": true, "license": "ISC" }, + "node_modules/elkjs": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", + "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", + "dev": true, + "license": "EPL-2.0" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -7343,23 +7199,23 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", + "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" } }, "node_modules/enhanced-resolve/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -7374,6 +7230,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -7434,16 +7291,16 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -7453,47 +7310,16 @@ "node": ">= 0.4" } }, - "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "node_modules/es-toolkit": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.0.tgz", + "integrity": "sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } + "workspaces": [ + "docs", + "benchmarks" + ] }, "node_modules/escalade": { "version": "3.2.0", @@ -7729,15 +7555,15 @@ } }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "~1.20.3", + "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", @@ -7756,7 +7582,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "~6.14.0", + "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", @@ -7793,9 +7619,9 @@ "license": "MIT" }, "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, "license": "MIT" }, @@ -7891,9 +7717,9 @@ "peer": true }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -7955,10 +7781,11 @@ } }, "node_modules/file-type": { - "version": "21.3.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.0.tgz", - "integrity": "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==", + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", "license": "MIT", + "peer": true, "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", @@ -8090,9 +7917,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, "funding": [ { @@ -8314,9 +8141,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -8358,9 +8185,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", "dev": true, "license": "MIT", "dependencies": { @@ -8488,9 +8315,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { @@ -8630,9 +8457,9 @@ "license": "MIT" }, "node_modules/happy-dom": { - "version": "20.8.3", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.8.3.tgz", - "integrity": "sha512-lMHQRRwIPyJ70HV0kkFT7jH/gXzSI7yDkQFe07E2flwmNDFoWUTRMKpW2sglsnpeA7b6S2TJPp98EbQxai8eaQ==", + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.9.0.tgz", + "integrity": "sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8678,9 +8505,9 @@ "license": "MIT" }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, "license": "MIT", "dependencies": { @@ -8701,13 +8528,13 @@ } }, "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": "*" + "node": ">=12.0.0" } }, "node_modules/hosted-git-info": { @@ -8827,9 +8654,9 @@ "license": "MIT" }, "node_modules/html-webpack-plugin": { - "version": "5.6.6", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.6.tgz", - "integrity": "sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==", + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", + "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", "dev": true, "license": "MIT", "dependencies": { @@ -8860,9 +8687,9 @@ } }, "node_modules/html-webpack-plugin/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -9086,9 +8913,9 @@ } }, "node_modules/immutable": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", - "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true, "license": "MIT" }, @@ -9157,9 +8984,9 @@ } }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "peer": true, @@ -9168,9 +8995,9 @@ } }, "node_modules/ipaddr.js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", - "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", "dev": true, "license": "MIT", "engines": { @@ -9198,13 +9025,13 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -9422,6 +9249,7 @@ "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", "license": "ISC", + "peer": true, "engines": { "node": ">=6" } @@ -9505,9 +9333,9 @@ } }, "node_modules/jotai": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.17.1.tgz", - "integrity": "sha512-TFNZZDa/0ewCLQyRC/Sq9crtixNj/Xdf/wmj9631xxMuKToVJZDbqcHIYN0OboH+7kh6P6tpIK7uKWClj86PKw==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.20.0.tgz", + "integrity": "sha512-b5GAqgmXmXzB4WPaTH26ppk9Sl7AA9WSQX7yfdM+gJ1rFROiWcVbi97gFuN/yVCojOcbcvop2sfLL+fjxW0JVg==", "dev": true, "license": "MIT", "engines": { @@ -9557,9 +9385,9 @@ } }, "node_modules/js-beautify/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -9589,13 +9417,13 @@ } }, "node_modules/js-beautify/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9605,23 +9433,23 @@ } }, "node_modules/js-beautify/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.7.tgz", + "integrity": "sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==", "dev": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=20" } }, "node_modules/js-message": { @@ -9703,9 +9531,9 @@ } }, "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -9758,110 +9586,365 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/katex": { - "version": "0.16.28", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.28.tgz", - "integrity": "sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==", + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/launch-editor": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz", + "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/launch-editor-middleware": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.13.2.tgz", + "integrity": "sha512-kI7VqA9g6mhoeQ6YdNgd+gKLaeuWHAUR8oDM8vFtt924wG8HbI2XO0n/hSX2ML4hcJbTgUihuPHfpnPjIKMdJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "launch-editor": "^2.13.2" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/libphonenumber-js": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.3.tgz", + "integrity": "sha512-xMkdAMqcyG7iN2WZZmGIfWbYxW4orRkny+0/AXIbwL0xll2zkDX0Vzo/BXFa6+7mh2UvJl9MbcTtHk0YXkFtBA==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], "dev": true, - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "katex": "cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/khroma": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", - "dev": true - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/langium": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", - "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "chevrotain": "~11.1.1", - "chevrotain-allstar": "~0.3.1", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.1.0" - }, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.10.0", - "npm": ">=10.2.3" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/launch-editor": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", - "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/launch-editor-middleware": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.12.0.tgz", - "integrity": "sha512-SgU5QWoR+Grq1sQedvS/RlfoyO6bdvrztpP+2RRg8UzE7Jz2Yup5J4jiFfm2J9dYBCQYD26AbJVbjnvgwdL6Pw==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "launch-editor": "^2.12.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/layout-base": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/libphonenumber-js": { - "version": "1.12.37", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.37.tgz", - "integrity": "sha512-rDU6bkpuMs8YRt/UpkuYEAsYSoNuDEbrE41I3KNvmXREGH6DGBJ8Wbak4by29wNOQ27zk4g4HL82zf0OGhwRuw==", - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, "node_modules/lilconfig": { "version": "3.1.3", @@ -9898,14 +9981,15 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=13.2.0" } }, "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, "license": "MIT", "engines": { @@ -9958,15 +10042,15 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "dev": true, "license": "MIT" }, @@ -10225,19 +10309,20 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", + "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } @@ -10349,32 +10434,33 @@ } }, "node_modules/mermaid": { - "version": "11.12.3", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", - "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", + "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", "dev": true, "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^1.0.0", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.1", "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "es-toolkit": "^1.45.1", + "katex": "^0.16.25", "khroma": "^2.1.0", - "lodash-es": "^4.17.23", - "marked": "^16.2.1", + "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", - "uuid": "^11.1.0" + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "node_modules/mermaid/node_modules/marked": { @@ -10428,9 +10514,9 @@ } }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", "engines": { @@ -10450,6 +10536,16 @@ "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -10461,9 +10557,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.0.tgz", - "integrity": "sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", "dev": true, "license": "MIT", "dependencies": { @@ -10482,9 +10578,9 @@ } }, "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -10539,9 +10635,9 @@ } }, "node_modules/mini-css-extract-plugin/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -10560,9 +10656,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -10603,19 +10699,6 @@ "license": "MIT", "peer": true }, - "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" - } - }, "node_modules/module-alias": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.3.4.tgz", @@ -10687,9 +10770,10 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, "funding": [ { "type": "github", @@ -10722,9 +10806,9 @@ "license": "MIT" }, "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", "dev": true, "license": "MIT", "peer": true, @@ -10780,9 +10864,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", - "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { @@ -10801,11 +10885,14 @@ } }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/nopt": { "version": "7.2.1", @@ -11084,16 +11171,16 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^1.1.1" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -11112,6 +11199,22 @@ "node": ">=8" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", @@ -11394,19 +11497,19 @@ "license": "ISC" }, "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "license": "MIT", "peer": true, "funding": { @@ -11449,12 +11552,13 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -11538,18 +11642,6 @@ "node": ">=8" } }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, "node_modules/plimit-lit": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.6.1.tgz", @@ -11596,9 +11688,10 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -11615,7 +11708,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -11853,9 +11946,9 @@ } }, "node_modules/postcss-loader/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { @@ -12547,9 +12640,9 @@ "license": "ISC" }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -12568,21 +12661,20 @@ } }, "node_modules/puppeteer": { - "version": "23.11.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.11.1.tgz", - "integrity": "sha512-53uIX3KR5en8l7Vd8n5DUv90Ae9QDQsyIthaUFVzwV6yU750RjqRznEtNMBT20VthqAdemnJN+hxVdmMHKt7Zw==", - "deprecated": "< 24.15.0 is no longer supported", + "version": "24.43.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.43.1.tgz", + "integrity": "sha512-/FSOViCrqRdb1HDocpsM9Z1giA71gTQPUt3SpHGVRALKAy/rJr1fLFYZW9F23qPxqVxTHQnbh/5B5opJST3kAw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "@puppeteer/browsers": "2.6.1", - "chromium-bidi": "0.11.0", + "@puppeteer/browsers": "2.13.2", + "chromium-bidi": "14.0.0", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1367902", - "puppeteer-core": "23.11.1", - "typed-query-selector": "^2.12.0" + "devtools-protocol": "0.0.1608973", + "puppeteer-core": "24.43.1", + "typed-query-selector": "^2.12.2" }, "bin": { "puppeteer": "lib/cjs/puppeteer/node/cli.js" @@ -12592,28 +12684,29 @@ } }, "node_modules/puppeteer-core": { - "version": "23.11.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.11.1.tgz", - "integrity": "sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg==", + "version": "24.43.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.1.tgz", + "integrity": "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "@puppeteer/browsers": "2.6.1", - "chromium-bidi": "0.11.0", - "debug": "^4.4.0", - "devtools-protocol": "0.0.1367902", - "typed-query-selector": "^2.12.0", - "ws": "^8.18.0" + "@puppeteer/browsers": "2.13.2", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1608973", + "typed-query-selector": "^2.12.2", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.20.0" }, "engines": { "node": ">=18" } }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12655,35 +12748,14 @@ "url": "https://feross.org/support" } ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "dev": true, - "license": "MIT" - }, - "node_modules/radash": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/radash/-/radash-12.1.1.tgz", - "integrity": "sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.18.0" - } + "license": "MIT" }, - "node_modules/ramda": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", - "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ramda" - } + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", @@ -12735,26 +12807,66 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/react-aria": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.48.0.tgz", + "integrity": "sha512-jQjd4rBEIMqecBaAKYJbVGK6EqIHLa5znVQ7jwFyK5vCyljoj6KhgtiahmcIPsG5vG5vEDLw+ba+bEWn6A2P4w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.1", + "@internationalized/number": "^3.6.6", + "@internationalized/string": "^3.2.8", + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "aria-hidden": "^1.2.3", + "clsx": "^2.0.0", + "react-stately": "3.46.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.6" + } + }, + "node_modules/react-stately": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.46.0.tgz", + "integrity": "sha512-OdxhWvHgs2L4OJGIs7hnuTr5WjjMM6enhNEAMRqiekhF8+ITvA2LRwNftOZwcogaoCslGYq5S2VQTQwnm0GbCA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.1", + "@internationalized/number": "^3.6.6", + "@internationalized/string": "^3.2.8", + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/read-cache": { @@ -12910,12 +13022,13 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" @@ -13003,55 +13116,44 @@ } }, "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "dev": true, "license": "Unlicense" }, - "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "node_modules/rolldown": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", + "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.132.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", - "fsevents": "~2.3.2" + "@rolldown/binding-android-arm64": "1.0.2", + "@rolldown/binding-darwin-arm64": "1.0.2", + "@rolldown/binding-darwin-x64": "1.0.2", + "@rolldown/binding-freebsd-x64": "1.0.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", + "@rolldown/binding-linux-arm64-gnu": "1.0.2", + "@rolldown/binding-linux-arm64-musl": "1.0.2", + "@rolldown/binding-linux-ppc64-gnu": "1.0.2", + "@rolldown/binding-linux-s390x-gnu": "1.0.2", + "@rolldown/binding-linux-x64-gnu": "1.0.2", + "@rolldown/binding-linux-x64-musl": "1.0.2", + "@rolldown/binding-openharmony-arm64": "1.0.2", + "@rolldown/binding-wasm32-wasi": "1.0.2", + "@rolldown/binding-win32-arm64-msvc": "1.0.2", + "@rolldown/binding-win32-x64-msvc": "1.0.2" } }, "node_modules/roughjs": { @@ -13146,56 +13248,66 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.97.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", + "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "chokidar": "^5.0.0", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" } }, "node_modules/sass/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/sass/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", "url": "https://paulmillr.com/funding/" } }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -13244,9 +13356,9 @@ } }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -13444,9 +13556,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "dev": true, "license": "MIT", "engines": { @@ -13477,14 +13589,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -13599,6 +13711,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, "license": "MIT", "bin": { @@ -13606,14 +13719,14 @@ } }, "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "ip-address": "^10.0.1", + "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -13661,6 +13774,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -13707,9 +13821,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, @@ -13816,16 +13930,16 @@ } }, "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, "node_modules/streamx": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", - "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.26.0.tgz", + "integrity": "sha512-VvNG1K72Po/xwJzxZFnZ++Tbrv4lwSptsbkFuzXCJAYZvCK5nnxsvXU6ajqkv7chyiI1Y0YXq2Jh8Iy8Y7NF/A==", "dev": true, "license": "MIT", "peer": true, @@ -13924,10 +14038,11 @@ } }, "node_modules/strtok3": { - "version": "10.3.4", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.4.tgz", - "integrity": "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==", + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", "license": "MIT", + "peer": true, "dependencies": { "@tokenizer/token": "^0.3.0" }, @@ -13957,9 +14072,9 @@ } }, "node_modules/stylis": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", - "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", "dev": true, "license": "MIT" }, @@ -14023,18 +14138,18 @@ } }, "node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.2.tgz", + "integrity": "sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA==", "dev": true, "license": "MIT", "dependencies": { - "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^4.1.3", "css-tree": "^1.1.3", "csso": "^4.2.0", "picocolors": "^1.0.0", + "sax": "^1.5.0", "stable": "^0.1.8" }, "bin": { @@ -14062,9 +14177,9 @@ "license": "MIT" }, "node_modules/tailwind-merge": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.1.tgz", - "integrity": "sha512-2OA0rFqWOkITEAOFWSBSApYkDeH9t2B3XSJuI4YztKBzK3mX0737A2qtxDZ7xkw9Zfh0bWl+r34sF3HXV+Ig7Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", "dev": true, "license": "MIT", "funding": { @@ -14121,9 +14236,9 @@ } }, "node_modules/tar-fs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", - "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", "dev": true, "license": "MIT", "peer": true, @@ -14137,14 +14252,15 @@ } }, "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "b4a": "^1.6.4", + "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } @@ -14155,16 +14271,15 @@ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", "dev": true, "license": "MIT", - "optional": true, "peer": true, "dependencies": { "streamx": "^2.12.5" } }, "node_modules/terser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -14181,16 +14296,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -14204,21 +14318,48 @@ "webpack": "^5.1.0" }, "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, "@swc/core": { "optional": true }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, "esbuild": { "optional": true }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, "uglify-js": { "optional": true } } }, "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -14381,14 +14522,6 @@ "real-require": "^0.2.0" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -14404,9 +14537,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.2.tgz", + "integrity": "sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==", "dev": true, "license": "MIT", "engines": { @@ -14414,14 +14547,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -14449,9 +14582,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -14462,9 +14595,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -14499,6 +14632,7 @@ "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", "license": "MIT", + "peer": true, "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", @@ -14547,9 +14681,9 @@ "license": "Apache-2.0" }, "node_modules/ts-loader": { - "version": "9.5.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", - "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.7.tgz", + "integrity": "sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==", "dev": true, "license": "MIT", "dependencies": { @@ -14595,9 +14729,9 @@ } }, "node_modules/tsc-alias": { - "version": "1.8.16", - "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.16.tgz", - "integrity": "sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==", + "version": "1.8.17", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.17.tgz", + "integrity": "sha512-EIduCZHqbNwPm8BZYfq1aD7BQ697A4h6uSGMOFQfYGoQwfrYFTKwYfy9Bv42YxHkduVBcn9Zx0DkX111DKskyg==", "dev": true, "license": "MIT", "dependencies": { @@ -14688,18 +14822,18 @@ } }, "node_modules/typed-query-selector": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", - "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", "dev": true, "license": "MIT", "peer": true }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -14709,18 +14843,12 @@ "node": ">=14.17" } }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "dev": true, - "license": "MIT" - }, "node_modules/uid": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", "license": "MIT", + "peer": true, "dependencies": { "@lukeed/csprng": "^1.0.0" }, @@ -14733,6 +14861,7 @@ "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -14740,48 +14869,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/unbzip2-stream/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, "node_modules/universalify": { @@ -14861,9 +14952,9 @@ } }, "node_modules/usb/node_modules/node-addon-api": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", - "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.8.0.tgz", + "integrity": "sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -14903,9 +14994,9 @@ } }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -14913,7 +15004,7 @@ ], "license": "MIT", "bin": { - "uuid": "dist/esm/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/validate-npm-package-license": { @@ -14928,9 +15019,9 @@ } }, "node_modules/validator": { - "version": "13.15.26", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", - "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", "license": "MIT", "engines": { "node": ">= 0.10" @@ -14947,18 +15038,17 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz", + "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.2", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" @@ -14974,9 +15064,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -14989,13 +15080,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { "optional": true }, - "lightningcss": { + "jiti": { + "optional": true + }, + "less": { "optional": true }, "sass": { @@ -15021,28 +15115,10 @@ } } }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -15053,31 +15129,31 @@ } }, "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.7.tgz", + "integrity": "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", + "@vitest/expect": "4.1.7", + "@vitest/mocker": "4.1.7", + "@vitest/pretty-format": "4.1.7", + "@vitest/runner": "4.1.7", + "@vitest/snapshot": "4.1.7", + "@vitest/spy": "4.1.7", + "@vitest/utils": "4.1.7", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -15093,12 +15169,15 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", + "@vitest/browser-playwright": "4.1.7", + "@vitest/browser-preview": "4.1.7", + "@vitest/browser-webdriverio": "4.1.7", + "@vitest/coverage-istanbul": "4.1.7", + "@vitest/coverage-v8": "4.1.7", + "@vitest/ui": "4.1.7", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -15119,6 +15198,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, @@ -15127,13 +15212,16 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -15143,54 +15231,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true, - "license": "MIT" - }, "node_modules/vscode-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", @@ -15199,16 +15239,17 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", - "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz", + "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==", + "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-sfc": "3.5.30", - "@vue/runtime-dom": "3.5.30", - "@vue/server-renderer": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.35", + "@vue/compiler-sfc": "3.5.35", + "@vue/runtime-dom": "3.5.35", + "@vue/server-renderer": "3.5.35", + "@vue/shared": "3.5.35" }, "peerDependencies": { "typescript": "*" @@ -15220,9 +15261,9 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", - "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.3.2.tgz", + "integrity": "sha512-l4Z2Y34m7nFMlx8vrslJaVtXxUpzgDMSESC7TakG/c5kwjYT/do+E0NcT2/vWDzaoIhsShg/2OKwX7Q4nbzC0g==", "dev": true, "license": "MIT" }, @@ -15299,14 +15340,14 @@ "license": "MIT" }, "node_modules/vue-tsc": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.5.tgz", - "integrity": "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.2.tgz", + "integrity": "sha512-n7nQoA3YWW/eiDR8jMiv/uJvlg0uLGs+YgUrsTrf9EZaYSt3tuvMZb5V8+7Mvh/EH5pnY/hoVdgfjH+XcK+wwA==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.2.5" + "@vue/language-core": "3.3.2" }, "bin": { "vue-tsc": "bin/vue-tsc.js" @@ -15349,6 +15390,14 @@ "defaults": "^1.0.3" } }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -15357,37 +15406,35 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.105.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", - "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", + "version": "5.107.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", + "integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.19.0", - "es-module-lexer": "^2.0.0", + "enhanced-resolve": "^5.22.0", + "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", + "terser-webpack-plugin": "^5.5.0", "watchpack": "^2.5.1", - "webpack-sources": "^3.3.3" + "webpack-sources": "^3.5.0" }, "bin": { "webpack": "bin/webpack.js" @@ -15456,9 +15503,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", "dev": true, "license": "MIT", "engines": { @@ -15527,9 +15574,9 @@ } }, "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -15644,9 +15691,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -15716,9 +15763,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "dev": true, "license": "MIT", "engines": { @@ -15733,9 +15780,9 @@ "license": "MIT" }, "node_modules/webpack/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -15762,13 +15809,6 @@ "ajv": "^8.8.2" } }, - "node_modules/webpack/node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -15797,9 +15837,9 @@ } }, "node_modules/webpack/node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -15945,9 +15985,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -15982,6 +16022,22 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "extraneous": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -16025,10 +16081,23 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", "peer": true, @@ -16038,67 +16107,74 @@ }, "packages/core": { "name": "@websdr/core", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "devDependencies": { - "@types/node": "^25.2.3" + "@types/emscripten": "^1.41.5", + "@types/node": "^25.9.1" } }, "packages/frontend-core": { "name": "@websdr/frontend-core", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "dependencies": { - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "usb": "^2.17.0" }, "devDependencies": { "@types/emscripten": "^1.41.5", - "@types/node": "^25.2.3", - "@types/w3c-web-usb": "^1.0.13" + "@types/node": "^25.6.0", + "@types/w3c-web-usb": "^1.0.14" } }, "packages/nestjs-microservice": { "name": "@websdr/nestjs-microservice", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "dependencies": { - "@nestjs/common": "^11.1.16", - "@nestjs/config": "^4.0.3", - "@nestjs/jwt": "^11.0.2", - "@nestjs/microservices": "^11.1.16", - "@nestjs/passport": "^11.0.5", - "@nestjs/testing": "^11.1.16", - "@nestjs/websockets": "^11.1.16", - "@types/node": "^25.3.5", - "@websdr/core": "^0.5.3", + "@websdr/core": "^0.6.0", "class-transformer": "^0.5.1", "class-validator": "^0.15.1", "passport-jwt": "^4.0.1", - "ws": "^8.19.0" + "ws": "^8.21.0" }, "devDependencies": { + "@nestjs/testing": "^11.1.24", + "@types/node": "^25.3.5", "@types/passport-jwt": "^4.0.1", "@types/ws": "^8.18.1" + }, + "peerDependencies": { + "@nestjs/common": "^11.1.24", + "@nestjs/config": "^4.0.4", + "@nestjs/core": "^11.1.24", + "@nestjs/jwt": "^11.0.2", + "@nestjs/microservices": "^11.1.24", + "@nestjs/passport": "^11.0.5", + "@nestjs/websockets": "^11.1.24" } }, "packages/vue3-components": { "name": "@websdr/vue3-components", - "version": "0.5.3", + "version": "0.6.0", "license": "MIT", "dependencies": { - "@websdr/core": "^0.5.3", - "@websdr/frontend-core": "^0.5.3", - "vue": "^3.5.30" + "@websdr/core": "^0.6.0", + "@websdr/frontend-core": "^0.6.0" }, "devDependencies": { - "@vitejs/plugin-vue": "^6.0.4", + "@vitejs/plugin-vue": "^6.0.7", "@vue/cli-plugin-typescript": "^5.0.9", "@vue/cli-service": "^5.0.9", - "@vue/test-utils": "^2.4.6", - "happy-dom": "^20.8.3", - "sass": "^1.97.3", - "vue-tsc": "^3.2.5" + "@vue/test-utils": "^2.4.10", + "happy-dom": "^20.9.0", + "sass": "^1.100.0", + "vue": "^3.5.35", + "vue-tsc": "^3.3.2" + }, + "peerDependencies": { + "vue": "^3.5.0" } } } diff --git a/package.json b/package.json index 3e6d391..c0b16ed 100644 --- a/package.json +++ b/package.json @@ -38,12 +38,12 @@ "test:ui": "vitest --ui" }, "devDependencies": { - "@mermaid-js/mermaid-cli": "^11.12.0", - "@vitest/coverage-v8": "^4.0.18", - "tsc-alias": "^1.8.16", + "@mermaid-js/mermaid-cli": "^11.15.0", + "@vitest/coverage-v8": "^4.1.7", + "tsc-alias": "^1.8.17", "tsc-esm-fix": "^3.1.2", - "typescript": "^5.9.3", - "vite": "^7.3.1", - "vitest": "^4.0.18" + "typescript": "^6.0.3", + "vite": "^8.0.14", + "vitest": "^4.1.7" } -} \ No newline at end of file +} From 8e2918a2ec54c2f0e2ceba640fc23130394dfa12 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 09:26:58 +0300 Subject: [PATCH 12/13] docs: add NLnet and NGI0 Commons funding information Add a funding section to the main README with NLnet and NGI0 Commons acknowledgements, project links, and sponsor logos. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 8569aec..2a044fa 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,13 @@ Manual test notes and troubleshooting: [test-apps/README.md](test-apps/README.md - `packages/nestjs-microservice` reads configuration from environment variables (prefixed with `WEBSDR_` in places). See the module entry and code for exact variable names. +## Funding + +This project is funded through [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/WSDR). + +[NLnet foundation logo](https://nlnet.nl) +[NGI Zero Logo](https://nlnet.nl/commonsfund) + ## License WebSDR is [MIT licensed](https://github.com/wavelet-lab/websdr/blob/main/LICENSE) From e2523d776c936ec7a06e42529a8e1ae0bb0a8982 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 28 May 2026 09:37:19 +0300 Subject: [PATCH 13/13] docs: remove outdated experimental development warning Drop the top-level README warning about unstable APIs and experimental features. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 2a044fa..937b217 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [WebSDR](https://github.com/wavelet-lab/websdr) is an open-source TypeScript monorepo that provides libraries and tools for building web applications that work with Software Defined Radios (SDR) using WebUSB and related browser/node tooling. -⚠️ This project is under active development. Some features are experimental and APIs may change. - ## Supported SDR hardware Currently supported SDR devices: