diff --git a/website/docs/from_provider/quickstart.mdx b/website/docs/from_provider/quickstart.mdx index 30335d5ee..8a9dc30e6 100644 --- a/website/docs/from_provider/quickstart.mdx +++ b/website/docs/from_provider/quickstart.mdx @@ -37,7 +37,7 @@ final myNotifierProvider = ChangeNotifierProvider((ref) { }); ``` -As you can see Riverpod exposes a [ChangeNotifierProvider] class, +As you can see, Riverpod exposes a [ChangeNotifierProvider] class, which is there precisely to support migrations from pkg:Provider. Keep in mind that this provider is not recommended when writing new code, @@ -45,12 +45,13 @@ and it is not the best way to use Riverpod, but it's a gentle and very easy way :::tip There is no rush to *immediately* try to change your `ChangeNotifier`s into the more modern [Riverpod's providers]. -Some requite a bit of a paradigm shift, so it may be difficult to do initially. +Some requite a bit of [work], so it may be difficult to do in one take. Take your time, as it is important to get yourself familiar with Riverpod first; you'll quickly find out that *almost* all Providers from pkg:provider have a strict equivalent in pkg:riverpod. ::: + ## Starts with *leaves* Start with Providers that do not depend on anything else, i.e. start with the *leaves* in your dependency tree. @@ -120,6 +121,10 @@ final myNotifierProvider = NotifierProvider(MyNotifier.new); This operation might take some time and might lead to some errors, so don't rush doing this all at once. +Please follow [this migration guide] to migrate from `ChangeNotifier` to the more modern +`Notifier` and `AsyncNotifier`, one step at a time. + + ## Migrating `ProxyProvider`s Within pkg:Provider, `ProxyProvider` is used to combine values from other Providers; its build depends on the value of other providers, reactively. @@ -204,4 +209,6 @@ Following this guide, you *can* migrate towards codegen as a further step forwar [are composable by default]: /docs/from_provider/motivation#combining-providers-is-hard-and-error-prone [as mentioned above]: /docs/from_provider/quickstart#start-with-changenotifierprovider [Riverpod's `Consumer` APIs]: /docs/concepts/reading -[lazy by default]: /docs/concepts/provider_lifecycles \ No newline at end of file +[lazy by default]: /docs/concepts/provider_lifecycles +[work]: /docs/from_provider/quickstart#migrate-one-provider-at-a-time +[this migration guide]: /docs/migration/1.0.0_to_2.0.0#migrating-from-statenotifier diff --git a/website/docs/migration/add_listener/add_listener.dart b/website/docs/migration/add_listener/add_listener.dart new file mode 100644 index 000000000..2b328e3d9 --- /dev/null +++ b/website/docs/migration/add_listener/add_listener.dart @@ -0,0 +1,16 @@ +// ignore_for_file: avoid_print + +import 'package:flutter/material.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'add_listener.g.dart'; + +/* SNIPPET START */ +@riverpod +class MyNotifier extends _$MyNotifier { + @override + int build() { + ref.listenSelf((_, next) => debugPrint('$next')); + return 0; + } +} diff --git a/website/docs/migration/add_listener/add_listener.g.dart b/website/docs/migration/add_listener/add_listener.g.dart new file mode 100644 index 000000000..d73ccad2e --- /dev/null +++ b/website/docs/migration/add_listener/add_listener.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'add_listener.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$myNotifierHash() => r'773acc007ef2764a2da4ad62c101a49101ac0a2c'; + +/// See also [MyNotifier]. +@ProviderFor(MyNotifier) +final myNotifierProvider = + AutoDisposeNotifierProvider.internal( + MyNotifier.new, + name: r'myNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$myNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$MyNotifier = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/add_listener/index.tsx b/website/docs/migration/add_listener/index.tsx new file mode 100644 index 000000000..6d7ac6d37 --- /dev/null +++ b/website/docs/migration/add_listener/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./add_listener.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/add_listener/raw.dart b/website/docs/migration/add_listener/raw.dart new file mode 100644 index 000000000..c150f049c --- /dev/null +++ b/website/docs/migration/add_listener/raw.dart @@ -0,0 +1,15 @@ +// ignore_for_file: avoid_print + +import 'package:flutter/material.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +/* SNIPPET START */ +class MyNotifier extends Notifier { + @override + int build() { + ref.listenSelf((_, next) => debugPrint('$next')); + return 0; + } +} + +final myNotifierProvider = NotifierProvider(MyNotifier.new); diff --git a/website/docs/migration/async_notifier/async_notifier.dart b/website/docs/migration/async_notifier/async_notifier.dart new file mode 100644 index 000000000..14f0ba1cc --- /dev/null +++ b/website/docs/migration/async_notifier/async_notifier.dart @@ -0,0 +1,19 @@ +// ignore_for_file: avoid_print + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'async_notifier.g.dart'; + +class Todo {} + +/* SNIPPET START */ +@riverpod +class AsyncTodosNotifier extends _$AsyncTodosNotifier { + @override + FutureOr> build() { + // mock of a network request + return Future.delayed(const Duration(seconds: 1), () => []); + } + + // ... +} diff --git a/website/docs/migration/async_notifier/async_notifier.g.dart b/website/docs/migration/async_notifier/async_notifier.g.dart new file mode 100644 index 000000000..955a4d417 --- /dev/null +++ b/website/docs/migration/async_notifier/async_notifier.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'async_notifier.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$asyncTodosNotifierHash() => + r'954b0a18d324fad35807140db2fcff39b5947571'; + +/// See also [AsyncTodosNotifier]. +@ProviderFor(AsyncTodosNotifier) +final asyncTodosNotifierProvider = + AutoDisposeAsyncNotifierProvider>.internal( + AsyncTodosNotifier.new, + name: r'asyncTodosNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$asyncTodosNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AsyncTodosNotifier = AutoDisposeAsyncNotifier>; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/async_notifier/index.tsx b/website/docs/migration/async_notifier/index.tsx new file mode 100644 index 000000000..a0ff513c3 --- /dev/null +++ b/website/docs/migration/async_notifier/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./async_notifier.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/async_notifier/raw.dart b/website/docs/migration/async_notifier/raw.dart new file mode 100644 index 000000000..74acea97a --- /dev/null +++ b/website/docs/migration/async_notifier/raw.dart @@ -0,0 +1,20 @@ +// ignore_for_file: avoid_print + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +class Todo {} + +/* SNIPPET START */ +class AsyncTodosNotifier extends AsyncNotifier> { + @override + FutureOr> build() { + // mock of a network request + return Future.delayed(const Duration(seconds: 1), () => []); + } + + // ... +} + +final asyncTodosNotifier = AsyncNotifierProvider>( + AsyncTodosNotifier.new, +); diff --git a/website/docs/migration/build_init/build_init.dart b/website/docs/migration/build_init/build_init.dart new file mode 100644 index 000000000..960f70fd9 --- /dev/null +++ b/website/docs/migration/build_init/build_init.dart @@ -0,0 +1,21 @@ +// ignore_for_file: avoid_print + +import 'dart:math'; + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../utils.dart'; + +part 'build_init.g.dart'; + +/* SNIPPET START */ +@riverpod +class WellNotifier extends _$WellNotifier { + @override + int build() { + final availableToDrink = ref.watch(availableWater); + return availableToDrink; + } + + void drink(int liters) => state = min(state - liters, 0); +} diff --git a/website/docs/migration/build_init/build_init.g.dart b/website/docs/migration/build_init/build_init.g.dart new file mode 100644 index 000000000..746763004 --- /dev/null +++ b/website/docs/migration/build_init/build_init.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'build_init.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$wellNotifierHash() => r'd13a501738fbba0347eb23956aed1b505f5f8eab'; + +/// See also [WellNotifier]. +@ProviderFor(WellNotifier) +final wellNotifierProvider = + AutoDisposeNotifierProvider.internal( + WellNotifier.new, + name: r'wellNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$wellNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$WellNotifier = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/build_init/index.tsx b/website/docs/migration/build_init/index.tsx new file mode 100644 index 000000000..276a143ac --- /dev/null +++ b/website/docs/migration/build_init/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./build_init.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/build_init/raw.dart b/website/docs/migration/build_init/raw.dart new file mode 100644 index 000000000..da61d975e --- /dev/null +++ b/website/docs/migration/build_init/raw.dart @@ -0,0 +1,21 @@ +// ignore_for_file: avoid_print + +import 'dart:math'; + +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../utils.dart'; + +/* SNIPPET START */ +class WellNotifier extends Notifier { + @override + int build() { + final availableToDrink = ref.watch(availableWater); + return availableToDrink; + } + + void drink(int liters) => state = min(state - liters, 0); +} + +final wellNotifierProvider = NotifierProvider(WellNotifier.new); diff --git a/website/docs/migration/family_and_dispose/family_and_dispose.dart b/website/docs/migration/family_and_dispose/family_and_dispose.dart new file mode 100644 index 000000000..140ceeaca --- /dev/null +++ b/website/docs/migration/family_and_dispose/family_and_dispose.dart @@ -0,0 +1,26 @@ +import 'dart:math'; + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../utils.dart'; + +part 'family_and_dispose.g.dart'; + +/* SNIPPET START */ +@riverpod +class BugsEncounteredNotifier extends _$BugsEncounteredNotifier { + late String _id; + @override + FutureOr build(String featureId) { + _id = featureId; + return 99; + } + + Future fix(int amount) async { + state = await AsyncValue.guard(() async { + final old = state.requireValue; + final result = await ref.read(taskTrackerProvider).fix(id: _id, fixed: amount); + return max(old - result, 0); + }); + } +} diff --git a/website/docs/migration/family_and_dispose/family_and_dispose.g.dart b/website/docs/migration/family_and_dispose/family_and_dispose.g.dart new file mode 100644 index 000000000..846d8bbc8 --- /dev/null +++ b/website/docs/migration/family_and_dispose/family_and_dispose.g.dart @@ -0,0 +1,131 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'family_and_dispose.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$bugsEncounteredNotifierHash() => + r'f45903bf1c7a2b38cad33907afcdce86901b738b'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +abstract class _$BugsEncounteredNotifier + extends BuildlessAutoDisposeAsyncNotifier { + late final String featureId; + + FutureOr build( + String featureId, + ); +} + +/// See also [BugsEncounteredNotifier]. +@ProviderFor(BugsEncounteredNotifier) +const bugsEncounteredNotifierProvider = BugsEncounteredNotifierFamily(); + +/// See also [BugsEncounteredNotifier]. +class BugsEncounteredNotifierFamily extends Family> { + /// See also [BugsEncounteredNotifier]. + const BugsEncounteredNotifierFamily(); + + /// See also [BugsEncounteredNotifier]. + BugsEncounteredNotifierProvider call( + String featureId, + ) { + return BugsEncounteredNotifierProvider( + featureId, + ); + } + + @override + BugsEncounteredNotifierProvider getProviderOverride( + covariant BugsEncounteredNotifierProvider provider, + ) { + return call( + provider.featureId, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'bugsEncounteredNotifierProvider'; +} + +/// See also [BugsEncounteredNotifier]. +class BugsEncounteredNotifierProvider + extends AutoDisposeAsyncNotifierProviderImpl { + /// See also [BugsEncounteredNotifier]. + BugsEncounteredNotifierProvider( + this.featureId, + ) : super.internal( + () => BugsEncounteredNotifier()..featureId = featureId, + from: bugsEncounteredNotifierProvider, + name: r'bugsEncounteredNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$bugsEncounteredNotifierHash, + dependencies: BugsEncounteredNotifierFamily._dependencies, + allTransitiveDependencies: + BugsEncounteredNotifierFamily._allTransitiveDependencies, + ); + + final String featureId; + + @override + bool operator ==(Object other) { + return other is BugsEncounteredNotifierProvider && + other.featureId == featureId; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, featureId.hashCode); + + return _SystemHash.finish(hash); + } + + @override + FutureOr runNotifierBuild( + covariant BugsEncounteredNotifier notifier, + ) { + return notifier.build( + featureId, + ); + } +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/family_and_dispose/index.tsx b/website/docs/migration/family_and_dispose/index.tsx new file mode 100644 index 000000000..0780f2135 --- /dev/null +++ b/website/docs/migration/family_and_dispose/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./family_and_dispose.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/family_and_dispose/raw.dart b/website/docs/migration/family_and_dispose/raw.dart new file mode 100644 index 000000000..0430e170c --- /dev/null +++ b/website/docs/migration/family_and_dispose/raw.dart @@ -0,0 +1,29 @@ +import 'dart:math'; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../utils.dart'; + +/* SNIPPET START */ +class BugsEncounteredNotifier extends AutoDisposeFamilyAsyncNotifier { + late String _id; + @override + FutureOr build(String featureId) { + _id = featureId; + return 99; + } + + Future fix(int amount) async { + state = await AsyncValue.guard(() async { + final old = state.requireValue; + final result = await ref.read(taskTrackerProvider).fix(id: _id, fixed: amount); + return max(old - result, 0); + }); + } +} + +final bugsEncounteredNotifierProvider = + AsyncNotifierProvider.family.autoDispose( + BugsEncounteredNotifier.new, +); diff --git a/website/docs/migration/from_change_notifier/from_change_notifier.dart b/website/docs/migration/from_change_notifier/from_change_notifier.dart new file mode 100644 index 000000000..490c0d268 --- /dev/null +++ b/website/docs/migration/from_change_notifier/from_change_notifier.dart @@ -0,0 +1,28 @@ +// ignore_for_file: avoid_print + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'from_change_notifier.g.dart'; + +class Todo { + const Todo(this.id); + final int id; +} + +/* SNIPPET START */ +@riverpod +class MyNotifier extends _$MyNotifier { + @override + FutureOr> build() { + // request mock + return Future.delayed(const Duration(seconds: 1), () => []); + } + + Future addTodo(int id) async { + state = const AsyncLoading(); + state = await AsyncValue.guard(() { + // request mock + return Future.delayed(const Duration(seconds: 1), () => [Todo(id)]); + }); + } +} diff --git a/website/docs/migration/from_change_notifier/from_change_notifier.g.dart b/website/docs/migration/from_change_notifier/from_change_notifier.g.dart new file mode 100644 index 000000000..7d8bc2da5 --- /dev/null +++ b/website/docs/migration/from_change_notifier/from_change_notifier.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'from_change_notifier.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$myNotifierHash() => r'fa0927a77e9a6161041c5c38e9fada566bebe6bc'; + +/// See also [MyNotifier]. +@ProviderFor(MyNotifier) +final myNotifierProvider = + AutoDisposeAsyncNotifierProvider>.internal( + MyNotifier.new, + name: r'myNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$myNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$MyNotifier = AutoDisposeAsyncNotifier>; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/from_change_notifier/index.tsx b/website/docs/migration/from_change_notifier/index.tsx new file mode 100644 index 000000000..cff9637c7 --- /dev/null +++ b/website/docs/migration/from_change_notifier/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./from_change_notifier.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/from_change_notifier/raw.dart b/website/docs/migration/from_change_notifier/raw.dart new file mode 100644 index 000000000..a2cbb31d4 --- /dev/null +++ b/website/docs/migration/from_change_notifier/raw.dart @@ -0,0 +1,28 @@ +// ignore_for_file: avoid_print + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +class Todo { + const Todo(this.id); + final int id; +} + +/* SNIPPET START */ +@riverpod +class MyNotifier extends AutoDisposeAsyncNotifier> { + @override + FutureOr> build() { + // request mock + return Future.delayed(const Duration(seconds: 1), () => []); + } + + Future addTodo(int id) async { + state = const AsyncLoading(); + state = await AsyncValue.guard(() { + // request mock + return Future.delayed(const Duration(seconds: 1), () => [Todo(id)]); + }); + } +} + +final myNotifierProvider = AsyncNotifierProvider.autoDispose(MyNotifier.new); diff --git a/website/docs/migration/from_state_notifier.mdx b/website/docs/migration/from_state_notifier.mdx new file mode 100644 index 000000000..155876fb3 --- /dev/null +++ b/website/docs/migration/from_state_notifier.mdx @@ -0,0 +1,386 @@ +--- +title: From `StateNotifier` and `ChangeNotifier` +--- + +import buildIinit from "./build_init"; +import familyAndDispose from "./family_and_dispose"; +import asyncNotifier from "./async_notifier"; +import addListener from "./add_listener"; +import fromChangeNotifier from "./from_change_notifier"; +import fromStateProvider from "./from_state_provider"; +import oldLifecycles from "./old_lifecycles"; +import { AutoSnippet } from "../../src/components/CodeSnippet"; + +Riverpod went `2.0`! To see the full list of changes, consult the +[Changelog](https://pub.dev/packages/flutter_riverpod/changelog#200). + +Riverpod `2.0` introduced the new `Notifier` and `AsyncNotifier` classes. +This page shows how to migrate from the deprecated `StateNotifier` (and from the legacy `ChangeNotifier`) +to the new APIs. + +The main benefit introduced by `AsyncNotifier` is a better `async` support; indeed, +`AsyncNotifier` can be thought as a `FutureProvider` with methods. + +Furthermore, the new `Notifier`s: + +- Expose a `Ref` object inside its class +- Offer similar syntax between codegen and non-codegen approaches +- Offer similar syntax between their sync and async versions +- Move away logic from Providers and centralize it into the Notifiers themselves + +Let's see how to define a `Notifier`, how it compares with `StateNotifier` and explore +the new `AsyncNotifier` for asynchronous state classes. + +## The new syntax + +Let's write some simple logic with a synchronous `Notifier`: + + + +Notice the following design choices: + +- Notifiers are initialized in their `build` method, along with their reactive dependencies +- Notifiers expose `ref` into their class, whereas their Provider don't + +### Comparison with `StateNotifier` + +Let's compare the new APIs with the old ones; here, we implement the above example with `StateNotifier`: + +```dart +class WellNotifier extends StateNotifier { + WellNotifier(int availableToDrink) : super(availableToDrink); + + void drink(int liters) => state = min(state - liters, 0); +} + +final wellNotifierProvider = StateNotifierProvider((ref) { + final availableToDrink = ref.watch(availableWater); + return WellNotifier(availableToDrink); +}); +``` + +Let's recap the main differences: + +- `StateNotifier`'s reactive dependencies are declared in its provider, whereas `Notifier` + centralizes this logic in its `build` method +- Indeed, `StateNotifier`'s whole initialization process is split between its provider and its constructor, + whereas `Notifier` reserves a single place to place such logic +- Notice how, as opposed to `StateNotifier`, no logic is ever written into a `Notifier`'s constructor + +Similar conclusions can be made with `AsyncNotifer`, `Notifier`'s asynchronous equivalent. +Let's check it out. + +## Better async support with `AsyncNotifier` + +The main appeal of the new API syntax is an improved DX on asynchronous states. +Previously, with `StateNotifier`, we would handle that like so: + +```dart +class AsyncTodosNotifier extends StateNotifier>> { + AsyncTodosNotifier() : super(const AsyncLoading()) { + _postInit(); + } + + Future _postInit() async { + state = await AsyncValue.guard( + // mock of a network request + () => Future.delayed(const Duration(seconds: 1), () => []), + ); + } + + // ... +} +``` + +This heavy syntax suffers from the same defects showed above. +`AsyncNotifer`, just like `Notifier`, brings a simple and uniform API. Here, it's easy to see +`AsyncNotifer` as a `FutureProvider` with methods. + +Here's the above example, rewritten with the new `AsyncNotifier` APIs: + + + +Therefore, migrating from `StateNotifier>` to a `AsyncNotifer` should be very straightforward: + +- Place the initialization logic directly into `build`: there's no need to define a `_postInit` method anymore +- There's no need to explicitly initialize `state` with `AsyncLoading`: as long as `build` returns a `Future`, + this will be handled by `AsyncNotifer`, directly +- You can evaluate an initialization synchronously, if ever needed: just avoid returning a `Future` in your `build` method, + i.e. let `build` be synchronous (this is the equivalent of initializing `StateNotifier` with an `AsyncData`) + +Finally, `AsyncNotifer` comes with a set of utilities and getters that `StateNotifier` doesn't have, such as e.g. +[`future`](https://pub.dev/documentation/riverpod/latest/riverpod/AutoDisposeAsyncNotifier/future.html) +and [`update`](https://pub.dev/documentation/riverpod/latest/riverpod/AutoDisposeAsyncNotifier/update.html). +This enables us to write much simpler logic when handling asynchronous mutations. + +## Explicit `.family` and `.autoDispose` modifications + +When a `StateNotifier` had family parameters, these were not found into its class, but they were +defined in its provider; also, and chances are that these parameters must have been piped down its constructor, too. + +`Notifier`, instead, has its own `.family` and `.autoDispose` counterparts, such as `FamilyNotifier` +and `AutoDisposeNotifier`. +Like any other provider, these can be combined (aka `AutoDisposeFamilyNotifier`). +`AsyncNotifer` has its asynchronous equivalent, too (e.g. `AutoDisposeFamilyAsyncNotifier`). + +The main difference (and advantage) is that modifications and any parameters are explicitly stated inside the class; +furthermore, they are directly injected in the `build` method, so that they're available to the initialization logic. +This should bring better readability, more conciseness and less mistakes. + +Take the following example, in which a `StateNotifierProvider.family` is being defined. + +```dart +class BugsEncounteredNotifier extends StateNotifier> { + BugsEncounteredNotifier({ + required this.ref, + required this.featureId, + }) : super(const AsyncData(99)); + final String featureId; + final Ref ref; + + Future fix(int amount) async { + state = await AsyncValue.guard(() async { + final old = state.requireValue; + final result = await ref.read(taskTrackerProvider).fix(id: featureId, fixed: amount); + return max(old - result, 0); + }); + } +} + +final bugsEncounteredNotifierProvider = + StateNotifierProvider.family.autoDispose((ref, id) { + return BugsEncounteredNotifier(ref: ref, featureId: id); +}); +``` + +The main gotcha here is that reading `BugsEncounteredNotifier` is _not_ enough to determine wheter or +not this `StateNotifier` has modifications (e.g. `.family` and/or `.autoDispose`). +To determine that, it is required to read the its provider definition. + +Now, let's take a look at its migrated `AsyncNotifier` counterpart: + + + +This last snippet should showcase better readability: it's possible to immediately tell +what modifications are being set for this Notifier. + +## Lifecycles have a different behavior + +Lifecycles between `Notifier`/`AsyncNotifier` and `StateNotifier`/`ChangeNotifier` differ substantially. + +`StateNotifier` and `ChangeNotifier` instances are indeed bound to their outer +`StateNotifierProvider` and `ChangeNotifierProvider` providers. +When their provider rebuilds, their exposed value, aka their `StateNotifier`/`ChangeNotifier` instance, +is `disposed`, and then re-created (i.e. its constructor gets invoked again). + +This example showcases - again - how the old API have sparse logic: + +```dart +class MyNotifier extends StateNotifier { + MyNotifier(this.period) : super(0) { // 1 init logic + _timer = Timer.periodic(period, (t) => update()); // 2 side effect on init + } + final Duration period; + late final Timer _timer; + + void update() => state++; // 3 mutation + + @override + void dispose() { + _timer.cancel(); // 4 custom dispose logic + super.dispose(); + } +} + +final myNotifierProvider = StateNotifierProvider((ref) { // 5 provider definition + final Duration period = ref.watch(durationProvider); // 6 reactive dependency logic + return MyNotifier(period); +}); +``` + +Here, if `durationProvider` updates, `MyNotifier` _disposes_: its instance is then re-instantiated +and its internal state is then re-initialized. +Furthermore, unlike every other provider, the `dispose` callback is to be defined +in the class, separately. +Finally, it is still possible to write `ref.onDispose` in its _provider_, showing once again how +sparse the logic can be with this API; potentially, the developer might have to look into six (6!) +different places to understand this Notifier behavior! + +Again, this ambiguity is solved with `Riverpod 2.0`. +Check the above example, migrated to its `Notifier` equivalent. + + + +This simplifies the API and, hopefully, your DX, for two reasons: + +1. There is only _one_ lifecycle to take care of, and it's managed via `ref.onDispose` + (and `ref.onCancel`, etc.), just like you would do with any other provider +2. There is only _one_ place to look at to understand lifecycle side-effects, its `build` method +3. Also, the above `MyNotifier`, will _not_ dispose when `durationProvider` updates: + only its _internal state_ will + +### `.mounted` is no more + +**TODO: talk about how there is no `.mounted` property and how to transition from it** + +## Other migrations + +Let's explore the less-impactful differences between `StateNotifier` and `Notifier` (or `AsyncNotifier`) + +### From `.addListener` and `.stream` + +`StateNotifier`'s `.addListener` and `.stream` can be used to listen for state changes. +These two APIs are now to be considered outdated. + +This is intentional due to the desire to reach full API uniformity with `Notifier`, `AsyncNotifier` and other providers. +Indeed, using a `Notifier` or an `AsyncNotifier` shouldn't be any different from any other provider. + +Therefore this: +```dart +class MyNotifier extends StateNotifier { + MyNotifier() : super(0); +} + +final myNotifierProvider = StateNotifierProvider((ref) { + final notifier = MyNotifier(); + + final cleanup = notifier.addListener((state) => debugPrint('$state')); + ref.onDispose(cleanup); + + // Or, equivalently: + // final listener = notifier.stream.listen((event) => debugPrint('$event')); + // ref.onDispose(listener.cancel); + + return notifier; +}); +``` +Becomes this: + + +In a nutshell: if you want to listen to a `Notifier`/`AsyncNotifer`, just use `ref.listen`, +[as explained here](/docs/concepts/reading#using-reflisten-to-react-to-a-provider-change). + +### From `.debugState` + +`StateNotifier` exposed `.debugState`: this property had some use within `state_notifier`, +as it enabled accessing state from outside the class when in development mode, for testing purposes. + +Again, for uniformity reasons, such property is not available in the new APIs. +If you want to interact with `Notifier`/`AsyncNotifier` in a testing environment, you should do +it just like with any other provider: by reading them directly (as opposed of directly instantiating +a `Notifier` by hand). + +The [testing guide](/docs/cookbooks/testing) fully explains how to use `ProviderContainer.read` to do so. + +## From `StateProvider` to `Notifier` + +`StateProvider` was exposed by Riverpod's libraries to save a few LoC when in need of a +simplified version of `StateNotifierProvider`. +Since `StateNotifierProvider` is deprecated, `StateProvider` is to be avoided, too. +Furthermore, as of now, there is not `StateProvider` equivalent for the new APIs. + +Nonetheless, migrating from `StateProvider` to `Notifier` is simple. + +This: + +```dart +final counterProvider = StateProvider((ref) { + return 0; +}); +``` + +Becomes: + + + +Even though it costs us a few more LoC, migrating away from `StateProvider` enables us to +definetively archive `StateNotifier`. + +## From `ChangeNotifier` to `AsyncNotifier` + +`ChangeNotifier` is meant to be used to offer a smooth transitionfrom pkg:Provider. +This paragraphs showcases a migration towards the new APIs going further than what's showcased +in the [quickstart guide](/docs/from_provider/quickstart). + +All in all, migrating from `ChangeNotifier` to `AsyncNotifer` requires a paradigm shift, but it +brings great simplification with the resulting migrated code. + +Take this example: +```dart +class MyChangeNotifier extends ChangeNotifier { + MyChangeNotifier() { + _init(); + } + List todos = []; + bool isLoading = true; + bool hasError = false; + + Future _init() async { + try { + // request mock + todos = Future.delayed(const Duration(seconds: 1), () => []); + } on Exception { + hasError = true; + } finally { + isLoading = false; + notifyListeners(); + } + } + + Future addTodo(int id) async { + isLoading = true; + notifyListeners(); + + try { + // request mock + todos = Future.delayed(const Duration(seconds: 1), () => [Todo(id)]); + hasError = false; + } on Exception { + hasError = true; + } finally { + isLoading = false; + notifyListeners(); + } + } +} + +final myChangeProvider = ChangeNotifierProvider((ref) { + return MyChangeNotifier(); +}); +``` + +This implementation shows several faulty design choices such as: +- The usage of `isLoading` and `hasError` to handle different asynchronous cases +- The need to carefully handle requests with tedious `try`/`catch`/`finally` expressions +- The need to inkove `notifyListeners` at the right times to make this implementation work +- The presence of inconsistent or possibly undesirable states, e.g. initialization with an empty list + +While this example has been crafted to show how `ChangeNotifier` can lead to faulty design choices +for newbie developers, the main takeaway is that mutable state might be harder than it looks. + +`Notifier`/`AsyncNotifer`, in combination with immutable state, can lead to better design choices +and less errors; this approach lifts the developer from several intricacies due to the nature +of asynchronous state. + +With `AsyncNotifier`, the above becomes: + + +### Migration Process +Let's analyze the migration process applied here: +1. We've moved the initialization from a method invoked in a constructor, directly into `build` +2. We've removed `todos`, `isLoading` and `hasError`: `state` suffice +3. Notice how, since `build` returns a `Future`, state is implicitly initialized with `AsyncLoading`, +waiting for the initial request to finish +4. We've returned the result of the (mocked) asynchronous request, with no try-catch-finally blocks +5. We've then simplified `addTodo`, exploiting `AsyncValue`'s APIs +6. Notice that, to apply mutations, we simply reassign `state` directly: +listeners will be automatically notified about it + +### Advantages +Finally, let's highlight the main advantages of the new APIs: +- There's a lot less code, and what's left is way more simple and readable +- Since `AsyncNotifier` implicitly uses `AsyncValue`, there's no need to manually define and handle + `isLoading` and `hasError` +- There's no need to explicitly handle errors (i.e. try-catch-finally blocks), since +`AsyncNotifier.build` converts errors into `AsyncError` and valid data into `AsyncData` +- `AsyncValue.guard` essentialy emulates `AsyncNotifier.build`, greatly simplifying mutations \ No newline at end of file diff --git a/website/docs/migration/from_state_provider/from_state_provider.dart b/website/docs/migration/from_state_provider/from_state_provider.dart new file mode 100644 index 000000000..7903778aa --- /dev/null +++ b/website/docs/migration/from_state_provider/from_state_provider.dart @@ -0,0 +1,15 @@ +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'from_state_provider.g.dart'; + +/* SNIPPET START */ +@riverpod +class CounterNotifier extends _$CounterNotifier { + @override + int build() => 0; + + @override + set state(int newState) => super.state = newState; + + int update(int Function(int state) cb) => state = cb(state); +} diff --git a/website/docs/migration/from_state_provider/from_state_provider.g.dart b/website/docs/migration/from_state_provider/from_state_provider.g.dart new file mode 100644 index 000000000..7aaf807f9 --- /dev/null +++ b/website/docs/migration/from_state_provider/from_state_provider.g.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'from_state_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$counterNotifierHash() => r'b32033040f0fff627f1a6dfd9cfb4e93a842390b'; + +/// See also [CounterNotifier]. +@ProviderFor(CounterNotifier) +final counterNotifierProvider = + AutoDisposeNotifierProvider.internal( + CounterNotifier.new, + name: r'counterNotifierProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$counterNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$CounterNotifier = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/from_state_provider/index.tsx b/website/docs/migration/from_state_provider/index.tsx new file mode 100644 index 000000000..f59794999 --- /dev/null +++ b/website/docs/migration/from_state_provider/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./from_state_provider.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/from_state_provider/raw.dart b/website/docs/migration/from_state_provider/raw.dart new file mode 100644 index 000000000..8bd1a60f0 --- /dev/null +++ b/website/docs/migration/from_state_provider/raw.dart @@ -0,0 +1,14 @@ +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +/* SNIPPET START */ +class CounterNotifier extends Notifier { + @override + int build() => 0; + + @override + set state(int newState) => super.state = newState; + + int update(int Function(int state) cb) => state = cb(state); +} + +final counterNotifierProvider = NotifierProvider(CounterNotifier.new); diff --git a/website/docs/migration/old_lifecycles/index.tsx b/website/docs/migration/old_lifecycles/index.tsx new file mode 100644 index 000000000..9b77f551a --- /dev/null +++ b/website/docs/migration/old_lifecycles/index.tsx @@ -0,0 +1,9 @@ +import raw from "!!raw-loader!./raw.dart"; +import codegen from "!!raw-loader!./old_lifecycles.dart"; + +export default { + raw, + hooks: raw, + codegen, + hooksCodegen: codegen, +}; diff --git a/website/docs/migration/old_lifecycles/old_lifecycles.dart b/website/docs/migration/old_lifecycles/old_lifecycles.dart new file mode 100644 index 000000000..5db06e15c --- /dev/null +++ b/website/docs/migration/old_lifecycles/old_lifecycles.dart @@ -0,0 +1,23 @@ +import 'dart:async'; + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../utils.dart'; + +part 'old_lifecycles.g.dart'; + +/* SNIPPET START */ +@riverpod +class MyNotifier extends _$MyNotifier { + @override + int build() { + // Just read/write the code here, in one place + final period = ref.watch(durationProvider); + final timer = Timer.periodic(period, (t) => update()); + ref.onDispose(timer.cancel); + + return 0; + } + + void update() => state++; +} diff --git a/website/docs/migration/old_lifecycles/old_lifecycles.g.dart b/website/docs/migration/old_lifecycles/old_lifecycles.g.dart new file mode 100644 index 000000000..5a1e1dbde --- /dev/null +++ b/website/docs/migration/old_lifecycles/old_lifecycles.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: non_constant_identifier_names + +part of 'old_lifecycles.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$myNotifierHash() => r'768ef0cc026b45823896a770bfb02c9781364838'; + +/// See also [MyNotifier]. +@ProviderFor(MyNotifier) +final myNotifierProvider = + AutoDisposeNotifierProvider.internal( + MyNotifier.new, + name: r'myNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$myNotifierHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$MyNotifier = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/website/docs/migration/old_lifecycles/raw.dart b/website/docs/migration/old_lifecycles/raw.dart new file mode 100644 index 000000000..8e5cf2df2 --- /dev/null +++ b/website/docs/migration/old_lifecycles/raw.dart @@ -0,0 +1,22 @@ +import 'dart:async'; + +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import '../utils.dart'; + +/* SNIPPET START */ +class MyNotifier extends Notifier { + @override + int build() { + // Just read/write the code here, in one place + final period = ref.watch(durationProvider); + final timer = Timer.periodic(period, (t) => update()); + ref.onDispose(timer.cancel); + + return 0; + } + + void update() => state++; +} + +final myNotifierProvider = NotifierProvider(MyNotifier.new); diff --git a/website/docs/migration/utils.dart b/website/docs/migration/utils.dart new file mode 100644 index 000000000..92d4f5824 --- /dev/null +++ b/website/docs/migration/utils.dart @@ -0,0 +1,23 @@ +import 'dart:math' as math; + +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +final randomProvider = Provider((ref) { + return math.Random().nextInt(6); +}); + +final taskTrackerProvider = Provider((ref) { + return TaskTrackerRepo(); +}); + +class TaskTrackerRepo { + Future fix({required String id, required int fixed}) async => 0; +} + +final durationProvider = Provider((ref) { + return Duration.zero; +}); + +final availableWater = Provider((ref) { + return 40; +}); diff --git a/website/sidebars.js b/website/sidebars.js index 6aaafa6a0..f0a678d9f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -192,12 +192,7 @@ module.exports = { label: "Migration guides", collapsible: false, items: [ - { - type: "link", - label: "Migrating StateNotifier/ChangeNotifier to Notifier (WIP)", - href: "https://github.com/rrousselGit/riverpod/tree/master/examples/marvel", - }, - + "migration/from_state_notifier", "migration/0.14.0_to_1.0.0", "migration/0.13.0_to_0.14.0", ], diff --git a/website/src/documents_meta.js b/website/src/documents_meta.js index f5c82524b..e7146a186 100644 --- a/website/src/documents_meta.js +++ b/website/src/documents_meta.js @@ -7,6 +7,7 @@ export const documentTitles = { "providers/notifier_provider": "(Async)NotifierProvider", "providers/future_provider": "FutureProvider", "providers/change_notifier_provider": "ChangeNotifierProvider", + "migration/from_state_notifier": "From `StateNotifier` and `ChangeNotifier`", "migration/0.14.0_to_1.0.0": "^0.14.0 to ^1.0.0", "migration/0.13.0_to_0.14.0": "^0.13.0 to ^0.14.0", "introduction/why_riverpod": "Why Riverpod?", diff --git a/website/yarn.lock b/website/yarn.lock index 9829ffe58..9892ac694 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -29,114 +29,114 @@ resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz#2e22e830d36f0a9cf2c0ccd3c7f6d59435b77dfa" integrity sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ== -"@algolia/cache-browser-local-storage@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.18.0.tgz#7bc0c9d8d346ed01384f4cf0dfaf6ba29ad5c20c" - integrity sha512-rUAs49NLlO8LVLgGzM4cLkw8NJLKguQLgvFmBEe3DyzlinoqxzQMHfKZs6TSq4LZfw/z8qHvRo8NcTAAUJQLcw== - dependencies: - "@algolia/cache-common" "4.18.0" - -"@algolia/cache-common@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.18.0.tgz#aac33afac53e191c595d14a4bb7e6d81aae4836f" - integrity sha512-BmxsicMR4doGbeEXQu8yqiGmiyvpNvejYJtQ7rvzttEAMxOPoWEHrWyzBQw4x7LrBY9pMrgv4ZlUaF8PGzewHg== - -"@algolia/cache-in-memory@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.18.0.tgz#9a40294c734819724a1b4e86afd5a7d4be9bcc2f" - integrity sha512-evD4dA1nd5HbFdufBxLqlJoob7E2ozlqJZuV3YlirNx5Na4q1LckIuzjNYZs2ddLzuTc/Xd5O3Ibf7OwPskHxw== - dependencies: - "@algolia/cache-common" "4.18.0" - -"@algolia/client-account@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.18.0.tgz#202d9e06b41e06e45cb919107bed0a65106883cc" - integrity sha512-XsDnlROr3+Z1yjxBJjUMfMazi1V155kVdte6496atvBgOEtwCzTs3A+qdhfsAnGUvaYfBrBkL0ThnhMIBCGcew== - dependencies: - "@algolia/client-common" "4.18.0" - "@algolia/client-search" "4.18.0" - "@algolia/transporter" "4.18.0" - -"@algolia/client-analytics@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.18.0.tgz#030b026bd9c13cb15437e35e4456bde25b0f1298" - integrity sha512-chEUSN4ReqU7uRQ1C8kDm0EiPE+eJeAXiWcBwLhEynfNuTfawN9P93rSZktj7gmExz0C8XmkbBU19IQ05wCNrQ== - dependencies: - "@algolia/client-common" "4.18.0" - "@algolia/client-search" "4.18.0" - "@algolia/requester-common" "4.18.0" - "@algolia/transporter" "4.18.0" - -"@algolia/client-common@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.18.0.tgz#e080c393e1becdd5f5f008815c57d3248d3a8483" - integrity sha512-7N+soJFP4wn8tjTr3MSUT/U+4xVXbz4jmeRfWfVAzdAbxLAQbHa0o/POSdTvQ8/02DjCLelloZ1bb4ZFVKg7Wg== - dependencies: - "@algolia/requester-common" "4.18.0" - "@algolia/transporter" "4.18.0" - -"@algolia/client-personalization@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.18.0.tgz#9042ce2773120158ad25e1dfb28d706cebb48dc2" - integrity sha512-+PeCjODbxtamHcPl+couXMeHEefpUpr7IHftj4Y4Nia1hj8gGq4VlIcqhToAw8YjLeCTfOR7r7xtj3pJcYdP8A== - dependencies: - "@algolia/client-common" "4.18.0" - "@algolia/requester-common" "4.18.0" - "@algolia/transporter" "4.18.0" - -"@algolia/client-search@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.18.0.tgz#83b37aacbe254fd7892154fe7a8f0395bd01c682" - integrity sha512-F9xzQXTjm6UuZtnsLIew6KSraXQ0AzS/Ee+OD+mQbtcA/K1sg89tqb8TkwjtiYZ0oij13u3EapB3gPZwm+1Y6g== - dependencies: - "@algolia/client-common" "4.18.0" - "@algolia/requester-common" "4.18.0" - "@algolia/transporter" "4.18.0" +"@algolia/cache-browser-local-storage@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.19.1.tgz#d29f42775ed4d117182897ac164519c593faf399" + integrity sha512-FYAZWcGsFTTaSAwj9Std8UML3Bu8dyWDncM7Ls8g+58UOe4XYdlgzXWbrIgjaguP63pCCbMoExKr61B+ztK3tw== + dependencies: + "@algolia/cache-common" "4.19.1" + +"@algolia/cache-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.19.1.tgz#faa5eeacaffd6023c2cf26e9866bdb06193f9b26" + integrity sha512-XGghi3l0qA38HiqdoUY+wvGyBsGvKZ6U3vTiMBT4hArhP3fOGLXpIINgMiiGjTe4FVlTa5a/7Zf2bwlIHfRqqg== + +"@algolia/cache-in-memory@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.19.1.tgz#afe4f0f21149800358379871089e0141fb72415b" + integrity sha512-+PDWL+XALGvIginigzu8oU6eWw+o76Z8zHbBovWYcrtWOEtinbl7a7UTt3x3lthv+wNuFr/YD1Gf+B+A9V8n5w== + dependencies: + "@algolia/cache-common" "4.19.1" + +"@algolia/client-account@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.19.1.tgz#1fa65881baab79ad35af6bcf44646a13b8d5edc9" + integrity sha512-Oy0ritA2k7AMxQ2JwNpfaEcgXEDgeyKu0V7E7xt/ZJRdXfEpZcwp9TOg4TJHC7Ia62gIeT2Y/ynzsxccPw92GA== + dependencies: + "@algolia/client-common" "4.19.1" + "@algolia/client-search" "4.19.1" + "@algolia/transporter" "4.19.1" + +"@algolia/client-analytics@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.19.1.tgz#e6ed79acd4de5a0284c9696bf4e1c25278ba34db" + integrity sha512-5QCq2zmgdZLIQhHqwl55ZvKVpLM3DNWjFI4T+bHr3rGu23ew2bLO4YtyxaZeChmDb85jUdPDouDlCumGfk6wOg== + dependencies: + "@algolia/client-common" "4.19.1" + "@algolia/client-search" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" + +"@algolia/client-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.19.1.tgz#40a8387316fa61d62ad1091beb3a8e227f008e75" + integrity sha512-3kAIVqTcPrjfS389KQvKzliC559x+BDRxtWamVJt8IVp7LGnjq+aVAXg4Xogkur1MUrScTZ59/AaUd5EdpyXgA== + dependencies: + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" + +"@algolia/client-personalization@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.19.1.tgz#fe362e0684dc74c3504c3641c5a7488c6ae02e07" + integrity sha512-8CWz4/H5FA+krm9HMw2HUQenizC/DxUtsI5oYC0Jxxyce1vsr8cb1aEiSJArQT6IzMynrERif1RVWLac1m36xw== + dependencies: + "@algolia/client-common" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" + +"@algolia/client-search@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.19.1.tgz#5e54601aa5f5cea790cec3f2cde4af9d6403871e" + integrity sha512-mBecfMFS4N+yK/p0ZbK53vrZbL6OtWMk8YmnOv1i0LXx4pelY8TFhqKoTit3NPVPwoSNN0vdSN9dTu1xr1XOVw== + dependencies: + "@algolia/client-common" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/transporter" "4.19.1" "@algolia/events@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== -"@algolia/logger-common@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.18.0.tgz#0e6a14e8b91fcb7861595169e1ca57cf219f8255" - integrity sha512-46etYgSlkoKepkMSyaoriSn2JDgcrpc/nkOgou/lm0y17GuMl9oYZxwKKTSviLKI5Irk9nSKGwnBTQYwXOYdRg== +"@algolia/logger-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.19.1.tgz#0e46a11510f3e94e1afc0ac780ae52e9597be78f" + integrity sha512-i6pLPZW/+/YXKis8gpmSiNk1lOmYCmRI6+x6d2Qk1OdfvX051nRVdalRbEcVTpSQX6FQAoyeaui0cUfLYW5Elw== -"@algolia/logger-console@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.18.0.tgz#3636e4b3e2154ee2ee2db2e5be2857203c9f7047" - integrity sha512-3P3VUYMl9CyJbi/UU1uUNlf6Z8N2ltW3Oqhq/nR7vH0CjWv32YROq3iGWGxB2xt3aXobdUPXs6P0tHSKRmNA6g== +"@algolia/logger-console@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.19.1.tgz#656a6f4ebb5de39af6ef7095c398d9ab3cceb87d" + integrity sha512-jj72k9GKb9W0c7TyC3cuZtTr0CngLBLmc8trzZlXdfvQiigpUdvTi1KoWIb2ZMcRBG7Tl8hSb81zEY3zI2RlXg== dependencies: - "@algolia/logger-common" "4.18.0" + "@algolia/logger-common" "4.19.1" -"@algolia/requester-browser-xhr@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.18.0.tgz#90ac575946e0ab196cdd87593b3fed563a32a9af" - integrity sha512-/AcWHOBub2U4TE/bPi4Gz1XfuLK6/7dj4HJG+Z2SfQoS1RjNLshZclU3OoKIkFp8D2NC7+BNsPvr9cPLyW8nyQ== +"@algolia/requester-browser-xhr@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.19.1.tgz#7341ea2f980b8980a2976110142026721e452187" + integrity sha512-09K/+t7lptsweRTueHnSnmPqIxbHMowejAkn9XIcJMLdseS3zl8ObnS5GWea86mu3vy4+8H+ZBKkUN82Zsq/zg== dependencies: - "@algolia/requester-common" "4.18.0" + "@algolia/requester-common" "4.19.1" -"@algolia/requester-common@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.18.0.tgz#12984aa4b10679ffa863536ceeae33cdd0ee4d42" - integrity sha512-xlT8R1qYNRBCi1IYLsx7uhftzdfsLPDGudeQs+xvYB4sQ3ya7+ppolB/8m/a4F2gCkEO6oxpp5AGemM7kD27jA== +"@algolia/requester-common@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.19.1.tgz#f3396c77631b9d36e8d4d6f819a2c27f9ddbf7a1" + integrity sha512-BisRkcWVxrDzF1YPhAckmi2CFYK+jdMT60q10d7z3PX+w6fPPukxHRnZwooiTUrzFe50UBmLItGizWHP5bDzVQ== -"@algolia/requester-node-http@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.18.0.tgz#8046b141c784cc7778bcf51e8a7888cce463754b" - integrity sha512-TGfwj9aeTVgOUhn5XrqBhwUhUUDnGIKlI0kCBMdR58XfXcfdwomka+CPIgThRbfYw04oQr31A6/95ZH2QVJ9UQ== +"@algolia/requester-node-http@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.19.1.tgz#ea210de9642628b3bdda1dd7fcd1fcb686da442e" + integrity sha512-6DK52DHviBHTG2BK/Vv2GIlEw7i+vxm7ypZW0Z7vybGCNDeWzADx+/TmxjkES2h15+FZOqVf/Ja677gePsVItA== dependencies: - "@algolia/requester-common" "4.18.0" + "@algolia/requester-common" "4.19.1" -"@algolia/transporter@4.18.0": - version "4.18.0" - resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.18.0.tgz#18de645c20fc5703196b2ad4fec55e98c315a1d8" - integrity sha512-xbw3YRUGtXQNG1geYFEDDuFLZt4Z8YNKbamHPkzr3rWc6qp4/BqEeXcI2u/P/oMq2yxtXgMxrCxOPA8lyIe5jw== +"@algolia/transporter@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.19.1.tgz#b5787299740c4bec9ba05502d98c14b5999860c8" + integrity sha512-nkpvPWbpuzxo1flEYqNIbGz7xhfhGOKGAZS7tzC+TELgEmi7z99qRyTfNSUlW7LZmB3ACdnqAo+9A9KFBENviQ== dependencies: - "@algolia/cache-common" "4.18.0" - "@algolia/logger-common" "4.18.0" - "@algolia/requester-common" "4.18.0" + "@algolia/cache-common" "4.19.1" + "@algolia/logger-common" "4.19.1" + "@algolia/requester-common" "4.19.1" "@ampproject/remapping@^2.2.0": version "2.2.1" @@ -260,10 +260,10 @@ regexpu-core "^5.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz#af1429c4a83ac316a6a8c2cc8ff45cb5d2998d3a" - integrity sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A== +"@babel/helper-define-polyfill-provider@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" + integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== dependencies: "@babel/helper-compilation-targets" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" @@ -1149,9 +1149,9 @@ semver "^6.3.1" "@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + version "0.1.6" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6.tgz#31bcdd8f19538437339d17af00d177d854d9d458" + integrity sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" @@ -1800,11 +1800,6 @@ resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== -"@nicolo-ribaudo/semver-v6@^6.3.3": - version "6.3.3" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29" - integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2034,9 +2029,9 @@ "@types/estree" "*" "@types/eslint@*": - version "8.44.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.0.tgz#55818eabb376e2272f77fbf5c96c43137c3c1e53" - integrity sha512-gsF+c/0XOguWgaOgvFs+xnnRqt9GwgTvIks36WpE6ueeI4KCEHHd8K/CKHqhOqrJKsYH8m27kRzQEvWXAwXUTw== + version "8.44.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.1.tgz#d1811559bb6bcd1a76009e3f7883034b78a0415e" + integrity sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -2137,9 +2132,9 @@ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== "@types/node@*": - version "20.4.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.2.tgz#129cc9ae69f93824f92fac653eebfb4812ab4af9" - integrity sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw== + version "20.4.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab" + integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g== "@types/node@^17.0.5": version "17.0.45" @@ -2205,9 +2200,9 @@ "@types/react" "*" "@types/react@*": - version "18.2.15" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.15.tgz#14792b35df676c20ec3cf595b262f8c615a73066" - integrity sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA== + version "18.2.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.18.tgz#c8b233919eef1bdc294f6f34b37f9727ad677516" + integrity sha512-da4NTSeBv/P34xoZPhtcLkmZuJ+oYaCxHmyHzwaDQo9RQPBeXV+06gEk2FpqEcsX9XrnNLvRpVh6bdavDSjtiQ== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2501,31 +2496,31 @@ ajv@^8.0.0, ajv@^8.9.0: uri-js "^4.2.2" algoliasearch-helper@^3.10.0: - version "3.13.3" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.13.3.tgz#d23341fb88f490c9b2b83fc2362d1551d52117b6" - integrity sha512-jhbbuYZ+fheXpaJlqdJdFa1jOsrTWKmRRTYDM3oVTto5VodZzM7tT+BHzslAotaJf/81CKrm6yLRQn8WIr/K4A== + version "3.14.0" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.14.0.tgz#2409c2591952719ab6fba1de77b3bbe5094ab85e" + integrity sha512-gXDXzsSS0YANn5dHr71CUXOo84cN4azhHKUbg71vAWnH+1JBiR4jf7to3t3JHXknXkbV0F7f055vUSBKrltHLQ== dependencies: "@algolia/events" "^4.0.1" algoliasearch@^4.0.0, algoliasearch@^4.13.1: - version "4.18.0" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.18.0.tgz#1183ad0384a5b2c14f381c3a361da611acc8edb3" - integrity sha512-pCuVxC1SVcpc08ENH32T4sLKSyzoU7TkRIDBMwSLfIiW+fq4znOmWDkAygHZ6pRcO9I1UJdqlfgnV7TRj+MXrA== - dependencies: - "@algolia/cache-browser-local-storage" "4.18.0" - "@algolia/cache-common" "4.18.0" - "@algolia/cache-in-memory" "4.18.0" - "@algolia/client-account" "4.18.0" - "@algolia/client-analytics" "4.18.0" - "@algolia/client-common" "4.18.0" - "@algolia/client-personalization" "4.18.0" - "@algolia/client-search" "4.18.0" - "@algolia/logger-common" "4.18.0" - "@algolia/logger-console" "4.18.0" - "@algolia/requester-browser-xhr" "4.18.0" - "@algolia/requester-common" "4.18.0" - "@algolia/requester-node-http" "4.18.0" - "@algolia/transporter" "4.18.0" + version "4.19.1" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.19.1.tgz#18111fb422eaf841737adb92d5ab12133d244218" + integrity sha512-IJF5b93b2MgAzcE/tuzW0yOPnuUyRgGAtaPv5UUywXM8kzqfdwZTO4sPJBzoGz1eOy6H9uEchsJsBFTELZSu+g== + dependencies: + "@algolia/cache-browser-local-storage" "4.19.1" + "@algolia/cache-common" "4.19.1" + "@algolia/cache-in-memory" "4.19.1" + "@algolia/client-account" "4.19.1" + "@algolia/client-analytics" "4.19.1" + "@algolia/client-common" "4.19.1" + "@algolia/client-personalization" "4.19.1" + "@algolia/client-search" "4.19.1" + "@algolia/logger-common" "4.19.1" + "@algolia/logger-console" "4.19.1" + "@algolia/requester-browser-xhr" "4.19.1" + "@algolia/requester-common" "4.19.1" + "@algolia/requester-node-http" "4.19.1" + "@algolia/transporter" "4.19.1" ansi-align@^3.0.0, ansi-align@^3.0.1: version "3.0.1" @@ -2670,28 +2665,28 @@ babel-plugin-extract-import-names@1.6.22: "@babel/helper-plugin-utils" "7.10.4" babel-plugin-polyfill-corejs2@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz#9f9a0e1cd9d645cc246a5e094db5c3aa913ccd2b" - integrity sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA== + version "0.4.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" + integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== dependencies: "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.4.1" - "@nicolo-ribaudo/semver-v6" "^6.3.3" + "@babel/helper-define-polyfill-provider" "^0.4.2" + semver "^6.3.1" babel-plugin-polyfill-corejs3@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz#d406c5738d298cd9c66f64a94cf8d5904ce4cc5e" - integrity sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ== + version "0.8.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz#b4f719d0ad9bb8e0c23e3e630c0c8ec6dd7a1c52" + integrity sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.4.1" + "@babel/helper-define-polyfill-provider" "^0.4.2" core-js-compat "^3.31.0" babel-plugin-polyfill-regenerator@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz#ace7a5eced6dff7d5060c335c52064778216afd3" - integrity sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw== + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" + integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.4.1" + "@babel/helper-define-polyfill-provider" "^0.4.2" bail@^1.0.0: version "1.0.5" @@ -2807,13 +2802,13 @@ braces@^3.0.2, braces@~3.0.2: fill-range "^7.0.1" browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.21.5, browserslist@^4.21.9: - version "4.21.9" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635" - integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== dependencies: - caniuse-lite "^1.0.30001503" - electron-to-chromium "^1.4.431" - node-releases "^2.0.12" + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" update-browserslist-db "^1.0.11" buffer-from@^1.0.0: @@ -2885,10 +2880,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503: - version "1.0.30001516" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz#621b1be7d85a8843ee7d210fd9d87b52e3daab3a" - integrity sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== ccount@^1.0.0: version "1.1.0" @@ -3205,21 +3200,21 @@ copy-webpack-plugin@^11.0.0: serialize-javascript "^6.0.0" core-js-compat@^3.31.0: - version "3.31.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.31.1.tgz#5084ad1a46858df50ff89ace152441a63ba7aae0" - integrity sha512-wIDWd2s5/5aJSdpOJHfSibxNODxoGoWOBHt8JSPB41NOE94M7kuTPZCYLOlTtuoXTsBPKobpJ6T+y0SSy5L9SA== + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90" + integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw== dependencies: browserslist "^4.21.9" core-js-pure@^3.30.2: - version "3.31.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.31.1.tgz#73d154958881873bc19381df80bddb20c8d0cdb5" - integrity sha512-w+C62kvWti0EPs4KPMCMVv9DriHSXfQOCQ94bGGBiEW5rrbtt/Rz8n5Krhfw9cpFyzXBjf3DB3QnPdEzGDY4Fw== + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.32.0.tgz#5d79f85da7a4373e9a06494ccbef995a4c639f8b" + integrity sha512-qsev1H+dTNYpDUEURRuOXMvpdtAnNEvQWS/FMJ2Vb5AY8ZP4rAPQldkE27joykZPJTe0+IVgHZYh1P5Xu1/i1g== core-js@^3.23.3: - version "3.31.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.31.1.tgz#f2b0eea9be9da0def2c5fece71064a7e5d687653" - integrity sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ== + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.0.tgz#7643d353d899747ab1f8b03d2803b0312a0fb3b6" + integrity sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww== core-util-is@~1.0.0: version "1.0.3" @@ -3556,9 +3551,9 @@ dns-packet@^5.2.2: "@leichtgewicht/ip-codec" "^2.0.1" docusaurus-plugin-sass@^0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.4.tgz#a9e95b08a35df977b7a782329db7483917c8e617" - integrity sha512-r9bLXW6X2z64bzQUQZB1SxmNlGvSO9swTFALgiMjr/1O4FRDti6BseU4Sw2mlZkYvVQTq8cJMJIP6w7z/5We8Q== + version "0.2.5" + resolved "https://registry.yarnpkg.com/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.5.tgz#6bfb8a227ac6265be685dcbc24ba1989e27b8005" + integrity sha512-Z+D0fLFUKcFpM+bqSUmqKIU+vO+YF1xoEQh5hoFreg2eMf722+siwXDD+sqtwU8E4MvVpuvsQfaHwODNlxJAEg== dependencies: sass-loader "^10.1.1" @@ -3659,10 +3654,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.431: - version "1.4.461" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.461.tgz#6b14af66042732bf883ab63a4d82cac8f35eb252" - integrity sha512-1JkvV2sgEGTDXjdsaQCeSwYYuhLRphRpc+g6EHTFELJXEiznLt3/0pZ9JuAOQ5p2rI3YxKTbivtvajirIfhrEQ== +electron-to-chromium@^1.4.477: + version "1.4.484" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.484.tgz#770358eba089471c5dae5719db3a5a4fbf02bfb2" + integrity sha512-nO3ZEomTK2PO/3TUXgEx0A97xZTpKVf4p427lABHuCpT1IQ2N+njVh29DkQkCk6Q4m2wjU+faK4xAcfFndwjvw== emoji-regex@^8.0.0: version "8.0.0" @@ -3884,9 +3879,9 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0" - integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA== + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -4588,9 +4583,9 @@ immer@^9.0.7: integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== immutable@^4.0.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.1.tgz#17988b356097ab0719e2f741d56f3ec6c317f9dc" - integrity sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A== + version "4.3.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.2.tgz#f89d910f8dfb6e15c03b2cae2faaf8c1f66455fe" + integrity sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA== import-fresh@^3.1.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" @@ -4874,18 +4869,18 @@ isobject@^3.0.1: integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== jackspeak@^2.0.3: - version "2.2.1" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.1.tgz#655e8cf025d872c9c03d3eb63e8f0c024fef16a6" - integrity sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw== + version "2.2.2" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.2.2.tgz#707c62733924b8dc2a0a629dc6248577788b5385" + integrity sha512-mgNtVv4vUuaKA97yxUHoA3+FkuhtxkjdXEWOyB/N76fjy0FjezEt34oy3epBtvCvS+7DyKwqCFWx/oJLV5+kCg== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: "@pkgjs/parseargs" "^0.11.0" -jest-util@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.1.tgz#c9e29a87a6edbf1e39e6dee2b4689b8a146679cb" - integrity sha512-NRFCcjc+/uO3ijUVyNOQJluf8PtGCe/W6cix36+M3cTFgiYqFOOW5MgN4JOOcvbUhcKTYVd1CvHz/LWi8d16Mg== +jest-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" + integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== dependencies: "@jest/types" "^29.6.1" "@types/node" "*" @@ -4904,12 +4899,12 @@ jest-worker@^27.4.5: supports-color "^8.0.0" jest-worker@^29.1.2: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.1.tgz#64b015f0e985ef3a8ad049b61fe92b3db74a5319" - integrity sha512-U+Wrbca7S8ZAxAe9L6nb6g8kPdia5hj32Puu5iOqBCMTMWFHXuK6dOV2IFrpedbTV8fjMFLdWNttQTBL6u2MRA== + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" + integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== dependencies: "@types/node" "*" - jest-util "^29.6.1" + jest-util "^29.6.2" merge-stream "^2.0.0" supports-color "^8.0.0" @@ -5399,7 +5394,7 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-releases@^2.0.12: +node-releases@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== @@ -6024,9 +6019,9 @@ postcss-zindex@^5.1.0: integrity sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A== postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.17, postcss@^8.4.21: - version "8.4.26" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.26.tgz#1bc62ab19f8e1e5463d98cf74af39702a00a9e94" - integrity sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw== + version "8.4.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057" + integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -6644,9 +6639,9 @@ sass-loader@^10.1.1: semver "^7.3.2" sass@^1.39.2: - version "1.63.6" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.63.6.tgz#481610e612902e0c31c46b46cf2dad66943283ea" - integrity sha512-MJuxGMHzaOW7ipp+1KdELtqKbfAWbH7OLIdoSMnVe3EXPMTmxTmlaZDCTsgIpPCs3w99lLo9/zDKkOrJuT5byw== + version "1.64.2" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.64.2.tgz#0d9805ad6acf31c59c3acc725fcfb91b7fcc6909" + integrity sha512-TnDlfc+CRnUAgLO9D8cQLFu/GIjJIzJCGkE7o4ekIGQOH7T3GetiRR/PsTWJUHhkzcSPrARkPI+gNWn5alCzDg== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -6877,9 +6872,9 @@ signal-exit@^3.0.2, signal-exit@^3.0.3: integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signal-exit@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" - integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== sirv@^1.0.7: version "1.0.19" @@ -7166,9 +7161,9 @@ terser-webpack-plugin@^5.3.3, terser-webpack-plugin@^5.3.7: terser "^5.16.8" terser@^5.10.0, terser@^5.16.8: - version "5.19.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.0.tgz#7b3137b01226bdd179978207b9c8148754a6da9c" - integrity sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q== + version "5.19.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e" + integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -7243,9 +7238,9 @@ trough@^1.0.0: integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" - integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== type-fest@^0.20.2: version "0.20.2" @@ -7656,9 +7651,9 @@ webpack-sources@^3.2.2, webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.73.0: - version "5.88.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.1.tgz#21eba01e81bd5edff1968aea726e2fbfd557d3f8" - integrity sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ== + version "5.88.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0"