├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── ci.yaml
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle.kts
├── buildSrc
├── build.gradle.kts
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── kotlin-conventions.gradle.kts
│ └── publish-conventions.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── kotlin-js-store
└── yarn.lock
├── kotlin-retry-result
├── build.gradle.kts
└── src
│ ├── commonMain
│ └── kotlin
│ │ └── com
│ │ └── github
│ │ └── michaelbull
│ │ └── retry
│ │ └── result
│ │ ├── Retry.kt
│ │ └── RunRetrying.kt
│ └── commonTest
│ └── kotlin
│ └── com
│ └── github
│ └── michaelbull
│ └── retry
│ └── result
│ └── RetryTest.kt
├── kotlin-retry
├── build.gradle.kts
└── src
│ ├── commonMain
│ └── kotlin
│ │ └── com
│ │ └── github
│ │ └── michaelbull
│ │ └── retry
│ │ ├── Math.kt
│ │ ├── Retry.kt
│ │ ├── RunRetrying.kt
│ │ ├── attempt
│ │ ├── Attempt.kt
│ │ └── FailedAttempt.kt
│ │ ├── instruction
│ │ ├── ContinueRetrying.kt
│ │ ├── RetryAfter.kt
│ │ ├── RetryInstruction.kt
│ │ └── StopRetrying.kt
│ │ └── policy
│ │ ├── Backoff.kt
│ │ ├── Delay.kt
│ │ ├── Predicate.kt
│ │ ├── RetryPolicy.kt
│ │ └── Stop.kt
│ ├── commonTest
│ └── kotlin
│ │ └── com
│ │ └── github
│ │ └── michaelbull
│ │ └── retry
│ │ ├── RetryTest.kt
│ │ └── policy
│ │ ├── BackoffTest.kt
│ │ ├── DelayTest.kt
│ │ ├── PredicateTest.kt
│ │ └── StopTest.kt
│ └── jvmTest
│ └── kotlin
│ └── com
│ └── github
│ └── michaelbull
│ └── retry
│ └── DispatcherTest.kt
└── settings.gradle.kts
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.yaml]
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.bat text eol=crlf
2 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | branches: [ "master" ]
6 | push:
7 | branches: [ "master" ]
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | build:
14 | name: Build on ${{ matrix.os }}
15 | runs-on: ${{ matrix.os }}
16 |
17 | strategy:
18 | matrix:
19 | include:
20 | - os: ubuntu-latest
21 | tasks: build
22 |
23 | - os: macos-latest
24 | tasks: >
25 | iosX64Test
26 | macosX64Test
27 | tvosX64Test
28 | watchosX64Test
29 |
30 | - os: windows-latest
31 | tasks: mingwX64Test
32 |
33 | steps:
34 | - name: Checkout Project
35 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
36 |
37 | - name: Validate Gradle Wrapper
38 | uses: gradle/actions/wrapper-validation@750cdda3edd6d51b7fdfc069d2e2818cf3c44f4c # v3.3.1
39 |
40 | - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
41 | with:
42 | path: |
43 | ~/.konan
44 | key: "${{ runner.os }}-${{ hashFiles('**/.lock') }}"
45 |
46 | - name: Setup JDK
47 | uses: actions/setup-java@9704b39bf258b59bc04b50fa2dd55e9ed76b47a8 # v4.1.0
48 | with:
49 | distribution: temurin
50 | java-version: 8
51 |
52 | - name: Setup Gradle
53 | uses: gradle/actions/setup-gradle@750cdda3edd6d51b7fdfc069d2e2818cf3c44f4c # v3.3.1
54 |
55 | - name: Build with Gradle Wrapper
56 | run: ./gradlew ${{ matrix.tasks }}
57 |
58 | publish:
59 | name: Publish on ${{ matrix.os }}
60 | runs-on: ${{ matrix.os }}
61 | if: github.ref == 'refs/heads/master' && github.repository == 'michaelbull/kotlin-retry'
62 | needs: build
63 |
64 | strategy:
65 | matrix:
66 | include:
67 | - os: ubuntu-latest
68 | tasks: >
69 | publishAndroidNativeArm32PublicationToMavenRepository
70 | publishAndroidNativeArm64PublicationToMavenRepository
71 | publishAndroidNativeX64PublicationToMavenRepository
72 | publishAndroidNativeX86PublicationToMavenRepository
73 | publishJsPublicationToMavenRepository
74 | publishJvmPublicationToMavenRepository
75 | publishKotlinMultiplatformPublicationToMavenRepository
76 | publishLinuxArm64PublicationToMavenRepository
77 | publishLinuxX64PublicationToMavenRepository
78 | publishWasmJsPublicationToMavenRepository
79 |
80 | - os: windows-latest
81 | tasks: publishMingwX64PublicationToMavenRepository
82 |
83 | - os: macos-latest
84 | tasks: >
85 | publishIosArm64PublicationToMavenRepository
86 | publishIosSimulatorArm64PublicationToMavenRepository
87 | publishIosX64PublicationToMavenRepository
88 | publishMacosArm64PublicationToMavenRepository
89 | publishMacosX64PublicationToMavenRepository
90 | publishTvosArm64PublicationToMavenRepository
91 | publishTvosSimulatorArm64PublicationToMavenRepository
92 | publishTvosX64PublicationToMavenRepository
93 | publishWatchosArm32PublicationToMavenRepository
94 | publishWatchosArm64PublicationToMavenRepository
95 | publishWatchosDeviceArm64PublicationToMavenRepository
96 | publishWatchosSimulatorArm64PublicationToMavenRepository
97 | publishWatchosX64PublicationToMavenRepository
98 |
99 | steps:
100 | - name: Checkout Project
101 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
102 |
103 | - name: Validate Gradle Wrapper
104 | uses: gradle/actions/wrapper-validation@750cdda3edd6d51b7fdfc069d2e2818cf3c44f4c # v3.3.1
105 |
106 | - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1
107 | with:
108 | path: |
109 | ~/.konan
110 | key: "${{ runner.os }}-${{ hashFiles('**/.lock') }}"
111 |
112 | - name: Setup JDK
113 | uses: actions/setup-java@9704b39bf258b59bc04b50fa2dd55e9ed76b47a8 # v4.1.0
114 | with:
115 | distribution: temurin
116 | java-version: 8
117 |
118 | - name: Setup Gradle
119 | uses: gradle/actions/setup-gradle@750cdda3edd6d51b7fdfc069d2e2818cf3c44f4c # v3.3.1
120 |
121 | - name: Publish with Gradle Wrapper
122 | run: ./gradlew ${{ matrix.tasks }}
123 | env:
124 | ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.OSSRH_USERNAME }}
125 | ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.OSSRH_PASSWORD }}
126 | ORG_GRADLE_PROJECT_signingKeyId: ${{ secrets.SIGNING_KEY_ID }}
127 | ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
128 | ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
129 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Hidden files
2 | .*
3 |
4 | # Temporary files
5 | *~
6 |
7 | # Git
8 | !.git*
9 |
10 | # GitHub
11 | !/.github
12 |
13 | # EditorConfig
14 | !.editorconfig
15 |
16 | # IntelliJ Idea
17 | out/
18 | *.iml
19 | *.ipr
20 | *.iws
21 |
22 | # Gradle
23 | build/
24 | local.properties
25 |
26 | # JVM error logs
27 | hs_err_pid*.log
28 | replay_pid*.log
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019-2024 Michael Bull (https://www.michael-bull.com)
2 |
3 | Permission to use, copy, modify, and/or distribute this software for any
4 | purpose with or without fee is hereby granted, provided that the above
5 | copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kotlin-retry
2 |
3 | [](https://search.maven.org/search?q=g:com.michael-bull.kotlin-retry)
4 | [](https://github.com/michaelbull/kotlin-retry/actions/workflows/ci.yaml)
5 | [](https://github.com/michaelbull/kotlin-retry/blob/master/LICENSE)
6 |
7 | ![badge][badge-android]
8 | ![badge][badge-jvm]
9 | ![badge][badge-js]
10 | ![badge][badge-nodejs]
11 | ![badge][badge-linux]
12 | ![badge][badge-windows]
13 | ![badge][badge-wasm]
14 | ![badge][badge-ios]
15 | ![badge][badge-mac]
16 | ![badge][badge-tvos]
17 | ![badge][badge-watchos]
18 | ![badge][badge-js-ir]
19 | ![badge][badge-android-native]
20 | ![badge][badge-apple-silicon]
21 |
22 | A multiplatform higher-order function for retrying operations that may fail.
23 |
24 | ```kotlin
25 | val everySecondTenTimes = constantDelay(delayMillis = 1000L) + stopAtAttempts(10)
26 |
27 | retry(everySecondTenTimes) {
28 | /* your code */
29 | }
30 | ```
31 |
32 | ## Installation
33 |
34 | ```groovy
35 | repositories {
36 | mavenCentral()
37 | }
38 |
39 | dependencies {
40 | implementation("com.michael-bull.kotlin-retry:kotlin-retry:2.0.1")
41 | }
42 | ```
43 |
44 | ## Introduction
45 |
46 | IO operations often experience temporary failures that warrant re-execution,
47 | e.g. a database transaction that may fail due to a deadlock.[1][innodb-deadlocks][2][postgres-deadlocks]
48 |
49 | > _“even if your application logic is correct, you must still handle the case
50 | > where a transaction must be retried”_
51 | >
52 | > — _[Deadlocks in InnoDB][innodb-deadlocks]_
53 |
54 | The [`retry`][retry] function simplifies this process by wrapping the
55 | application logic and applying a specified [`RetryPolicy`][retry-policy].
56 |
57 | In the example below, either of the calls to `customers.nameFromId` may fail,
58 | abandoning the remaining logic within the `printExchangeBetween` function. As
59 | such, we may want to retry this operation until 5 invocations in total have been
60 | executed:
61 |
62 | ```kotlin
63 | import com.github.michaelbull.retry.policy.stopAtAttempts
64 | import com.github.michaelbull.retry.retry
65 | import kotlinx.coroutines.runBlocking
66 |
67 | suspend fun printExchangeBetween(a: Long, b: Long) {
68 | val customer1 = customers.nameFromId(a)
69 | val customer2 = customers.nameFromId(b)
70 | println("$customer1 exchanged with $customer2")
71 | }
72 |
73 | val fiveTimes = stopAtAttempts(5)
74 |
75 | fun main() = runBlocking {
76 | retry(fiveTimes) {
77 | printExchangeBetween(1L, 2L)
78 | }
79 | }
80 | ```
81 |
82 | We can also provide a [`RetryPolicy`][retry-policy] that only retries failures
83 | of a specific type. The example below will retry the operation only if the
84 | reason for failure was a `SQLDataException`, pausing for 20 milliseconds before
85 | retrying and stopping after 5 total invocations.
86 |
87 | ```kotlin
88 | import com.github.michaelbull.retry.ContinueRetrying
89 | import com.github.michaelbull.retry.StopRetrying
90 | import com.github.michaelbull.retry.policy.RetryPolicy
91 | import com.github.michaelbull.retry.policy.constantDelay
92 | import com.github.michaelbull.retry.policy.continueIf
93 | import com.github.michaelbull.retry.policy.plus
94 | import com.github.michaelbull.retry.policy.stopAtAttempts
95 | import com.github.michaelbull.retry.retry
96 | import kotlinx.coroutines.runBlocking
97 | import java.sql.SQLDataException
98 |
99 | suspend fun printExchangeBetween(a: Long, b: Long) {
100 | val customer1 = customers.nameFromId(a)
101 | val customer2 = customers.nameFromId(b)
102 | println("$customer1 exchanged with $customer2")
103 | }
104 |
105 | val continueOnTimeout = continueIf { (failure) ->
106 | failure is SQLDataException
107 | }
108 |
109 | val timeoutsEverySecondFiveTimes = continueOnTimeout + constantDelay(1000) + stopAtAttempts(5)
110 |
111 | fun main() = runBlocking {
112 | retry(timeoutsEverySecondFiveTimes) {
113 | printExchangeBetween(1L, 2L)
114 | }
115 | }
116 | ```
117 |
118 | ## Integration with [kotlin-result][kotlin-result]
119 |
120 | If the code you wish to try returns a `Result` instead of throwing an
121 | `Exception`, add the following dependency for access to a Result-based `retry`
122 | function that shares the same policy code:
123 |
124 | ```groovy
125 | repositories {
126 | mavenCentral()
127 | }
128 |
129 | dependencies {
130 | implementation("com.michael-bull.kotlin-retry:kotlin-retry-result:2.0.1")
131 | }
132 | ```
133 |
134 | Usage:
135 |
136 | ```kotlin
137 |
138 | import com.github.michaelbull.result.Result
139 | import com.github.michaelbull.retry.policy.constantDelay
140 | import com.github.michaelbull.retry.result.retry
141 |
142 | fun somethingThatCanFail(): Result = TODO()
143 |
144 | val everyTwoSeconds = constantDelay(2000)
145 |
146 | fun main() = runBlocking {
147 | val result: Result = retry(everyTwoSeconds) {
148 | somethingThatCanFail()
149 | }
150 | }
151 | ```
152 |
153 | ## Backoff
154 |
155 | The examples above retry executions immediately after they fail, however we may
156 | wish to spread out retries with an ever-increasing delay. This is known as a
157 | "backoff" and comes in many forms. This library includes all the forms of
158 | backoff strategy detailed the article by Marc Brooker on the AWS Architecture
159 | Blog entitled ["Exponential Backoff And Jitter"][aws-backoff].
160 |
161 | #### Binary Exponential
162 |
163 | > _“exponential backoff means that clients multiply their backoff by a constant
164 | > after each attempt, up to some maximum value”_
165 | >
166 | > ```
167 | > sleep = min(cap, base * 2 ** attempt)
168 | > ```
169 |
170 | ```kotlin
171 | retry(binaryExponentialBackoff(min = 10L, max = 5000L)) {
172 | /* code */
173 | }
174 | ```
175 |
176 | #### Full Jitter
177 |
178 | > _“trying to improve the performance of a system by adding randomness ... we
179 | > want to spread out the spikes to an approximately constant rate”_
180 | >
181 | > ```
182 | > sleep = random_between(0, min(cap, base * 2 ** attempt))
183 | > ```
184 |
185 | ```kotlin
186 | retry(fullJitterBackoff(min = 10L, max = 5000L)) {
187 | /* code */
188 | }
189 | ```
190 |
191 | #### Equal Jitter
192 |
193 | > _“Equal Jitter, where we always keep some of the backoff and jitter by a
194 | > smaller amount”_
195 | >
196 | > ```
197 | > temp = min(cap, base * 2 ** attempt)
198 | > sleep = temp / 2 + random_between(0, temp / 2)
199 | > ```
200 |
201 | ```kotlin
202 | retry(equalJitterBackoff(min = 10L, max = 5000L)) {
203 | /* code */
204 | }
205 | ```
206 |
207 | #### Decorrelated Jitter
208 |
209 | > _“Decorrelated Jitter, which is similar to “Full Jitter”, but we also
210 | > increase the maximum jitter based on the last random value”_
211 | >
212 | > ```
213 | > sleep = min(cap, random_between(base, sleep * 3))
214 | > ```
215 |
216 | ```kotlin
217 | retry(decorrelatedJitterBackoff(min = 10L, max = 5000L)) {
218 | /* code */
219 | }
220 | ```
221 |
222 | ## Inspiration
223 |
224 | - [Control.Retry](http://hackage.haskell.org/package/retry-0.8.0.1/docs/Control-Retry.html)
225 | - [tokio_retry](https://docs.rs/tokio-retry/0.2.0/tokio_retry/)
226 |
227 | ## Contributing
228 |
229 | Bug reports and pull requests are welcome on [GitHub][github].
230 |
231 | ## License
232 |
233 | This project is available under the terms of the ISC license. See the
234 | [`LICENSE`](LICENSE) file for the copyright information and licensing terms.
235 |
236 | [github]: https://github.com/michaelbull/kotlin-retry
237 | [retry]: https://github.com/michaelbull/kotlin-retry/blob/master/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/Retry.kt
238 | [innodb-deadlocks]: https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlocks.html
239 | [postgres-deadlocks]: https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-DEADLOCKS
240 | [retry-policy]: https://github.com/michaelbull/kotlin-retry/blob/master/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/policy/RetryPolicy.kt
241 | [aws-backoff]: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
242 | [haskell-retry]: http://hackage.haskell.org/package/retry-0.8.0.1/docs/Control-Retry.html
243 | [kotlin-result]: https://github.com/michaelbull/kotlin-result
244 |
245 | [badge-android]: http://img.shields.io/badge/-android-6EDB8D.svg?style=flat
246 | [badge-android-native]: http://img.shields.io/badge/support-[AndroidNative]-6EDB8D.svg?style=flat
247 | [badge-jvm]: http://img.shields.io/badge/-jvm-DB413D.svg?style=flat
248 | [badge-js]: http://img.shields.io/badge/-js-F8DB5D.svg?style=flat
249 | [badge-js-ir]: https://img.shields.io/badge/support-[IR]-AAC4E0.svg?style=flat
250 | [badge-nodejs]: https://img.shields.io/badge/-nodejs-68a063.svg?style=flat
251 | [badge-linux]: http://img.shields.io/badge/-linux-2D3F6C.svg?style=flat
252 | [badge-windows]: http://img.shields.io/badge/-windows-4D76CD.svg?style=flat
253 | [badge-wasm]: https://img.shields.io/badge/-wasm-624FE8.svg?style=flat
254 | [badge-apple-silicon]: http://img.shields.io/badge/support-[AppleSilicon]-43BBFF.svg?style=flat
255 | [badge-ios]: http://img.shields.io/badge/-ios-CDCDCD.svg?style=flat
256 | [badge-mac]: http://img.shields.io/badge/-macos-111111.svg?style=flat
257 | [badge-watchos]: http://img.shields.io/badge/-watchos-C0C0C0.svg?style=flat
258 | [badge-tvos]: http://img.shields.io/badge/-tvos-808080.svg?style=flat
259 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
2 | import com.github.benmanes.gradle.versions.updates.gradle.GradleReleaseChannel
3 |
4 | plugins {
5 | alias(libs.plugins.versions)
6 | }
7 |
8 | tasks.withType {
9 | gradleReleaseChannel = GradleReleaseChannel.CURRENT.id
10 |
11 | rejectVersionIf {
12 | listOf("alpha", "beta", "rc", "cr", "m", "eap", "pr", "dev").any {
13 | candidate.version.contains(it, ignoreCase = true)
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | dependencies {
6 | implementation(libs.kotlin.gradle.plugin)
7 | }
8 |
--------------------------------------------------------------------------------
/buildSrc/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | mavenCentral()
4 | gradlePluginPortal()
5 | }
6 | }
7 |
8 | dependencyResolutionManagement {
9 | repositories {
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 |
14 | versionCatalogs {
15 | create("libs") {
16 | from(files("../gradle/libs.versions.toml"))
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/kotlin-conventions.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
2 | import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
3 | import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
4 |
5 | plugins {
6 | kotlin("multiplatform")
7 | }
8 |
9 | kotlin {
10 | explicitApi()
11 |
12 | jvmToolchain(8)
13 |
14 | jvm()
15 |
16 | js(IR) {
17 | browser()
18 | nodejs()
19 | }
20 |
21 | @OptIn(ExperimentalWasmDsl::class)
22 | wasmJs {
23 | binaries.executable()
24 | nodejs()
25 | }
26 |
27 | /* https://kotlinlang.org/docs/native-target-support.html#tier-1 */
28 |
29 | macosX64()
30 | macosArm64()
31 | iosSimulatorArm64()
32 | iosX64()
33 |
34 | /* https://kotlinlang.org/docs/native-target-support.html#tier-2 */
35 |
36 | linuxX64()
37 | linuxArm64()
38 |
39 | watchosSimulatorArm64()
40 | watchosX64()
41 | watchosArm32()
42 | watchosArm64()
43 |
44 | tvosSimulatorArm64()
45 | tvosX64()
46 | tvosArm64()
47 |
48 | iosArm64()
49 |
50 | /* https://kotlinlang.org/docs/native-target-support.html#tier-3 */
51 |
52 | androidNativeArm32()
53 | androidNativeArm64()
54 | androidNativeX86()
55 | androidNativeX64()
56 |
57 | mingwX64()
58 |
59 | watchosDeviceArm64()
60 |
61 | sourceSets {
62 | all {
63 | languageSettings.apply {
64 | optIn("kotlin.contracts.ExperimentalContracts")
65 | }
66 | }
67 |
68 | commonTest {
69 | dependencies {
70 | implementation(kotlin("test"))
71 | }
72 | }
73 |
74 | jvmTest {
75 | dependencies {
76 | implementation(kotlin("test-junit"))
77 | }
78 | }
79 |
80 | jsTest {
81 | dependencies {
82 | implementation(kotlin("test-js"))
83 | }
84 | }
85 | }
86 | }
87 |
88 | tasks.withType {
89 | from(rootDir.resolve("LICENSE")) {
90 | into("META-INF")
91 | }
92 | }
93 |
94 | /* https://youtrack.jetbrains.com/issue/KT-63014/Running-tests-with-wasmJs-in-1.9.20-requires-Chrome-Canary#focus=Comments-27-8321383.0-0 */
95 | rootProject.the().apply {
96 | nodeVersion = "21.0.0-v8-canary202309143a48826a08"
97 | nodeDownloadBaseUrl = "https://nodejs.org/download/v8-canary"
98 | }
99 |
100 | rootProject.tasks.withType {
101 | args.add("--ignore-engines")
102 | }
103 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/publish-conventions.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `maven-publish`
3 | signing
4 | }
5 |
6 | publishing {
7 | repositories {
8 | maven {
9 | if (project.version.toString().endsWith("SNAPSHOT")) {
10 | setUrl("https://oss.sonatype.org/content/repositories/snapshots")
11 | } else {
12 | setUrl("https://oss.sonatype.org/service/local/staging/deploy/maven2")
13 | }
14 |
15 | credentials {
16 | val ossrhUsername: String? by project
17 | val ossrhPassword: String? by project
18 |
19 | username = ossrhUsername
20 | password = ossrhPassword
21 | }
22 | }
23 | }
24 |
25 | publications.withType {
26 | val targetName = this@withType.name
27 |
28 | artifact(tasks.register("${targetName}JavadocJar", Jar::class) {
29 | group = LifecycleBasePlugin.BUILD_GROUP
30 | description = "Assembles a jar archive containing the Javadoc API documentation of target '$targetName'."
31 | archiveClassifier.set("javadoc")
32 | archiveAppendix.set(targetName)
33 | })
34 |
35 | pom {
36 | name.set(project.name)
37 | description.set(project.description)
38 | url.set("https://github.com/michaelbull/kotlin-retry")
39 | inceptionYear.set("2019")
40 |
41 | licenses {
42 | license {
43 | name.set("ISC License")
44 | url.set("https://opensource.org/licenses/isc-license.txt")
45 | }
46 | }
47 |
48 | developers {
49 | developer {
50 | name.set("Michael Bull")
51 | url.set("https://www.michael-bull.com")
52 | }
53 | }
54 |
55 | contributors {
56 | contributor {
57 | name.set("Nicolas Dermine")
58 | url.set("https://github.com/nicoder")
59 | }
60 |
61 | contributor {
62 | name.set("Thorsten Hake")
63 | url.set("http://www.thorsten-hake.com/")
64 | }
65 |
66 | contributor {
67 | name.set("gnefedev")
68 | url.set("https://github.com/gnefedev")
69 | }
70 |
71 | contributor {
72 | name.set("cherrydev")
73 | url.set("https://github.com/cherrydev")
74 | }
75 |
76 | contributor {
77 | name.set("Joose Fjällström")
78 | url.set("https://github.com/jfjallstrom")
79 | }
80 | }
81 |
82 | scm {
83 | connection.set("scm:git:https://github.com/michaelbull/kotlin-retry")
84 | developerConnection.set("scm:git:git@github.com:michaelbull/kotlin-retry.git")
85 | url.set("https://github.com/michaelbull/kotlin-retry")
86 | }
87 |
88 | issueManagement {
89 | system.set("GitHub Issues")
90 | url.set("https://github.com/michaelbull/kotlin-retry/issues")
91 | }
92 |
93 | ciManagement {
94 | system.set("GitHub Actions")
95 | url.set("https://github.com/michaelbull/kotlin-retry/actions")
96 | }
97 | }
98 | }
99 | }
100 |
101 | signing {
102 | val signingKeyId: String? by project // must be the last 8 digits of the key
103 | val signingKey: String? by project
104 | val signingPassword: String? by project
105 |
106 | useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
107 | sign(publishing.publications)
108 | }
109 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | group=com.michael-bull.kotlin-retry
2 | version=2.0.2-SNAPSHOT
3 | description=A multiplatform higher-order function for retrying operations that may fail.
4 |
5 | kotlin.code.style=official
6 | kotlin.native.ignoreDisabledTargets=true
7 | kotlin.mpp.stability.nowarn=true
8 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | kotlin = "1.9.22"
3 | kotlin-coroutines = "1.8.0"
4 | kotlin-result = "2.0.0"
5 | mockk = "1.13.10"
6 | versions-plugin = "0.51.0"
7 |
8 | [libraries]
9 | kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
10 | kotlin-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
11 | kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlin-coroutines" }
12 | kotlin-result = { module = "com.michael-bull.kotlin-result:kotlin-result", version.ref = "kotlin-result" }
13 | mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
14 |
15 | [plugins]
16 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
17 | versions = { id = "com.github.ben-manes.versions", version.ref = "versions-plugin" }
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/michaelbull/kotlin-retry/7a0d2cb2ecdec96046d07de3132d5ab88973340e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | # This is normally unused
84 | # shellcheck disable=SC2034
85 | APP_BASE_NAME=${0##*/}
86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
88 |
89 | # Use the maximum available, or set MAX_FD != -1 to use that value.
90 | MAX_FD=maximum
91 |
92 | warn () {
93 | echo "$*"
94 | } >&2
95 |
96 | die () {
97 | echo
98 | echo "$*"
99 | echo
100 | exit 1
101 | } >&2
102 |
103 | # OS specific support (must be 'true' or 'false').
104 | cygwin=false
105 | msys=false
106 | darwin=false
107 | nonstop=false
108 | case "$( uname )" in #(
109 | CYGWIN* ) cygwin=true ;; #(
110 | Darwin* ) darwin=true ;; #(
111 | MSYS* | MINGW* ) msys=true ;; #(
112 | NONSTOP* ) nonstop=true ;;
113 | esac
114 |
115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
116 |
117 |
118 | # Determine the Java command to use to start the JVM.
119 | if [ -n "$JAVA_HOME" ] ; then
120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
121 | # IBM's JDK on AIX uses strange locations for the executables
122 | JAVACMD=$JAVA_HOME/jre/sh/java
123 | else
124 | JAVACMD=$JAVA_HOME/bin/java
125 | fi
126 | if [ ! -x "$JAVACMD" ] ; then
127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
128 |
129 | Please set the JAVA_HOME variable in your environment to match the
130 | location of your Java installation."
131 | fi
132 | else
133 | JAVACMD=java
134 | if ! command -v java >/dev/null 2>&1
135 | then
136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 | fi
142 |
143 | # Increase the maximum file descriptors if we can.
144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
145 | case $MAX_FD in #(
146 | max*)
147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
148 | # shellcheck disable=SC2039,SC3045
149 | MAX_FD=$( ulimit -H -n ) ||
150 | warn "Could not query maximum file descriptor limit"
151 | esac
152 | case $MAX_FD in #(
153 | '' | soft) :;; #(
154 | *)
155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
156 | # shellcheck disable=SC2039,SC3045
157 | ulimit -n "$MAX_FD" ||
158 | warn "Could not set maximum file descriptor limit to $MAX_FD"
159 | esac
160 | fi
161 |
162 | # Collect all arguments for the java command, stacking in reverse order:
163 | # * args from the command line
164 | # * the main class name
165 | # * -classpath
166 | # * -D...appname settings
167 | # * --module-path (only if needed)
168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
169 |
170 | # For Cygwin or MSYS, switch paths to Windows format before running java
171 | if "$cygwin" || "$msys" ; then
172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
174 |
175 | JAVACMD=$( cygpath --unix "$JAVACMD" )
176 |
177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
178 | for arg do
179 | if
180 | case $arg in #(
181 | -*) false ;; # don't mess with options #(
182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
183 | [ -e "$t" ] ;; #(
184 | *) false ;;
185 | esac
186 | then
187 | arg=$( cygpath --path --ignore --mixed "$arg" )
188 | fi
189 | # Roll the args list around exactly as many times as the number of
190 | # args, so each arg winds up back in the position where it started, but
191 | # possibly modified.
192 | #
193 | # NB: a `for` loop captures its iteration list before it begins, so
194 | # changing the positional parameters here affects neither the number of
195 | # iterations, nor the values presented in `arg`.
196 | shift # remove old arg
197 | set -- "$@" "$arg" # push replacement arg
198 | done
199 | fi
200 |
201 |
202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
204 |
205 | # Collect all arguments for the java command:
206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
207 | # and any embedded shellness will be escaped.
208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
209 | # treated as '${Hostname}' itself on the command line.
210 |
211 | set -- \
212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
213 | -classpath "$CLASSPATH" \
214 | org.gradle.wrapper.GradleWrapperMain \
215 | "$@"
216 |
217 | # Stop when "xargs" is not available.
218 | if ! command -v xargs >/dev/null 2>&1
219 | then
220 | die "xargs is not available"
221 | fi
222 |
223 | # Use "xargs" to parse quoted args.
224 | #
225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
226 | #
227 | # In Bash we could simply go:
228 | #
229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
230 | # set -- "${ARGS[@]}" "$@"
231 | #
232 | # but POSIX shell has neither arrays nor command substitution, so instead we
233 | # post-process each arg (as a line of input to sed) to backslash-escape any
234 | # character that might be a shell metacharacter, then use eval to reverse
235 | # that process (while maintaining the separation between arguments), and wrap
236 | # the whole thing up as a single "set" statement.
237 | #
238 | # This will of course break if any of these variables contains a newline or
239 | # an unmatched quote.
240 | #
241 |
242 | eval "set -- $(
243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
244 | xargs -n1 |
245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
246 | tr '\n' ' '
247 | )" '"$@"'
248 |
249 | exec "$JAVACMD" "$@"
250 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo. 1>&2
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
48 | echo. 1>&2
49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
50 | echo location of your Java installation. 1>&2
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo. 1>&2
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
62 | echo. 1>&2
63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
64 | echo location of your Java installation. 1>&2
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/kotlin-js-store/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@colors/colors@1.5.0":
6 | version "1.5.0"
7 | resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
8 | integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
9 |
10 | "@discoveryjs/json-ext@^0.5.0":
11 | version "0.5.7"
12 | resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
13 | integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
14 |
15 | "@jridgewell/gen-mapping@^0.3.0":
16 | version "0.3.5"
17 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
18 | integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
19 | dependencies:
20 | "@jridgewell/set-array" "^1.2.1"
21 | "@jridgewell/sourcemap-codec" "^1.4.10"
22 | "@jridgewell/trace-mapping" "^0.3.24"
23 |
24 | "@jridgewell/resolve-uri@^3.1.0":
25 | version "3.1.2"
26 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
27 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
28 |
29 | "@jridgewell/set-array@^1.2.1":
30 | version "1.2.1"
31 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
32 | integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
33 |
34 | "@jridgewell/source-map@^0.3.3":
35 | version "0.3.5"
36 | resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91"
37 | integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==
38 | dependencies:
39 | "@jridgewell/gen-mapping" "^0.3.0"
40 | "@jridgewell/trace-mapping" "^0.3.9"
41 |
42 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
43 | version "1.4.15"
44 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
45 | integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
46 |
47 | "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.9":
48 | version "0.3.25"
49 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
50 | integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
51 | dependencies:
52 | "@jridgewell/resolve-uri" "^3.1.0"
53 | "@jridgewell/sourcemap-codec" "^1.4.14"
54 |
55 | "@socket.io/component-emitter@~3.1.0":
56 | version "3.1.0"
57 | resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
58 | integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
59 |
60 | "@types/cookie@^0.4.1":
61 | version "0.4.1"
62 | resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
63 | integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
64 |
65 | "@types/cors@^2.8.12":
66 | version "2.8.17"
67 | resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b"
68 | integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==
69 | dependencies:
70 | "@types/node" "*"
71 |
72 | "@types/eslint-scope@^3.7.3":
73 | version "3.7.7"
74 | resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
75 | integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==
76 | dependencies:
77 | "@types/eslint" "*"
78 | "@types/estree" "*"
79 |
80 | "@types/eslint@*":
81 | version "8.56.5"
82 | resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.5.tgz#94b88cab77588fcecdd0771a6d576fa1c0af9d02"
83 | integrity sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==
84 | dependencies:
85 | "@types/estree" "*"
86 | "@types/json-schema" "*"
87 |
88 | "@types/estree@*", "@types/estree@^1.0.0":
89 | version "1.0.5"
90 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
91 | integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
92 |
93 | "@types/json-schema@*", "@types/json-schema@^7.0.8":
94 | version "7.0.15"
95 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
96 | integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
97 |
98 | "@types/node@*", "@types/node@>=10.0.0":
99 | version "20.11.24"
100 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.24.tgz#cc207511104694e84e9fb17f9a0c4c42d4517792"
101 | integrity sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==
102 | dependencies:
103 | undici-types "~5.26.4"
104 |
105 | "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
106 | version "1.11.6"
107 | resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
108 | integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==
109 | dependencies:
110 | "@webassemblyjs/helper-numbers" "1.11.6"
111 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
112 |
113 | "@webassemblyjs/floating-point-hex-parser@1.11.6":
114 | version "1.11.6"
115 | resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
116 | integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
117 |
118 | "@webassemblyjs/helper-api-error@1.11.6":
119 | version "1.11.6"
120 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
121 | integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
122 |
123 | "@webassemblyjs/helper-buffer@1.11.6":
124 | version "1.11.6"
125 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093"
126 | integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==
127 |
128 | "@webassemblyjs/helper-numbers@1.11.6":
129 | version "1.11.6"
130 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
131 | integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
132 | dependencies:
133 | "@webassemblyjs/floating-point-hex-parser" "1.11.6"
134 | "@webassemblyjs/helper-api-error" "1.11.6"
135 | "@xtuc/long" "4.2.2"
136 |
137 | "@webassemblyjs/helper-wasm-bytecode@1.11.6":
138 | version "1.11.6"
139 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
140 | integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
141 |
142 | "@webassemblyjs/helper-wasm-section@1.11.6":
143 | version "1.11.6"
144 | resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577"
145 | integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==
146 | dependencies:
147 | "@webassemblyjs/ast" "1.11.6"
148 | "@webassemblyjs/helper-buffer" "1.11.6"
149 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
150 | "@webassemblyjs/wasm-gen" "1.11.6"
151 |
152 | "@webassemblyjs/ieee754@1.11.6":
153 | version "1.11.6"
154 | resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
155 | integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
156 | dependencies:
157 | "@xtuc/ieee754" "^1.2.0"
158 |
159 | "@webassemblyjs/leb128@1.11.6":
160 | version "1.11.6"
161 | resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
162 | integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
163 | dependencies:
164 | "@xtuc/long" "4.2.2"
165 |
166 | "@webassemblyjs/utf8@1.11.6":
167 | version "1.11.6"
168 | resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
169 | integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
170 |
171 | "@webassemblyjs/wasm-edit@^1.11.5":
172 | version "1.11.6"
173 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab"
174 | integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==
175 | dependencies:
176 | "@webassemblyjs/ast" "1.11.6"
177 | "@webassemblyjs/helper-buffer" "1.11.6"
178 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
179 | "@webassemblyjs/helper-wasm-section" "1.11.6"
180 | "@webassemblyjs/wasm-gen" "1.11.6"
181 | "@webassemblyjs/wasm-opt" "1.11.6"
182 | "@webassemblyjs/wasm-parser" "1.11.6"
183 | "@webassemblyjs/wast-printer" "1.11.6"
184 |
185 | "@webassemblyjs/wasm-gen@1.11.6":
186 | version "1.11.6"
187 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268"
188 | integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==
189 | dependencies:
190 | "@webassemblyjs/ast" "1.11.6"
191 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
192 | "@webassemblyjs/ieee754" "1.11.6"
193 | "@webassemblyjs/leb128" "1.11.6"
194 | "@webassemblyjs/utf8" "1.11.6"
195 |
196 | "@webassemblyjs/wasm-opt@1.11.6":
197 | version "1.11.6"
198 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2"
199 | integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==
200 | dependencies:
201 | "@webassemblyjs/ast" "1.11.6"
202 | "@webassemblyjs/helper-buffer" "1.11.6"
203 | "@webassemblyjs/wasm-gen" "1.11.6"
204 | "@webassemblyjs/wasm-parser" "1.11.6"
205 |
206 | "@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5":
207 | version "1.11.6"
208 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1"
209 | integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==
210 | dependencies:
211 | "@webassemblyjs/ast" "1.11.6"
212 | "@webassemblyjs/helper-api-error" "1.11.6"
213 | "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
214 | "@webassemblyjs/ieee754" "1.11.6"
215 | "@webassemblyjs/leb128" "1.11.6"
216 | "@webassemblyjs/utf8" "1.11.6"
217 |
218 | "@webassemblyjs/wast-printer@1.11.6":
219 | version "1.11.6"
220 | resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20"
221 | integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==
222 | dependencies:
223 | "@webassemblyjs/ast" "1.11.6"
224 | "@xtuc/long" "4.2.2"
225 |
226 | "@webpack-cli/configtest@^2.1.0":
227 | version "2.1.1"
228 | resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646"
229 | integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==
230 |
231 | "@webpack-cli/info@^2.0.1":
232 | version "2.0.2"
233 | resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd"
234 | integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==
235 |
236 | "@webpack-cli/serve@^2.0.3":
237 | version "2.0.5"
238 | resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e"
239 | integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==
240 |
241 | "@xtuc/ieee754@^1.2.0":
242 | version "1.2.0"
243 | resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
244 | integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
245 |
246 | "@xtuc/long@4.2.2":
247 | version "4.2.2"
248 | resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
249 | integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
250 |
251 | abab@^2.0.6:
252 | version "2.0.6"
253 | resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
254 | integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
255 |
256 | accepts@~1.3.4:
257 | version "1.3.8"
258 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
259 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
260 | dependencies:
261 | mime-types "~2.1.34"
262 | negotiator "0.6.3"
263 |
264 | acorn-import-assertions@^1.7.6:
265 | version "1.9.0"
266 | resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac"
267 | integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==
268 |
269 | acorn@^8.7.1, acorn@^8.8.2:
270 | version "8.11.3"
271 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
272 | integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
273 |
274 | ajv-keywords@^3.5.2:
275 | version "3.5.2"
276 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
277 | integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
278 |
279 | ajv@^6.12.5:
280 | version "6.12.6"
281 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
282 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
283 | dependencies:
284 | fast-deep-equal "^3.1.1"
285 | fast-json-stable-stringify "^2.0.0"
286 | json-schema-traverse "^0.4.1"
287 | uri-js "^4.2.2"
288 |
289 | ansi-colors@4.1.1:
290 | version "4.1.1"
291 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
292 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
293 |
294 | ansi-regex@^5.0.1:
295 | version "5.0.1"
296 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
297 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
298 |
299 | ansi-styles@^4.0.0, ansi-styles@^4.1.0:
300 | version "4.3.0"
301 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
302 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
303 | dependencies:
304 | color-convert "^2.0.1"
305 |
306 | anymatch@~3.1.2:
307 | version "3.1.3"
308 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
309 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
310 | dependencies:
311 | normalize-path "^3.0.0"
312 | picomatch "^2.0.4"
313 |
314 | argparse@^2.0.1:
315 | version "2.0.1"
316 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
317 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
318 |
319 | balanced-match@^1.0.0:
320 | version "1.0.2"
321 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
322 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
323 |
324 | base64id@2.0.0, base64id@~2.0.0:
325 | version "2.0.0"
326 | resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
327 | integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
328 |
329 | binary-extensions@^2.0.0:
330 | version "2.2.0"
331 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
332 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
333 |
334 | body-parser@^1.19.0:
335 | version "1.20.2"
336 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
337 | integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
338 | dependencies:
339 | bytes "3.1.2"
340 | content-type "~1.0.5"
341 | debug "2.6.9"
342 | depd "2.0.0"
343 | destroy "1.2.0"
344 | http-errors "2.0.0"
345 | iconv-lite "0.4.24"
346 | on-finished "2.4.1"
347 | qs "6.11.0"
348 | raw-body "2.5.2"
349 | type-is "~1.6.18"
350 | unpipe "1.0.0"
351 |
352 | brace-expansion@^1.1.7:
353 | version "1.1.11"
354 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
355 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
356 | dependencies:
357 | balanced-match "^1.0.0"
358 | concat-map "0.0.1"
359 |
360 | brace-expansion@^2.0.1:
361 | version "2.0.1"
362 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
363 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
364 | dependencies:
365 | balanced-match "^1.0.0"
366 |
367 | braces@^3.0.2, braces@~3.0.2:
368 | version "3.0.2"
369 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
370 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
371 | dependencies:
372 | fill-range "^7.0.1"
373 |
374 | browser-stdout@1.3.1:
375 | version "1.3.1"
376 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
377 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
378 |
379 | browserslist@^4.14.5:
380 | version "4.23.0"
381 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab"
382 | integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==
383 | dependencies:
384 | caniuse-lite "^1.0.30001587"
385 | electron-to-chromium "^1.4.668"
386 | node-releases "^2.0.14"
387 | update-browserslist-db "^1.0.13"
388 |
389 | buffer-from@^1.0.0:
390 | version "1.1.2"
391 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
392 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
393 |
394 | bytes@3.1.2:
395 | version "3.1.2"
396 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
397 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
398 |
399 | call-bind@^1.0.7:
400 | version "1.0.7"
401 | resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
402 | integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
403 | dependencies:
404 | es-define-property "^1.0.0"
405 | es-errors "^1.3.0"
406 | function-bind "^1.1.2"
407 | get-intrinsic "^1.2.4"
408 | set-function-length "^1.2.1"
409 |
410 | camelcase@^6.0.0:
411 | version "6.3.0"
412 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
413 | integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
414 |
415 | caniuse-lite@^1.0.30001587:
416 | version "1.0.30001593"
417 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001593.tgz#7cda1d9e5b0cad6ebab4133b1f239d4ea44fe659"
418 | integrity sha512-UWM1zlo3cZfkpBysd7AS+z+v007q9G1+fLTUU42rQnY6t2axoogPW/xol6T7juU5EUoOhML4WgBIdG+9yYqAjQ==
419 |
420 | chalk@^4.1.0:
421 | version "4.1.2"
422 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
423 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
424 | dependencies:
425 | ansi-styles "^4.1.0"
426 | supports-color "^7.1.0"
427 |
428 | chokidar@3.5.3:
429 | version "3.5.3"
430 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
431 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
432 | dependencies:
433 | anymatch "~3.1.2"
434 | braces "~3.0.2"
435 | glob-parent "~5.1.2"
436 | is-binary-path "~2.1.0"
437 | is-glob "~4.0.1"
438 | normalize-path "~3.0.0"
439 | readdirp "~3.6.0"
440 | optionalDependencies:
441 | fsevents "~2.3.2"
442 |
443 | chokidar@^3.5.1:
444 | version "3.6.0"
445 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
446 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
447 | dependencies:
448 | anymatch "~3.1.2"
449 | braces "~3.0.2"
450 | glob-parent "~5.1.2"
451 | is-binary-path "~2.1.0"
452 | is-glob "~4.0.1"
453 | normalize-path "~3.0.0"
454 | readdirp "~3.6.0"
455 | optionalDependencies:
456 | fsevents "~2.3.2"
457 |
458 | chrome-trace-event@^1.0.2:
459 | version "1.0.3"
460 | resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
461 | integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
462 |
463 | cliui@^7.0.2:
464 | version "7.0.4"
465 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
466 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
467 | dependencies:
468 | string-width "^4.2.0"
469 | strip-ansi "^6.0.0"
470 | wrap-ansi "^7.0.0"
471 |
472 | clone-deep@^4.0.1:
473 | version "4.0.1"
474 | resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
475 | integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
476 | dependencies:
477 | is-plain-object "^2.0.4"
478 | kind-of "^6.0.2"
479 | shallow-clone "^3.0.0"
480 |
481 | color-convert@^2.0.1:
482 | version "2.0.1"
483 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
484 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
485 | dependencies:
486 | color-name "~1.1.4"
487 |
488 | color-name@~1.1.4:
489 | version "1.1.4"
490 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
491 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
492 |
493 | colorette@^2.0.14:
494 | version "2.0.20"
495 | resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
496 | integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
497 |
498 | commander@^10.0.1:
499 | version "10.0.1"
500 | resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
501 | integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
502 |
503 | commander@^2.20.0:
504 | version "2.20.3"
505 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
506 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
507 |
508 | concat-map@0.0.1:
509 | version "0.0.1"
510 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
511 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
512 |
513 | connect@^3.7.0:
514 | version "3.7.0"
515 | resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8"
516 | integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==
517 | dependencies:
518 | debug "2.6.9"
519 | finalhandler "1.1.2"
520 | parseurl "~1.3.3"
521 | utils-merge "1.0.1"
522 |
523 | content-type@~1.0.5:
524 | version "1.0.5"
525 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
526 | integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
527 |
528 | cookie@~0.4.1:
529 | version "0.4.2"
530 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
531 | integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
532 |
533 | cors@~2.8.5:
534 | version "2.8.5"
535 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
536 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
537 | dependencies:
538 | object-assign "^4"
539 | vary "^1"
540 |
541 | cross-spawn@^7.0.3:
542 | version "7.0.3"
543 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
544 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
545 | dependencies:
546 | path-key "^3.1.0"
547 | shebang-command "^2.0.0"
548 | which "^2.0.1"
549 |
550 | custom-event@~1.0.0:
551 | version "1.0.1"
552 | resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
553 | integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==
554 |
555 | date-format@^4.0.14:
556 | version "4.0.14"
557 | resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400"
558 | integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==
559 |
560 | debug@2.6.9:
561 | version "2.6.9"
562 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
563 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
564 | dependencies:
565 | ms "2.0.0"
566 |
567 | debug@4.3.4, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4:
568 | version "4.3.4"
569 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
570 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
571 | dependencies:
572 | ms "2.1.2"
573 |
574 | decamelize@^4.0.0:
575 | version "4.0.0"
576 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
577 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
578 |
579 | define-data-property@^1.1.2:
580 | version "1.1.4"
581 | resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
582 | integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
583 | dependencies:
584 | es-define-property "^1.0.0"
585 | es-errors "^1.3.0"
586 | gopd "^1.0.1"
587 |
588 | depd@2.0.0:
589 | version "2.0.0"
590 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
591 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
592 |
593 | destroy@1.2.0:
594 | version "1.2.0"
595 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
596 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
597 |
598 | di@^0.0.1:
599 | version "0.0.1"
600 | resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
601 | integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==
602 |
603 | diff@5.0.0:
604 | version "5.0.0"
605 | resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
606 | integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
607 |
608 | dom-serialize@^2.2.1:
609 | version "2.2.1"
610 | resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b"
611 | integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==
612 | dependencies:
613 | custom-event "~1.0.0"
614 | ent "~2.2.0"
615 | extend "^3.0.0"
616 | void-elements "^2.0.0"
617 |
618 | ee-first@1.1.1:
619 | version "1.1.1"
620 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
621 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
622 |
623 | electron-to-chromium@^1.4.668:
624 | version "1.4.690"
625 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.690.tgz#dd5145d45c49c08a9a6f7454127e660bdf9a3fa7"
626 | integrity sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA==
627 |
628 | emoji-regex@^8.0.0:
629 | version "8.0.0"
630 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
631 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
632 |
633 | encodeurl@~1.0.2:
634 | version "1.0.2"
635 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
636 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
637 |
638 | engine.io-parser@~5.2.1:
639 | version "5.2.2"
640 | resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.2.tgz#37b48e2d23116919a3453738c5720455e64e1c49"
641 | integrity sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==
642 |
643 | engine.io@~6.5.2:
644 | version "6.5.4"
645 | resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.5.4.tgz#6822debf324e781add2254e912f8568508850cdc"
646 | integrity sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==
647 | dependencies:
648 | "@types/cookie" "^0.4.1"
649 | "@types/cors" "^2.8.12"
650 | "@types/node" ">=10.0.0"
651 | accepts "~1.3.4"
652 | base64id "2.0.0"
653 | cookie "~0.4.1"
654 | cors "~2.8.5"
655 | debug "~4.3.1"
656 | engine.io-parser "~5.2.1"
657 | ws "~8.11.0"
658 |
659 | enhanced-resolve@^5.13.0:
660 | version "5.15.1"
661 | resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz#384391e025f099e67b4b00bfd7f0906a408214e1"
662 | integrity sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==
663 | dependencies:
664 | graceful-fs "^4.2.4"
665 | tapable "^2.2.0"
666 |
667 | ent@~2.2.0:
668 | version "2.2.0"
669 | resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
670 | integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==
671 |
672 | envinfo@^7.7.3:
673 | version "7.11.1"
674 | resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.11.1.tgz#2ffef77591057081b0129a8fd8cf6118da1b94e1"
675 | integrity sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==
676 |
677 | es-define-property@^1.0.0:
678 | version "1.0.0"
679 | resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
680 | integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
681 | dependencies:
682 | get-intrinsic "^1.2.4"
683 |
684 | es-errors@^1.3.0:
685 | version "1.3.0"
686 | resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
687 | integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
688 |
689 | es-module-lexer@^1.2.1:
690 | version "1.4.1"
691 | resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
692 | integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==
693 |
694 | escalade@^3.1.1:
695 | version "3.1.2"
696 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
697 | integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
698 |
699 | escape-html@~1.0.3:
700 | version "1.0.3"
701 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
702 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
703 |
704 | escape-string-regexp@4.0.0:
705 | version "4.0.0"
706 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
707 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
708 |
709 | eslint-scope@5.1.1:
710 | version "5.1.1"
711 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
712 | integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
713 | dependencies:
714 | esrecurse "^4.3.0"
715 | estraverse "^4.1.1"
716 |
717 | esrecurse@^4.3.0:
718 | version "4.3.0"
719 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
720 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
721 | dependencies:
722 | estraverse "^5.2.0"
723 |
724 | estraverse@^4.1.1:
725 | version "4.3.0"
726 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
727 | integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
728 |
729 | estraverse@^5.2.0:
730 | version "5.3.0"
731 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
732 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
733 |
734 | eventemitter3@^4.0.0:
735 | version "4.0.7"
736 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
737 | integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
738 |
739 | events@^3.2.0:
740 | version "3.3.0"
741 | resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
742 | integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
743 |
744 | extend@^3.0.0:
745 | version "3.0.2"
746 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
747 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
748 |
749 | fast-deep-equal@^3.1.1:
750 | version "3.1.3"
751 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
752 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
753 |
754 | fast-json-stable-stringify@^2.0.0:
755 | version "2.1.0"
756 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
757 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
758 |
759 | fastest-levenshtein@^1.0.12:
760 | version "1.0.16"
761 | resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
762 | integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
763 |
764 | fill-range@^7.0.1:
765 | version "7.0.1"
766 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
767 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
768 | dependencies:
769 | to-regex-range "^5.0.1"
770 |
771 | finalhandler@1.1.2:
772 | version "1.1.2"
773 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
774 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
775 | dependencies:
776 | debug "2.6.9"
777 | encodeurl "~1.0.2"
778 | escape-html "~1.0.3"
779 | on-finished "~2.3.0"
780 | parseurl "~1.3.3"
781 | statuses "~1.5.0"
782 | unpipe "~1.0.0"
783 |
784 | find-up@5.0.0:
785 | version "5.0.0"
786 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
787 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
788 | dependencies:
789 | locate-path "^6.0.0"
790 | path-exists "^4.0.0"
791 |
792 | find-up@^4.0.0:
793 | version "4.1.0"
794 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
795 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
796 | dependencies:
797 | locate-path "^5.0.0"
798 | path-exists "^4.0.0"
799 |
800 | flat@^5.0.2:
801 | version "5.0.2"
802 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
803 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
804 |
805 | flatted@^3.2.7:
806 | version "3.3.1"
807 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
808 | integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
809 |
810 | follow-redirects@^1.0.0:
811 | version "1.15.5"
812 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
813 | integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
814 |
815 | format-util@^1.0.5:
816 | version "1.0.5"
817 | resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271"
818 | integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==
819 |
820 | fs-extra@^8.1.0:
821 | version "8.1.0"
822 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
823 | integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
824 | dependencies:
825 | graceful-fs "^4.2.0"
826 | jsonfile "^4.0.0"
827 | universalify "^0.1.0"
828 |
829 | fs.realpath@^1.0.0:
830 | version "1.0.0"
831 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
832 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
833 |
834 | fsevents@~2.3.2:
835 | version "2.3.3"
836 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
837 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
838 |
839 | function-bind@^1.1.2:
840 | version "1.1.2"
841 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
842 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
843 |
844 | get-caller-file@^2.0.5:
845 | version "2.0.5"
846 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
847 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
848 |
849 | get-intrinsic@^1.1.3, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
850 | version "1.2.4"
851 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
852 | integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
853 | dependencies:
854 | es-errors "^1.3.0"
855 | function-bind "^1.1.2"
856 | has-proto "^1.0.1"
857 | has-symbols "^1.0.3"
858 | hasown "^2.0.0"
859 |
860 | glob-parent@~5.1.2:
861 | version "5.1.2"
862 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
863 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
864 | dependencies:
865 | is-glob "^4.0.1"
866 |
867 | glob-to-regexp@^0.4.1:
868 | version "0.4.1"
869 | resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
870 | integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
871 |
872 | glob@7.2.0:
873 | version "7.2.0"
874 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
875 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
876 | dependencies:
877 | fs.realpath "^1.0.0"
878 | inflight "^1.0.4"
879 | inherits "2"
880 | minimatch "^3.0.4"
881 | once "^1.3.0"
882 | path-is-absolute "^1.0.0"
883 |
884 | glob@^7.1.3, glob@^7.1.7:
885 | version "7.2.3"
886 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
887 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
888 | dependencies:
889 | fs.realpath "^1.0.0"
890 | inflight "^1.0.4"
891 | inherits "2"
892 | minimatch "^3.1.1"
893 | once "^1.3.0"
894 | path-is-absolute "^1.0.0"
895 |
896 | gopd@^1.0.1:
897 | version "1.0.1"
898 | resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
899 | integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
900 | dependencies:
901 | get-intrinsic "^1.1.3"
902 |
903 | graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
904 | version "4.2.11"
905 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
906 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
907 |
908 | has-flag@^4.0.0:
909 | version "4.0.0"
910 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
911 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
912 |
913 | has-property-descriptors@^1.0.1:
914 | version "1.0.2"
915 | resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
916 | integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
917 | dependencies:
918 | es-define-property "^1.0.0"
919 |
920 | has-proto@^1.0.1:
921 | version "1.0.3"
922 | resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
923 | integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
924 |
925 | has-symbols@^1.0.3:
926 | version "1.0.3"
927 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
928 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
929 |
930 | hasown@^2.0.0:
931 | version "2.0.1"
932 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa"
933 | integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==
934 | dependencies:
935 | function-bind "^1.1.2"
936 |
937 | he@1.2.0:
938 | version "1.2.0"
939 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
940 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
941 |
942 | http-errors@2.0.0:
943 | version "2.0.0"
944 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
945 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
946 | dependencies:
947 | depd "2.0.0"
948 | inherits "2.0.4"
949 | setprototypeof "1.2.0"
950 | statuses "2.0.1"
951 | toidentifier "1.0.1"
952 |
953 | http-proxy@^1.18.1:
954 | version "1.18.1"
955 | resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
956 | integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
957 | dependencies:
958 | eventemitter3 "^4.0.0"
959 | follow-redirects "^1.0.0"
960 | requires-port "^1.0.0"
961 |
962 | iconv-lite@0.4.24:
963 | version "0.4.24"
964 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
965 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
966 | dependencies:
967 | safer-buffer ">= 2.1.2 < 3"
968 |
969 | iconv-lite@^0.6.3:
970 | version "0.6.3"
971 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
972 | integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
973 | dependencies:
974 | safer-buffer ">= 2.1.2 < 3.0.0"
975 |
976 | import-local@^3.0.2:
977 | version "3.1.0"
978 | resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"
979 | integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
980 | dependencies:
981 | pkg-dir "^4.2.0"
982 | resolve-cwd "^3.0.0"
983 |
984 | inflight@^1.0.4:
985 | version "1.0.6"
986 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
987 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
988 | dependencies:
989 | once "^1.3.0"
990 | wrappy "1"
991 |
992 | inherits@2, inherits@2.0.4:
993 | version "2.0.4"
994 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
995 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
996 |
997 | interpret@^3.1.1:
998 | version "3.1.1"
999 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4"
1000 | integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==
1001 |
1002 | is-binary-path@~2.1.0:
1003 | version "2.1.0"
1004 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
1005 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
1006 | dependencies:
1007 | binary-extensions "^2.0.0"
1008 |
1009 | is-core-module@^2.13.0:
1010 | version "2.13.1"
1011 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
1012 | integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
1013 | dependencies:
1014 | hasown "^2.0.0"
1015 |
1016 | is-extglob@^2.1.1:
1017 | version "2.1.1"
1018 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
1019 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
1020 |
1021 | is-fullwidth-code-point@^3.0.0:
1022 | version "3.0.0"
1023 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
1024 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
1025 |
1026 | is-glob@^4.0.1, is-glob@~4.0.1:
1027 | version "4.0.3"
1028 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
1029 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
1030 | dependencies:
1031 | is-extglob "^2.1.1"
1032 |
1033 | is-number@^7.0.0:
1034 | version "7.0.0"
1035 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
1036 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
1037 |
1038 | is-plain-obj@^2.1.0:
1039 | version "2.1.0"
1040 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
1041 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
1042 |
1043 | is-plain-object@^2.0.4:
1044 | version "2.0.4"
1045 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
1046 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
1047 | dependencies:
1048 | isobject "^3.0.1"
1049 |
1050 | is-unicode-supported@^0.1.0:
1051 | version "0.1.0"
1052 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
1053 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
1054 |
1055 | isbinaryfile@^4.0.8:
1056 | version "4.0.10"
1057 | resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3"
1058 | integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==
1059 |
1060 | isexe@^2.0.0:
1061 | version "2.0.0"
1062 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
1063 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
1064 |
1065 | isobject@^3.0.1:
1066 | version "3.0.1"
1067 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
1068 | integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
1069 |
1070 | jest-worker@^27.4.5:
1071 | version "27.5.1"
1072 | resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
1073 | integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
1074 | dependencies:
1075 | "@types/node" "*"
1076 | merge-stream "^2.0.0"
1077 | supports-color "^8.0.0"
1078 |
1079 | js-yaml@4.1.0:
1080 | version "4.1.0"
1081 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
1082 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
1083 | dependencies:
1084 | argparse "^2.0.1"
1085 |
1086 | json-parse-even-better-errors@^2.3.1:
1087 | version "2.3.1"
1088 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
1089 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
1090 |
1091 | json-schema-traverse@^0.4.1:
1092 | version "0.4.1"
1093 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
1094 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
1095 |
1096 | jsonfile@^4.0.0:
1097 | version "4.0.0"
1098 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
1099 | integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
1100 | optionalDependencies:
1101 | graceful-fs "^4.1.6"
1102 |
1103 | karma-chrome-launcher@3.2.0:
1104 | version "3.2.0"
1105 | resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9"
1106 | integrity sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==
1107 | dependencies:
1108 | which "^1.2.1"
1109 |
1110 | karma-mocha@2.0.1:
1111 | version "2.0.1"
1112 | resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d"
1113 | integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==
1114 | dependencies:
1115 | minimist "^1.2.3"
1116 |
1117 | karma-sourcemap-loader@0.4.0:
1118 | version "0.4.0"
1119 | resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.4.0.tgz#b01d73f8f688f533bcc8f5d273d43458e13b5488"
1120 | integrity sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==
1121 | dependencies:
1122 | graceful-fs "^4.2.10"
1123 |
1124 | karma-webpack@5.0.0:
1125 | version "5.0.0"
1126 | resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840"
1127 | integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA==
1128 | dependencies:
1129 | glob "^7.1.3"
1130 | minimatch "^3.0.4"
1131 | webpack-merge "^4.1.5"
1132 |
1133 | karma@6.4.2:
1134 | version "6.4.2"
1135 | resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.2.tgz#a983f874cee6f35990c4b2dcc3d274653714de8e"
1136 | integrity sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==
1137 | dependencies:
1138 | "@colors/colors" "1.5.0"
1139 | body-parser "^1.19.0"
1140 | braces "^3.0.2"
1141 | chokidar "^3.5.1"
1142 | connect "^3.7.0"
1143 | di "^0.0.1"
1144 | dom-serialize "^2.2.1"
1145 | glob "^7.1.7"
1146 | graceful-fs "^4.2.6"
1147 | http-proxy "^1.18.1"
1148 | isbinaryfile "^4.0.8"
1149 | lodash "^4.17.21"
1150 | log4js "^6.4.1"
1151 | mime "^2.5.2"
1152 | minimatch "^3.0.4"
1153 | mkdirp "^0.5.5"
1154 | qjobs "^1.2.0"
1155 | range-parser "^1.2.1"
1156 | rimraf "^3.0.2"
1157 | socket.io "^4.4.1"
1158 | source-map "^0.6.1"
1159 | tmp "^0.2.1"
1160 | ua-parser-js "^0.7.30"
1161 | yargs "^16.1.1"
1162 |
1163 | kind-of@^6.0.2:
1164 | version "6.0.3"
1165 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
1166 | integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
1167 |
1168 | loader-runner@^4.2.0:
1169 | version "4.3.0"
1170 | resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
1171 | integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
1172 |
1173 | locate-path@^5.0.0:
1174 | version "5.0.0"
1175 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
1176 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
1177 | dependencies:
1178 | p-locate "^4.1.0"
1179 |
1180 | locate-path@^6.0.0:
1181 | version "6.0.0"
1182 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
1183 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
1184 | dependencies:
1185 | p-locate "^5.0.0"
1186 |
1187 | lodash@^4.17.15, lodash@^4.17.21:
1188 | version "4.17.21"
1189 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
1190 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
1191 |
1192 | log-symbols@4.1.0:
1193 | version "4.1.0"
1194 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
1195 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
1196 | dependencies:
1197 | chalk "^4.1.0"
1198 | is-unicode-supported "^0.1.0"
1199 |
1200 | log4js@^6.4.1:
1201 | version "6.9.1"
1202 | resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6"
1203 | integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==
1204 | dependencies:
1205 | date-format "^4.0.14"
1206 | debug "^4.3.4"
1207 | flatted "^3.2.7"
1208 | rfdc "^1.3.0"
1209 | streamroller "^3.1.5"
1210 |
1211 | media-typer@0.3.0:
1212 | version "0.3.0"
1213 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
1214 | integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
1215 |
1216 | merge-stream@^2.0.0:
1217 | version "2.0.0"
1218 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
1219 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
1220 |
1221 | mime-db@1.52.0:
1222 | version "1.52.0"
1223 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
1224 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
1225 |
1226 | mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34:
1227 | version "2.1.35"
1228 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
1229 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
1230 | dependencies:
1231 | mime-db "1.52.0"
1232 |
1233 | mime@^2.5.2:
1234 | version "2.6.0"
1235 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
1236 | integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
1237 |
1238 | minimatch@5.0.1:
1239 | version "5.0.1"
1240 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
1241 | integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
1242 | dependencies:
1243 | brace-expansion "^2.0.1"
1244 |
1245 | minimatch@^3.0.4, minimatch@^3.1.1:
1246 | version "3.1.2"
1247 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
1248 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
1249 | dependencies:
1250 | brace-expansion "^1.1.7"
1251 |
1252 | minimist@^1.2.3, minimist@^1.2.6:
1253 | version "1.2.8"
1254 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
1255 | integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
1256 |
1257 | mkdirp@^0.5.5:
1258 | version "0.5.6"
1259 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
1260 | integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
1261 | dependencies:
1262 | minimist "^1.2.6"
1263 |
1264 | mocha@10.2.0:
1265 | version "10.2.0"
1266 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
1267 | integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==
1268 | dependencies:
1269 | ansi-colors "4.1.1"
1270 | browser-stdout "1.3.1"
1271 | chokidar "3.5.3"
1272 | debug "4.3.4"
1273 | diff "5.0.0"
1274 | escape-string-regexp "4.0.0"
1275 | find-up "5.0.0"
1276 | glob "7.2.0"
1277 | he "1.2.0"
1278 | js-yaml "4.1.0"
1279 | log-symbols "4.1.0"
1280 | minimatch "5.0.1"
1281 | ms "2.1.3"
1282 | nanoid "3.3.3"
1283 | serialize-javascript "6.0.0"
1284 | strip-json-comments "3.1.1"
1285 | supports-color "8.1.1"
1286 | workerpool "6.2.1"
1287 | yargs "16.2.0"
1288 | yargs-parser "20.2.4"
1289 | yargs-unparser "2.0.0"
1290 |
1291 | ms@2.0.0:
1292 | version "2.0.0"
1293 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
1294 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
1295 |
1296 | ms@2.1.2:
1297 | version "2.1.2"
1298 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
1299 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
1300 |
1301 | ms@2.1.3:
1302 | version "2.1.3"
1303 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
1304 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
1305 |
1306 | nanoid@3.3.3:
1307 | version "3.3.3"
1308 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
1309 | integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
1310 |
1311 | negotiator@0.6.3:
1312 | version "0.6.3"
1313 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
1314 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
1315 |
1316 | neo-async@^2.6.2:
1317 | version "2.6.2"
1318 | resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
1319 | integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
1320 |
1321 | node-releases@^2.0.14:
1322 | version "2.0.14"
1323 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
1324 | integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
1325 |
1326 | normalize-path@^3.0.0, normalize-path@~3.0.0:
1327 | version "3.0.0"
1328 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
1329 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
1330 |
1331 | object-assign@^4:
1332 | version "4.1.1"
1333 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
1334 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
1335 |
1336 | object-inspect@^1.13.1:
1337 | version "1.13.1"
1338 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
1339 | integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
1340 |
1341 | on-finished@2.4.1:
1342 | version "2.4.1"
1343 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
1344 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
1345 | dependencies:
1346 | ee-first "1.1.1"
1347 |
1348 | on-finished@~2.3.0:
1349 | version "2.3.0"
1350 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
1351 | integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==
1352 | dependencies:
1353 | ee-first "1.1.1"
1354 |
1355 | once@^1.3.0:
1356 | version "1.4.0"
1357 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
1358 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
1359 | dependencies:
1360 | wrappy "1"
1361 |
1362 | p-limit@^2.2.0:
1363 | version "2.3.0"
1364 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
1365 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
1366 | dependencies:
1367 | p-try "^2.0.0"
1368 |
1369 | p-limit@^3.0.2:
1370 | version "3.1.0"
1371 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
1372 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
1373 | dependencies:
1374 | yocto-queue "^0.1.0"
1375 |
1376 | p-locate@^4.1.0:
1377 | version "4.1.0"
1378 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
1379 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
1380 | dependencies:
1381 | p-limit "^2.2.0"
1382 |
1383 | p-locate@^5.0.0:
1384 | version "5.0.0"
1385 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
1386 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
1387 | dependencies:
1388 | p-limit "^3.0.2"
1389 |
1390 | p-try@^2.0.0:
1391 | version "2.2.0"
1392 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
1393 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
1394 |
1395 | parseurl@~1.3.3:
1396 | version "1.3.3"
1397 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
1398 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
1399 |
1400 | path-exists@^4.0.0:
1401 | version "4.0.0"
1402 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
1403 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
1404 |
1405 | path-is-absolute@^1.0.0:
1406 | version "1.0.1"
1407 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
1408 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
1409 |
1410 | path-key@^3.1.0:
1411 | version "3.1.1"
1412 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
1413 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
1414 |
1415 | path-parse@^1.0.7:
1416 | version "1.0.7"
1417 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
1418 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
1419 |
1420 | picocolors@^1.0.0:
1421 | version "1.0.0"
1422 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
1423 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
1424 |
1425 | picomatch@^2.0.4, picomatch@^2.2.1:
1426 | version "2.3.1"
1427 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
1428 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
1429 |
1430 | pkg-dir@^4.2.0:
1431 | version "4.2.0"
1432 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
1433 | integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
1434 | dependencies:
1435 | find-up "^4.0.0"
1436 |
1437 | punycode@^2.1.0:
1438 | version "2.3.1"
1439 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
1440 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
1441 |
1442 | qjobs@^1.2.0:
1443 | version "1.2.0"
1444 | resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071"
1445 | integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==
1446 |
1447 | qs@6.11.0:
1448 | version "6.11.0"
1449 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
1450 | integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
1451 | dependencies:
1452 | side-channel "^1.0.4"
1453 |
1454 | randombytes@^2.1.0:
1455 | version "2.1.0"
1456 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
1457 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
1458 | dependencies:
1459 | safe-buffer "^5.1.0"
1460 |
1461 | range-parser@^1.2.1:
1462 | version "1.2.1"
1463 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
1464 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
1465 |
1466 | raw-body@2.5.2:
1467 | version "2.5.2"
1468 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
1469 | integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
1470 | dependencies:
1471 | bytes "3.1.2"
1472 | http-errors "2.0.0"
1473 | iconv-lite "0.4.24"
1474 | unpipe "1.0.0"
1475 |
1476 | readdirp@~3.6.0:
1477 | version "3.6.0"
1478 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
1479 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
1480 | dependencies:
1481 | picomatch "^2.2.1"
1482 |
1483 | rechoir@^0.8.0:
1484 | version "0.8.0"
1485 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22"
1486 | integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==
1487 | dependencies:
1488 | resolve "^1.20.0"
1489 |
1490 | require-directory@^2.1.1:
1491 | version "2.1.1"
1492 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
1493 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
1494 |
1495 | requires-port@^1.0.0:
1496 | version "1.0.0"
1497 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
1498 | integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
1499 |
1500 | resolve-cwd@^3.0.0:
1501 | version "3.0.0"
1502 | resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
1503 | integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
1504 | dependencies:
1505 | resolve-from "^5.0.0"
1506 |
1507 | resolve-from@^5.0.0:
1508 | version "5.0.0"
1509 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
1510 | integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
1511 |
1512 | resolve@^1.20.0:
1513 | version "1.22.8"
1514 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
1515 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
1516 | dependencies:
1517 | is-core-module "^2.13.0"
1518 | path-parse "^1.0.7"
1519 | supports-preserve-symlinks-flag "^1.0.0"
1520 |
1521 | rfdc@^1.3.0:
1522 | version "1.3.1"
1523 | resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f"
1524 | integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==
1525 |
1526 | rimraf@^3.0.2:
1527 | version "3.0.2"
1528 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
1529 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
1530 | dependencies:
1531 | glob "^7.1.3"
1532 |
1533 | safe-buffer@^5.1.0:
1534 | version "5.2.1"
1535 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
1536 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
1537 |
1538 | "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
1539 | version "2.1.2"
1540 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
1541 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
1542 |
1543 | schema-utils@^3.1.1, schema-utils@^3.1.2:
1544 | version "3.3.0"
1545 | resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
1546 | integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
1547 | dependencies:
1548 | "@types/json-schema" "^7.0.8"
1549 | ajv "^6.12.5"
1550 | ajv-keywords "^3.5.2"
1551 |
1552 | serialize-javascript@6.0.0:
1553 | version "6.0.0"
1554 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
1555 | integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
1556 | dependencies:
1557 | randombytes "^2.1.0"
1558 |
1559 | serialize-javascript@^6.0.1:
1560 | version "6.0.2"
1561 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
1562 | integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==
1563 | dependencies:
1564 | randombytes "^2.1.0"
1565 |
1566 | set-function-length@^1.2.1:
1567 | version "1.2.1"
1568 | resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425"
1569 | integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==
1570 | dependencies:
1571 | define-data-property "^1.1.2"
1572 | es-errors "^1.3.0"
1573 | function-bind "^1.1.2"
1574 | get-intrinsic "^1.2.3"
1575 | gopd "^1.0.1"
1576 | has-property-descriptors "^1.0.1"
1577 |
1578 | setprototypeof@1.2.0:
1579 | version "1.2.0"
1580 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
1581 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
1582 |
1583 | shallow-clone@^3.0.0:
1584 | version "3.0.1"
1585 | resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
1586 | integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
1587 | dependencies:
1588 | kind-of "^6.0.2"
1589 |
1590 | shebang-command@^2.0.0:
1591 | version "2.0.0"
1592 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
1593 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
1594 | dependencies:
1595 | shebang-regex "^3.0.0"
1596 |
1597 | shebang-regex@^3.0.0:
1598 | version "3.0.0"
1599 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
1600 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
1601 |
1602 | side-channel@^1.0.4:
1603 | version "1.0.6"
1604 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
1605 | integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
1606 | dependencies:
1607 | call-bind "^1.0.7"
1608 | es-errors "^1.3.0"
1609 | get-intrinsic "^1.2.4"
1610 | object-inspect "^1.13.1"
1611 |
1612 | socket.io-adapter@~2.5.2:
1613 | version "2.5.4"
1614 | resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz#4fdb1358667f6d68f25343353bd99bd11ee41006"
1615 | integrity sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==
1616 | dependencies:
1617 | debug "~4.3.4"
1618 | ws "~8.11.0"
1619 |
1620 | socket.io-parser@~4.2.4:
1621 | version "4.2.4"
1622 | resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
1623 | integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
1624 | dependencies:
1625 | "@socket.io/component-emitter" "~3.1.0"
1626 | debug "~4.3.1"
1627 |
1628 | socket.io@^4.4.1:
1629 | version "4.7.4"
1630 | resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.4.tgz#2401a2d7101e4bdc64da80b140d5d8b6a8c7738b"
1631 | integrity sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==
1632 | dependencies:
1633 | accepts "~1.3.4"
1634 | base64id "~2.0.0"
1635 | cors "~2.8.5"
1636 | debug "~4.3.2"
1637 | engine.io "~6.5.2"
1638 | socket.io-adapter "~2.5.2"
1639 | socket.io-parser "~4.2.4"
1640 |
1641 | source-map-js@^1.0.2:
1642 | version "1.0.2"
1643 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
1644 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
1645 |
1646 | source-map-loader@4.0.1:
1647 | version "4.0.1"
1648 | resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-4.0.1.tgz#72f00d05f5d1f90f80974eda781cbd7107c125f2"
1649 | integrity sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==
1650 | dependencies:
1651 | abab "^2.0.6"
1652 | iconv-lite "^0.6.3"
1653 | source-map-js "^1.0.2"
1654 |
1655 | source-map-support@0.5.21, source-map-support@~0.5.20:
1656 | version "0.5.21"
1657 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
1658 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
1659 | dependencies:
1660 | buffer-from "^1.0.0"
1661 | source-map "^0.6.0"
1662 |
1663 | source-map@^0.6.0, source-map@^0.6.1:
1664 | version "0.6.1"
1665 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
1666 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
1667 |
1668 | statuses@2.0.1:
1669 | version "2.0.1"
1670 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
1671 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
1672 |
1673 | statuses@~1.5.0:
1674 | version "1.5.0"
1675 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
1676 | integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
1677 |
1678 | streamroller@^3.1.5:
1679 | version "3.1.5"
1680 | resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff"
1681 | integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==
1682 | dependencies:
1683 | date-format "^4.0.14"
1684 | debug "^4.3.4"
1685 | fs-extra "^8.1.0"
1686 |
1687 | string-width@^4.1.0, string-width@^4.2.0:
1688 | version "4.2.3"
1689 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
1690 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
1691 | dependencies:
1692 | emoji-regex "^8.0.0"
1693 | is-fullwidth-code-point "^3.0.0"
1694 | strip-ansi "^6.0.1"
1695 |
1696 | strip-ansi@^6.0.0, strip-ansi@^6.0.1:
1697 | version "6.0.1"
1698 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1699 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
1700 | dependencies:
1701 | ansi-regex "^5.0.1"
1702 |
1703 | strip-json-comments@3.1.1:
1704 | version "3.1.1"
1705 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
1706 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
1707 |
1708 | supports-color@8.1.1, supports-color@^8.0.0:
1709 | version "8.1.1"
1710 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
1711 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
1712 | dependencies:
1713 | has-flag "^4.0.0"
1714 |
1715 | supports-color@^7.1.0:
1716 | version "7.2.0"
1717 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
1718 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
1719 | dependencies:
1720 | has-flag "^4.0.0"
1721 |
1722 | supports-preserve-symlinks-flag@^1.0.0:
1723 | version "1.0.0"
1724 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
1725 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
1726 |
1727 | tapable@^2.1.1, tapable@^2.2.0:
1728 | version "2.2.1"
1729 | resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
1730 | integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
1731 |
1732 | terser-webpack-plugin@^5.3.7:
1733 | version "5.3.10"
1734 | resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199"
1735 | integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==
1736 | dependencies:
1737 | "@jridgewell/trace-mapping" "^0.3.20"
1738 | jest-worker "^27.4.5"
1739 | schema-utils "^3.1.1"
1740 | serialize-javascript "^6.0.1"
1741 | terser "^5.26.0"
1742 |
1743 | terser@^5.26.0:
1744 | version "5.28.1"
1745 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.28.1.tgz#bf00f7537fd3a798c352c2d67d67d65c915d1b28"
1746 | integrity sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==
1747 | dependencies:
1748 | "@jridgewell/source-map" "^0.3.3"
1749 | acorn "^8.8.2"
1750 | commander "^2.20.0"
1751 | source-map-support "~0.5.20"
1752 |
1753 | tmp@^0.2.1:
1754 | version "0.2.3"
1755 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae"
1756 | integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==
1757 |
1758 | to-regex-range@^5.0.1:
1759 | version "5.0.1"
1760 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1761 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1762 | dependencies:
1763 | is-number "^7.0.0"
1764 |
1765 | toidentifier@1.0.1:
1766 | version "1.0.1"
1767 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
1768 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
1769 |
1770 | type-is@~1.6.18:
1771 | version "1.6.18"
1772 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
1773 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
1774 | dependencies:
1775 | media-typer "0.3.0"
1776 | mime-types "~2.1.24"
1777 |
1778 | typescript@5.0.4:
1779 | version "5.0.4"
1780 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
1781 | integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
1782 |
1783 | ua-parser-js@^0.7.30:
1784 | version "0.7.37"
1785 | resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832"
1786 | integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==
1787 |
1788 | undici-types@~5.26.4:
1789 | version "5.26.5"
1790 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
1791 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
1792 |
1793 | universalify@^0.1.0:
1794 | version "0.1.2"
1795 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
1796 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
1797 |
1798 | unpipe@1.0.0, unpipe@~1.0.0:
1799 | version "1.0.0"
1800 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
1801 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
1802 |
1803 | update-browserslist-db@^1.0.13:
1804 | version "1.0.13"
1805 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
1806 | integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
1807 | dependencies:
1808 | escalade "^3.1.1"
1809 | picocolors "^1.0.0"
1810 |
1811 | uri-js@^4.2.2:
1812 | version "4.4.1"
1813 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
1814 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
1815 | dependencies:
1816 | punycode "^2.1.0"
1817 |
1818 | utils-merge@1.0.1:
1819 | version "1.0.1"
1820 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
1821 | integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
1822 |
1823 | vary@^1:
1824 | version "1.1.2"
1825 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
1826 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
1827 |
1828 | void-elements@^2.0.0:
1829 | version "2.0.1"
1830 | resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
1831 | integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==
1832 |
1833 | watchpack@^2.4.0:
1834 | version "2.4.0"
1835 | resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
1836 | integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
1837 | dependencies:
1838 | glob-to-regexp "^0.4.1"
1839 | graceful-fs "^4.1.2"
1840 |
1841 | webpack-cli@5.1.0:
1842 | version "5.1.0"
1843 | resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.0.tgz#abc4b1f44b50250f2632d8b8b536cfe2f6257891"
1844 | integrity sha512-a7KRJnCxejFoDpYTOwzm5o21ZXMaNqtRlvS183XzGDUPRdVEzJNImcQokqYZ8BNTnk9DkKiuWxw75+DCCoZ26w==
1845 | dependencies:
1846 | "@discoveryjs/json-ext" "^0.5.0"
1847 | "@webpack-cli/configtest" "^2.1.0"
1848 | "@webpack-cli/info" "^2.0.1"
1849 | "@webpack-cli/serve" "^2.0.3"
1850 | colorette "^2.0.14"
1851 | commander "^10.0.1"
1852 | cross-spawn "^7.0.3"
1853 | envinfo "^7.7.3"
1854 | fastest-levenshtein "^1.0.12"
1855 | import-local "^3.0.2"
1856 | interpret "^3.1.1"
1857 | rechoir "^0.8.0"
1858 | webpack-merge "^5.7.3"
1859 |
1860 | webpack-merge@^4.1.5:
1861 | version "4.2.2"
1862 | resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d"
1863 | integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==
1864 | dependencies:
1865 | lodash "^4.17.15"
1866 |
1867 | webpack-merge@^5.7.3:
1868 | version "5.10.0"
1869 | resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
1870 | integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
1871 | dependencies:
1872 | clone-deep "^4.0.1"
1873 | flat "^5.0.2"
1874 | wildcard "^2.0.0"
1875 |
1876 | webpack-sources@^3.2.3:
1877 | version "3.2.3"
1878 | resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
1879 | integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
1880 |
1881 | webpack@5.82.0:
1882 | version "5.82.0"
1883 | resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.82.0.tgz#3c0d074dec79401db026b4ba0fb23d6333f88e7d"
1884 | integrity sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==
1885 | dependencies:
1886 | "@types/eslint-scope" "^3.7.3"
1887 | "@types/estree" "^1.0.0"
1888 | "@webassemblyjs/ast" "^1.11.5"
1889 | "@webassemblyjs/wasm-edit" "^1.11.5"
1890 | "@webassemblyjs/wasm-parser" "^1.11.5"
1891 | acorn "^8.7.1"
1892 | acorn-import-assertions "^1.7.6"
1893 | browserslist "^4.14.5"
1894 | chrome-trace-event "^1.0.2"
1895 | enhanced-resolve "^5.13.0"
1896 | es-module-lexer "^1.2.1"
1897 | eslint-scope "5.1.1"
1898 | events "^3.2.0"
1899 | glob-to-regexp "^0.4.1"
1900 | graceful-fs "^4.2.9"
1901 | json-parse-even-better-errors "^2.3.1"
1902 | loader-runner "^4.2.0"
1903 | mime-types "^2.1.27"
1904 | neo-async "^2.6.2"
1905 | schema-utils "^3.1.2"
1906 | tapable "^2.1.1"
1907 | terser-webpack-plugin "^5.3.7"
1908 | watchpack "^2.4.0"
1909 | webpack-sources "^3.2.3"
1910 |
1911 | which@^1.2.1:
1912 | version "1.3.1"
1913 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
1914 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
1915 | dependencies:
1916 | isexe "^2.0.0"
1917 |
1918 | which@^2.0.1:
1919 | version "2.0.2"
1920 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
1921 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
1922 | dependencies:
1923 | isexe "^2.0.0"
1924 |
1925 | wildcard@^2.0.0:
1926 | version "2.0.1"
1927 | resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
1928 | integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
1929 |
1930 | workerpool@6.2.1:
1931 | version "6.2.1"
1932 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
1933 | integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
1934 |
1935 | wrap-ansi@^7.0.0:
1936 | version "7.0.0"
1937 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1938 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
1939 | dependencies:
1940 | ansi-styles "^4.0.0"
1941 | string-width "^4.1.0"
1942 | strip-ansi "^6.0.0"
1943 |
1944 | wrappy@1:
1945 | version "1.0.2"
1946 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1947 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
1948 |
1949 | ws@~8.11.0:
1950 | version "8.11.0"
1951 | resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
1952 | integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
1953 |
1954 | y18n@^5.0.5:
1955 | version "5.0.8"
1956 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
1957 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
1958 |
1959 | yargs-parser@20.2.4:
1960 | version "20.2.4"
1961 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
1962 | integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
1963 |
1964 | yargs-parser@^20.2.2:
1965 | version "20.2.9"
1966 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
1967 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
1968 |
1969 | yargs-unparser@2.0.0:
1970 | version "2.0.0"
1971 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
1972 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
1973 | dependencies:
1974 | camelcase "^6.0.0"
1975 | decamelize "^4.0.0"
1976 | flat "^5.0.2"
1977 | is-plain-obj "^2.1.0"
1978 |
1979 | yargs@16.2.0, yargs@^16.1.1:
1980 | version "16.2.0"
1981 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
1982 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
1983 | dependencies:
1984 | cliui "^7.0.2"
1985 | escalade "^3.1.1"
1986 | get-caller-file "^2.0.5"
1987 | require-directory "^2.1.1"
1988 | string-width "^4.2.0"
1989 | y18n "^5.0.5"
1990 | yargs-parser "^20.2.2"
1991 |
1992 | yocto-queue@^0.1.0:
1993 | version "0.1.0"
1994 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
1995 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
1996 |
--------------------------------------------------------------------------------
/kotlin-retry-result/build.gradle.kts:
--------------------------------------------------------------------------------
1 | description = "Extensions for integrating with kotlin-result."
2 |
3 | plugins {
4 | id("kotlin-conventions")
5 | id("publish-conventions")
6 | }
7 |
8 | kotlin {
9 | sourceSets {
10 | commonMain {
11 | dependencies {
12 | api(project(":kotlin-retry"))
13 | api(libs.kotlin.result)
14 | implementation(libs.kotlin.coroutines.core)
15 | }
16 | }
17 |
18 | commonTest {
19 | dependencies {
20 | implementation(project(":kotlin-retry"))
21 | implementation(libs.kotlin.coroutines.test)
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/kotlin-retry-result/src/commonMain/kotlin/com/github/michaelbull/retry/result/Retry.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.result
2 |
3 | import com.github.michaelbull.result.Err
4 | import com.github.michaelbull.result.Result
5 | import com.github.michaelbull.result.asErr
6 | import com.github.michaelbull.retry.attempt.Attempt
7 | import com.github.michaelbull.retry.attempt.firstAttempt
8 | import com.github.michaelbull.retry.instruction.ContinueRetrying
9 | import com.github.michaelbull.retry.instruction.RetryInstruction
10 | import com.github.michaelbull.retry.instruction.StopRetrying
11 | import com.github.michaelbull.retry.policy.RetryPolicy
12 | import kotlinx.coroutines.delay
13 | import kotlin.contracts.InvocationKind
14 | import kotlin.contracts.contract
15 |
16 | /**
17 | * Calls the specified function [block] and returns its [Result], handling any [Err] returned from the [block] function
18 | * execution retrying the invocation according to [instructions][RetryInstruction] from the [policy].
19 | */
20 | public suspend inline fun retry(policy: RetryPolicy, block: () -> Result): Result {
21 | contract {
22 | callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
23 | }
24 |
25 | var attempt: Attempt? = null
26 |
27 | while (true) {
28 | val result = block()
29 |
30 | if (result.isOk) {
31 | return result
32 | } else {
33 | if (attempt == null) {
34 | attempt = firstAttempt()
35 | }
36 |
37 | val failedAttempt = attempt.failedWith(result.error)
38 |
39 | when (val instruction = policy(failedAttempt)) {
40 | StopRetrying -> {
41 | return result.asErr()
42 | }
43 |
44 | ContinueRetrying -> {
45 | attempt.retryImmediately()
46 | }
47 |
48 | else -> {
49 | val (delayMillis) = instruction
50 | delay(delayMillis)
51 | attempt.retryAfter(delayMillis)
52 | }
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/kotlin-retry-result/src/commonMain/kotlin/com/github/michaelbull/retry/result/RunRetrying.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.result
2 |
3 | import com.github.michaelbull.result.Err
4 | import com.github.michaelbull.result.Result
5 | import com.github.michaelbull.retry.instruction.RetryInstruction
6 | import com.github.michaelbull.retry.policy.RetryPolicy
7 | import kotlin.contracts.InvocationKind
8 | import kotlin.contracts.contract
9 |
10 | /**
11 | * Calls the specified function [block] and returns its [Result], handling any [Err] returned from the [block] function
12 | * execution retrying the invocation according to [instructions][RetryInstruction] from the [policy].
13 | */
14 | public suspend inline fun runRetrying(policy: RetryPolicy, block: () -> Result): Result {
15 | contract {
16 | callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
17 | }
18 |
19 | return retry(policy, block)
20 | }
21 |
--------------------------------------------------------------------------------
/kotlin-retry-result/src/commonTest/kotlin/com/github/michaelbull/retry/result/RetryTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.result
2 |
3 | import com.github.michaelbull.result.Err
4 | import com.github.michaelbull.result.Ok
5 | import com.github.michaelbull.retry.policy.constantDelay
6 | import com.github.michaelbull.retry.policy.continueIf
7 | import com.github.michaelbull.retry.policy.stopAtAttempts
8 | import kotlinx.coroutines.Deferred
9 | import kotlinx.coroutines.ExperimentalCoroutinesApi
10 | import kotlinx.coroutines.async
11 | import kotlinx.coroutines.cancel
12 | import kotlinx.coroutines.delay
13 | import kotlinx.coroutines.launch
14 | import kotlinx.coroutines.test.runTest
15 | import kotlin.coroutines.cancellation.CancellationException
16 | import kotlin.test.Test
17 | import kotlin.test.assertEquals
18 | import kotlin.test.assertFailsWith
19 | import kotlin.test.assertFalse
20 | import kotlin.test.assertTrue
21 |
22 | @ExperimentalCoroutinesApi
23 | class RetryTest {
24 |
25 | private data class AttemptsError(val attempts: Int)
26 |
27 | @Test
28 | fun retryToAttemptLimit() = runTest {
29 | val fiveTimes = stopAtAttempts(5)
30 | var attempts = 0
31 |
32 | val result = retry(fiveTimes) {
33 | attempts++
34 |
35 | if (attempts < 5) {
36 | Err(AttemptsError(attempts))
37 | } else {
38 | Ok(Unit)
39 | }
40 | }
41 |
42 | assertEquals(Ok(Unit), result)
43 | assertEquals(5, attempts)
44 | }
45 |
46 | @Test
47 | fun retryExhaustingAttemptLimit() = runTest {
48 | val tenTimes = stopAtAttempts(10)
49 | var attempts = 0
50 |
51 | val result = retry(tenTimes) {
52 | attempts++
53 |
54 | if (attempts < 15) {
55 | Err(AttemptsError(attempts))
56 | } else {
57 | Ok(Unit)
58 | }
59 | }
60 |
61 | assertEquals(Err(AttemptsError(10)), result)
62 | assertEquals(10, attempts)
63 | }
64 |
65 | @Test
66 | fun retryThrowsCancellationException() = runTest {
67 | val tenTimes = stopAtAttempts(10)
68 |
69 | assertFailsWith {
70 | retry(tenTimes) {
71 | Ok(Unit).also {
72 | throw CancellationException()
73 | }
74 | }
75 | }
76 | }
77 |
78 | @Test
79 | fun retryStopsAfterCancellation() = runTest {
80 | val fiveTimes = stopAtAttempts(5)
81 | var attempts = 0
82 |
83 | assertFailsWith {
84 | retry(fiveTimes) {
85 | attempts++
86 |
87 | if (attempts == 2) {
88 | throw CancellationException()
89 | } else {
90 | Err(Unit)
91 | }
92 | }
93 | }
94 |
95 | assertEquals(2, attempts)
96 | }
97 |
98 | @Test
99 | fun retryWithCustomPolicy() = runTest {
100 | val uptoFifteenTimes = continueIf { (failure) ->
101 | failure.attempts < 15
102 | }
103 |
104 | var attempts = 0
105 |
106 | val result = retry(uptoFifteenTimes) {
107 | attempts++
108 | Err(AttemptsError(attempts))
109 | }
110 |
111 | assertEquals(Err(AttemptsError(15)), result)
112 | }
113 |
114 | @Test
115 | fun cancelRetryFromJob() = runTest {
116 | val every100ms = constantDelay(100)
117 | var attempts = 0
118 |
119 | val job = backgroundScope.launch {
120 | retry(every100ms) {
121 | attempts++
122 | Err(AttemptsError(attempts))
123 | }
124 | }
125 |
126 | testScheduler.advanceTimeBy(350)
127 | testScheduler.runCurrent()
128 |
129 | job.cancel()
130 |
131 | testScheduler.advanceUntilIdle()
132 |
133 | assertTrue(job.isCancelled)
134 | assertEquals(4, attempts)
135 |
136 | testScheduler.advanceTimeBy(2000)
137 | testScheduler.runCurrent()
138 |
139 | assertTrue(job.isCancelled)
140 | assertEquals(4, attempts)
141 | }
142 |
143 | @Test
144 | fun cancelRetryWithinJob() = runTest {
145 | val every20ms = constantDelay(20)
146 | var attempts = 0
147 |
148 | val job = launch {
149 | retry(every20ms) {
150 | attempts++
151 |
152 | if (attempts == 15) {
153 | cancel()
154 | }
155 |
156 | Err(AttemptsError(attempts))
157 | }
158 | }
159 |
160 | testScheduler.advanceUntilIdle()
161 |
162 | assertTrue(job.isCancelled)
163 | assertEquals(15, attempts)
164 |
165 | testScheduler.advanceTimeBy(2000)
166 | testScheduler.runCurrent()
167 |
168 | assertTrue(job.isCancelled)
169 | assertEquals(15, attempts)
170 | }
171 |
172 | @Test
173 | fun cancelRetryWithinChildJob() = runTest {
174 | val every20ms = constantDelay(20)
175 | var attempts = 0
176 |
177 | lateinit var childJobOne: Deferred
178 | lateinit var childJobTwo: Deferred
179 |
180 | val parentJob = launch {
181 | retry(every20ms) {
182 | childJobOne = async {
183 | delay(100)
184 | attempts
185 | }
186 |
187 | childJobTwo = async {
188 | delay(50)
189 |
190 | if (attempts == 15) {
191 | cancel()
192 | }
193 |
194 | 1
195 | }
196 |
197 | attempts = childJobOne.await() + childJobTwo.await()
198 |
199 | Err(AttemptsError(attempts))
200 | }
201 | }
202 |
203 | testScheduler.advanceUntilIdle()
204 |
205 | assertTrue(parentJob.isCancelled)
206 | assertFalse(childJobOne.isCancelled)
207 | assertTrue(childJobTwo.isCancelled)
208 | assertEquals(15, attempts)
209 |
210 | testScheduler.advanceTimeBy(2000)
211 | testScheduler.runCurrent()
212 |
213 | assertTrue(parentJob.isCancelled)
214 | assertFalse(childJobOne.isCancelled)
215 | assertTrue(childJobTwo.isCancelled)
216 | assertEquals(15, attempts)
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/kotlin-retry/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kotlin-conventions")
3 | id("publish-conventions")
4 | }
5 |
6 | kotlin {
7 | sourceSets {
8 | commonMain {
9 | dependencies {
10 | implementation(libs.kotlin.coroutines.core)
11 | }
12 | }
13 |
14 | commonTest {
15 | dependencies {
16 | implementation(libs.kotlin.coroutines.test)
17 | }
18 | }
19 |
20 | jvmTest {
21 | dependencies {
22 | implementation(libs.mockk)
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/Math.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry
2 |
3 | /**
4 | * Multiplies [this] value by the [other] value, unless it would overflow in which case [Long.MAX_VALUE] is returned.
5 | *
6 | * @throws IllegalArgumentException if either [this] or the [other] value are negative.
7 | */
8 | public infix fun Long.saturatedMultiply(other: Long): Long {
9 | require(this >= 0 && other >= 0) { "saturatedMultiply is optimized for non-negative longs: $this x $other" }
10 |
11 | return if (this == 0L || other <= Long.MAX_VALUE / this) {
12 | this * other
13 | } else {
14 | Long.MAX_VALUE
15 | }
16 | }
17 |
18 | /**
19 | * Adds the [other] value to [this] value, unless it would overflow in which case [Long.MAX_VALUE] is returned.
20 | *
21 | * @throws IllegalArgumentException if either [this] or the [other] value are negative.
22 | */
23 | public infix fun Long.saturatedAdd(other: Long): Long {
24 | require(this >= 0 && other >= 0) { "saturatedAdd is optimized for non-negative longs: $this + $other" }
25 |
26 | return if (this == 0L || other <= Long.MAX_VALUE - this) {
27 | this + other
28 | } else {
29 | Long.MAX_VALUE
30 | }
31 | }
32 |
33 | /**
34 | * Returns 2 to the power of [this], unless it would overflow in which case [Long.MAX_VALUE] is returned.
35 | */
36 | public fun Int.binaryExponential(): Long {
37 | return if (this < Long.SIZE_BITS - 1) {
38 | 1L shl this
39 | } else {
40 | Long.MAX_VALUE
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/Retry.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry
2 |
3 | import com.github.michaelbull.retry.attempt.Attempt
4 | import com.github.michaelbull.retry.attempt.firstAttempt
5 | import com.github.michaelbull.retry.instruction.ContinueRetrying
6 | import com.github.michaelbull.retry.instruction.RetryInstruction
7 | import com.github.michaelbull.retry.instruction.StopRetrying
8 | import com.github.michaelbull.retry.policy.RetryPolicy
9 | import kotlinx.coroutines.delay
10 | import kotlin.contracts.InvocationKind
11 | import kotlin.contracts.contract
12 | import kotlin.coroutines.cancellation.CancellationException
13 |
14 | /**
15 | * Calls the specified function [block] and returns its result if invocation was successful, catching any [Throwable]
16 | * exception that was thrown from the [block] function execution and retrying the invocation according to
17 | * [instructions][RetryInstruction] from the [policy].
18 | */
19 | public suspend inline fun retry(policy: RetryPolicy, block: () -> T): T {
20 | contract {
21 | callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
22 | }
23 |
24 | var attempt: Attempt? = null
25 |
26 | while (true) {
27 | try {
28 | return block()
29 | } catch (failure: Throwable) {
30 | /* avoid swallowing CancellationExceptions */
31 | if (failure is CancellationException) {
32 | throw failure
33 | } else {
34 | if (attempt == null) {
35 | attempt = firstAttempt()
36 | }
37 |
38 | val failedAttempt = attempt.failedWith(failure)
39 |
40 | when (val instruction = policy(failedAttempt)) {
41 | StopRetrying -> {
42 | throw failure
43 | }
44 |
45 | ContinueRetrying -> {
46 | attempt.retryImmediately()
47 | }
48 |
49 | else -> {
50 | val (delayMillis) = instruction
51 | delay(delayMillis)
52 | attempt.retryAfter(delayMillis)
53 | }
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/RunRetrying.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry
2 |
3 | import com.github.michaelbull.retry.instruction.RetryInstruction
4 | import com.github.michaelbull.retry.policy.RetryPolicy
5 | import kotlin.contracts.InvocationKind
6 | import kotlin.contracts.contract
7 |
8 | /**
9 | * Calls the specified function [block] and returns its result if invocation was successful, catching any [Throwable]
10 | * exception that was thrown from the [block] function execution and retrying the invocation according to
11 | * [instructions][RetryInstruction] from the [policy].
12 | */
13 | public suspend inline fun runRetrying(policy: RetryPolicy, block: () -> T): T {
14 | contract {
15 | callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
16 | }
17 |
18 | return retry(policy, block)
19 | }
20 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/attempt/Attempt.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.attempt
2 |
3 | public fun firstAttempt(): Attempt {
4 | return Attempt(
5 | number = 0,
6 | previousDelay = 0,
7 | cumulativeDelay = 0,
8 | )
9 | }
10 |
11 | public data class Attempt(
12 |
13 | /**
14 | * The zero-based attempt number.
15 | */
16 | private var number: Int,
17 |
18 | /**
19 | * The delay between this attempt and the previous.
20 | */
21 | private var previousDelay: Long,
22 |
23 | /**
24 | * The cumulative delay across all attempts.
25 | */
26 | private var cumulativeDelay: Long,
27 | ) {
28 |
29 | init {
30 | require(number >= 0) { "number must be non-negative, but was $number" }
31 | require(previousDelay >= 0) { "previousDelay must be non-negative, but was $previousDelay" }
32 | require(cumulativeDelay >= 0) { "cumulativeDelay must be non-negative, but was $cumulativeDelay" }
33 | }
34 |
35 | public fun failedWith(failure: E): FailedAttempt {
36 | return FailedAttempt(
37 | failure = failure,
38 | number = number,
39 | previousDelay = previousDelay,
40 | cumulativeDelay = cumulativeDelay,
41 | )
42 | }
43 |
44 | public fun retryImmediately() {
45 | number += 1
46 | previousDelay = 0
47 | }
48 |
49 | public fun retryAfter(delayMillis: Long) {
50 | number += 1
51 | previousDelay = delayMillis
52 | cumulativeDelay += delayMillis
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/attempt/FailedAttempt.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.attempt
2 |
3 | public data class FailedAttempt(
4 |
5 | /**
6 | * The attempt failure.
7 | */
8 | val failure: E,
9 |
10 | /**
11 | * The zero-based attempt number.
12 | */
13 | val number: Int,
14 |
15 | /**
16 | * The delay between this attempt and the previous.
17 | */
18 | val previousDelay: Long,
19 |
20 | /**
21 | * The cumulative delay across all attempts.
22 | */
23 | val cumulativeDelay: Long,
24 | )
25 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/instruction/ContinueRetrying.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.instruction
2 |
3 | import com.github.michaelbull.retry.retry
4 |
5 | /**
6 | * Instructs the [retry] function to continue attempting.
7 | */
8 | public val ContinueRetrying: RetryInstruction = RetryInstruction(0L)
9 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/instruction/RetryAfter.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.instruction
2 |
3 | import com.github.michaelbull.retry.retry
4 |
5 | /**
6 | * Instructs the [retry] function to retry the operation after [delayMillis].
7 | *
8 | * @throws IllegalArgumentException if [delayMillis] is not positive.
9 | */
10 | @Suppress("FunctionName")
11 | public fun RetryAfter(delayMillis: Long): RetryInstruction {
12 | require(delayMillis > 0) { "delayMillis must be positive, but was: $delayMillis" }
13 | return RetryInstruction(delayMillis)
14 | }
15 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/instruction/RetryInstruction.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.instruction
2 |
3 | import com.github.michaelbull.retry.policy.RetryPolicy
4 | import com.github.michaelbull.retry.retry
5 | import kotlin.jvm.JvmInline
6 |
7 | /**
8 | * Represents an instruction for the [retry] function to follow after
9 | * evaluating a [RetryPolicy].
10 | */
11 | @JvmInline
12 | public value class RetryInstruction @PublishedApi internal constructor(
13 | public val delayMillis: Long,
14 | ) {
15 | public operator fun component1(): Long = delayMillis
16 | }
17 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/instruction/StopRetrying.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.instruction
2 |
3 | import com.github.michaelbull.retry.retry
4 |
5 | /**
6 | * Instructs the [retry] function to stop attempting retries.
7 | */
8 | public val StopRetrying: RetryInstruction = RetryInstruction(-1L)
9 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/policy/Backoff.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.binaryExponential
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.RetryAfter
6 | import com.github.michaelbull.retry.instruction.RetryInstruction
7 | import com.github.michaelbull.retry.saturatedAdd
8 | import com.github.michaelbull.retry.saturatedMultiply
9 | import kotlin.math.max
10 | import kotlin.math.min
11 | import kotlin.random.Random
12 |
13 | /* https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ */
14 |
15 | /**
16 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to
17 | * [RetryAfter] an amount of milliseconds between [min] and [max] inclusive,
18 | * increasing the delay by 2 to the power of the number of attempts made.
19 | *
20 | * @throws IllegalArgumentException if [min] or [max] are not positive.
21 | */
22 | public fun binaryExponentialBackoff(
23 | min: Long,
24 | max: Long,
25 | ): RetryPolicy {
26 | require(min > 0) { "min must be positive, but was $min" }
27 | require(max > 0) { "max must be positive, but was $max" }
28 |
29 | return RetryPolicy { attempt ->
30 | val delay = min(max, min saturatedMultiply attempt.number.binaryExponential())
31 | RetryAfter(delay)
32 | }
33 | }
34 |
35 | public fun binaryExponentialBackoff(range: LongRange): RetryPolicy {
36 | return binaryExponentialBackoff(range.first, range.last)
37 | }
38 |
39 | /**
40 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to
41 | * [RetryAfter] a random amount of milliseconds between 0 and [max] inclusive,
42 | * increasing the delay by 2 to the power of number of attempts made.
43 | *
44 | * @throws IllegalArgumentException if [min] or [max] are not positive.
45 | */
46 | public fun fullJitterBackoff(
47 | min: Long,
48 | max: Long,
49 | random: Random = Random,
50 | ): RetryPolicy {
51 | require(min > 0) { "min must be positive, but was $min" }
52 | require(max > 0) { "max must be positive, but was $max" }
53 |
54 | return RetryPolicy { attempt ->
55 | val jitter = min(max, min saturatedMultiply attempt.number.binaryExponential())
56 | val randomJitter = random.nextLong(jitter saturatedAdd 1)
57 |
58 | if (randomJitter == 0L) {
59 | ContinueRetrying
60 | } else {
61 | RetryAfter(randomJitter)
62 | }
63 | }
64 | }
65 |
66 | public fun fullJitterBackoff(range: LongRange, random: Random = Random): RetryPolicy {
67 | return fullJitterBackoff(range.first, range.last, random)
68 | }
69 |
70 | /**
71 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to
72 | * [RetryAfter] an amount of milliseconds equally portioned between the
73 | * [binaryExponentialBackoff] and [fullJitterBackoff].
74 | *
75 | * @throws IllegalArgumentException if [min] or [max] are not positive.
76 | */
77 | public fun equalJitterBackoff(
78 | min: Long,
79 | max: Long,
80 | random: Random = Random,
81 | ): RetryPolicy {
82 | require(min > 0) { "min must be positive, but was $min" }
83 | require(max > 0) { "max must be positive, but was $max" }
84 |
85 | return RetryPolicy { attempt ->
86 | val jitter = min(max, min saturatedMultiply attempt.number.binaryExponential())
87 | val randomJitter = random.nextLong((jitter / 2) saturatedAdd 1)
88 | val delayWithJitter = (jitter / 2) saturatedAdd randomJitter
89 |
90 | RetryAfter(delayWithJitter)
91 | }
92 | }
93 |
94 | public fun equalJitterBackoff(range: LongRange, random: Random = Random): RetryPolicy {
95 | return equalJitterBackoff(range.first, range.last, random)
96 | }
97 |
98 | /**
99 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to
100 | * [RetryAfter] a random amount of milliseconds between [min] and [max]
101 | * inclusive, increasing by [correlation] times the previous delay.
102 | *
103 | * @throws IllegalArgumentException if [min] or [max] are not positive.
104 | */
105 | public fun decorrelatedJitterBackoff(
106 | min: Long,
107 | max: Long,
108 | correlation: Long = 3,
109 | random: Random = Random,
110 | ): RetryPolicy {
111 | require(min > 0) { "min must be positive, but was $min" }
112 | require(max > 0) { "max must be positive, but was $max" }
113 |
114 | return RetryPolicy { attempt ->
115 | val jitter = max(min, attempt.previousDelay saturatedMultiply correlation)
116 | val randomJitter = random.nextLong(min, jitter saturatedAdd 1)
117 | val delayWithJitter = min(max, randomJitter)
118 |
119 | RetryAfter(delayWithJitter)
120 | }
121 | }
122 |
123 | public fun decorrelatedJitterBackoff(
124 | range: LongRange,
125 | correlation: Long = 3,
126 | random: Random = Random,
127 | ): RetryPolicy {
128 | return decorrelatedJitterBackoff(range.first, range.last, correlation, random)
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/policy/Delay.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.instruction.ContinueRetrying
4 | import com.github.michaelbull.retry.instruction.RetryAfter
5 | import com.github.michaelbull.retry.instruction.RetryInstruction
6 | import com.github.michaelbull.retry.instruction.StopRetrying
7 |
8 | /**
9 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [RetryAfter] the specified [delayMillis].
10 | */
11 | public fun constantDelay(delayMillis: Long): RetryPolicy {
12 | val instruction = RetryAfter(delayMillis)
13 | return RetryPolicy { instruction }
14 | }
15 |
16 | /**
17 | * Creates a [RetryPolicy] ensuring the [delay][RetryInstruction.delayMillis] of instructions is at least
18 | * [minDelayMillis].
19 | *
20 | * @throws [IllegalArgumentException] if [minDelayMillis] is not positive.
21 | */
22 | public fun RetryPolicy.delayAtLeast(minDelayMillis: Long): RetryPolicy {
23 | require(minDelayMillis > 0) { "minDelayMillis must be positive, but was $minDelayMillis" }
24 |
25 | return RetryPolicy { attempt ->
26 | val instruction = this(attempt)
27 |
28 | if (instruction == StopRetrying || instruction == ContinueRetrying) {
29 | instruction
30 | } else {
31 | val delay = instruction.delayMillis.coerceAtLeast(minDelayMillis)
32 | RetryAfter(delay)
33 | }
34 | }
35 | }
36 |
37 | /**
38 | * Creates a [RetryPolicy] ensuring the [delay][RetryInstruction.delayMillis] of instructions is at most
39 | * [maxDelayMillis].
40 | *
41 | * @throws IllegalArgumentException if [maxDelayMillis] is not positive.
42 | */
43 | public fun RetryPolicy.delayAtMost(maxDelayMillis: Long): RetryPolicy {
44 | require(maxDelayMillis > 0) { "maxDelayMillis must be positive, but was $maxDelayMillis" }
45 |
46 | return RetryPolicy { attempt ->
47 | val instruction = this(attempt)
48 |
49 | if (instruction == StopRetrying || instruction == ContinueRetrying) {
50 | instruction
51 | } else {
52 | val delay = instruction.delayMillis.coerceAtMost(maxDelayMillis)
53 | RetryAfter(delay)
54 | }
55 | }
56 | }
57 |
58 | /**
59 | * Creates a [RetryPolicy] ensuring the [delay][RetryInstruction.delayMillis] of instructions lies in the specified
60 | * range [minDelayMillis]..[maxDelayMillis].
61 | *
62 | * @throws IllegalArgumentException if [minDelayMillis] or [maxDelayMillis] are not positive.
63 | */
64 | public fun RetryPolicy.delayIn(minDelayMillis: Long, maxDelayMillis: Long): RetryPolicy {
65 | require(minDelayMillis > 0) { "minDelayMillis must be positive, but was $minDelayMillis" }
66 | require(maxDelayMillis > 0) { "maxDelayMillis must be positive, but was $maxDelayMillis" }
67 |
68 | return RetryPolicy { attempt ->
69 | val instruction = this(attempt)
70 |
71 | if (instruction == StopRetrying || instruction == ContinueRetrying) {
72 | instruction
73 | } else {
74 | val delay = instruction.delayMillis.coerceIn(minDelayMillis, maxDelayMillis)
75 | RetryAfter(delay)
76 | }
77 | }
78 | }
79 |
80 | /**
81 | * Creates a [RetryPolicy] ensuring the [delay][RetryInstruction.delayMillis] of instructions lies in the specified
82 | * [range].
83 | *
84 | * @throws IllegalArgumentException if the specified [range] is empty.
85 | */
86 | public fun RetryPolicy.delayIn(range: LongRange): RetryPolicy {
87 | require(!range.isEmpty()) { "range must not be empty" }
88 |
89 | return RetryPolicy { attempt ->
90 | val instruction = this(attempt)
91 |
92 | if (instruction == StopRetrying || instruction == ContinueRetrying) {
93 | instruction
94 | } else {
95 | val delay = instruction.delayMillis.coerceIn(range)
96 | RetryAfter(delay)
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/policy/Predicate.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.FailedAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.RetryInstruction
6 | import com.github.michaelbull.retry.instruction.StopRetrying
7 |
8 | public fun interface RetryPredicate {
9 | public operator fun invoke(attempt: FailedAttempt): Boolean
10 | }
11 |
12 | /**
13 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [ContinueRetrying] if the [FailedAttempt]
14 | * satisfies the given [predicate], or an [instruction][RetryInstruction] to [StopRetrying] if it doesn't.
15 | */
16 | public fun continueIf(predicate: RetryPredicate): RetryPolicy {
17 | return RetryPolicy { attempt ->
18 | if (predicate(attempt)) {
19 | ContinueRetrying
20 | } else {
21 | StopRetrying
22 | }
23 | }
24 | }
25 |
26 | /**
27 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [ContinueRetrying] if the [FailedAttempt]
28 | * _does not_ satisfy the given [predicate], or an [instruction][RetryInstruction] to [StopRetrying] if it does.
29 | */
30 | public fun continueUnless(predicate: RetryPredicate): RetryPolicy {
31 | return RetryPolicy { attempt ->
32 | if (!predicate(attempt)) {
33 | ContinueRetrying
34 | } else {
35 | StopRetrying
36 | }
37 | }
38 | }
39 |
40 | /**
41 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [StopRetrying] if the [FailedAttempt]
42 | * satisfies the given [predicate], or an [instruction][RetryInstruction] to [ContinueRetrying] if it doesn't.
43 | */
44 | public fun stopIf(predicate: RetryPredicate): RetryPolicy {
45 | return RetryPolicy { attempt ->
46 | if (predicate(attempt)) {
47 | StopRetrying
48 | } else {
49 | ContinueRetrying
50 | }
51 | }
52 | }
53 |
54 | /**
55 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [StopRetrying] if the [FailedAttempt]
56 | * _does not_ satisfy the given [predicate], or an [instruction][RetryInstruction] to [ContinueRetrying] if it does.
57 | */
58 | public fun stopUnless(predicate: RetryPredicate): RetryPolicy {
59 | return RetryPolicy { attempt ->
60 | if (!predicate(attempt)) {
61 | StopRetrying
62 | } else {
63 | ContinueRetrying
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/policy/RetryPolicy.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.FailedAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.RetryAfter
6 | import com.github.michaelbull.retry.instruction.RetryInstruction
7 | import com.github.michaelbull.retry.instruction.StopRetrying
8 | import kotlin.math.max
9 |
10 | public fun interface RetryPolicy {
11 | public operator fun invoke(attempt: FailedAttempt): RetryInstruction
12 | }
13 |
14 | /**
15 | * Merges the [previous](prev) and [current](curr) [RetryPolicy] into a single [RetryPolicy].
16 | *
17 | * If either policy returns an [instruction][RetryInstruction] to [StopRetrying], the combined [policy][RetryPolicy]
18 | * will return an [instruction][RetryInstruction] to [StopRetrying].
19 | *
20 | * If both [policies][RetryPolicy] return an [instruction][RetryInstruction] to [RetryAfter] a given delay, the combined
21 | * [policy][RetryPolicy] will return an [instruction][RetryInstruction] to [RetryAfter] the larger delay.
22 | */
23 | public fun RetryPolicy(prev: RetryPolicy, curr: RetryPolicy): RetryPolicy {
24 | return RetryPolicy { attempt ->
25 | val prevInstruction = prev(attempt)
26 | val currInstruction = curr(attempt)
27 |
28 | val eitherStopping = prevInstruction == StopRetrying || currInstruction == StopRetrying
29 | val bothContinuing = prevInstruction == ContinueRetrying && currInstruction == ContinueRetrying
30 |
31 | when {
32 | eitherStopping -> StopRetrying
33 | bothContinuing -> ContinueRetrying
34 | else -> {
35 | val prevDelay = prevInstruction.delayMillis;
36 | val currDelay = currInstruction.delayMillis;
37 | val greatestDelay = max(prevDelay, currDelay)
38 | RetryAfter(greatestDelay)
39 | }
40 | }
41 | }
42 | }
43 |
44 | public fun RetryPolicy(first: RetryPolicy, second: RetryPolicy, vararg rest: RetryPolicy): RetryPolicy {
45 | return listOf(first, second, *rest).reduce(::RetryPolicy)
46 | }
47 |
48 | public operator fun RetryPolicy.plus(other: RetryPolicy): RetryPolicy {
49 | return RetryPolicy(this, other)
50 | }
51 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonMain/kotlin/com/github/michaelbull/retry/policy/Stop.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.FailedAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.RetryAfter
6 | import com.github.michaelbull.retry.instruction.RetryInstruction
7 | import com.github.michaelbull.retry.instruction.StopRetrying
8 | import com.github.michaelbull.retry.saturatedAdd
9 |
10 | /**
11 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [StopRetrying] after the
12 | * [number of attempts][FailedAttempt.number] reaches the specified [count].
13 | *
14 | * Unlike [stopAtRetries], the first invocation **is** counted towards the limit.
15 | *
16 | * ```kotlin
17 | * var attempts = 1
18 | *
19 | * retry(stopAtAttempts(3)) {
20 | * println(attempts++)
21 | * throw RuntimeException()
22 | * }
23 | *
24 | * // prints:
25 | * // 1
26 | * // 2
27 | * // 3
28 | * ```
29 | *
30 | * @throws IllegalArgumentException if [count] is not positive.
31 | */
32 | public fun stopAtAttempts(count: Int): RetryPolicy {
33 | require(count > 0) { "count must be positive, but was $count" }
34 |
35 | return stopIf { attempt ->
36 | attempt.number + 1 >= count
37 | }
38 | }
39 |
40 | /**
41 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [StopRetrying] after the
42 | * [number of attempts][FailedAttempt.number] reaches the specified [count].
43 | *
44 | * Unlike [stopAtAttempts], the first invocation **is not** counted towards the limit.
45 | *
46 | * ```kotlin
47 | * var attempt = 1
48 | *
49 | * retry(stopAtRetries(3)) {
50 | * println(attempt++)
51 | * throw RuntimeException()
52 | * }
53 | *
54 | * // prints:
55 | * // 1
56 | * // 2
57 | * // 3
58 | * // 4
59 | * ```
60 | *
61 | * @throws [IllegalArgumentException] if [count] is negative.
62 | */
63 | public fun stopAtRetries(count: Int): RetryPolicy {
64 | require(count >= 0) { "count must be non-negative, but was $count" }
65 |
66 | return stopIf { attempt ->
67 | attempt.number >= count
68 | }
69 | }
70 |
71 | /**
72 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [StopRetrying] if this policy returns an
73 | * [instruction][RetryInstruction] to [RetryAfter] an amount of time that is greater than or equal to [delayMillis].
74 | *
75 | * @throws IllegalArgumentException if [delayMillis] is not positive.
76 | */
77 | public fun RetryPolicy.stopAtDelay(delayMillis: Long): RetryPolicy {
78 | require(delayMillis > 0) { "delayMillis must be positive, but was: $delayMillis" }
79 |
80 | return RetryPolicy { attempt ->
81 | val instruction = this(attempt)
82 |
83 | if (instruction == StopRetrying || instruction == ContinueRetrying) {
84 | instruction
85 | } else if (instruction.delayMillis >= delayMillis) {
86 | StopRetrying
87 | } else {
88 | instruction
89 | }
90 | }
91 | }
92 |
93 | /**
94 | * Creates a [RetryPolicy] that returns an [instruction][RetryInstruction] to [StopRetrying] if this policy returns an
95 | * [instruction][RetryInstruction] to [RetryAfter] an amount of time that, when added to the
96 | * [FailedAttempt.cumulativeDelay], is greater than or equal to [delayMillis].
97 | *
98 | * @throws IllegalArgumentException if [delayMillis] is not positive.
99 | */
100 | public fun RetryPolicy.stopAtCumulativeDelay(delayMillis: Long): RetryPolicy {
101 | require(delayMillis > 0) { "delayMillis must be positive, but was: $delayMillis" }
102 |
103 | return RetryPolicy { attempt ->
104 | val instruction = this(attempt)
105 |
106 | if (instruction == StopRetrying || instruction == ContinueRetrying) {
107 | instruction
108 | } else {
109 | val delay = attempt.cumulativeDelay saturatedAdd instruction.delayMillis
110 |
111 | if (delay >= delayMillis) {
112 | StopRetrying
113 | } else {
114 | instruction
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonTest/kotlin/com/github/michaelbull/retry/RetryTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry
2 |
3 | import com.github.michaelbull.retry.policy.constantDelay
4 | import com.github.michaelbull.retry.policy.continueIf
5 | import com.github.michaelbull.retry.policy.plus
6 | import com.github.michaelbull.retry.policy.stopAtAttempts
7 | import kotlinx.coroutines.Deferred
8 | import kotlinx.coroutines.ExperimentalCoroutinesApi
9 | import kotlinx.coroutines.async
10 | import kotlinx.coroutines.cancel
11 | import kotlinx.coroutines.delay
12 | import kotlinx.coroutines.launch
13 | import kotlinx.coroutines.test.runTest
14 | import kotlin.coroutines.cancellation.CancellationException
15 | import kotlin.test.Test
16 | import kotlin.test.assertEquals
17 | import kotlin.test.assertFailsWith
18 | import kotlin.test.assertFalse
19 | import kotlin.test.assertTrue
20 |
21 | @ExperimentalCoroutinesApi
22 | class RetryTest {
23 |
24 | private data class AttemptsException(val attempts: Int) : Exception()
25 |
26 | @Test
27 | fun retryToAttemptLimit() = runTest {
28 | val fiveTimes = stopAtAttempts(5)
29 | var attempts = 0
30 |
31 | retry(fiveTimes) {
32 | attempts++
33 |
34 | if (attempts < 5) {
35 | throw AttemptsException(attempts)
36 | }
37 | }
38 |
39 | assertEquals(5, attempts)
40 | }
41 |
42 | @Test
43 | fun retryExhaustingAttemptLimit() = runTest {
44 | val tenTimes = stopAtAttempts(10)
45 | var attempts = 0
46 |
47 | val exception = assertFailsWith {
48 | retry(tenTimes) {
49 | attempts++
50 |
51 | if (attempts < 15) {
52 | throw AttemptsException(attempts)
53 | }
54 | }
55 | }
56 |
57 | assertEquals(AttemptsException(10), exception)
58 | }
59 |
60 | @Test
61 | fun retryThrowsCancellationException() = runTest {
62 | val tenTimes = stopAtAttempts(10)
63 |
64 | assertFailsWith {
65 | retry(tenTimes) {
66 | throw CancellationException()
67 | }
68 | }
69 | }
70 |
71 | @Test
72 | fun retryStopsAfterCancellation() = runTest {
73 | val fiveTimes = stopAtAttempts(5)
74 | var attempts = 0
75 |
76 | assertFailsWith {
77 | retry(fiveTimes) {
78 | attempts++
79 |
80 | if (attempts == 2) {
81 | throw CancellationException()
82 | } else {
83 | throw Exception()
84 | }
85 | }
86 | }
87 |
88 | assertEquals(2, attempts)
89 | }
90 |
91 | @Test
92 | fun retryWithCustomPolicy() = runTest {
93 | val customPolicy = continueIf { (failure) ->
94 | failure is AttemptsException
95 | }
96 |
97 | val uptoFifteenTimes = customPolicy + stopAtAttempts(15)
98 |
99 | var attempts = 0
100 | lateinit var mostRecentException: Exception
101 |
102 | try {
103 | retry(uptoFifteenTimes) {
104 | attempts++
105 | throw AttemptsException(attempts)
106 | }
107 | } catch (ex: AttemptsException) {
108 | mostRecentException = ex
109 | }
110 |
111 | assertEquals(AttemptsException(15), mostRecentException)
112 | }
113 |
114 | @Test
115 | fun cancelRetryFromJob() = runTest {
116 | val every100ms = constantDelay(100)
117 | var attempts = 0
118 |
119 | val job = backgroundScope.launch {
120 | retry(every100ms) {
121 | attempts++
122 | throw AttemptsException(attempts)
123 | }
124 | }
125 |
126 | testScheduler.advanceTimeBy(350)
127 | testScheduler.runCurrent()
128 |
129 | job.cancel()
130 |
131 | testScheduler.advanceUntilIdle()
132 |
133 | assertTrue(job.isCancelled)
134 | assertEquals(4, attempts)
135 |
136 | testScheduler.advanceTimeBy(2000)
137 | testScheduler.runCurrent()
138 |
139 | assertTrue(job.isCancelled)
140 | assertEquals(4, attempts)
141 | }
142 |
143 | @Test
144 | fun cancelRetryWithinJob() = runTest {
145 | val every20ms = constantDelay(20)
146 | var attempts = 0
147 |
148 | val job = launch {
149 | retry(every20ms) {
150 | attempts++
151 |
152 | if (attempts == 15) {
153 | cancel()
154 | }
155 |
156 | throw AttemptsException(attempts)
157 | }
158 | }
159 |
160 | testScheduler.advanceUntilIdle()
161 |
162 | assertTrue(job.isCancelled)
163 | assertEquals(15, attempts)
164 |
165 | testScheduler.advanceTimeBy(2000)
166 | testScheduler.runCurrent()
167 |
168 | assertTrue(job.isCancelled)
169 | assertEquals(15, attempts)
170 | }
171 |
172 | @Test
173 | fun cancelRetryWithinChildJob() = runTest {
174 | val every20ms = constantDelay(20)
175 | var attempts = 0
176 |
177 | lateinit var childJobOne: Deferred
178 | lateinit var childJobTwo: Deferred
179 |
180 | val parentJob = launch {
181 | retry(every20ms) {
182 | childJobOne = async {
183 | delay(100)
184 | attempts
185 | }
186 |
187 | childJobTwo = async {
188 | delay(50)
189 |
190 | if (attempts == 15) {
191 | cancel()
192 | }
193 |
194 | 1
195 | }
196 |
197 | attempts = childJobOne.await() + childJobTwo.await()
198 |
199 | throw AttemptsException(attempts)
200 | }
201 | }
202 |
203 | testScheduler.advanceUntilIdle()
204 |
205 | assertTrue(parentJob.isCancelled)
206 | assertFalse(childJobOne.isCancelled)
207 | assertTrue(childJobTwo.isCancelled)
208 | assertEquals(15, attempts)
209 |
210 | testScheduler.advanceTimeBy(2000)
211 | testScheduler.runCurrent()
212 |
213 | assertTrue(parentJob.isCancelled)
214 | assertFalse(childJobOne.isCancelled)
215 | assertTrue(childJobTwo.isCancelled)
216 | assertEquals(15, attempts)
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonTest/kotlin/com/github/michaelbull/retry/policy/BackoffTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.firstAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.RetryAfter
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlin.random.Random
8 | import kotlin.test.Test
9 | import kotlin.test.assertEquals
10 |
11 | @ExperimentalCoroutinesApi
12 | class BackoffTest {
13 |
14 | @Test
15 | fun binaryExponentialBackoff() {
16 | val policy = binaryExponentialBackoff(10L..8000L)
17 |
18 | val expected = listOf(
19 | RetryAfter(10L),
20 | RetryAfter(20L),
21 | RetryAfter(40L),
22 | RetryAfter(80L),
23 | RetryAfter(160L),
24 | RetryAfter(320L),
25 | RetryAfter(640L),
26 | RetryAfter(1280L),
27 | RetryAfter(2560L),
28 | RetryAfter(5120L),
29 | RetryAfter(8000L),
30 | )
31 |
32 | val actual = policy.simulate(expected.size, Unit)
33 |
34 | assertEquals(expected, actual)
35 | }
36 |
37 | @Test
38 | fun fullJitterBackoff() {
39 | val policy = fullJitterBackoff(10L..8000L, PenultimateRandom)
40 |
41 | val expected = listOf(
42 | RetryAfter(10L),
43 | RetryAfter(20L),
44 | RetryAfter(40L),
45 | RetryAfter(80L),
46 | RetryAfter(160L),
47 | RetryAfter(320L),
48 | RetryAfter(640L),
49 | RetryAfter(1280L),
50 | RetryAfter(2560L),
51 | RetryAfter(5120L),
52 | RetryAfter(8000L),
53 | )
54 |
55 | val actual = policy.simulate(expected.size, Unit)
56 |
57 | assertEquals(expected, actual)
58 | }
59 |
60 | @Test
61 | fun fullJitterBackoffLowerBound() {
62 | val policy = fullJitterBackoff(10L..8000L, LowerBoundRandom)
63 |
64 | val expected = listOf(
65 | ContinueRetrying,
66 | ContinueRetrying,
67 | ContinueRetrying,
68 | ContinueRetrying,
69 | ContinueRetrying,
70 | ContinueRetrying,
71 | ContinueRetrying,
72 | ContinueRetrying,
73 | ContinueRetrying,
74 | ContinueRetrying,
75 | )
76 |
77 | val actual = policy.simulate(expected.size, Unit)
78 |
79 | assertEquals(expected, actual)
80 | }
81 |
82 | @Test
83 | fun equalJitter() {
84 | val policy = equalJitterBackoff(10L..8000L, PenultimateRandom)
85 |
86 | val expected = listOf(
87 | RetryAfter(10L),
88 | RetryAfter(20L),
89 | RetryAfter(40L),
90 | RetryAfter(80L),
91 | RetryAfter(160L),
92 | RetryAfter(320L),
93 | RetryAfter(640L),
94 | RetryAfter(1280L),
95 | RetryAfter(2560L),
96 | RetryAfter(5120L),
97 | RetryAfter(8000L),
98 | )
99 |
100 | val actual = policy.simulate(expected.size, Unit)
101 |
102 | assertEquals(expected, actual)
103 | }
104 |
105 | @Test
106 | fun decorrelatedJitter() {
107 | val policy = decorrelatedJitterBackoff(10L..8000L, 3, PenultimateRandom)
108 |
109 | val expected = listOf(
110 | RetryAfter(10L),
111 | RetryAfter(30L),
112 | RetryAfter(90L),
113 | RetryAfter(270L),
114 | RetryAfter(810L),
115 | RetryAfter(2430L),
116 | RetryAfter(7290L),
117 | RetryAfter(8000L),
118 | RetryAfter(8000L),
119 | RetryAfter(8000L),
120 | RetryAfter(8000L)
121 | )
122 |
123 | val actual = policy.simulate(expected.size, Unit)
124 |
125 | assertEquals(expected, actual)
126 | }
127 |
128 | private fun RetryPolicy.simulate(times: Int, failure: E) = buildList {
129 | val attempt = firstAttempt()
130 |
131 | repeat(times) {
132 | val failedAttempt = attempt.failedWith(failure)
133 | val instruction = this@simulate.invoke(failedAttempt)
134 |
135 | add(instruction)
136 |
137 | if (instruction == ContinueRetrying) {
138 | attempt.retryImmediately()
139 | } else if (instruction.delayMillis > 0) {
140 | attempt.retryAfter(instruction.delayMillis)
141 | }
142 | }
143 | }
144 |
145 |
146 | private object PenultimateRandom : Random() {
147 | override fun nextBits(bitCount: Int) = 0
148 |
149 | override fun nextLong(until: Long): Long {
150 | return until - 1
151 | }
152 |
153 | override fun nextLong(from: Long, until: Long): Long {
154 | return until - 1
155 | }
156 | }
157 |
158 | private object LowerBoundRandom : Random() {
159 | override fun nextBits(bitCount: Int) = 0
160 |
161 | override fun nextLong(until: Long): Long {
162 | return 0
163 | }
164 |
165 | override fun nextLong(from: Long, until: Long): Long {
166 | return from
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonTest/kotlin/com/github/michaelbull/retry/policy/DelayTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.FailedAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.StopRetrying
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlin.test.Test
8 | import kotlin.test.assertEquals
9 |
10 | @ExperimentalCoroutinesApi
11 | class DelayTest {
12 |
13 | @Test
14 | fun delayAtMostStoppedPolicy() {
15 | val policy = constantDelay(30)
16 | .stopAtDelay(5)
17 | .delayAtMost(50)
18 |
19 | val attempt = FailedAttempt(
20 | failure = Unit,
21 | number = 0,
22 | previousDelay = 0,
23 | cumulativeDelay = 0,
24 | )
25 |
26 | val instruction = policy(attempt)
27 |
28 | assertEquals(StopRetrying, instruction)
29 | }
30 |
31 | @Test
32 | fun delayAtMostRunningPolicy() {
33 | val policy = stopAtAttempts(5).delayAtMost(20)
34 |
35 | val attempt = FailedAttempt(
36 | failure = Unit,
37 | number = 0,
38 | previousDelay = 0,
39 | cumulativeDelay = 0,
40 | )
41 |
42 | val instruction = policy(attempt)
43 |
44 | assertEquals(ContinueRetrying, instruction)
45 | }
46 |
47 | @Test
48 | fun delayAtMostLowerBound() {
49 | val policy = constantDelay(30).delayAtMost(50)
50 |
51 | val attempt = FailedAttempt(
52 | failure = Unit,
53 | number = 0,
54 | previousDelay = 0,
55 | cumulativeDelay = 0,
56 | )
57 |
58 | val instruction = policy(attempt)
59 |
60 | assertEquals(30, instruction.delayMillis)
61 | }
62 |
63 | @Test
64 | fun delayAtMostUpperBound() {
65 | val policy = constantDelay(100).delayAtMost(100)
66 |
67 | val attempt = FailedAttempt(
68 | failure = Unit,
69 | number = 0,
70 | previousDelay = 0,
71 | cumulativeDelay = 0,
72 | )
73 |
74 | val instruction = policy(attempt)
75 |
76 | assertEquals(100, instruction.delayMillis)
77 | }
78 |
79 | @Test
80 | fun delayAtMostReduce() {
81 | val policy = constantDelay(200).delayAtMost(150)
82 |
83 | val attempt = FailedAttempt(
84 | failure = Unit,
85 | number = 0,
86 | previousDelay = 0,
87 | cumulativeDelay = 0,
88 | )
89 |
90 | val instruction = policy(attempt)
91 |
92 | assertEquals(150, instruction.delayMillis)
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonTest/kotlin/com/github/michaelbull/retry/policy/PredicateTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.FailedAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.StopRetrying
6 | import kotlinx.coroutines.ExperimentalCoroutinesApi
7 | import kotlin.test.Test
8 | import kotlin.test.assertEquals
9 |
10 | @ExperimentalCoroutinesApi
11 | class PredicateTest {
12 |
13 | @Test
14 | fun continueIfExpectedException() {
15 | val policy = continueIf { (failure) ->
16 | failure is IllegalStateException
17 | }
18 |
19 | val attempt = FailedAttempt(
20 | failure = IllegalStateException(),
21 | number = 0,
22 | previousDelay = 0,
23 | cumulativeDelay = 0,
24 | )
25 |
26 | val instruction = policy(attempt)
27 |
28 | assertEquals(ContinueRetrying, instruction)
29 | }
30 |
31 | @Test
32 | fun continueIfUnexpectedException() {
33 | val policy = continueIf { (failure) ->
34 | failure is IllegalStateException
35 | }
36 |
37 | val attempt = FailedAttempt(
38 | failure = UnsupportedOperationException(),
39 | number = 0,
40 | previousDelay = 0,
41 | cumulativeDelay = 0,
42 | )
43 |
44 | val instruction = policy(attempt)
45 |
46 | assertEquals(StopRetrying, instruction)
47 | }
48 |
49 | @Test
50 | fun continueUnlessExpectedException() {
51 | val policy = continueUnless { (failure) ->
52 | failure is IllegalStateException
53 | }
54 |
55 | val attempt = FailedAttempt(
56 | failure = IllegalStateException(),
57 | number = 0,
58 | previousDelay = 0,
59 | cumulativeDelay = 0,
60 | )
61 |
62 | val instruction = policy(attempt)
63 |
64 | assertEquals(StopRetrying, instruction)
65 | }
66 |
67 | @Test
68 | fun continueUnlessUnexpectedException() {
69 | val policy = continueUnless { (failure) ->
70 | failure is IllegalStateException
71 | }
72 |
73 | val attempt = FailedAttempt(
74 | failure = UnsupportedOperationException(),
75 | number = 0,
76 | previousDelay = 0,
77 | cumulativeDelay = 0,
78 | )
79 |
80 | val instruction = policy(attempt)
81 |
82 | assertEquals(ContinueRetrying, instruction)
83 | }
84 |
85 | @Test
86 | fun stopIfExpectedException() {
87 | val policy = stopIf { (failure) ->
88 | failure is IllegalStateException
89 | }
90 |
91 | val attempt = FailedAttempt(
92 | failure = IllegalStateException(),
93 | number = 0,
94 | previousDelay = 0,
95 | cumulativeDelay = 0,
96 | )
97 |
98 | val instruction = policy(attempt)
99 |
100 | assertEquals(StopRetrying, instruction)
101 | }
102 |
103 | @Test
104 | fun stopIfUnexpectedException() {
105 | val policy = stopIf { (failure) ->
106 | failure is IllegalStateException
107 | }
108 |
109 | val attempt = FailedAttempt(
110 | failure = UnsupportedOperationException(),
111 | number = 0,
112 | previousDelay = 0,
113 | cumulativeDelay = 0,
114 | )
115 |
116 | val instruction = policy(attempt)
117 |
118 | assertEquals(ContinueRetrying, instruction)
119 | }
120 |
121 | @Test
122 | fun stopUnlessUnexpectedException() {
123 | val policy = stopUnless { (failure) ->
124 | failure is IllegalStateException
125 | }
126 |
127 | val attempt = FailedAttempt(
128 | failure = UnsupportedOperationException(),
129 | number = 0,
130 | previousDelay = 0,
131 | cumulativeDelay = 0,
132 | )
133 |
134 | val instruction = policy(attempt)
135 |
136 | assertEquals(StopRetrying, instruction)
137 | }
138 |
139 | @Test
140 | fun stopUnlessExpectedException() {
141 | val policy = stopUnless { (failure) ->
142 | failure is IllegalStateException
143 | }
144 |
145 | val attempt = FailedAttempt(
146 | failure = IllegalStateException(),
147 | number = 0,
148 | previousDelay = 0,
149 | cumulativeDelay = 0,
150 | )
151 |
152 | val instruction = policy(attempt)
153 |
154 | assertEquals(ContinueRetrying, instruction)
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/kotlin-retry/src/commonTest/kotlin/com/github/michaelbull/retry/policy/StopTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry.policy
2 |
3 | import com.github.michaelbull.retry.attempt.FailedAttempt
4 | import com.github.michaelbull.retry.instruction.ContinueRetrying
5 | import com.github.michaelbull.retry.instruction.RetryAfter
6 | import com.github.michaelbull.retry.instruction.StopRetrying
7 | import kotlinx.coroutines.ExperimentalCoroutinesApi
8 | import kotlin.test.Test
9 | import kotlin.test.assertEquals
10 |
11 | @ExperimentalCoroutinesApi
12 | class StopTest {
13 |
14 | @Test
15 | fun stopAtAttemptsContinuesUnderMaximum() {
16 | val policy = stopAtAttempts(5)
17 |
18 | val attempt = FailedAttempt(
19 | failure = Unit,
20 | number = 0,
21 | previousDelay = 0,
22 | cumulativeDelay = 0
23 | )
24 |
25 | val instruction = policy(attempt)
26 |
27 | assertEquals(ContinueRetrying, instruction)
28 | }
29 |
30 | @Test
31 | fun stopAtAttemptsStopsAtMaximum() {
32 | val policy = stopAtAttempts(2)
33 |
34 | val attempt = FailedAttempt(
35 | failure = Unit,
36 | number = 2,
37 | previousDelay = 100,
38 | cumulativeDelay = 300
39 | )
40 |
41 | val instruction = policy(attempt)
42 |
43 | assertEquals(StopRetrying, instruction)
44 | }
45 |
46 | @Test
47 | fun stopAtDelayContinuesUnderMaximum() {
48 | val policy = constantDelay(20).stopAtDelay(50)
49 |
50 | val attempt = FailedAttempt(
51 | failure = Unit,
52 | number = 0,
53 | previousDelay = 0,
54 | cumulativeDelay = 0,
55 | )
56 |
57 | val instruction = policy(attempt)
58 |
59 | assertEquals(RetryAfter(20), instruction)
60 | }
61 |
62 | @Test
63 | fun stopAtDelayStopsAtMaximum() {
64 | val policy = constantDelay(80).stopAtDelay(80)
65 |
66 | val attempt = FailedAttempt(
67 | failure = Unit,
68 | number = 0,
69 | previousDelay = 0,
70 | cumulativeDelay = 0,
71 | )
72 |
73 | val instruction = policy(attempt)
74 |
75 | assertEquals(StopRetrying, instruction)
76 | }
77 |
78 | @Test
79 | fun stopAtDelayStopsAboveMaximum() {
80 | val policy = constantDelay(300).stopAtDelay(150)
81 |
82 | val attempt = FailedAttempt(
83 | failure = Unit,
84 | number = 0,
85 | previousDelay = 0,
86 | cumulativeDelay = 0,
87 | )
88 |
89 | val instruction = policy(attempt)
90 |
91 | assertEquals(StopRetrying, instruction)
92 | }
93 |
94 | @Test
95 | fun stopAtCumulativeDelayContinuesUnderMaximum() {
96 | val policy = constantDelay(20).stopAtCumulativeDelay(50)
97 |
98 | val attempt = FailedAttempt(
99 | failure = Unit,
100 | number = 1,
101 | previousDelay = 20,
102 | cumulativeDelay = 20,
103 | )
104 |
105 | val instruction = policy(attempt)
106 |
107 | assertEquals(RetryAfter(20), instruction)
108 | }
109 |
110 | @Test
111 | fun stopAtCumulativeDelayStopsAtMaximum() {
112 | val policy = constantDelay(40).stopAtCumulativeDelay(80)
113 |
114 | val attempt = FailedAttempt(
115 | failure = Unit,
116 | number = 2,
117 | previousDelay = 40,
118 | cumulativeDelay = 80,
119 | )
120 |
121 | val instruction = policy(attempt)
122 |
123 | assertEquals(StopRetrying, instruction)
124 | }
125 |
126 | @Test
127 | fun stopAtCumulativeDelayStopsAboveMaximum() {
128 | val policy = constantDelay(60).stopAtCumulativeDelay(150)
129 |
130 | val attempt = FailedAttempt(
131 | failure = Unit,
132 | number = 3,
133 | previousDelay = 60,
134 | cumulativeDelay = 180,
135 | )
136 |
137 | val instruction = policy(attempt)
138 |
139 | assertEquals(StopRetrying, instruction)
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/kotlin-retry/src/jvmTest/kotlin/com/github/michaelbull/retry/DispatcherTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.michaelbull.retry
2 |
3 | import com.github.michaelbull.retry.instruction.RetryAfter
4 | import com.github.michaelbull.retry.policy.RetryPolicy
5 | import com.github.michaelbull.retry.policy.plus
6 | import com.github.michaelbull.retry.policy.stopAtRetries
7 | import io.mockk.coVerifyOrder
8 | import io.mockk.spyk
9 | import kotlinx.coroutines.ExperimentalCoroutinesApi
10 | import kotlinx.coroutines.test.StandardTestDispatcher
11 | import kotlinx.coroutines.test.runTest
12 | import kotlin.test.Test
13 | import kotlin.test.fail
14 |
15 | @ExperimentalCoroutinesApi
16 | class DispatcherTest {
17 |
18 | private data class AttemptsException(val attempts: Int) : Exception()
19 |
20 | @Test
21 | fun retryDelaysCoroutineDispatcher() {
22 | val dispatcher = spyk(StandardTestDispatcher())
23 |
24 | var attempts = 0
25 |
26 | val backoff = RetryPolicy { attempt ->
27 | when (attempt.number) {
28 | 0 -> RetryAfter(1000L)
29 | 1 -> RetryAfter(2000L)
30 | 2 -> RetryAfter(3000L)
31 | 3 -> RetryAfter(4000L)
32 | else -> fail()
33 | }
34 | }
35 |
36 | val policy = backoff + stopAtRetries(4)
37 |
38 | runTest(dispatcher) {
39 | retry(policy) {
40 | attempts++
41 |
42 | if (attempts <= 4) {
43 | throw AttemptsException(attempts)
44 | }
45 | }
46 | }
47 |
48 | coVerifyOrder {
49 | dispatcher.scheduleResumeAfterDelay(1000, any())
50 | dispatcher.scheduleResumeAfterDelay(2000, any())
51 | dispatcher.scheduleResumeAfterDelay(3000, any())
52 | dispatcher.scheduleResumeAfterDelay(4000, any())
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | mavenCentral()
4 | gradlePluginPortal()
5 | }
6 | }
7 |
8 | plugins {
9 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
10 | }
11 |
12 | dependencyResolutionManagement {
13 | repositories {
14 | mavenCentral()
15 | }
16 | }
17 |
18 | rootProject.name = "kotlin-retry"
19 |
20 | include("kotlin-retry")
21 | include("kotlin-retry-result")
22 |
--------------------------------------------------------------------------------