From 8c43450f56fa5b2f4f97aecdafbad2b7095433ec Mon Sep 17 00:00:00 2001 From: Reynaldo Endis Date: Sat, 3 Oct 2026 22:13:08 +0000 Subject: [PATCH 1/3] fix: preserve snapshot numbers and expose capture errors --- docs/runtime.md | 25 +++++ experimental/laws.go | 31 ++++-- experimental/machine.go | 53 ++++++--- experimental/snapshot_precision_test.go | 142 ++++++++++++++++++++++++ experimental/universe.go | 59 +++++++--- instrumentation/machine.go | 2 + instrumentation/snapshot.go | 39 ++++++- internal/util/numbers_test.go | 36 ++++++ internal/util/util.go | 105 +++++++++++++++++- 9 files changed, 449 insertions(+), 43 deletions(-) create mode 100644 experimental/snapshot_precision_test.go create mode 100644 internal/util/numbers_test.go diff --git a/docs/runtime.md b/docs/runtime.md index 301ac69..c2da5f6 100644 --- a/docs/runtime.md +++ b/docs/runtime.md @@ -130,6 +130,31 @@ Zero changes to the JSON definition. The existing `on.create-form` transition wi Use `qm.LoadSnapshot(snapshot, machineContext)` to restore a machine. Snapshots capture the latest machine context metadata but you must provide any external context objects when reloading. +For persistence, use the optional checked capture capability: + +```go +snapshot, err := instrumentation.GetSnapshotWithError(qm) +if err != nil { + return err +} +encoded, err := snapshot.ToJson() +``` + +The experimental runtime returns a complete snapshot or an error. Unsupported JSON values in +metadata or event data (such as channels, functions, cycles, or non-finite floats) fail capture. +The legacy `GetSnapshot()` method logs the failure and returns `nil`; check that result before use. +Existing third-party implementations do not need to add a method to the machine interface. The +checked helper returns an unsupported-capability error when a provider lacks `SnapshotProvider`. + +Snapshot capture, `json.Unmarshal` into `MachineSnapshot`, and `LoadSnapshot` preserve numeric +values through JSON round-trips. Ordinary values retain the previous `float64` representation; +integers and decimals whose value would change through that conversion retain `json.Number`. +Consumers of untyped metadata must support both representations. This includes integers above +the exact float64 range and long decimal fractions. Captured maps remain detached from live data. + +Inside a synchronous action, call `instrumentation.GetSnapshotWithError(args)` using the callback +arguments. Calling the owning machine directly would try to reacquire its execution lock. + `qm.ReplayOnEntry(ctx)` re-executes entry actions and invokes for every active universe without changing reality assignments. This is useful when you need to re-run side effects after downtime. diff --git a/experimental/laws.go b/experimental/laws.go index c58020c..588e139 100644 --- a/experimental/laws.go +++ b/experimental/laws.go @@ -1,6 +1,7 @@ package experimental import ( + "fmt" "log/slog" "sync" @@ -131,17 +132,18 @@ func (o *observerExecutorArgs) UpdateUniverseMetadata(md map[string]any) { // --------- ActionExecutorArgs ---------// type actionExecutorArgs struct { - context any - realityName string - universeCanonicalName string - universeID string - universeMetadata map[string]any - metadataMu *sync.Mutex - event instrumentation.Event - action theoretical.ActionModel - actionType instrumentation.ActionType - getSnapshotFn func() *instrumentation.MachineSnapshot - emittedEvents *[]instrumentation.EmittedEvent + context any + realityName string + universeCanonicalName string + universeID string + universeMetadata map[string]any + metadataMu *sync.Mutex + event instrumentation.Event + action theoretical.ActionModel + actionType instrumentation.ActionType + getSnapshotFn func() *instrumentation.MachineSnapshot + getSnapshotWithErrorFn func() (*instrumentation.MachineSnapshot, error) + emittedEvents *[]instrumentation.EmittedEvent } func (a *actionExecutorArgs) GetContext() any { @@ -176,6 +178,13 @@ func (a *actionExecutorArgs) GetSnapshot() *instrumentation.MachineSnapshot { return a.getSnapshotFn() } +func (a *actionExecutorArgs) GetSnapshotWithError() (*instrumentation.MachineSnapshot, error) { + if a.getSnapshotWithErrorFn == nil { + return nil, fmt.Errorf("snapshot provider does not support capture errors") + } + return a.getSnapshotWithErrorFn() +} + func (a *actionExecutorArgs) GetUniverseMetadata() map[string]any { return metaGet(a.metadataMu, a.universeMetadata) } diff --git a/experimental/machine.go b/experimental/machine.go index 5d3fb51..fb183f1 100644 --- a/experimental/machine.go +++ b/experimental/machine.go @@ -57,6 +57,7 @@ func NewExQuantumMachine(qmm *theoretical.QuantumMachineModel, universes []*ExUn u.constantsLawsExecutor = qm u.getSnapshotFn = qm.snapshotUnlocked + u.getSnapshotWithErrorFn = qm.snapshotUnlockedWithError qm.universes[u.model.ID] = u } @@ -169,16 +170,39 @@ func (qm *ExQuantumMachine) LoadSnapshot(snapshot *instrumentation.MachineSnapsh } func (qm *ExQuantumMachine) GetSnapshot() *instrumentation.MachineSnapshot { + snapshot, err := qm.GetSnapshotWithError() + if err != nil { + slog.Error("snapshot capture failed", "error", err) + } + return snapshot +} + +// GetSnapshotWithError returns a complete snapshot or an error, never a partial snapshot. +func (qm *ExQuantumMachine) GetSnapshotWithError() (*instrumentation.MachineSnapshot, error) { + if qm == nil { + return nil, fmt.Errorf("quantum machine must not be nil") + } qm.quantumMachineMtx.Lock() defer qm.quantumMachineMtx.Unlock() - return qm.snapshotUnlocked() + return qm.snapshotUnlockedWithError() } func (qm *ExQuantumMachine) snapshotUnlocked() *instrumentation.MachineSnapshot { + snapshot, err := qm.snapshotUnlockedWithError() + if err != nil { + slog.Error("snapshot capture failed", "error", err) + } + return snapshot +} + +func (qm *ExQuantumMachine) snapshotUnlockedWithError() (*instrumentation.MachineSnapshot, error) { var machineSnapshot = &instrumentation.MachineSnapshot{} for _, u := range qm.universes { - universeSnapshot := u.getSnapshot() + universeSnapshot, err := u.getSnapshotWithError() + if err != nil { + return nil, fmt.Errorf("capture snapshot for universe '%s': %w", u.model.ID, err) + } // add snapshot machineSnapshot.AddUniverseSnapshot(u.model.ID, universeSnapshot) @@ -205,7 +229,7 @@ func (qm *ExQuantumMachine) snapshotUnlocked() *instrumentation.MachineSnapshot machineSnapshot.AddTracking(u.model.ID, cloneStringSlice(u.tracking)) } - return machineSnapshot + return machineSnapshot, nil } func (qm *ExQuantumMachine) ReplayOnEntry(ctx context.Context) error { @@ -531,17 +555,18 @@ func (qm *ExQuantumMachine) executeAction(ctx context.Context, model *theoretica } a := &actionExecutorArgs{ - context: args.Context, - realityName: args.RealityName, - universeCanonicalName: args.UniverseCanonicalName, - universeID: args.UniverseID, - universeMetadata: u.metadata, - metadataMu: &u.metadataMu, - event: args.Event, - action: *model, - actionType: actionType, - getSnapshotFn: qm.snapshotUnlocked, - emittedEvents: args.EmittedEvents, + context: args.Context, + realityName: args.RealityName, + universeCanonicalName: args.UniverseCanonicalName, + universeID: args.UniverseID, + universeMetadata: u.metadata, + metadataMu: &u.metadataMu, + event: args.Event, + action: *model, + actionType: actionType, + getSnapshotFn: qm.snapshotUnlocked, + getSnapshotWithErrorFn: qm.snapshotUnlockedWithError, + emittedEvents: args.EmittedEvents, } if fn := builtin.GetAction(model.Src); fn != nil { diff --git a/experimental/snapshot_precision_test.go b/experimental/snapshot_precision_test.go new file mode 100644 index 0000000..4df231e --- /dev/null +++ b/experimental/snapshot_precision_test.go @@ -0,0 +1,142 @@ +package experimental + +import ( + "context" + "encoding/json" + "errors" + "strings" + "testing" + "time" + + "github.com/rendis/statepro/v3/instrumentation" + "github.com/rendis/statepro/v3/theoretical" +) + +func TestSnapshot_PreservaNumerosEnCapturaJSONYRestauracion(t *testing.T) { + qm, u := buildQM(t, "stateA", map[string]*theoretical.RealityModel{"stateA": newTransitionReality("stateA")}) + if err := qm.Init(context.Background(), nil); err != nil { + t.Fatal(err) + } + u.metadata = map[string]any{ + "integer": int64(9007199254740993), + "unsigned": uint64(18446744073709551615), + "decimal": json.Number("0.12345678901234567890123456789"), + "nested": []any{map[string]any{"count": json.Number("9007199254740993e0")}}, + "small": 42, + } + snapshot, err := instrumentation.GetSnapshotWithError(qm) + if err != nil { + t.Fatal(err) + } + metadata := snapshot.Snapshots["u1"]["metadata"].(map[string]any) + if metadata["small"] != float64(42) { + t.Fatal("numeros representables deben conservar el tipo legacy") + } + for key, expected := range map[string]string{"integer": "9007199254740993", "unsigned": "18446744073709551615", "decimal": "0.12345678901234567890123456789"} { + if metadata[key] != json.Number(expected) { + t.Fatalf("numero alterado %s: %#v", key, metadata[key]) + } + } + encoded, err := snapshot.ToJson() + if err != nil { + t.Fatal(err) + } + var decoded instrumentation.MachineSnapshot + if err := json.Unmarshal([]byte(encoded), &decoded); err != nil { + t.Fatal(err) + } + if err := qm.LoadSnapshot(&decoded, nil); err != nil { + t.Fatal(err) + } + restored, err := qm.GetSnapshotWithError() + if err != nil { + t.Fatal(err) + } + roundtrip, err := restored.ToJson() + if err != nil { + t.Fatal(err) + } + if encoded != roundtrip { + t.Fatalf("roundtrip modifica numeros:\n%s\n%s", encoded, roundtrip) + } + // Captured nested metadata must not alias live metadata after restoration. + u.metadata["nested"].([]any)[0].(map[string]any)["count"] = "changed" + if metadata["nested"].([]any)[0].(map[string]any)["count"] != json.Number("9007199254740993e0") { + t.Fatal("snapshot comparte metadata anidada") + } +} + +func TestSnapshot_ErrorNoDevuelveCapturaParcial(t *testing.T) { + realities := map[string]*theoretical.RealityModel{"stateA": newTransitionReality("stateA")} + qm, _, bad := buildMultiUniverseQM(t, "stateA", realities, "stateA", realities) + bad.metadata["unsupported"] = make(chan int) + snapshot, err := qm.GetSnapshotWithError() + var serializationError *json.UnsupportedTypeError + if snapshot != nil || !errors.As(err, &serializationError) || !strings.Contains(err.Error(), "u2") { + t.Fatalf("captura parcial o error perdido: %#v, %v", snapshot, err) + } + if qm.GetSnapshot() != nil { + t.Fatal("API legacy no debe devolver un snapshot incompleto") + } +} + +func TestSnapshot_PreservaNumerosEnEventosAcumulados(t *testing.T) { + qm, u := buildQM(t, "stateA", map[string]*theoretical.RealityModel{"stateA": newTransitionReality("stateA")}) + if err := qm.Init(context.Background(), nil); err != nil { + t.Fatal(err) + } + u.realityBeforeSuperposition = u.currentReality + u.currentReality = nil + u.inSuperposition = true + u.eventAccumulator = newEventAccumulator() + u.eventAccumulator.Accumulate("stateA", &Event{Name: "COUNT", Data: map[string]any{ + "count": int64(9007199254740993), "ratio": json.Number("0.12345678901234567890123456789"), "small": 42, + }}) + snapshot, err := qm.GetSnapshotWithError() + if err != nil { + t.Fatal(err) + } + encoded, err := snapshot.ToJson() + if err != nil { + t.Fatal(err) + } + var decoded instrumentation.MachineSnapshot + if err := json.Unmarshal([]byte(encoded), &decoded); err != nil { + t.Fatal(err) + } + if err := qm.LoadSnapshot(&decoded, nil); err != nil { + t.Fatal(err) + } + events := u.eventAccumulator.GetStatistics().GetRealitiesEvents()["stateA"] + if len(events) != 1 { + t.Fatalf("eventos alterados: %v", events) + } + data := events[0].GetData() + if data["count"] != json.Number("9007199254740993") || data["ratio"] != json.Number("0.12345678901234567890123456789") || data["small"] != float64(42) { + t.Fatalf("datos de evento alterados: %#v", data) + } +} + +func TestSnapshot_AccionCapturaConErrorSinReentrarMutex(t *testing.T) { + var captured error + registerTestAction(t, "test:checked-snapshot", func(_ context.Context, args instrumentation.ActionExecutorArgs) error { + _, captured = instrumentation.GetSnapshotWithError(args) + return nil + }) + qm, u := buildQM(t, "stateA", map[string]*theoretical.RealityModel{"stateA": newTransitionReality("stateA", withEntryAction("test:checked-snapshot"))}) + u.metadata["unsupported"] = make(chan int) + done := make(chan error, 1) + go func() { done <- qm.Init(context.Background(), nil) }() + select { + case err := <-done: + if err != nil { + t.Fatal(err) + } + var serializationError *json.UnsupportedTypeError + if !errors.As(captured, &serializationError) { + t.Fatalf("error de captura perdido: %v", captured) + } + case <-time.After(2 * time.Second): + t.Fatal("captura desde args bloqueada por reentrada") + } +} diff --git a/experimental/universe.go b/experimental/universe.go index c5140e7..61532af 100644 --- a/experimental/universe.go +++ b/experimental/universe.go @@ -106,7 +106,8 @@ type ExUniverse struct { // getSnapshotFn returns a snapshot without taking the machine mutex. // Used from actions that already run under quantumMachineMtx. - getSnapshotFn func() *instrumentation.MachineSnapshot + getSnapshotFn func() *instrumentation.MachineSnapshot + getSnapshotWithErrorFn func() (*instrumentation.MachineSnapshot, error) } //------------------------------- External Operations -------------------------------// @@ -182,6 +183,14 @@ func (u *ExUniverse) startOnReality(ctx context.Context, realityName string, uni // getSnapshot returns a snapshot of the universe func (u *ExUniverse) getSnapshot() instrumentation.SerializedUniverseSnapshot { + snapshot, err := u.getSnapshotWithError() + if err != nil { + slog.Error("snapshot capture failed", "universe", u.model.ID, "error", err) + } + return snapshot +} + +func (u *ExUniverse) getSnapshotWithError() (instrumentation.SerializedUniverseSnapshot, error) { u.metadataMu.Lock() metadataCopy := cloneAnyMap(u.metadata) u.metadataMu.Unlock() @@ -204,8 +213,8 @@ func (u *ExUniverse) getSnapshot() instrumentation.SerializedUniverseSnapshot { } } - m, _ := util.StructToMap(infoSnapshot) - return m + m, err := util.StructToMap(infoSnapshot) + return m, err } // decodeSnapshot validates a detached snapshot without changing live state. @@ -213,10 +222,20 @@ func (u *ExUniverse) decodeSnapshot(universeSnapshot instrumentation.SerializedU if universeSnapshot == nil { return nil, fmt.Errorf("snapshot for universe '%s' must not be nil", u.model.ID) } - snapshot, err := util.MapToStruct[UniverseInfoSnapshot](universeSnapshot) + snapshot, err := util.MapToStructWithNumbers[UniverseInfoSnapshot](universeSnapshot) if err != nil { return nil, errors.Join(fmt.Errorf("error loading snapshot for universe '%s'", u.model.ID), err) } + util.NormalizeJSONNumbers(snapshot.Metadata) + if snapshot.Accumulator != nil { + for _, events := range snapshot.Accumulator.RealitiesEvents { + for _, event := range events { + if event != nil { + util.NormalizeJSONNumbers(event.Data) + } + } + } + } invalid := func(reason string) (*UniverseInfoSnapshot, error) { return nil, fmt.Errorf("invalid snapshot for universe '%s': %s", u.model.ID, reason) } @@ -997,17 +1016,18 @@ func (u *ExUniverse) executeActions( // execute actions for _, action := range actionModels { args := &actionExecutorArgs{ - context: u.universeContext, - realityName: *u.currentReality, - universeCanonicalName: u.model.CanonicalName, - universeID: u.model.ID, - universeMetadata: u.metadata, - metadataMu: &u.metadataMu, - event: event, - action: *action, - actionType: actionType, - getSnapshotFn: u.snapshotProvider(), - emittedEvents: emittedEvents, + context: u.universeContext, + realityName: *u.currentReality, + universeCanonicalName: u.model.CanonicalName, + universeID: u.model.ID, + universeMetadata: u.metadata, + metadataMu: &u.metadataMu, + event: event, + action: *action, + actionType: actionType, + getSnapshotFn: u.snapshotProvider(), + getSnapshotWithErrorFn: u.snapshotWithErrorProvider(), + emittedEvents: emittedEvents, } if err := u.runActionExecutor(ctx, action.Src, args); err != nil { return errors.Join(fmt.Errorf("error executing action '%s'", action.Src), err) @@ -1211,6 +1231,15 @@ func (u *ExUniverse) snapshotProvider() func() *instrumentation.MachineSnapshot return func() *instrumentation.MachineSnapshot { return nil } } +func (u *ExUniverse) snapshotWithErrorProvider() func() (*instrumentation.MachineSnapshot, error) { + if u.getSnapshotWithErrorFn != nil { + return u.getSnapshotWithErrorFn + } + return func() (*instrumentation.MachineSnapshot, error) { + return instrumentation.GetSnapshotWithError(u.constantsLawsExecutor) + } +} + func (u *ExUniverse) universeConstants() *theoretical.UniversalConstantsModel { if u.model == nil { return nil diff --git a/instrumentation/machine.go b/instrumentation/machine.go index 55040dd..633e3e0 100644 --- a/instrumentation/machine.go +++ b/instrumentation/machine.go @@ -52,6 +52,8 @@ type QuantumMachine interface { LoadSnapshot(snapshot *MachineSnapshot, machineContext any) error // GetSnapshot captures the current complete state of the quantum machine. + // The experimental runtime logs serialization failures and returns nil. Use + // GetSnapshotWithError for checked capture when the provider supports it. // The snapshot includes for each universe: current reality, superposition state, tracking history, // and categorization into active universes (running), finalized universes (in final state), // or superposition universes (awaiting collapse). diff --git a/instrumentation/snapshot.go b/instrumentation/snapshot.go index 0ab34b4..6eae968 100644 --- a/instrumentation/snapshot.go +++ b/instrumentation/snapshot.go @@ -1,6 +1,27 @@ package instrumentation -import "encoding/json" +import ( + "bytes" + "encoding/json" + "errors" + + "github.com/rendis/statepro/v3/internal/util" +) + +// SnapshotProvider is an optional capability for callers that need capture errors. +// QuantumMachine and executor interfaces remain compatible with existing implementations. +type SnapshotProvider interface { + GetSnapshotWithError() (*MachineSnapshot, error) +} + +// GetSnapshotWithError captures from a machine or synchronous action args exposing +// SnapshotProvider. It returns an error for providers without that capability. +func GetSnapshotWithError(source interface{ GetSnapshot() *MachineSnapshot }) (*MachineSnapshot, error) { + if provider, ok := source.(SnapshotProvider); ok { + return provider.GetSnapshotWithError() + } + return nil, errors.New("snapshot provider does not support capture errors") +} type SerializedUniverseSnapshot map[string]any @@ -17,6 +38,22 @@ type MachineSnapshot struct { Tracking map[string][]string `json:"tracking,omitempty" bson:"tracking,omitempty" xml:"tracking,omitempty"` } +// UnmarshalJSON preserves numeric values that cannot round-trip through float64. +func (ms *MachineSnapshot) UnmarshalJSON(data []byte) error { + type snapshotJSON MachineSnapshot + var decoded snapshotJSON + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + if err := decoder.Decode(&decoded); err != nil { + return err + } + for _, snapshot := range decoded.Snapshots { + util.NormalizeJSONNumbers(map[string]any(snapshot)) + } + *ms = MachineSnapshot(decoded) + return nil +} + type UniversesResume struct { // ActiveUniverses is the map of the active universes // key: universe id, value: universe current reality diff --git a/internal/util/numbers_test.go b/internal/util/numbers_test.go new file mode 100644 index 0000000..bdb1836 --- /dev/null +++ b/internal/util/numbers_test.go @@ -0,0 +1,36 @@ +package util + +import ( + "encoding/json" + "testing" +) + +func TestNormalizeJSONNumbers_ConservaValorDecimal(t *testing.T) { + for _, test := range []struct { + number string + precise bool + }{ + {"42", true}, {"1.25", true}, {"1e3", true}, {"-0", true}, {"0e99999999999999999999", false}, + {"9007199254740993", false}, {"9007199254740994", true}, {"0.1234567890123456789", false}, {"1e400", false}, + } { + t.Run(test.number, func(t *testing.T) { + got := NormalizeJSONNumbers(json.Number(test.number)) + _, isFloat := got.(float64) + if isFloat != test.precise { + t.Fatalf("tipo inesperado: %#v", got) + } + if !test.precise && got != json.Number(test.number) { + t.Fatal("numero alterado") + } + }) + } +} + +func TestToInt_AceptaJSONNumberYRechazaOverflow(t *testing.T) { + if value, ok := ToInt(json.Number("42")); !ok || value != 42 { + t.Fatal("contador JSON no soportado") + } + if _, ok := ToInt(json.Number("18446744073709551615")); ok { + t.Fatal("overflow aceptado") + } +} diff --git a/internal/util/util.go b/internal/util/util.go index 777a7c2..84ba852 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -1,11 +1,20 @@ package util -import "encoding/json" +import ( + "bytes" + "encoding/json" + "math" + "strconv" + "strings" +) // ToInt converts any built-in numeric type to int. // Returns false if v is not a recognized numeric type. func ToInt(v any) (int, bool) { switch n := v.(type) { + case json.Number: + value, err := strconv.Atoi(n.String()) + return value, err == nil case float64: return int(n), true case float32: @@ -42,12 +51,104 @@ func StructToMap(s any) (map[string]any, error) { return nil, err } var out map[string]any - if err := json.Unmarshal(data, &out); err != nil { + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + if err := decoder.Decode(&out); err != nil { return nil, err } + NormalizeJSONNumbers(out) return out, nil } +// NormalizeJSONNumbers keeps legacy float64 values when JSON round-tripping is +// exact, and retains json.Number when conversion would alter the numeric value. +// The maps and slices supplied by a JSON decoder are normalized in place. +func NormalizeJSONNumbers(value any) any { + switch value := value.(type) { + case map[string]any: + for key, entry := range value { + value[key] = NormalizeJSONNumbers(entry) + } + case []any: + for index, entry := range value { + value[index] = NormalizeJSONNumbers(entry) + } + case json.Number: + candidate, err := strconv.ParseFloat(value.String(), 64) + if err != nil { + return value + } + encoded, err := json.Marshal(candidate) + if err != nil { + return value + } + original, ok := canonicalNumber(value.String()) + roundtrip, roundtripOK := canonicalNumber(string(encoded)) + if ok && roundtripOK && original == roundtrip { + return candidate + } + } + return value +} + +type decimalNumber struct { + negative bool + digits string + exponent int64 +} + +// Compare decimal values without expanding exponents or allocating large integers. +func canonicalNumber(value string) (decimalNumber, bool) { + var result decimalNumber + if strings.HasPrefix(value, "-") { + result.negative = true + value = value[1:] + } + if index := strings.IndexAny(value, "eE"); index >= 0 { + exponent, err := strconv.ParseInt(value[index+1:], 10, 64) + if err != nil { + return result, false + } + result.exponent = exponent + value = value[:index] + } + if index := strings.IndexByte(value, '.'); index >= 0 { + fractionLength := int64(len(value) - index - 1) + if result.exponent < math.MinInt64+fractionLength { + return result, false + } + result.exponent -= fractionLength + value = value[:index] + value[index+1:] + } + value = strings.TrimLeft(value, "0") + if value == "" { + return decimalNumber{digits: "0"}, true + } + trimmed := strings.TrimRight(value, "0") + trailing := int64(len(value) - len(trimmed)) + if result.exponent > math.MaxInt64-trailing { + return result, false + } + result.exponent += trailing + result.digits = trimmed + return result, true +} + +// MapToStructWithNumbers preserves numbers in interface-valued fields. +func MapToStructWithNumbers[T any](m map[string]any) (*T, error) { + data, err := json.Marshal(m) + if err != nil { + return nil, err + } + var out T + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + if err := decoder.Decode(&out); err != nil { + return nil, err + } + return &out, nil +} + // MapToStruct converts a map[string]any to a struct of type T via JSON round-trip. func MapToStruct[T any](m map[string]any) (*T, error) { data, err := json.Marshal(m) From 2557fb4c82a93db6bfc39851d7a377d60c379555 Mon Sep 17 00:00:00 2001 From: Reynaldo Endis Date: Sat, 3 Oct 2026 22:13:09 +0000 Subject: [PATCH 2/3] build: update Studio dependencies and enforce quality checks --- .github/workflows/quality.yml | 55 + studio/app/package.json | 9 +- studio/app/postcss.config.cjs | 6 - studio/app/src/styles.css | 15 +- studio/app/tailwind.config.ts | 13 - studio/app/vite.config.ts | 3 +- studio/eslint.config.mjs | 24 + studio/package.json | 14 +- studio/packages/editor-core/package.json | 7 +- .../editor-core/src/StateProEditor.tsx | 8 +- .../src/__tests__/JsonIOModal.test.tsx | 30 + .../src/__tests__/PropertiesModal.test.tsx | 27 + .../src/__tests__/serializeStatePro.test.ts | 14 +- .../shared/MetadataPackBindingsEditor.tsx | 2 +- .../shared/tooltip/StudioTooltip.tsx | 2 +- .../src/features/modals/JsonIOModal.tsx | 8 +- .../src/features/modals/LibraryModal.tsx | 2 - .../src/features/modals/PropertiesModal.tsx | 8 +- .../editor-core/src/utils/issueMapping.ts | 6 +- .../editor-core/vitest.mutation.config.ts | 6 +- studio/packages/web-component/package.json | 4 +- studio/pnpm-lock.yaml | 1746 ++++++++++++----- 22 files changed, 1405 insertions(+), 604 deletions(-) create mode 100644 .github/workflows/quality.yml delete mode 100644 studio/app/postcss.config.cjs delete mode 100644 studio/app/tailwind.config.ts create mode 100644 studio/eslint.config.mjs create mode 100644 studio/packages/editor-core/src/__tests__/JsonIOModal.test.tsx diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..61c73f0 --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,55 @@ +name: Quality + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: quality-${{ github.ref }} + cancel-in-progress: true + +jobs: + go: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 + with: + go-version-file: go.mod + check-latest: true + - run: go build ./... + - run: go vet ./... + - run: go test -race -cover ./... + - run: make test-fuzz-smoke + env: + GOMAXPROCS: "2" + + studio: + runs-on: ubuntu-latest + timeout-minutes: 20 + defaults: + run: + working-directory: studio + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 + with: + version: 10.11.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: "24" + cache: pnpm + cache-dependency-path: studio/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + - run: pnpm lint + - run: pnpm typecheck + - run: pnpm test + - run: pnpm --filter @rendis/statepro-studio-react exec stryker run --dryRunOnly + - run: pnpm build + - run: pnpm audit --audit-level=low diff --git a/studio/app/package.json b/studio/app/package.json index ad48590..9a8f22a 100644 --- a/studio/app/package.json +++ b/studio/app/package.json @@ -10,7 +10,7 @@ "preview": "vite preview", "test": "vitest run --passWithNoTests", "typecheck": "tsc --noEmit", - "lint": "echo 'lint: pendiente de reglas'" + "lint": "eslint . --max-warnings 0" }, "dependencies": { "@rendis/statepro-studio-react": "workspace:*", @@ -25,12 +25,11 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^4.4.1", - "autoprefixer": "^10.4.20", "jsdom": "^26.0.1", - "postcss": "^8.5.26", - "tailwindcss": "^3.4.17", + "tailwindcss": "^4.3.3", "typescript": "^5.7.3", "vite": "^6.4.3", - "vitest": "^3.2.6" + "vitest": "^4.1.11", + "@tailwindcss/vite": "^4.3.3" } } diff --git a/studio/app/postcss.config.cjs b/studio/app/postcss.config.cjs deleted file mode 100644 index 12a703d..0000000 --- a/studio/app/postcss.config.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/studio/app/src/styles.css b/studio/app/src/styles.css index 14bf126..fac0068 100644 --- a/studio/app/src/styles.css +++ b/studio/app/src/styles.css @@ -1,6 +1,15 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; +@source "../../packages/editor-core/src"; + +/* Preserve the previous reset while migrating the build pipeline. */ +@layer base { + *, ::before, ::after { + border-color: var(--color-gray-200, currentColor); + } + button:not(:disabled), [role="button"]:not(:disabled) { + cursor: pointer; + } +} html, body, diff --git a/studio/app/tailwind.config.ts b/studio/app/tailwind.config.ts deleted file mode 100644 index e7348d1..0000000 --- a/studio/app/tailwind.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Config } from "tailwindcss"; - -export default { - content: [ - "./index.html", - "./src/**/*.{ts,tsx}", - "../packages/editor-core/src/**/*.{ts,tsx}" - ], - theme: { - extend: {}, - }, - plugins: [], -} satisfies Config; diff --git a/studio/app/vite.config.ts b/studio/app/vite.config.ts index 40cde80..edb9b5a 100644 --- a/studio/app/vite.config.ts +++ b/studio/app/vite.config.ts @@ -3,6 +3,7 @@ import { fileURLToPath } from "node:url"; import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; const appRoot = path.dirname(fileURLToPath(import.meta.url)); const workspaceRoot = path.resolve(appRoot, ".."); @@ -23,7 +24,7 @@ export default defineConfig(({ mode }) => { const useSourceAlias = isSourceAliasEnabled(mode); return { - plugins: [react()], + plugins: [react(), tailwindcss()], resolve: { alias: useSourceAlias ? [ diff --git a/studio/eslint.config.mjs b/studio/eslint.config.mjs new file mode 100644 index 0000000..d08e9ba --- /dev/null +++ b/studio/eslint.config.mjs @@ -0,0 +1,24 @@ +import js from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; +import reactHooks from "eslint-plugin-react-hooks"; + +export default tseslint.config( + { ignores: ["**/dist/**", "**/node_modules/**", "**/reports/**", "**/coverage/**", "**/.stryker-tmp/**", "**/src/generated/**"] }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ["**/*.{js,mjs,cjs,ts,tsx}"], + languageOptions: { globals: { ...globals.browser, ...globals.node } }, + rules: { + // JSON metadata and executor arguments intentionally accept dynamic values. + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": ["error", { args: "none", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_", ignoreRestSiblings: true }], + }, + }, + { + files: ["**/*.{ts,tsx}"], + plugins: { "react-hooks": reactHooks }, + rules: { "react-hooks/rules-of-hooks": "error" }, + }, +); diff --git a/studio/package.json b/studio/package.json index 0d3e1a6..5eb4737 100644 --- a/studio/package.json +++ b/studio/package.json @@ -10,10 +10,15 @@ "build": "pnpm -r --if-present build", "test": "pnpm -r --if-present test", "typecheck": "pnpm -r --if-present typecheck", - "lint": "pnpm -r --if-present lint" + "lint": "eslint app packages scripts --max-warnings 0" }, "devDependencies": { - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "eslint": "^9.39.5", + "@eslint/js": "^9.39.5", + "typescript-eslint": "^8.0.0", + "globals": "^16.0.0", + "eslint-plugin-react-hooks": "^7.0.0" }, "pnpm": { "overrides": { @@ -23,7 +28,7 @@ "fast-uri": "^3.1.8", "postcss": "^8.5.26", "vite": "^6.4.3", - "vitest": "^3.2.6", + "vitest": "^4.1.11", "qs": "^6.16.0", "browserslist": "^4.28.7", "baseline-browser-mapping": "^2.11.0", @@ -32,5 +37,8 @@ "@babel/core": "^7.29.6", "esbuild@^0.27.0": "0.28.2" } + }, + "engines": { + "node": ">=22" } } diff --git a/studio/packages/editor-core/package.json b/studio/packages/editor-core/package.json index c135066..93d3cf7 100644 --- a/studio/packages/editor-core/package.json +++ b/studio/packages/editor-core/package.json @@ -28,7 +28,7 @@ "test": "pnpm run generate:builtin-catalog && vitest run", "test:mutation": "pnpm run generate:builtin-catalog && stryker run", "typecheck": "tsc --noEmit", - "lint": "echo 'lint: pendiente de reglas'" + "lint": "eslint . --max-warnings 0" }, "peerDependencies": { "react": "^19.2.4", @@ -39,7 +39,8 @@ "ajv": "^8.17.1", "elkjs": "^0.11.0", "lucide-react": "^0.468.0", - "react-zoom-pan-pinch": "^3.7.0" + "react-zoom-pan-pinch": "^3.7.0", + "fast-deep-equal": "^3.1.3" }, "devDependencies": { "@stryker-mutator/core": "^10.0.0", @@ -52,6 +53,6 @@ "jsdom": "^26.0.1", "tsup": "^8.5.0", "typescript": "^5.7.3", - "vitest": "^3.2.6" + "vitest": "^4.1.11" } } diff --git a/studio/packages/editor-core/src/StateProEditor.tsx b/studio/packages/editor-core/src/StateProEditor.tsx index d0b125e..7bfd5a1 100644 --- a/studio/packages/editor-core/src/StateProEditor.tsx +++ b/studio/packages/editor-core/src/StateProEditor.tsx @@ -4,7 +4,6 @@ import { Copy, Info, Maximize, - Play, PlusCircle, Settings2, StickyNote, @@ -122,7 +121,6 @@ import { import { MachineGlobalPanel } from "./features/machine"; import { resolveInitialStudioLocale, - resolveSerializeIssueMessage, StudioI18nProvider, useI18n, type StudioLocale, @@ -1915,7 +1913,7 @@ function StateProEditorInner({ ? (viewport.height / 2 - transform.positionY) / transform.scale - height / 2 : 1000; - let newX = centerX; + const newX = centerX; let newY = centerY; let overlaps = true; @@ -3804,7 +3802,7 @@ function StateProEditorInner({ if (!r) return; const newId = `reality-${Date.now()}`; - let newX = r.x; + const newX = r.x; let newY = r.y + 170; let overlaps = true; @@ -3903,7 +3901,7 @@ function StateProEditorInner({ ); const newUniverseId = `universe-${Date.now()}`; - let newX = universe.x; + const newX = universe.x; let newY = universe.y + universe.h + 30; let overlaps = true; diff --git a/studio/packages/editor-core/src/__tests__/JsonIOModal.test.tsx b/studio/packages/editor-core/src/__tests__/JsonIOModal.test.tsx new file mode 100644 index 0000000..b6ce260 --- /dev/null +++ b/studio/packages/editor-core/src/__tests__/JsonIOModal.test.tsx @@ -0,0 +1,30 @@ +import "@testing-library/jest-dom"; +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import { JsonIOModal } from "../features/modals/JsonIOModal"; + +describe("JsonIOModal", () => { + it("permite habilitar pestañas y reabrir sin cambiar el orden de hooks", () => { + const props = { + isOpen: true, + modelJson: '{"id":"machine"}', + layoutJson: "{}", + modelIssues: [], + canExportModel: true, + onClose: vi.fn(), + onImportModel: vi.fn(), + onImportLayout: vi.fn(), + }; + const { container, rerender } = render( + , + ); + expect(container).toBeEmptyDOMElement(); + rerender(); + expect(screen.getByRole("textbox")).toBeInTheDocument(); + rerender(); + expect(container).toBeEmptyDOMElement(); + rerender(); + expect(screen.getByText(props.modelJson)).toBeInTheDocument(); + }); +}); diff --git a/studio/packages/editor-core/src/__tests__/PropertiesModal.test.tsx b/studio/packages/editor-core/src/__tests__/PropertiesModal.test.tsx index e32e38c..28ffcbe 100644 --- a/studio/packages/editor-core/src/__tests__/PropertiesModal.test.tsx +++ b/studio/packages/editor-core/src/__tests__/PropertiesModal.test.tsx @@ -79,6 +79,33 @@ const noopRenameHandlers = { }; describe("PropertiesModal transition behavior", () => { + it("permite abrir, cerrar y volver a abrir sin cambiar el orden de hooks", () => { + const universe = nodes.find(node => node.type === "universe")!; + const reality = nodes.find(node => node.type === "reality")!; + const props = { + nodes, + transitions: [transition], + onClose: vi.fn(), + updateNodeData: vi.fn(), + ...noopRenameHandlers, + updateTransitionData: vi.fn(), + moveTransition: vi.fn(), + openBehaviorModal: vi.fn(), + registry: [], + metadataPackRegistry: [], + metadataPackBindings: { machine: [], universe: [], reality: [], transition: [] }, + setMetadataPackBindings: vi.fn(), + }; + const { container, rerender } = render(); + expect(container).toBeEmptyDOMElement(); + rerender(); + expect(screen.getAllByDisplayValue("main").length).toBeGreaterThan(0); + rerender(); + expect(container).toBeEmptyDOMElement(); + rerender(); + expect(screen.getByDisplayValue("idle")).toBeInTheDocument(); + }); + it("en universo emparejado bloquea id y edita canonical con syncId", () => { const universe = nodes.find( (node): node is Extract => node.type === "universe", diff --git a/studio/packages/editor-core/src/__tests__/serializeStatePro.test.ts b/studio/packages/editor-core/src/__tests__/serializeStatePro.test.ts index 4b7e10e..6114b0c 100644 --- a/studio/packages/editor-core/src/__tests__/serializeStatePro.test.ts +++ b/studio/packages/editor-core/src/__tests__/serializeStatePro.test.ts @@ -292,21 +292,21 @@ describe("serializeStatePro", () => { throw new Error("Missing fixtures"); } - universe.data.metadata = '{\"origin\":\"manual\",\"_ui_note\":{\"text\":\"stale\",\"colorIndex\":4}}'; + universe.data.metadata = '{"origin":"manual","_ui_note":{"text":"stale","colorIndex":4}}'; universe.data.note = { text: "Universe note", colorIndex: 2 }; - reality.data.metadata = '{\"hint\":\"manual reality\",\"_ui_note\":{\"text\":\"stale\"}}'; + reality.data.metadata = '{"hint":"manual reality","_ui_note":{"text":"stale"}}'; reality.data.note = { text: "Reality note", colorIndex: 1 }; state.transitions = [ { ...state.transitions[0], - metadata: '{\"debug\":true,\"_ui_note\":{\"text\":\"stale transition\",\"colorIndex\":4}}', + metadata: '{"debug":true,"_ui_note":{"text":"stale transition","colorIndex":4}}', note: { text: "Transition note", colorIndex: 3 }, }, ]; state.machineConfig.metadata = - '{\"author\":\"rendis\",\"_ui_notes\":[{\"x\":1,\"y\":2,\"text\":\"stale\",\"colorIndex\":4}]}'; + '{"author":"rendis","_ui_notes":[{"x":1,"y":2,"text":"stale","colorIndex":4}]}'; state.nodes.push({ id: "note-1", type: "note", @@ -351,12 +351,12 @@ describe("serializeStatePro", () => { throw new Error("Missing universe fixture"); } - universe.data.metadata = '{\"custom\":true,\"_ui_note\":{\"text\":\"legacy\",\"colorIndex\":2}}'; - state.machineConfig.metadata = '{\"name\":\"machine\",\"_ui_notes\":[{\"x\":1,\"y\":1,\"text\":\"legacy\"}]}'; + universe.data.metadata = '{"custom":true,"_ui_note":{"text":"legacy","colorIndex":2}}'; + state.machineConfig.metadata = '{"name":"machine","_ui_notes":[{"x":1,"y":1,"text":"legacy"}]}'; state.transitions = [ { ...state.transitions[0], - metadata: '{\"custom\":true,\"_ui_note\":{\"text\":\"legacy transition\"}}', + metadata: '{"custom":true,"_ui_note":{"text":"legacy transition"}}', }, ]; diff --git a/studio/packages/editor-core/src/components/shared/MetadataPackBindingsEditor.tsx b/studio/packages/editor-core/src/components/shared/MetadataPackBindingsEditor.tsx index 975c66e..916a560 100644 --- a/studio/packages/editor-core/src/components/shared/MetadataPackBindingsEditor.tsx +++ b/studio/packages/editor-core/src/components/shared/MetadataPackBindingsEditor.tsx @@ -327,7 +327,7 @@ export const MetadataPackBindingsEditor = ({ onClick={() => setCollapsedByBindingId((previous) => ({ ...previous, - [binding.id]: !Boolean(previous[binding.id]), + [binding.id]: !previous[binding.id], })) } className="absolute top-2 right-2 inline-flex items-center justify-center w-5 h-5 rounded border border-slate-700 text-slate-300 hover:bg-slate-900/50" diff --git a/studio/packages/editor-core/src/components/shared/tooltip/StudioTooltip.tsx b/studio/packages/editor-core/src/components/shared/tooltip/StudioTooltip.tsx index 154bdd1..6375440 100644 --- a/studio/packages/editor-core/src/components/shared/tooltip/StudioTooltip.tsx +++ b/studio/packages/editor-core/src/components/shared/tooltip/StudioTooltip.tsx @@ -54,7 +54,7 @@ export const StudioTooltip = ({ }: StudioTooltipProps) => { const [isVisible, setIsVisible] = useState(false); - const { refs, floatingStyles, context } = useFloating({ + const { refs, floatingStyles } = useFloating({ open: isVisible, onOpenChange: setIsVisible, placement: TOOLTIP_SIDE_TO_PLACEMENT[side], diff --git a/studio/packages/editor-core/src/features/modals/JsonIOModal.tsx b/studio/packages/editor-core/src/features/modals/JsonIOModal.tsx index 745a381..e58bf2b 100644 --- a/studio/packages/editor-core/src/features/modals/JsonIOModal.tsx +++ b/studio/packages/editor-core/src/features/modals/JsonIOModal.tsx @@ -69,10 +69,6 @@ export const JsonIOModal = ({ return tabs; }, [allowExport, allowImport]); - if (visibleTabs.length === 0) { - return null; - } - const importValidation = useMemo(() => { if (!jsonText.trim()) { return { @@ -113,12 +109,12 @@ export const JsonIOModal = ({ }, [documentType, jsonText]); useEffect(() => { - if (!visibleTabs.includes(activeTab)) { + if (visibleTabs.length > 0 && !visibleTabs.includes(activeTab)) { setActiveTab(visibleTabs[0]); } }, [activeTab, visibleTabs]); - if (!isOpen) return null; + if (!isOpen || visibleTabs.length === 0) return null; const exportIssues = documentType === "model" ? modelIssues : []; const exportErrorIssues = exportIssues.filter((issue) => issue.severity === "error"); diff --git a/studio/packages/editor-core/src/features/modals/LibraryModal.tsx b/studio/packages/editor-core/src/features/modals/LibraryModal.tsx index f36285c..1ed56e4 100644 --- a/studio/packages/editor-core/src/features/modals/LibraryModal.tsx +++ b/studio/packages/editor-core/src/features/modals/LibraryModal.tsx @@ -900,8 +900,6 @@ export const LibraryModal = ({ const [showPackGeneratedPreview, setShowPackGeneratedPreview] = useState(false); const resolveBehaviorOrigin = (src: string): BehaviorRegistrySource => behaviorSourceIndex[src] || "user"; - const isBuiltinBehavior = (src: string): boolean => - resolveBehaviorOrigin(src) === "builtin"; const packFieldValidation = useMemo( () => buildVisualFieldValidation(packForm?.fields || [], t), [packForm?.fields, t], diff --git a/studio/packages/editor-core/src/features/modals/PropertiesModal.tsx b/studio/packages/editor-core/src/features/modals/PropertiesModal.tsx index d4ed9e1..78d78c6 100644 --- a/studio/packages/editor-core/src/features/modals/PropertiesModal.tsx +++ b/studio/packages/editor-core/src/features/modals/PropertiesModal.tsx @@ -102,10 +102,8 @@ const PropertiesModal = ({ setActiveTab("general"); }, [element?.id]); - if (!element) return null; - - const universeElement = element.type === "universe" ? element : null; - const realityElement = element.type === "reality" ? element : null; + const universeElement = element?.type === "universe" ? element : null; + const realityElement = element?.type === "reality" ? element : null; useEffect(() => { if (universeElement) { @@ -129,6 +127,8 @@ const PropertiesModal = ({ universeElement?.id, ]); + if (!element) return null; + const commitUniverseIdDraft = () => { if (!universeElement || universeIdCanonicalLinked) { return; diff --git a/studio/packages/editor-core/src/utils/issueMapping.ts b/studio/packages/editor-core/src/utils/issueMapping.ts index cf77c0e..c8016c1 100644 --- a/studio/packages/editor-core/src/utils/issueMapping.ts +++ b/studio/packages/editor-core/src/utils/issueMapping.ts @@ -134,13 +134,13 @@ export const buildIssueIndex = ( const field = issue.field || ""; let assigned = false; - const transitionById = field.match(/^transition:([^.\[]+)/); + const transitionById = field.match(/^transition:([^.[]+)/); if (transitionById?.[1]) { pushIssue(index.transitions, transitionById[1], issue); assigned = true; } - const universeMeta = field.match(/^universe:([^.\[]+)/); + const universeMeta = field.match(/^universe:([^.[]+)/); if (universeMeta?.[1]) { const universeNode = universeByDataId.get(universeMeta[1]); if (universeNode) { @@ -149,7 +149,7 @@ export const buildIssueIndex = ( } } - const realityMeta = field.match(/^reality:([^.\[]+)\.([^.\[]+)/); + const realityMeta = field.match(/^reality:([^.[]+)\.([^.[]+)/); if (realityMeta?.[1] && realityMeta[2]) { const universeNode = universeByDataId.get(realityMeta[1]); const realityNode = universeNode diff --git a/studio/packages/editor-core/vitest.mutation.config.ts b/studio/packages/editor-core/vitest.mutation.config.ts index 99b0107..dd49d87 100644 --- a/studio/packages/editor-core/vitest.mutation.config.ts +++ b/studio/packages/editor-core/vitest.mutation.config.ts @@ -12,11 +12,7 @@ export default defineConfig({ "src/__tests__/issueMapping.test.ts", ], pool: "forks", - poolOptions: { - forks: { - singleFork: true, - }, - }, + maxWorkers: 1, fileParallelism: false, }, }); diff --git a/studio/packages/web-component/package.json b/studio/packages/web-component/package.json index 804849e..9f0965c 100644 --- a/studio/packages/web-component/package.json +++ b/studio/packages/web-component/package.json @@ -23,7 +23,7 @@ "build": "tsup src/index.ts --format esm,cjs --dts --sourcemap --clean", "test": "vitest run --passWithNoTests", "typecheck": "tsc --noEmit", - "lint": "echo 'lint: pendiente de reglas'" + "lint": "eslint . --max-warnings 0" }, "dependencies": { "@rendis/statepro-studio-react": "workspace:*", @@ -35,6 +35,6 @@ "@types/react-dom": "^19.2.3", "tsup": "^8.5.0", "typescript": "^5.7.3", - "vitest": "^3.2.6" + "vitest": "^4.1.11" } } diff --git a/studio/pnpm-lock.yaml b/studio/pnpm-lock.yaml index db5751a..845f5eb 100644 --- a/studio/pnpm-lock.yaml +++ b/studio/pnpm-lock.yaml @@ -11,7 +11,7 @@ overrides: fast-uri: ^3.1.8 postcss: ^8.5.26 vite: ^6.4.3 - vitest: ^3.2.6 + vitest: ^4.1.11 qs: ^6.16.0 browserslist: ^4.28.7 baseline-browser-mapping: ^2.11.0 @@ -24,9 +24,24 @@ importers: .: devDependencies: + '@eslint/js': + specifier: ^9.39.5 + version: 9.39.5 + eslint: + specifier: ^9.39.5 + version: 9.39.5(jiti@2.7.0) + eslint-plugin-react-hooks: + specifier: ^7.0.0 + version: 7.1.1(eslint@9.39.5(jiti@2.7.0)) + globals: + specifier: ^16.0.0 + version: 16.5.0 typescript: specifier: ^5.7.3 version: 5.9.3 + typescript-eslint: + specifier: ^8.0.0 + version: 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) app: dependencies: @@ -40,6 +55,9 @@ importers: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) devDependencies: + '@tailwindcss/vite': + specifier: ^4.3.3 + version: 4.3.3(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) '@testing-library/jest-dom': specifier: ^6.6.3 version: 6.9.1 @@ -60,28 +78,22 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^4.4.1 - version: 4.7.0(vite@6.4.3(@types/node@24.11.0)(jiti@1.21.7)) - autoprefixer: - specifier: ^10.4.20 - version: 10.4.27(postcss@8.5.26) + version: 4.7.0(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) jsdom: specifier: ^26.0.1 version: 26.1.0 - postcss: - specifier: ^8.5.26 - version: 8.5.26 tailwindcss: - specifier: ^3.4.17 - version: 3.4.19 + specifier: ^4.3.3 + version: 4.3.3 typescript: specifier: ^5.7.3 version: 5.9.3 vite: specifier: ^6.4.3 - version: 6.4.3(@types/node@24.11.0)(jiti@1.21.7) + version: 6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0) vitest: - specifier: ^3.2.6 - version: 3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0) + specifier: ^4.1.11 + version: 4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) packages/editor-core: dependencies: @@ -94,6 +106,9 @@ importers: elkjs: specifier: ^0.11.0 version: 0.11.0 + fast-deep-equal: + specifier: ^3.1.3 + version: 3.1.3 lucide-react: specifier: ^0.468.0 version: 0.468.0(react@19.2.4) @@ -112,7 +127,7 @@ importers: version: 10.0.0(@types/node@24.11.0) '@stryker-mutator/vitest-runner': specifier: ^10.0.0 - version: 10.0.0(@stryker-mutator/core@10.0.0(@types/node@24.11.0))(vitest@3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0)) + version: 10.0.0(@stryker-mutator/core@10.0.0(@types/node@24.11.0))(vitest@4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0))) '@testing-library/jest-dom': specifier: ^6.6.3 version: 6.9.1 @@ -133,13 +148,13 @@ importers: version: 26.1.0 tsup: specifier: ^8.5.0 - version: 8.5.1(jiti@1.21.7)(postcss@8.5.26)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.26)(typescript@5.9.3) typescript: specifier: ^5.7.3 version: 5.9.3 vitest: - specifier: ^3.2.6 - version: 3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0) + specifier: ^4.1.11 + version: 4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) packages/web-component: dependencies: @@ -161,23 +176,19 @@ importers: version: 19.2.3(@types/react@19.2.14) tsup: specifier: ^8.5.0 - version: 8.5.1(jiti@1.21.7)(postcss@8.5.26)(typescript@5.9.3) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.26)(typescript@5.9.3) typescript: specifier: ^5.7.3 version: 5.9.3 vitest: - specifier: ^3.2.6 - version: 3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0) + specifier: ^4.1.11 + version: 4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -794,6 +805,44 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.7': + resolution: {integrity: sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.5': + resolution: {integrity: sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.4': resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} @@ -815,6 +864,26 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@inquirer/ansi@2.0.7': resolution: {integrity: sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -965,18 +1034,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -1112,6 +1169,9 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@stryker-mutator/api@10.0.0': resolution: {integrity: sha512-ZtAJ0ZT3MVRCWJTBE2h90XB/6E+4lifHYtcTyNG6nU2nLekPgTo4gD5esjX6Okxo1b/JB4jJzyxYB54fwKAoJw==} engines: {node: '>=22.0.0'} @@ -1133,7 +1193,97 @@ packages: engines: {node: '>=22.0.0'} peerDependencies: '@stryker-mutator/core': 10.0.0 - vitest: ^3.2.6 + vitest: ^4.1.11 + + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} + + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.3': + resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==} + peerDependencies: + vite: ^6.4.3 '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -1191,6 +1341,9 @@ packages: '@types/jsesc@2.5.1': resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node@24.11.0': resolution: {integrity: sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==} @@ -1202,17 +1355,76 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@typescript-eslint/eslint-plugin@8.71.0': + resolution: {integrity: sha512-pqcS9c1HxZTHt7End4nXqd0s5lJrrFzrgCkKFJrsbUnaL6M3+6oBFZaslg6Gjsl3argl2DDRFROnXARaZ2e4Nw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.71.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.71.0': + resolution: {integrity: sha512-CG4nPk1f2zc8yw4pALqHsFYH2hdo+h1T9daSp21+Hnxi9LOE3GT9hAfTKJCBXVNM2GmYs1eMEP615wPoeOgk3A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.71.0': + resolution: {integrity: sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.71.0': + resolution: {integrity: sha512-gWF0BhUcnjZxSpLE8ngS/59n2SB0J3YqRxvX1+2aoRJk9hNtHSLOV+TcarFiOr5ipXm3yc1QrI4c9YZc8zyCxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.71.0': + resolution: {integrity: sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.71.0': + resolution: {integrity: sha512-i8uO1qbdxeKgRnS5sCRt6On3/nfo2d2DwQe3Yvjx543zLy7r8ySqRuPPiIIXAhS03U0v5NfAFx+rUgxFzKKwNw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.71.0': + resolution: {integrity: sha512-cJ4OoxPGWvFnBTnSZyaU+qJzGTqPTGJY+gDchj6cRyLRdmIdt4rcsE4twj+zPfrNiWuVi38wijHzShL++Z9atQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.71.0': + resolution: {integrity: sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.71.0': + resolution: {integrity: sha512-pKR/tEMVrXZG23UFKUn5BQf3zfmfk7KQceI2cGzywZ5nxM5Eu3hEJU1utjWzydtzBbcJAQhHN8iPCxobHpPcZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.71.0': + resolution: {integrity: sha512-8eQ9R218XORK+KLosnf4bu/QsUXvUyVwTbArg7/0NMB1Pu87OJKvj4nhFblkYE8gQV73mW1dx1ptlPCkwRGa7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^6.4.3 - '@vitest/expect@3.2.6': - resolution: {integrity: sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==} + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@3.2.6': - resolution: {integrity: sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==} + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} peerDependencies: msw: ^2.4.9 vite: ^6.4.3 @@ -1222,23 +1434,25 @@ packages: vite: optional: true - '@vitest/pretty-format@3.2.6': - resolution: {integrity: sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==} + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/pretty-format@3.2.7': - resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/runner@3.2.6': - resolution: {integrity: sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==} + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/snapshot@3.2.6': - resolution: {integrity: sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==} + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} - '@vitest/spy@3.2.6': - resolution: {integrity: sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==} + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} - '@vitest/utils@3.2.6': - resolution: {integrity: sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==} + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} @@ -1249,6 +1463,9 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} @@ -1263,6 +1480,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} @@ -1270,12 +1491,8 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -1288,12 +1505,8 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - autoprefixer@10.4.27: - resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.5.26 + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} @@ -1304,18 +1517,13 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + brace-expansion@1.1.21: + resolution: {integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==} brace-expansion@5.0.12: resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} engines: {node: 20 || >=22} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - browserslist@4.29.3: resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -1339,20 +1547,21 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - - caniuse-lite@1.0.30001774: - resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} caniuse-lite@1.0.30001814: resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==} - chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} engines: {node: '>=18'} + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -1360,14 +1569,6 @@ packages: chardet@2.2.0: resolution: {integrity: sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==} - check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -1376,6 +1577,13 @@ packages: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -1384,6 +1592,9 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -1401,11 +1612,6 @@ packages: css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - cssstyle@4.6.0: resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} engines: {node: '>=18'} @@ -1429,9 +1635,8 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} @@ -1440,15 +1645,13 @@ packages: des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} diff-match-patch@1.0.5: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -1468,6 +1671,10 @@ packages: emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} + engines: {node: '>=10.13.0'} + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -1480,8 +1687,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} @@ -1501,9 +1708,66 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.5: + resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + execa@9.6.1: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} @@ -1515,9 +1779,11 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} fast-string-truncated-width@3.0.3: resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} @@ -1531,9 +1797,6 @@ packages: fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1547,15 +1810,23 @@ packages: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} - fraction.js@5.3.4: - resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} @@ -1581,18 +1852,29 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -1601,6 +1883,12 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -1625,6 +1913,22 @@ packages: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.12: + resolution: {integrity: sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -1632,14 +1936,6 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1648,10 +1944,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -1670,8 +1962,8 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true joycon@3.1.1: @@ -1687,8 +1979,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true jsdom@26.1.0: resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} @@ -1704,17 +1997,103 @@ packages: engines: {node: '>=6'} hasBin: true + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-rpc-2.0@1.7.1: resolution: {integrity: sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg==} + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -1726,11 +2105,15 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + lodash.groupby@4.6.0: resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} - loupe@3.2.1: - resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -1754,14 +2137,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -1773,6 +2148,9 @@ packages: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -1804,14 +2182,13 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-releases@2.0.57: resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==} engines: {node: '>=18'} - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - npm-run-path@6.0.0: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} @@ -1823,10 +2200,6 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -1835,6 +2208,22 @@ packages: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} @@ -1842,6 +2231,10 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1850,16 +2243,9 @@ packages: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1867,10 +2253,6 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -1878,18 +2260,6 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.5.26 - - postcss-js@4.1.0: - resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.5.26 - postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -1908,23 +2278,14 @@ packages: yaml: optional: true - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.5.26 - - postcss-selector-parser@6.1.4: - resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} - engines: {node: '>=4'} - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.26: resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -1945,9 +2306,6 @@ packages: resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} engines: {node: '>=0.6'} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: @@ -1971,13 +2329,6 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -1990,19 +2341,14 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.59.0: resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -2011,9 +2357,6 @@ packages: rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -2078,8 +2421,8 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} strip-final-newline@4.0.0: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} @@ -2089,17 +2432,18 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} - strip-literal@3.1.0: - resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -2107,10 +2451,12 @@ packages: tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - tailwindcss@3.4.19: - resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} - engines: {node: '>=14.0.0'} - hasBin: true + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -2125,20 +2471,16 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + tinyrainbow@3.2.0: + resolution: {integrity: sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==} engines: {node: '>=14.0.0'} tldts-core@6.1.86: @@ -2148,10 +2490,6 @@ packages: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} @@ -2164,6 +2502,12 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -2193,6 +2537,10 @@ packages: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + typed-inject@5.0.0: resolution: {integrity: sha512-0Ql2ORqBORLMdAW89TQKZsb1PQkFGImFfVmncXWe7a+AA3+7dh7Se9exxZowH4kbnlvKEFkMxUYdHUpjYWFJaA==} engines: {node: '>=18'} @@ -2201,6 +2549,13 @@ packages: resolution: {integrity: sha512-k4kX5Up6qA68D0Cby2AK+6+vM5k3qTxe+/3FqhnHRExjY5cfbOnzjQZbP/LXleF8hVoDvDqxlgk9KK83HoBZlQ==} engines: {node: '>= 16.0.0'} + typescript-eslint@8.71.0: + resolution: {integrity: sha512-fBdHYiqQ14RW6mOMXD14Svn82ZsCYAoQSzGRzyEjR59S5A2Krh/l7fGTOQ7iCr8gGy/mHVXtEF7s5fgjEdV0Pw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -2225,13 +2580,8 @@ packages: peerDependencies: browserslist: ^4.28.7 - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} vite@6.4.3: resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} @@ -2273,26 +2623,39 @@ packages: yaml: optional: true - vitest@3.2.6: - resolution: {integrity: sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.6 - '@vitest/ui': 3.2.6 + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' + vite: ^6.4.3 peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': optional: true '@vitest/ui': optional: true @@ -2335,6 +2698,10 @@ packages: engines: {node: '>=8'} hasBin: true + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + ws@8.21.3: resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} @@ -2357,10 +2724,20 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + yoctocolors@2.2.0: resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} engines: {node: '>=18'} + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -2368,8 +2745,6 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@alloc/quick-lru@5.2.0': {} - '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -2871,6 +3246,52 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0))': + dependencies: + eslint: 9.39.5(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.7': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.3.2 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.5': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + '@floating-ui/core@1.7.4': dependencies: '@floating-ui/utils': 0.2.10 @@ -2896,6 +3317,22 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@inquirer/ansi@2.0.7': {} '@inquirer/checkbox@5.2.2(@types/node@24.11.0)': @@ -3034,18 +3471,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/rollup-android-arm-eabi@4.59.0': @@ -3127,6 +3552,8 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} + '@standard-schema/spec@1.1.0': {} + '@stryker-mutator/api@10.0.0': dependencies: mutation-testing-metrics: 3.8.4 @@ -3187,14 +3614,82 @@ snapshots: '@stryker-mutator/util@10.0.0': {} - '@stryker-mutator/vitest-runner@10.0.0(@stryker-mutator/core@10.0.0(@types/node@24.11.0))(vitest@3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0))': + '@stryker-mutator/vitest-runner@10.0.0(@stryker-mutator/core@10.0.0(@types/node@24.11.0))(vitest@4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)))': dependencies: '@stryker-mutator/api': 10.0.0 '@stryker-mutator/core': 10.0.0(@types/node@24.11.0) '@stryker-mutator/util': 10.0.0 semver: 7.8.5 tslib: 2.8.1 - vitest: 3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0) + vitest: 4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) + + '@tailwindcss/node@4.3.3': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.26.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.3 + + '@tailwindcss/oxide-android-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide@4.3.3': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/vite@4.3.3(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0))': + dependencies: + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 + vite: 6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0) '@testing-library/dom@10.4.1': dependencies: @@ -3264,6 +3759,8 @@ snapshots: '@types/jsesc@2.5.1': {} + '@types/json-schema@7.0.15': {} + '@types/node@24.11.0': dependencies: undici-types: 7.16.0 @@ -3276,7 +3773,98 @@ snapshots: dependencies: csstype: 3.2.3 - '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@24.11.0)(jiti@1.21.7))': + '@typescript-eslint/eslint-plugin@8.71.0(@typescript-eslint/parser@8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.71.0 + '@typescript-eslint/type-utils': 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.71.0 + eslint: 9.39.5(jiti@2.7.0) + ignore: 7.0.12 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.71.0 + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/typescript-estree': 8.71.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.71.0 + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.71.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.71.0(typescript@5.9.3) + '@typescript-eslint/types': 8.71.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.71.0': + dependencies: + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/visitor-keys': 8.71.0 + + '@typescript-eslint/tsconfig-utils@8.71.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/typescript-estree': 8.71.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.5(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.71.0': {} + + '@typescript-eslint/typescript-estree@8.71.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.71.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.71.0(typescript@5.9.3) + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/visitor-keys': 8.71.0 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.71.0 + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/typescript-estree': 8.71.0(typescript@5.9.3) + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.71.0': + dependencies: + '@typescript-eslint/types': 8.71.0 + eslint-visitor-keys: 5.0.1 + + '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.7) @@ -3284,60 +3872,66 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.3(@types/node@24.11.0)(jiti@1.21.7) + vite: 6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@vitest/expect@3.2.6': + '@vitest/expect@4.1.11': dependencies: + '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 3.2.6 - '@vitest/utils': 3.2.6 - chai: 5.3.3 - tinyrainbow: 2.0.0 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + chai: 6.3.0 + tinyrainbow: 3.2.0 - '@vitest/mocker@3.2.6(vite@6.4.3(@types/node@24.11.0)(jiti@1.21.7))': + '@vitest/mocker@4.1.11(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0))': dependencies: - '@vitest/spy': 3.2.6 + '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.3(@types/node@24.11.0)(jiti@1.21.7) - - '@vitest/pretty-format@3.2.6': - dependencies: - tinyrainbow: 2.0.0 + vite: 6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0) - '@vitest/pretty-format@3.2.7': + '@vitest/pretty-format@4.1.11': dependencies: - tinyrainbow: 2.0.0 + tinyrainbow: 3.2.0 - '@vitest/runner@3.2.6': + '@vitest/runner@4.1.11': dependencies: - '@vitest/utils': 3.2.6 + '@vitest/utils': 4.1.11 pathe: 2.0.3 - strip-literal: 3.1.0 - '@vitest/snapshot@3.2.6': + '@vitest/snapshot@4.1.11': dependencies: - '@vitest/pretty-format': 3.2.6 + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@3.2.6': + '@vitest/spy@4.1.11': {} + + '@vitest/utils@4.1.11': dependencies: - tinyspy: 4.0.4 + '@vitest/pretty-format': 4.1.11 + convert-source-map: 2.0.0 + tinyrainbow: 3.2.0 - '@vitest/utils@3.2.6': + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - '@vitest/pretty-format': 3.2.6 - loupe: 3.2.1 - tinyrainbow: 2.0.0 + acorn: 8.16.0 acorn@8.16.0: {} agent-base@7.1.4: {} + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 @@ -3356,16 +3950,15 @@ snapshots: ansi-regex@5.0.1: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + ansi-styles@5.2.0: {} any-promise@1.3.0: {} - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 4.0.4 - - arg@5.0.2: {} + argparse@2.0.1: {} aria-query@5.3.0: dependencies: @@ -3375,29 +3968,21 @@ snapshots: assertion-error@2.0.1: {} - autoprefixer@10.4.27(postcss@8.5.26): - dependencies: - browserslist: 4.29.3 - caniuse-lite: 1.0.30001774 - fraction.js: 5.3.4 - picocolors: 1.1.1 - postcss: 8.5.26 - postcss-value-parser: 4.2.0 + balanced-match@1.0.2: {} balanced-match@4.0.4: {} baseline-browser-mapping@2.11.27: {} - binary-extensions@2.3.0: {} + brace-expansion@1.1.21: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 brace-expansion@5.0.12: dependencies: balanced-match: 4.0.4 - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - browserslist@4.29.3: dependencies: baseline-browser-mapping: 2.11.27 @@ -3423,48 +4008,39 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - camelcase-css@2.0.1: {} - - caniuse-lite@1.0.30001774: {} + callsites@3.1.0: {} caniuse-lite@1.0.30001814: {} - chai@5.3.3: + chai@6.3.0: {} + + chalk@4.1.2: dependencies: - assertion-error: 2.0.1 - check-error: 2.1.3 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 + ansi-styles: 4.3.0 + supports-color: 7.2.0 chalk@5.6.2: {} chardet@2.2.0: {} - check-error@2.1.3: {} - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@4.0.3: dependencies: readdirp: 4.1.2 cli-width@4.1.0: {} + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + commander@14.0.3: {} commander@4.1.1: {} + concat-map@0.0.1: {} + confbox@0.1.8: {} consola@3.4.2: {} @@ -3479,8 +4055,6 @@ snapshots: css.escape@1.5.1: {} - cssesc@3.0.0: {} - cssstyle@4.6.0: dependencies: '@asamuzakjp/css-color': 3.2.0 @@ -3499,7 +4073,7 @@ snapshots: decimal.js@10.6.0: {} - deep-eql@5.0.2: {} + deep-is@0.1.4: {} dequal@2.0.3: {} @@ -3508,12 +4082,10 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 - didyoumean@1.2.2: {} + detect-libc@2.1.2: {} diff-match-patch@1.0.5: {} - dlv@1.1.3: {} - dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} @@ -3530,13 +4102,18 @@ snapshots: emoji-regex@10.6.0: {} + enhanced-resolve@5.26.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + entities@6.0.1: {} es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.3.2: {} es-object-atoms@1.1.2: dependencies: @@ -3602,10 +4179,93 @@ snapshots: escalade@3.2.0: {} + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.5(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.8 + eslint: 9.39.5(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.5(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.7 + '@eslint/js': 9.39.5 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 + esutils@2.0.3: {} + execa@9.6.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 @@ -3625,13 +4285,9 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} fast-string-truncated-width@3.0.3: {} @@ -3645,10 +4301,6 @@ snapshots: dependencies: fast-string-width: 3.0.2 - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -3657,9 +4309,14 @@ snapshots: dependencies: is-unicode-supported: 2.1.0 - fill-range@7.1.1: + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: dependencies: - to-regex-range: 5.0.1 + locate-path: 6.0.0 + path-exists: 4.0.0 fix-dts-default-cjs-exports@1.0.1: dependencies: @@ -3667,7 +4324,12 @@ snapshots: mlly: 1.8.0 rollup: 4.59.0 - fraction.js@5.3.4: {} + flat-cache@4.0.1: + dependencies: + flatted: 3.4.4 + keyv: 4.5.4 + + flatted@3.4.4: {} fsevents@2.3.3: optional: true @@ -3699,22 +4361,32 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - glob-parent@6.0.2: dependencies: is-glob: 4.0.3 + globals@14.0.0: {} + + globals@16.5.0: {} + gopd@1.2.0: {} + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + has-symbols@1.1.0: {} hasown@2.0.2: dependencies: function-bind: 1.1.2 + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 @@ -3743,17 +4415,20 @@ snapshots: dependencies: safer-buffer: 2.1.2 - indent-string@4.0.0: {} + ignore@5.3.2: {} - inherits@2.0.4: {} + ignore@7.0.12: {} - is-binary-path@2.1.0: + import-fresh@3.3.1: dependencies: - binary-extensions: 2.3.0 + parent-module: 1.0.1 + resolve-from: 4.0.0 - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inherits@2.0.4: {} is-extglob@2.1.1: {} @@ -3761,8 +4436,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-number@7.0.0: {} - is-plain-obj@4.1.0: {} is-potential-custom-element-name@1.0.1: {} @@ -3773,7 +4446,7 @@ snapshots: isexe@2.0.0: {} - jiti@1.21.7: {} + jiti@2.7.0: {} joycon@3.1.1: {} @@ -3783,7 +4456,9 @@ snapshots: js-tokens@4.0.0: {} - js-tokens@9.0.1: {} + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 jsdom@26.1.0: dependencies: @@ -3814,21 +4489,89 @@ snapshots: jsesc@3.1.0: {} + json-buffer@3.0.1: {} + json-rpc-2.0@1.7.1: {} + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} + json5@2.2.3: {} + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + 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 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} load-tsconfig@0.2.5: {} + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + lodash.groupby@4.6.0: {} - loupe@3.2.1: {} + lodash.merge@4.6.2: {} lru-cache@10.4.3: {} @@ -3848,13 +4591,6 @@ snapshots: math-intrinsics@1.1.0: {} - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 4.0.4 - min-indent@1.0.1: {} minimalistic-assert@1.0.1: {} @@ -3863,6 +4599,10 @@ snapshots: dependencies: brace-expansion: 5.0.12 + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.21 + mlly@1.8.0: dependencies: acorn: 8.16.0 @@ -3894,9 +4634,9 @@ snapshots: nanoid@3.3.18: {} - node-releases@2.0.57: {} + natural-compare@1.4.0: {} - normalize-path@3.0.0: {} + node-releases@2.0.57: {} npm-run-path@6.0.0: dependencies: @@ -3907,34 +4647,49 @@ snapshots: object-assign@4.1.1: {} - object-hash@3.0.0: {} - object-inspect@1.13.4: {} obug@2.1.4: {} + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + parse-ms@4.0.0: {} parse5@7.3.0: dependencies: entities: 6.0.1 + path-exists@4.0.0: {} + path-key@3.1.1: {} path-key@4.0.0: {} - path-parse@1.0.7: {} - pathe@2.0.3: {} - pathval@2.0.1: {} - picocolors@1.1.1: {} picomatch@4.0.4: {} - pify@2.3.0: {} - pirates@4.0.7: {} pkg-types@1.3.1: @@ -3943,36 +4698,12 @@ snapshots: mlly: 1.8.0 pathe: 2.0.3 - postcss-import@15.1.0(postcss@8.5.26): - dependencies: - postcss: 8.5.26 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.11 - - postcss-js@4.1.0(postcss@8.5.26): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.26 - - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.26): + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.26): dependencies: lilconfig: 3.1.3 optionalDependencies: - jiti: 1.21.7 - postcss: 8.5.26 - - postcss-nested@6.2.0(postcss@8.5.26): - dependencies: + jiti: 2.7.0 postcss: 8.5.26 - postcss-selector-parser: 6.1.4 - - postcss-selector-parser@6.1.4: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-value-parser@4.2.0: {} postcss@8.5.26: dependencies: @@ -3980,6 +4711,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prelude-ls@1.2.1: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -3999,8 +4732,6 @@ snapshots: es-define-property: 1.0.1 side-channel: 1.1.1 - queue-microtask@1.2.3: {} - react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 @@ -4017,14 +4748,6 @@ snapshots: react@19.2.4: {} - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - - readdirp@3.6.0: - dependencies: - picomatch: 4.0.4 - readdirp@4.1.2: {} redent@3.0.0: @@ -4034,15 +4757,9 @@ snapshots: require-from-string@2.0.2: {} - resolve-from@5.0.0: {} - - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 + resolve-from@4.0.0: {} - reusify@1.1.0: {} + resolve-from@5.0.0: {} rollup@4.59.0: dependencies: @@ -4077,10 +4794,6 @@ snapshots: rrweb-cssom@0.8.0: {} - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -4141,7 +4854,7 @@ snapshots: stackback@0.0.2: {} - std-env@3.10.0: {} + std-env@4.3.0: {} strip-final-newline@4.0.0: {} @@ -4149,9 +4862,7 @@ snapshots: dependencies: min-indent: 1.0.1 - strip-literal@3.1.0: - dependencies: - js-tokens: 9.0.1 + strip-json-comments@3.1.1: {} sucrase@3.35.1: dependencies: @@ -4163,39 +4874,17 @@ snapshots: tinyglobby: 0.2.15 ts-interface-checker: 0.1.13 - supports-preserve-symlinks-flag@1.0.0: {} + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 symbol-tree@3.2.4: {} tabbable@6.4.0: {} - tailwindcss@3.4.19: - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.26 - postcss-import: 15.1.0(postcss@8.5.26) - postcss-js: 4.1.0(postcss@8.5.26) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.26) - postcss-nested: 6.2.0(postcss@8.5.26) - postcss-selector-parser: 6.1.4 - resolve: 1.22.11 - sucrase: 3.35.1 - transitivePeerDependencies: - - tsx - - yaml + tailwindcss@4.3.3: {} + + tapable@2.3.3: {} thenify-all@1.6.0: dependencies: @@ -4209,16 +4898,14 @@ snapshots: tinyexec@0.3.2: {} + tinyexec@1.3.1: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.4: {} + tinyrainbow@3.2.0: {} tldts-core@6.1.86: {} @@ -4226,10 +4913,6 @@ snapshots: dependencies: tldts-core: 6.1.86 - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -4240,11 +4923,15 @@ snapshots: tree-kill@1.2.2: {} + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + ts-interface-checker@0.1.13: {} tslib@2.8.1: {} - tsup@8.5.1(jiti@1.21.7)(postcss@8.5.26)(typescript@5.9.3): + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.26)(typescript@5.9.3): dependencies: bundle-require: 5.1.0(esbuild@0.28.2) cac: 6.7.14 @@ -4255,7 +4942,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.26) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.26) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 @@ -4274,6 +4961,10 @@ snapshots: tunnel@0.0.6: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + typed-inject@5.0.0: {} typed-rest-client@2.3.1: @@ -4284,6 +4975,17 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.8 + typescript-eslint@8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.71.0(@typescript-eslint/parser@8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.71.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.5(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} ufo@1.6.3: {} @@ -4300,30 +5002,11 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - util-deprecate@1.0.2: {} - - vite-node@3.2.4(@types/node@24.11.0)(jiti@1.21.7): + uri-js@4.4.1: dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 6.4.3(@types/node@24.11.0)(jiti@1.21.7) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml + punycode: 2.3.1 - vite@6.4.3(@types/node@24.11.0)(jiti@1.21.7): + vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.4) @@ -4334,49 +5017,36 @@ snapshots: optionalDependencies: '@types/node': 24.11.0 fsevents: 2.3.3 - jiti: 1.21.7 - - vitest@3.2.6(@types/node@24.11.0)(jiti@1.21.7)(jsdom@26.1.0): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(vite@6.4.3(@types/node@24.11.0)(jiti@1.21.7)) - '@vitest/pretty-format': 3.2.7 - '@vitest/runner': 3.2.6 - '@vitest/snapshot': 3.2.6 - '@vitest/spy': 3.2.6 - '@vitest/utils': 3.2.6 - chai: 5.3.3 - debug: 4.4.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + + vitest@4.1.11(@types/node@24.11.0)(jsdom@26.1.0)(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)): + dependencies: + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0)) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + es-module-lexer: 2.3.2 expect-type: 1.3.0 magic-string: 0.30.21 + obug: 2.1.4 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 3.10.0 + std-env: 4.3.0 tinybench: 2.9.0 - tinyexec: 0.3.2 + tinyexec: 1.3.1 tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 6.4.3(@types/node@24.11.0)(jiti@1.21.7) - vite-node: 3.2.4(@types/node@24.11.0)(jiti@1.21.7) + tinyrainbow: 3.2.0 + vite: 6.4.3(@types/node@24.11.0)(jiti@2.7.0)(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.11.0 jsdom: 26.1.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml w3c-xmlserializer@5.0.0: dependencies: @@ -4406,6 +5076,8 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + word-wrap@1.2.5: {} + ws@8.21.3: {} xml-name-validator@5.0.0: {} @@ -4414,6 +5086,12 @@ snapshots: yallist@3.1.1: {} + yocto-queue@0.1.0: {} + yoctocolors@2.2.0: {} + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + zod@4.4.3: {} From 2c28441b15e143f86c2ca7ee5c8f4d6a9e1fec36 Mon Sep 17 00:00:00 2001 From: Reynaldo Endis Date: Sat, 3 Oct 2026 22:13:09 +0000 Subject: [PATCH 3/3] perf: reduce history traversal and load ELK on demand --- docs/reviews/2026-10-03-follow-up.md | 102 ++++++++++++++++++ .../src/__tests__/autoLayoutLoading.test.ts | 51 +++++++++ .../src/model/serializeStatePro.ts | 10 +- .../src/state/editorHistoryReducer.ts | 9 +- .../editor-core/src/utils/autoLayout.ts | 24 +++-- 5 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 docs/reviews/2026-10-03-follow-up.md create mode 100644 studio/packages/editor-core/src/__tests__/autoLayoutLoading.test.ts diff --git a/docs/reviews/2026-10-03-follow-up.md b/docs/reviews/2026-10-03-follow-up.md new file mode 100644 index 0000000..1e6bf2c --- /dev/null +++ b/docs/reviews/2026-10-03-follow-up.md @@ -0,0 +1,102 @@ +# Snapshot correctness and Studio quality follow-up + +Base: `ea00b2b776c99c0d7e788826c508336f21360480` (main after PR #22). +This change completes the dependency, snapshot, performance and quality-gate follow-ups from +the [initial review](2026-10-03-security-quality.md), including R12, R15 and R16. + +## Runtime changes + +Snapshot capture used a JSON round-trip that converted every untyped number to `float64` and +discarded serialization errors. For example, metadata containing integer `9007199254740993` +could be persisted as `9007199254740992`. Invalid metadata could produce incomplete snapshots. + +- Capture, snapshot JSON decoding and restoration now retain `json.Number` when conversion to + `float64` would change the numeric value after re-encoding. Values that round-trip exactly + retain their existing `float64` representation. +- Precision is preserved in nested metadata and accumulated event data, including unsigned + integers and long decimal fractions. Decimal comparison does not expand exponent magnitudes. +- The optional `instrumentation.SnapshotProvider` capability and `GetSnapshotWithError` helper + return a complete snapshot or a contextual serialization error. Existing machine and executor + interfaces remain compatible. Synchronous actions can use the helper with their arguments + without reacquiring the owning machine's lock. +- Legacy `GetSnapshot()` logs capture errors and returns `nil`. Consumers must check that result. + Metadata consumers must handle `json.Number` as well as `float64`. + +See [runtime guidance](../runtime.md#snapshots) for usage and compatibility details. + +## Dependency and quality changes + +- Upgrade Vitest to 4.1.11 and migrate the mutation runner configuration. Stryker 10 supports + this Vitest version; its initial instrumented test run was verified. +- Migrate the app from Tailwind 3 to Tailwind 4's Vite plugin, removing the old watcher/glob + dependency chain that introduced the unpatched `braces` advisory. Regenerate the lockfile. +- The full workspace dependency audit reports **zero advisories**, including development + dependencies, at the time of verification. This does not guarantee future advisories are absent. +- Replace placeholder lint commands with ESLint and enforce React hook ordering. Fix early + returns in PropertiesModal and JsonIOModal that could change hook order across renders. +- Add a GitHub Actions workflow for Go build, vet, race tests and fuzz smoke; Studio frozen + installation, lint, type checking, tests, Stryker dry-run, build and dependency audit. + Actions use immutable commit pins and read-only repository permissions. Go setup selects + the latest patch for the declared toolchain; Studio CI uses Node 24 and pnpm 10.11.0. + +The Studio development workspace now requires Node 22 or later. Tailwind 4 requires modern +browsers; legacy browser support was not validated. The standalone app owns the Tailwind setup; +the published editor's React peer dependency remains unchanged. + +## Performance changes and measurements + +- Compare unchanged history sections by identity and changed sections by deep equality instead + of serializing the entire graph twice per comparison. Undo checkpoints still clone their data. +- Group ordered transitions by source once during serialization, eliminating a full transition + scan for each reality while preserving ordering. +- Load ELK asynchronously on the first layout request. Concurrent requests share its instance; + a failed load can be retried. Existing automatic layout behavior is preserved, so apps requesting + layout on mount still fetch the chunk then. + +Production app build, compared with PR #22: + +| Asset | Before | After | +| --- | ---: | ---: | +| Main JavaScript, minified | 2,283.01 kB | 802.13 kB | +| Main JavaScript, gzip | 676.52 kB | 225.09 kB | +| Separate ELK JavaScript, minified | Included above | 1,458.21 kB | +| CSS, minified | 45.52 kB | 68.40 kB | + +The main JavaScript entry is about 65% smaller. ELK remains a large dependency; total downloaded +JavaScript is similar when layout is requested. Tailwind 4 increased the generated CSS size. + +A local reducer benchmark used generated graphs with 256-character metadata per reality, +20 coalesced machine-ID edits, and the median of three runs with Node 24.19.0. Both versions +used their built CommonJS package on the same machine: + +| Realities | Before | After | +| ---: | ---: | ---: | +| 100 | 6.41 ms | 0.40 ms | +| 1,000 | 49.40 ms | 2.96 ms | +| 5,000 | 250.12 ms | 21.39 ms | + +These are measurements of that scenario, not a general latency guarantee. Checkpoint cloning +and other graph operations still have costs proportional to graph size. + +## Validation + +All checks below passed locally: + +- Go build and vet; race-enabled tests with coverage across all 11 packages. +- Three native fuzz smoke targets, five seconds each, with two workers. +- Snapshot regressions for precise nested metadata, accumulated events, JSON persistence and + restoration, detached data, serialization errors and callback capture without lock reentry. +- Frozen pnpm installation; workspace lint and type checking; **255 tests in 46 files**; + all three package builds; dependency audit with zero advisories. +- Stryker dry-run: 16 tests passed with instrumented source. No full mutation campaign or + mutation score is claimed. +- Chromium browser checks at 1440×900 and 390×844: rendered canvas, JSON export parsing, + library opening/closing and auto layout. Production preview additionally fetched the + separate ELK chunk successfully. No console or page errors occurred in these flows. +- Desktop baseline comparison preserved header geometry. Mobile rendering remains cramped + in the existing header; this is not a responsive-layout redesign. Screenshots and command + logs were retained in the review workspace. + +The remaining callback ownership and asynchronous invoke lifecycle contracts described in the +initial review still apply. No production deployment or compatibility test against every +embedding application was performed. diff --git a/studio/packages/editor-core/src/__tests__/autoLayoutLoading.test.ts b/studio/packages/editor-core/src/__tests__/autoLayoutLoading.test.ts new file mode 100644 index 0000000..a12ce9c --- /dev/null +++ b/studio/packages/editor-core/src/__tests__/autoLayoutLoading.test.ts @@ -0,0 +1,51 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import type { EditorNode } from "../types"; + +const nodes: EditorNode[] = [{ + id: "u-1", type: "universe", x: 12, y: 24, w: 400, h: 300, + data: { id: "main", name: "main", canonicalName: "main", version: "1.0.0" }, +}]; + +afterEach(() => { + vi.doUnmock("elkjs/lib/elk.bundled.js"); + vi.resetModules(); +}); + +describe("Carga diferida de ELK", () => { + it("no carga ELK al importar ni al distribuir un grafo vacío", async () => { + const load = vi.fn(() => ({ default: class {} })); + vi.doMock("elkjs/lib/elk.bundled.js", load); + const { computeAutoLayout } = await import("../utils/autoLayout"); + expect(load).not.toHaveBeenCalled(); + const empty: EditorNode[] = []; + expect(await computeAutoLayout(empty, [], {})).toBe(empty); + expect(load).not.toHaveBeenCalled(); + }); + + it("comparte la instancia entre solicitudes concurrentes y reintenta una carga fallida", async () => { + const construct = vi.fn(); + let fail = true; + vi.doMock("elkjs/lib/elk.bundled.js", () => ({ + default: class { + constructor() { + construct(); + if (fail) throw new Error("ELK unavailable"); + } + async layout(graph: { children?: Array> }) { + return { ...graph, children: graph.children?.map(child => ({ ...child, x: 0, y: 0 })) }; + } + }, + })); + const { computeAutoLayout } = await import("../utils/autoLayout"); + await expect(computeAutoLayout(nodes, [], {})).rejects.toThrow("ELK unavailable"); + fail = false; + const results = await Promise.all([ + computeAutoLayout(nodes, [], {}), computeAutoLayout(nodes, [], {}), + ]); + expect(construct).toHaveBeenCalledTimes(2); + results.forEach(result => { + expect(result[0]).toMatchObject({ x: 12, y: 24, w: 240, h: 220 }); + }); + }); +}); diff --git a/studio/packages/editor-core/src/model/serializeStatePro.ts b/studio/packages/editor-core/src/model/serializeStatePro.ts index 06020b0..070e73e 100644 --- a/studio/packages/editor-core/src/model/serializeStatePro.ts +++ b/studio/packages/editor-core/src/model/serializeStatePro.ts @@ -409,6 +409,12 @@ export const serializeStatePro = (state: EditorState): SerializeResult => { } const orderedTransitions = normalizeTransitionsOrder(transitions); + const transitionsBySource = new Map(); + orderedTransitions.forEach((transition) => { + const outgoing = transitionsBySource.get(transition.sourceRealityId) || []; + outgoing.push(transition); + transitionsBySource.set(transition.sourceRealityId, outgoing); + }); const universeNodes = nodes.filter((node) => node.type === "universe"); const realityNodes = nodes.filter((node) => node.type === "reality"); const universeByNodeId = new Map(universeNodes.map((universe) => [universe.id, universe])); @@ -610,9 +616,7 @@ export const serializeStatePro = (state: EditorState): SerializeResult => { : undefined, }); - const outgoingTransitions = orderedTransitions.filter( - (transition) => transition.sourceRealityId === reality.id, - ); + const outgoingTransitions = transitionsBySource.get(reality.id) || []; const alwaysTransitions = outgoingTransitions.filter( (transition) => transition.triggerKind === "always", diff --git a/studio/packages/editor-core/src/state/editorHistoryReducer.ts b/studio/packages/editor-core/src/state/editorHistoryReducer.ts index 60b4b0c..48c4594 100644 --- a/studio/packages/editor-core/src/state/editorHistoryReducer.ts +++ b/studio/packages/editor-core/src/state/editorHistoryReducer.ts @@ -11,6 +11,7 @@ import type { StateProMachine, } from "../types"; import { editorReducer, type EditorAction } from "./editorReducer"; +import deepEqual from "fast-deep-equal"; export const HISTORY_LIMIT = 100; export const COALESCE_WINDOW_MS = 600; @@ -66,13 +67,15 @@ const toSnapshot = (state: EditorState): EditorHistorySnapshot => ({ isDirtyFromImport: state.isDirtyFromImport, }); -const serializeSnapshot = (snapshot: EditorHistorySnapshot): string => JSON.stringify(snapshot); - const snapshotsEqual = ( left: EditorHistorySnapshot, right: EditorHistorySnapshot, ): boolean => { - return serializeSnapshot(left) === serializeSnapshot(right); + // Unchanged graph sections keep their identity across immutable reducer edits. + // Only traverse sections which actually changed, rather than serializing the graph. + return (Object.keys(left) as Array).every( + (key) => Object.is(left[key], right[key]) || deepEqual(left[key], right[key]), + ); }; const pushPast = ( diff --git a/studio/packages/editor-core/src/utils/autoLayout.ts b/studio/packages/editor-core/src/utils/autoLayout.ts index 32068c0..7c31723 100644 --- a/studio/packages/editor-core/src/utils/autoLayout.ts +++ b/studio/packages/editor-core/src/utils/autoLayout.ts @@ -1,4 +1,3 @@ -import * as ELKBundle from "elkjs/lib/elk.bundled.js"; import type { ELK as ElkInstance, ELKConstructorArguments, ElkExtendedEdge, ElkNode } from "elkjs/lib/elk-api"; import type { EditorNode, EditorTransition, NodeSizeMap } from "../types"; @@ -29,8 +28,8 @@ const DISCONNECTED_COMPONENT_GAP = 180; type ElkConstructorLike = new (args?: ELKConstructorArguments) => ElkInstance; -const resolveElkConstructor = (): ElkConstructorLike => { - const moduleShape = ELKBundle as unknown as { +const resolveElkConstructor = (bundle: unknown): ElkConstructorLike => { + const moduleShape = bundle as { default?: ElkConstructorLike; ELK?: ElkConstructorLike; }; @@ -46,12 +45,19 @@ const resolveElkConstructor = (): ElkConstructorLike => { return elkCtor; }; -const createElk = () => { - const ElkConstructor = resolveElkConstructor(); - return new ElkConstructor(); -}; +let elkPromise: Promise | undefined; -const elk = createElk(); +const getElk = (): Promise => { + if (!elkPromise) { + elkPromise = import("elkjs/lib/elk.bundled.js") + .then((bundle) => new (resolveElkConstructor(bundle))()) + .catch((error) => { + elkPromise = undefined; + throw error; + }); + } + return elkPromise; +}; type UniverseNode = Extract; type RealityNode = Extract; @@ -338,6 +344,7 @@ const computeInternalUniverseLayout = async ( edges, }; + const elk = await getElk(); const result = await elk.layout(graph, { measureExecutionTime: true }); const childById = new Map((result.children || []).map((child) => [child.id, child])); @@ -592,6 +599,7 @@ export const computeAutoLayout = async ( edges: externalEdges, }; + const elk = await getElk(); const externalLayout = await elk.layout(externalGraph, { measureExecutionTime: true }); const externalById = new Map((externalLayout.children || []).map((child) => [child.id, child]));