From b534d62b30c5d774a822026509cc743332b6560f Mon Sep 17 00:00:00 2001 From: James Rodewig Date: Mon, 20 May 2024 13:13:49 -0400 Subject: [PATCH] Move streaming to GA (#262) Co-authored-by: Paul Paterson Co-authored-by: Lucas Pedroza --- README.md | 146 +- .../stream-client-configuration.test.ts | 71 + __tests__/integration/doc.test.ts | 16 +- __tests__/integration/query.test.ts | 77 +- __tests__/integration/set.test.ts | 6 +- __tests__/integration/stream.test.ts | 484 ++++++ __tests__/integration/template-format.test.ts | 70 +- __tests__/unit/doc.test.ts | 18 + __tests__/unit/error.test.ts | 96 ++ __tests__/unit/query.test.ts | 65 +- __tests__/unit/tagged-format.test.ts | 50 +- concourse/pipeline.yml | 44 +- package.json | 21 +- src/client-configuration.ts | 43 + src/client.ts | 441 ++++-- src/errors.ts | 132 +- src/http-client/fetch-client.ts | 116 +- src/http-client/http-client.ts | 41 +- src/http-client/index.ts | 22 +- src/http-client/node-http2-client.ts | 150 +- src/index.ts | 13 +- src/query-builder.ts | 13 +- src/tagged-type.ts | 39 +- src/util/package-version.ts | 2 +- src/values/doc.ts | 19 +- src/values/index.ts | 1 + src/values/stream.ts | 26 + src/wire-protocol.ts | 28 +- yarn.lock | 1344 ++++++----------- 29 files changed, 2406 insertions(+), 1188 deletions(-) create mode 100644 __tests__/functional/stream-client-configuration.test.ts create mode 100644 __tests__/integration/stream.test.ts create mode 100644 __tests__/unit/error.test.ts create mode 100644 src/values/stream.ts diff --git a/README.md b/README.md index f695c0f2..6945b1ed 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additio - [Query options](#query-options) - [Query statistics](#query-statistics) - [Pagination](#pagination) - - [Event Streaming (beta)](#event-streaming-beta) - [Client configuration](#client-configuration) - [Environment variables](#environment-variables) - [Retry](#retry) @@ -29,6 +28,11 @@ See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additio - [Query timeout](#query-timeout) - [Client timeout](#client-timeout) - [HTTP/2 session idle timeout](#http2-session-idle-timeout) + - [Event Streaming](#event-streaming) + - [Start a stream](#start-a-stream) + - [Iterate on a stream](#iterate-on-a-stream) + - [Close a stream](#close-a-stream) + - [Stream options](#stream-options) - [Contributing](#contributing) - [Set up the repo](#set-up-the-repo) - [Run tests](#run-tests) @@ -312,16 +316,6 @@ for await (const products of pages) { client.close(); ``` - -## Event Streaming (beta) - -[Event Streaming](https://docs.fauna.com/fauna/current/learn/streaming) is -currently available in the beta version of the driver: - -- [Beta JavaScript driver](https://www.npmjs.com/package/fauna/v/1.4.0-beta.0) -- [Beta JavaScript driver docs](https://github.com/fauna/fauna-js/tree/beta) - - ## Client configuration The driver's `Client` instance comes with reasonable defaults that should be @@ -443,6 +437,136 @@ const client = new Client({ http2_session_idle_ms: 6000 }); > **Warning** > Setting `http2_session_idle_ms` to small values can lead to a race condition where requests cannot be transmitted before the session is closed, yielding `ERR_HTTP2_GOAWAY_SESSION` errors. +## Event Streaming + +The driver supports [Event Streaming](https://docs.fauna.com/fauna/current/learn/streaming). + +### Start a stream + +To get a stream token, append +[`toStream()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/tostream) +or +[`changesOn()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/changeson) +to a set from a [supported +source](https://docs.fauna.com/fauna/current/reference/streaming_reference/#supported-sources). + +To start and subscribe to the stream, pass the stream token to `Client.stream()`: + +```javascript +const response = await client.query(fql` + let set = Product.all() + + { + initialPage: set.pageSize(10), + streamToken: set.toStream() + } +`); +const { initialPage, streamToken } = response.data; + +client.stream(streamToken) +``` + +You can also pass a query that produces a stream token directly to `Client.stream()`: + +```javascript +const query = fql`Product.all().changesOn(.price, .quantity)` + +client.stream(query) +``` + +### Iterate on a stream + +You can iterate on the stream using an async loop: + +```javascript +try { + for await (const event of stream) { + switch (event.type) { + case "update": + case "add": + case "remove": + console.log("Stream event:", event); + // ... + break; + } + } +} catch (error) { + // An error will be handled here if Fauna returns a terminal, "error" event, or + // if Fauna returns a non-200 response when trying to connect, or + // if the max number of retries on network errors is reached. + + // ... handle fatal error +} +``` + +Or you can use a callback function: + +```javascript +stream.start( + function onEvent(event) { + switch (event.type) { + case "update": + case "add": + case "remove": + console.log("Stream event:", event); + // ... + break; + } + }, + function onFatalError(error) { + // An error will be handled here if Fauna returns a terminal, "error" event, or + // if Fauna returns a non-200 response when trying to connect, or + // if the max number of retries on network errors is reached. + + // ... handle fatal error + } +); +``` + +### Close a stream + +Use `.close()` to close a stream: + +```javascript +const stream = await client.stream(fql`Product.all().toStream()`) + +let count = 0; +for await (const event of stream) { + console.log("Stream event:", event); + // ... + count++; + + // Close the stream after 2 events + if (count === 2) { + stream.close() + break; + } +} +``` + +### Stream options + +The [client configuration](#client-configuration) sets default options for the +`Client.stream()` method. + +You can pass an `options` object to override these defaults: + +```javascript +const options = { + long_type: "number", + max_attempts: 5, + max_backoff: 1000, + secret: "YOUR_FAUNA_SECRET", + status_events: true, +}; + +client.stream(fql`Product.all().toStream()`, options) +``` + +For supported properties, see [Stream +options](https://docs.fauna.com/fauna/current/drivers/js-client#stream-options) +in the Fauna docs. + ## Contributing diff --git a/__tests__/functional/stream-client-configuration.test.ts b/__tests__/functional/stream-client-configuration.test.ts new file mode 100644 index 00000000..00fa3bec --- /dev/null +++ b/__tests__/functional/stream-client-configuration.test.ts @@ -0,0 +1,71 @@ +import { + StreamClient, + StreamToken, + getDefaultHTTPClient, + StreamClientConfiguration, +} from "../../src"; +import { getDefaultHTTPClientOptions } from "../client"; + +const defaultHttpClient = getDefaultHTTPClient(getDefaultHTTPClientOptions()); +const defaultConfig: StreamClientConfiguration = { + secret: "secret", + long_type: "number", + max_attempts: 3, + max_backoff: 20, + httpStreamClient: defaultHttpClient, +}; +const dummyStreamToken = new StreamToken("dummy"); + +describe("StreamClientConfiguration", () => { + it("can be instantiated directly with a token", () => { + new StreamClient(dummyStreamToken, defaultConfig); + }); + + it("can be instantiated directly with a lambda", async () => { + new StreamClient(() => Promise.resolve(dummyStreamToken), defaultConfig); + }); + + it.each` + fieldName + ${"long_type"} + ${"httpStreamClient"} + ${"max_backoff"} + ${"max_attempts"} + ${"secret"} + `( + "throws a TypeError if $fieldName provided is undefined", + async ({ fieldName }: { fieldName: keyof StreamClientConfiguration }) => { + expect.assertions(1); + + const config = { ...defaultConfig }; + delete config[fieldName]; + try { + new StreamClient(dummyStreamToken, config); + } catch (e: any) { + expect(e).toBeInstanceOf(TypeError); + } + }, + ); + + it("throws a RangeError if 'max_backoff' is less than or equal to zero", async () => { + expect.assertions(1); + + const config = { ...defaultConfig, max_backoff: 0 }; + try { + new StreamClient(dummyStreamToken, config); + } catch (e: any) { + expect(e).toBeInstanceOf(RangeError); + } + }); + + it("throws a RangeError if 'max_attempts' is less than or equal to zero", async () => { + expect.assertions(1); + + const config = { ...defaultConfig, max_attempts: 0 }; + try { + new StreamClient(dummyStreamToken, config); + } catch (e: any) { + expect(e).toBeInstanceOf(RangeError); + } + }); +}); diff --git a/__tests__/integration/doc.test.ts b/__tests__/integration/doc.test.ts index 9dae4dce..b6df40d1 100644 --- a/__tests__/integration/doc.test.ts +++ b/__tests__/integration/doc.test.ts @@ -138,11 +138,23 @@ describe("querying for doc types", () => { expect(result.data.module).toBeInstanceOf(Module); expect(result.data.document).toBeInstanceOf(Document); expect(result.data.document.documentReference).toBeInstanceOf( - DocumentReference + DocumentReference, ); expect(result.data.document.namedDocumentReference).toBeInstanceOf( - NamedDocumentReference + NamedDocumentReference, ); expect(result.data.namedDocument).toBeInstanceOf(NamedDocument); }); + + it("can set and read ttl", async () => { + const queryBuilder = fql`${testDoc}`; + const result = await client.query(queryBuilder); + + expect(result.data.ttl).toBeUndefined(); + + const queryBuilderUpdate = fql`${testDoc}.update({ ttl: Time.now().add(1, "day") })`; + const resultUpdate = await client.query(queryBuilderUpdate); + + expect(resultUpdate.data.ttl).toBeInstanceOf(TimeStub); + }); }); diff --git a/__tests__/integration/query.test.ts b/__tests__/integration/query.test.ts index 57ffe28e..3ceac266 100644 --- a/__tests__/integration/query.test.ts +++ b/__tests__/integration/query.test.ts @@ -127,13 +127,13 @@ describe("query", () => { expect(req.headers[expectedHeader.key]).toBe(expectedHeader.value); }); expect(req.headers["x-driver-env"]).toEqual( - expect.stringContaining("driver=") + expect.stringContaining("driver="), ); expect(req.headers["x-driver-env"]).toEqual( - expect.stringContaining("os=") + expect.stringContaining("os="), ); expect(req.headers["x-driver-env"]).toEqual( - expect.stringContaining("runtime=") + expect.stringContaining("runtime="), ); return dummyResponse; }, @@ -150,33 +150,31 @@ describe("query", () => { const headers = { [fieldName]: fieldValue }; await myClient.query(fql`"taco".length`, headers); myClient.close(); - } + }, ); - it( - "respects typechecked: undefined", async () => { - const httpClient: HTTPClient = { - async request(req) { - const contains = new Set(Object.keys(req.headers)).has("x-typecheck"); - expect(contains).toBe(false); - return dummyResponse; - }, - close() {}, - }; - - let clientConfiguration: Partial = { - typecheck: true, - }; - let myClient = getClient(clientConfiguration, httpClient); - await myClient.query(fql`"taco".length`, { typecheck: undefined }); - myClient.close(); + it("respects typechecked: undefined", async () => { + const httpClient: HTTPClient = { + async request(req) { + const contains = new Set(Object.keys(req.headers)).has("x-typecheck"); + expect(contains).toBe(false); + return dummyResponse; + }, + close() {}, + }; - clientConfiguration = { typecheck: undefined }; - myClient = getClient(clientConfiguration, httpClient); - await myClient.query(fql`"taco".length`); - myClient.close(); - } - ); + let clientConfiguration: Partial = { + typecheck: true, + }; + let myClient = getClient(clientConfiguration, httpClient); + await myClient.query(fql`"taco".length`, { typecheck: undefined }); + myClient.close(); + + clientConfiguration = { typecheck: undefined }; + myClient = getClient(clientConfiguration, httpClient); + await myClient.query(fql`"taco".length`); + myClient.close(); + }); it("can send arguments directly", async () => { const foo = { @@ -234,10 +232,10 @@ describe("query", () => { expect.assertions(6); try { await client.query( - fql`Function.create({"name": "my_double", "body": "x => x * 2"})` + fql`Function.create({"name": "my_double", "body": "x => x * 2"})`, ); await client.query( - fql`Function.create({"name": "my_double", "body": "x => x * 2"})` + fql`Function.create({"name": "my_double", "body": "x => x * 2"})`, ); } catch (e) { if (e instanceof ServiceError) { @@ -266,7 +264,7 @@ describe("query", () => { data: "{}" as unknown as QueryRequest, }; return getDefaultHTTPClient(getDefaultHTTPClientOptions()).request( - bad_req + bad_req, ); }, close() {}, @@ -307,7 +305,7 @@ describe("query", () => { } catch (e) { if (e instanceof QueryTimeoutError) { expect(e.message).toEqual( - expect.stringContaining("aggressive deadline") + expect.stringContaining("aggressive deadline"), ); expect(e.httpStatus).toBe(440); expect(e.code).toBe("time_out"); @@ -366,7 +364,7 @@ describe("query", () => { }); it("throws a NetworkError on client timeout", async () => { - expect.assertions(2); + expect.assertions(3); const httpClient = getDefaultHTTPClient(getDefaultHTTPClientOptions()); const badHTTPClient = { @@ -384,6 +382,7 @@ describe("query", () => { try { await badClient.query(fql``); } catch (e: any) { + expect(e).toBeInstanceOf(NetworkError); if (e instanceof NetworkError) { expect(e.message).toBe("The network connection encountered a problem."); expect(e.cause).toBeDefined(); @@ -403,7 +402,7 @@ describe("query", () => { { query_timeout_ms: 60, }, - httpClient + httpClient, ); try { await badClient.query(fql`foo`); @@ -411,7 +410,7 @@ describe("query", () => { if (e instanceof ClientError) { expect(e.cause).toBeDefined(); expect(e.message).toBe( - "A client level error occurred. Fauna was not called." + "A client level error occurred. Fauna was not called.", ); } } finally { @@ -440,13 +439,13 @@ describe("query", () => { it("session is closed regardless of number of clients", async () => { const httpClient1 = NodeHTTP2Client.getClient( - getDefaultHTTPClientOptions() + getDefaultHTTPClientOptions(), ); const httpClient2 = NodeHTTP2Client.getClient( - getDefaultHTTPClientOptions() + getDefaultHTTPClientOptions(), ); const httpClient3 = NodeHTTP2Client.getClient( - getDefaultHTTPClientOptions() + getDefaultHTTPClientOptions(), ); const client1 = getClient({}, httpClient1); const client2 = getClient({}, httpClient2); @@ -500,7 +499,7 @@ describe("query can encode / decode QueryValue correctly", () => { }; // Do not use a dynamic Collection name by using `${new Module(collectionName)}`. See ENG-5003 const docCreated = await client.query( - fql`UndefinedTest.create(${toughInput})` + fql`UndefinedTest.create(${toughInput})`, ); expect(docCreated.data.should_exist).toBeUndefined(); expect(docCreated.data.nested_object.i_dont_exist).toBeUndefined(); @@ -519,7 +518,7 @@ describe("query can encode / decode QueryValue correctly", () => { if (e instanceof TypeError) { expect(e.name).toBe("TypeError"); expect(e.message).toBe( - "Passing undefined as a QueryValue is not supported" + "Passing undefined as a QueryValue is not supported", ); } } diff --git a/__tests__/integration/set.test.ts b/__tests__/integration/set.test.ts index a68a9bbb..49698fed 100644 --- a/__tests__/integration/set.test.ts +++ b/__tests__/integration/set.test.ts @@ -36,10 +36,10 @@ describe("SetIterator", () => { beforeAll(async () => { await client.query(fql` if (Collection.byName("IterTestSmall") != null) { - IterTestSmall.definition.delete() + Collection.byName("IterTestSmall")!.delete() } if (Collection.byName("IterTestBig") != null) { - IterTestBig.definition.delete() + Collection.byName("IterTestBig")!.delete() } `); await client.query(fql` @@ -220,7 +220,7 @@ describe("SetIterator", () => { fql`IterTestBig.all()`, { query_timeout_ms: 12345, - } + }, ); const page = response.data; const setIterator = testClient.paginate(page, { diff --git a/__tests__/integration/stream.test.ts b/__tests__/integration/stream.test.ts new file mode 100644 index 00000000..11b6a5b2 --- /dev/null +++ b/__tests__/integration/stream.test.ts @@ -0,0 +1,484 @@ +import { + AbortError, + Client, + DocumentT, + DateStub, + Document, + InvalidRequestError, + StreamClient, + StreamClientConfiguration, + StreamToken, + TimeStub, + fql, + getDefaultHTTPClient, + QueryRuntimeError, +} from "../../src"; +import { + getClient, + getDefaultHTTPClientOptions, + getDefaultSecretAndEndpoint, +} from "../client"; + +const defaultHttpClient = getDefaultHTTPClient(getDefaultHTTPClientOptions()); +const { secret } = getDefaultSecretAndEndpoint(); + +let client: Client; +const STREAM_DB_NAME = "StreamTestDB"; +const STREAM_SECRET = `${secret}:${STREAM_DB_NAME}:admin`; +const defaultStreamConfig: StreamClientConfiguration = { + secret: STREAM_SECRET, + long_type: "number", + max_attempts: 3, + max_backoff: 20, + httpStreamClient: defaultHttpClient, +}; + +type StreamTest = { value: number }; + +beforeAll(async () => { + const rootClient = getClient(); + + // create a child database to use for Streams, since streaming FF will not + // work on the root database + await rootClient.query(fql` + if (Database.byName(${STREAM_DB_NAME}) == null) { + Database.create({ name: ${STREAM_DB_NAME} }) + } + `); + + // scope the client to the child db + client = getClient({ secret: STREAM_SECRET }); + + await client.query(fql` + if (Collection.byName("StreamTest") != null) { + Collection.byName("StreamTest")!.delete() + } + `); + await client.query(fql` + Collection.create({ name: "StreamTest" }) + `); +}); + +afterAll(() => { + if (client) { + client.close(); + } +}); + +describe("Client", () => { + it("can initiate a stream from a Client", async () => { + expect.assertions(1); + + let stream: StreamClient | null = null; + try { + const response = await client.query( + fql`StreamTest.all().toStream()`, + ); + const token = response.data; + + stream = client.stream(token, { status_events: true }); + + for await (const event of stream) { + expect(event.type).toEqual("status"); + break; + } + } finally { + stream?.close(); + } + }); + + it("can initiate a stream from a Client, providing a query", async () => { + expect.assertions(1); + + let stream: StreamClient | null = null; + try { + stream = client.stream(fql`StreamTest.all().toStream()`, { + status_events: true, + }); + + for await (const event of stream) { + expect(event.type).toEqual("status"); + break; + } + } finally { + stream?.close(); + } + }); +}); + +describe("StreamClient", () => { + it("can initiate a stream", async () => { + expect.assertions(1); + + let stream: StreamClient | null = null; + try { + const response = await client.query( + fql`StreamTest.all().toStream()`, + ); + const token = response.data; + + stream = new StreamClient(token, { + ...defaultStreamConfig, + status_events: true, + }); + + for await (const event of stream) { + expect(event.type).toEqual("status"); + break; + } + } finally { + stream?.close(); + } + }); + + it("can initiate a stream with a lambda", async () => { + expect.assertions(1); + + let stream: StreamClient | null = null; + try { + const getToken = async () => { + const response = await client.query( + fql`StreamTest.all().toStream()`, + ); + return response.data; + }; + + stream = new StreamClient(getToken, { + ...defaultStreamConfig, + status_events: true, + }); + + for await (const event of stream) { + expect(event.type).toEqual("status"); + break; + } + } finally { + stream?.close(); + } + }); + + it("can get events with async iterator", async () => { + expect.assertions(2); + + let stream: StreamClient> | null = null; + try { + const response = await client.query( + fql`StreamTest.all().toStream()`, + ); + const token = response.data; + + stream = new StreamClient(token, defaultStreamConfig); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + await client.query(fql`StreamTest.create({ value: 1 })`); + + let count = 0; + for await (const event of stream) { + if (event.type == "add") { + if (count === 0) { + expect(event.data.value).toEqual(0); + } else { + expect(event.data.value).toEqual(1); + break; + } + } + count++; + } + } finally { + stream?.close(); + } + }); + + it("can get events with callbacks", async () => { + expect.assertions(2); + + const response = await client.query( + fql`StreamTest.all().toStream()`, + ); + const token = response.data; + + const stream = new StreamClient>( + token, + defaultStreamConfig, + ); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + await client.query(fql`StreamTest.create({ value: 1 })`); + + let resolve: () => void; + const promise = new Promise((res) => { + resolve = () => res(null); + }); + + let count = 0; + stream.start(function onEvent(event) { + if (event.type == "add") { + if (count === 0) { + expect(event.data.value).toEqual(0); + } else { + expect(event.data.value).toEqual(1); + stream.close(); + resolve(); + } + } + count++; + }); + + await promise; + }); + + it("catches InvalidRequestError when establishing a stream", async () => { + expect.assertions(1); + + try { + // create a stream with a bad token + const stream = new StreamClient( + new StreamToken("2"), + defaultStreamConfig, + ); + + for await (const _ of stream) { + /* do nothing */ + } + } catch (e) { + expect(e).toBeInstanceOf(InvalidRequestError); + } + }); + + it("handles InvalidRequestError via callback when establishing a stream", async () => { + expect.assertions(1); + + // create a stream with a bad token + const stream = new StreamClient(new StreamToken("2"), defaultStreamConfig); + + let resolve: () => void; + const promise = new Promise((res) => { + resolve = () => res(null); + }); + + stream.start( + function onEvent(_) {}, + function onError(e) { + expect(e).toBeInstanceOf(InvalidRequestError); + resolve(); + }, + ); + + await promise; + }); + + it("catches an AbortError if abort is called when processing an event", async () => { + expect.assertions(3); + + let stream: StreamClient> | null = null; + try { + const response = await client.query( + fql`StreamTest.all().map((doc) => abort("oops")).toStream()`, + ); + const token = response.data; + + stream = new StreamClient(token, defaultStreamConfig); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + + for await (const _ of stream) { + /* do nothing */ + } + } catch (e: any) { + expect(e).toBeInstanceOf(AbortError); + expect(e.httpStatus).toBeUndefined(); + expect(e.abort).toBe("oops"); + } finally { + stream?.close(); + } + }); + + it("catches a QueryRuntimeError when processing an event", async () => { + expect.assertions(2); + + let stream: StreamClient> | null = null; + try { + const response = await client.query( + fql`StreamTest.all().map((doc) => notARealFn(doc)).toStream()`, + ); + const token = response.data; + + stream = new StreamClient(token, defaultStreamConfig); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + + for await (const _ of stream) { + /* do nothing */ + } + } catch (e: any) { + expect(e).toBeInstanceOf(QueryRuntimeError); + expect(e.httpStatus).toBeUndefined(); + } finally { + stream?.close(); + } + }); + + it("handles an AbortError via callback if abort is called when processing an event", async () => { + expect.assertions(2); + + const response = await client.query( + fql`StreamTest.all().map((doc) => abort("oops")).toStream()`, + ); + const token = response.data; + + const stream = new StreamClient>( + token, + defaultStreamConfig, + ); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + + let resolve: () => void; + const promise = new Promise((res) => { + resolve = () => res(null); + }); + + stream.start( + function onEvent(_) {}, + function onError(e) { + if (e instanceof AbortError) { + expect(e.httpStatus).toBeUndefined(); + expect(e.abort).toBe("oops"); + } + resolve(); + }, + ); + + await promise; + }); + + it("handles a QueryRuntimeError via callback when processing an event", async () => { + expect.assertions(1); + + const response = await client.query( + fql`StreamTest.all().map((doc) => notARealFn(doc)).toStream()`, + ); + const token = response.data; + + const stream = new StreamClient>( + token, + defaultStreamConfig, + ); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + + let resolve: () => void; + const promise = new Promise((res) => { + resolve = () => res(null); + }); + + stream.start( + function onEvent(_) {}, + function onError(e) { + if (e instanceof QueryRuntimeError) { + expect(e.httpStatus).toBeUndefined(); + } + resolve(); + }, + ); + + await promise; + }); + + it("decodes values from streams correctly", async () => { + expect.assertions(5); + + let stream: StreamClient | null = null; + let stream2: StreamClient | null = null; + try { + const response = await client.query( + fql`StreamTest.all().map((doc) => { + time: Time.now(), + date: Date.today(), + doc: doc, + bigInt: 922337036854775808, + }).toStream()`, + ); + const token = response.data; + + stream = new StreamClient(token, defaultStreamConfig); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + + for await (const event of stream) { + if (event.type == "add") { + const data = event.data; + expect(data.time).toBeInstanceOf(TimeStub); + expect(data.date).toBeInstanceOf(DateStub); + expect(data.doc).toBeInstanceOf(Document); + expect(typeof data.bigInt).toBe("number"); + } + break; + } + + stream2 = new StreamClient(token, { + ...defaultStreamConfig, + long_type: "bigint", + }); + + for await (const event of stream2) { + if (event.type == "add") { + const data = event.data; + expect(typeof data.bigInt).toBe("bigint"); + } + break; + } + } finally { + stream?.close(); + stream2?.close(); + } + }); + + it("yields all events when Fauna sends them as a single chunk", async () => { + // This test has a chance of creating a false positive. Since we are not in + // control of the actual stream, we will use a query that has been shown to + // behave how we expect MOST of the time. + // This test will not create a false negative. + expect.assertions(6); + + let stream: StreamClient> | null = null; + try { + // clear the collection + await client.query(fql`StreamTest.all().forEach(.delete())`); + + const response = await client.query( + fql`StreamTest.all().toStream()`, + ); + const token = response.data; + + stream = new StreamClient(token, defaultStreamConfig); + + // create some events that will be played back + await client.query(fql`StreamTest.create({ value: 0 })`); + await client.query(fql`StreamTest.create({ value: 1 })`); + await client.query(fql`StreamTest.create({ value: 2 })`); + // This has a very high probability of creating multiple events sent as a single chunk + await client.query(fql`StreamTest.all().forEach(.delete())`); + + let count = 0; + for await (const event of stream) { + if (event.type != "status") { + expect(event.data).toBeDefined(); + } + count++; + if (count === 6) { + break; + } + } + } finally { + stream?.close(); + } + }); +}); diff --git a/__tests__/integration/template-format.test.ts b/__tests__/integration/template-format.test.ts index 71bfb60a..8651666d 100644 --- a/__tests__/integration/template-format.test.ts +++ b/__tests__/integration/template-format.test.ts @@ -1,4 +1,4 @@ -import { fql } from "../../src"; +import { ClientError, fql, TimeStub } from "../../src"; import { getClient } from "../client"; const client = getClient({ @@ -118,4 +118,72 @@ describe("query using template format", () => { const response = await client.query(queryBuilder); expect(response.data).toBe("Hello, Alice"); }); + + it("succeeds with a Date arg", async () => { + const date = new Date(); + const queryBuilder = fql`${date}`; + const response = await client.query(queryBuilder); + expect(response.data.isoString).toBe(date.toISOString()); + }); + + it("succeeds with an ArrayBuffer variable", async () => { + const buf = new Uint8Array([1, 2, 3]); + const queryBuilder = fql`${buf.buffer}`; + const response = await client.query(queryBuilder); + expect(response.data.byteLength).toBe(3); + expect(response.data).toEqual(buf); + }); + + it("succeeds with Uint8Array variables", async () => { + const buf = new Uint8Array([1, 2, 3]); + const queryBuilder = fql`${buf}`; + const response = await client.query(queryBuilder); + expect(response.data.byteLength).toBe(3); + expect(response.data).toEqual(buf); + }); + + /** + * See table of various TypedArrays here + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#typedarray_objects + */ + it.each` + ViewType + ${Int8Array} + ${Uint8ClampedArray} + ${Int16Array} + ${Uint16Array} + ${Int32Array} + ${Uint32Array} + ${Float32Array} + ${Float64Array} + `("fails with $ViewType variables", async ({ ViewType }) => { + const buf = new ViewType([1, 2]); + + await expect(client.query(fql`${buf}`)).rejects.toThrow(ClientError); + }); + + /** + * See table of various TypedArrays here + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#typedarray_objects + */ + it.each` + ViewType + ${BigInt64Array} + ${BigUint64Array} + `("fails with $ViewType variables", async ({ ViewType }) => { + const buf = new ViewType([BigInt(1), BigInt(2)]); + + await expect(client.query(fql`${buf}`)).rejects.toThrow(ClientError); + }); + + it("succeeds using Node Buffer to encode strings", async () => { + const str = + "This is a test string 🚀 with various characters: !@#$%^&*()_+=-`~[]{}|;:'\",./<>?"; + const buf = Buffer.from(str); + const queryBuilder = fql`${buf}`; + const response = await client.query(queryBuilder); + + const decoded = Buffer.from(response.data).toString(); + expect(decoded).toBe(str); + }); }); diff --git a/__tests__/unit/doc.test.ts b/__tests__/unit/doc.test.ts index 0684b9c7..9593b648 100644 --- a/__tests__/unit/doc.test.ts +++ b/__tests__/unit/doc.test.ts @@ -38,6 +38,24 @@ describe("Document", () => { expect(doc.ts.isoString).toBe("2023-10-16T00:00:00Z"); }); + it("can access ttl", () => { + const doc = new Document({ + coll: new Module("User"), + id: "1234", + ts: TimeStub.from("2023-03-09T00:00:00Z"), + }); + + const doc_w_ttl = new Document({ + coll: new Module("User"), + id: "1234", + ts: TimeStub.from("2023-03-09T00:00:00Z"), + ttl: TimeStub.from("2023-03-10T00:00:00Z"), + }); + + expect(doc.ttl).toBeUndefined(); + expect(doc_w_ttl.ttl).toBeInstanceOf(TimeStub); + }); + it("can access user data", () => { const doc = new Document({ coll: new Module("User"), diff --git a/__tests__/unit/error.test.ts b/__tests__/unit/error.test.ts new file mode 100644 index 00000000..370b565b --- /dev/null +++ b/__tests__/unit/error.test.ts @@ -0,0 +1,96 @@ +import { + AbortError, + AuthenticationError, + AuthorizationError, + ConstraintFailureError, + ContendedTransactionError, + InvalidRequestError, + QueryCheckError, + QueryFailure, + QueryRuntimeError, + QueryTimeoutError, + ServiceInternalError, + ThrottlingError, +} from "../../src"; +import { getServiceError } from "../../src/errors"; + +describe("query", () => { + it.each` + httpStatus | code | errorClass + ${400} | ${"invalid_query"} | ${QueryCheckError} + ${400} | ${"unbound_variable"} | ${QueryRuntimeError} + ${400} | ${"index_out_of_bounds"} | ${QueryRuntimeError} + ${400} | ${"type_mismatch"} | ${QueryRuntimeError} + ${400} | ${"invalid_argument"} | ${QueryRuntimeError} + ${400} | ${"invalid_bounds"} | ${QueryRuntimeError} + ${400} | ${"invalid_regex"} | ${QueryRuntimeError} + ${400} | ${"invalid_schema"} | ${QueryRuntimeError} + ${400} | ${"invalid_document_id"} | ${QueryRuntimeError} + ${400} | ${"document_id_exists"} | ${QueryRuntimeError} + ${400} | ${"document_not_found"} | ${QueryRuntimeError} + ${400} | ${"document_deleted"} | ${QueryRuntimeError} + ${400} | ${"invalid_function_invocation"} | ${QueryRuntimeError} + ${400} | ${"invalid_index_invocation"} | ${QueryRuntimeError} + ${400} | ${"null_value"} | ${QueryRuntimeError} + ${400} | ${"invalid_null_access"} | ${QueryRuntimeError} + ${400} | ${"invalid_cursor"} | ${QueryRuntimeError} + ${400} | ${"permission_denied"} | ${QueryRuntimeError} + ${400} | ${"invalid_effect"} | ${QueryRuntimeError} + ${400} | ${"invalid_write"} | ${QueryRuntimeError} + ${400} | ${"internal_failure"} | ${QueryRuntimeError} + ${400} | ${"divide_by_zero"} | ${QueryRuntimeError} + ${400} | ${"invalid_id"} | ${QueryRuntimeError} + ${400} | ${"invalid_secret"} | ${QueryRuntimeError} + ${400} | ${"invalid_time"} | ${QueryRuntimeError} + ${400} | ${"invalid_unit"} | ${QueryRuntimeError} + ${400} | ${"invalid_date"} | ${QueryRuntimeError} + ${400} | ${"limit_exceeded"} | ${QueryRuntimeError} + ${400} | ${"stack_overflow"} | ${QueryRuntimeError} + ${400} | ${"invalid_computed_field_access"} | ${QueryRuntimeError} + ${400} | ${"disabled_feature"} | ${QueryRuntimeError} + ${400} | ${"invalid_receiver"} | ${QueryRuntimeError} + ${400} | ${"invalid_timestamp_field_access"} | ${QueryRuntimeError} + ${400} | ${"invalid_request"} | ${InvalidRequestError} + ${400} | ${"abort"} | ${AbortError} + ${400} | ${"constraint_failure"} | ${ConstraintFailureError} + ${401} | ${"unauthorized"} | ${AuthenticationError} + ${403} | ${"forbidden"} | ${AuthorizationError} + ${409} | ${"contended_transaction"} | ${ContendedTransactionError} + ${429} | ${"throttle"} | ${ThrottlingError} + ${440} | ${"time_out"} | ${QueryTimeoutError} + ${503} | ${"time_out"} | ${QueryTimeoutError} + ${500} | ${"internal_error"} | ${ServiceInternalError} + ${400} | ${"some unhandled code"} | ${QueryRuntimeError} + ${401} | ${"some unhandled code"} | ${QueryRuntimeError} + ${403} | ${"some unhandled code"} | ${QueryRuntimeError} + ${409} | ${"some unhandled code"} | ${QueryRuntimeError} + ${429} | ${"some unhandled code"} | ${QueryRuntimeError} + ${440} | ${"some unhandled code"} | ${QueryRuntimeError} + ${500} | ${"some unhandled code"} | ${QueryRuntimeError} + ${503} | ${"some unhandled code"} | ${QueryRuntimeError} + ${999} | ${"some unhandled code"} | ${QueryRuntimeError} + ${undefined} | ${"some unhandled code"} | ${QueryRuntimeError} + `( + "QueryFailures with status '$httpStatus' and code '$code' are correctly mapped to $errorClass", + ({ httpStatus, code, errorClass }) => { + const failure: QueryFailure = { + error: { + message: "error message", + code, + abort: "oops", + constraint_failures: [{ message: "oops" }], + }, + }; + + const error = getServiceError(failure, httpStatus); + expect(error).toBeInstanceOf(errorClass); + expect(error.httpStatus).toEqual(httpStatus); + expect(error.code).toEqual(code); + + const error_no_status = getServiceError(failure); + expect(error_no_status).toBeInstanceOf(errorClass); + expect(error_no_status.httpStatus).toBeUndefined(); + expect(error_no_status.code).toEqual(code); + }, + ); +}); diff --git a/__tests__/unit/query.test.ts b/__tests__/unit/query.test.ts index 5bd728e9..7d80bb74 100644 --- a/__tests__/unit/query.test.ts +++ b/__tests__/unit/query.test.ts @@ -8,7 +8,6 @@ import { QueryTimeoutError, ServiceError, ServiceInternalError, - ServiceTimeoutError, ThrottlingError, } from "../../src"; import { getClient, getDefaultHTTPClientOptions } from "../client"; @@ -22,7 +21,7 @@ const client = getClient( query_timeout_ms: 60, }, // use the FetchClient implementation, so we can mock requests - new FetchClient(getDefaultHTTPClientOptions()) + new FetchClient(getDefaultHTTPClientOptions()), ); describe("query", () => { @@ -30,15 +29,15 @@ describe("query", () => { fetchMock.resetMocks(); }); - // do not treat these codes as canonical. Refer to documentation. These are simply for logical testing. + // Error handling uses the code field to determine the error type. These codes must match the actual code expected from the API. it.each` httpStatus | expectedErrorType | expectedErrorFields - ${403} | ${AuthorizationError} | ${{ code: "no_permission", message: "nope" }} - ${440} | ${QueryTimeoutError} | ${{ code: "query_timeout", message: "too slow - increase your timeout" }} + ${403} | ${AuthorizationError} | ${{ code: "forbidden", message: "nope" }} + ${440} | ${QueryTimeoutError} | ${{ code: "time_out", message: "too slow - increase your timeout" }} ${999} | ${ServiceError} | ${{ code: "error_not_yet_subclassed_in_client", message: "who knows!!!" }} ${429} | ${ThrottlingError} | ${{ code: "throttle", message: "too much" }} ${500} | ${ServiceInternalError} | ${{ code: "internal_error", message: "unexpected error" }} - ${503} | ${ServiceTimeoutError} | ${{ code: "service_timeout", message: "too slow on our side" }} + ${503} | ${QueryTimeoutError} | ${{ code: "time_out", message: "too slow on our side" }} `( "throws an $expectedErrorType on a $httpStatus", async ({ httpStatus, expectedErrorType, expectedErrorFields }) => { @@ -56,56 +55,18 @@ describe("query", () => { expect(e.code).toEqual(expectedErrorFields.code); } } - } + }, ); - // do not treat these codes as canonical. Refer to documentation. These are simply for logical testing. + // Error handling uses the code field to determine the error type. These codes must match the actual code expected from the API. it.each` httpStatus | expectedErrorType | expectedErrorFields - ${403} | ${AuthorizationError} | ${{ code: "no_permission", message: "nope", summary: "the summary" }} - ${440} | ${QueryTimeoutError} | ${{ code: "query_timeout", message: "too slow - increase your timeout", summary: "the summary" }} - ${999} | ${ServiceError} | ${{ code: "error_not_yet_subclassed_in_client", message: "who knows!!!", summary: "the summary" }} - ${429} | ${ThrottlingError} | ${{ code: "throttle", message: "too much", summary: "the summary" }} - ${500} | ${ServiceInternalError} | ${{ code: "internal_error", message: "unexpected error", summary: "the summary" }} - ${503} | ${ServiceTimeoutError} | ${{ code: "service_timeout", message: "too slow on our side", summary: "the summary" }} - `( - "Includes a summary when present in error field", - async ({ httpStatus, expectedErrorType, expectedErrorFields }) => { - expect.assertions(5); - fetchMock.mockResponse( - JSON.stringify({ - error: { - code: expectedErrorFields.code, - message: expectedErrorFields.message, - }, - summary: expectedErrorFields.summary, - }), - { - status: httpStatus, - } - ); - try { - await client.query(fql`'foo'.length`); - } catch (e) { - if (e instanceof ServiceError) { - expect(e).toBeInstanceOf(expectedErrorType); - expect(e.message).toEqual(expectedErrorFields.message); - expect(e.httpStatus).toEqual(httpStatus); - expect(e.code).toEqual(expectedErrorFields.code); - expect(e.queryInfo?.summary).toEqual(expectedErrorFields.summary); - } - } - } - ); - - it.each` - httpStatus | expectedErrorType | expectedErrorFields - ${403} | ${AuthorizationError} | ${{ code: "no_permission", message: "nope" }} - ${440} | ${QueryTimeoutError} | ${{ code: "query_timeout", message: "too slow - increase your timeout" }} + ${403} | ${AuthorizationError} | ${{ code: "forbidden", message: "nope" }} + ${440} | ${QueryTimeoutError} | ${{ code: "time_out", message: "too slow - increase your timeout" }} ${999} | ${ServiceError} | ${{ code: "error_not_yet_subclassed_in_client", message: "who knows!!!" }} ${429} | ${ThrottlingError} | ${{ code: "throttle", message: "too much" }} ${500} | ${ServiceInternalError} | ${{ code: "internal_error", message: "unexpected error" }} - ${503} | ${ServiceTimeoutError} | ${{ code: "service_timeout", message: "too slow on our side" }} + ${503} | ${QueryTimeoutError} | ${{ code: "time_out", message: "too slow on our side" }} `( "Includes a summary when not present in error field but present at top-level", async ({ httpStatus, expectedErrorType, expectedErrorFields }) => { @@ -117,7 +78,7 @@ describe("query", () => { }), { status: httpStatus, - } + }, ); try { @@ -131,7 +92,7 @@ describe("query", () => { expect(e.queryInfo?.summary).toEqual("the summary"); } } - } + }, ); it("retries throttling errors and then succeeds", async () => { @@ -146,7 +107,7 @@ describe("query", () => { [ JSON.stringify({ data: 3, summary: "the summary", stats: {} }), { status: 200 }, - ] + ], ); const actual = await client.query(fql`'foo'.length`); expect(actual.data).toEqual(3); diff --git a/__tests__/unit/tagged-format.test.ts b/__tests__/unit/tagged-format.test.ts index 573181f1..6778ca56 100644 --- a/__tests__/unit/tagged-format.test.ts +++ b/__tests__/unit/tagged-format.test.ts @@ -14,6 +14,18 @@ import { EmbeddedSet, } from "../../src"; +const testBytesString = + "This is a test string 🚀 with various characters: !@#$%^&*()_+=-`~[]{}|;:'\",./<>?"; +const testBuffer = Buffer.from(testBytesString); +const testBytesBase64 = Buffer.from(testBytesString).toString("base64"); + +const testArrayBufferU8 = new ArrayBuffer(4); +const testArrayBufferViewU8 = new Uint8Array(testArrayBufferU8); +testArrayBufferViewU8[1] = 1; +testArrayBufferViewU8[2] = 2; +testArrayBufferViewU8[3] = 3; +testArrayBufferViewU8[4] = 4; + describe.each` long_type ${"number"} @@ -79,7 +91,8 @@ describe.each` } }, "page": { "@set": { "data": ["a", "b"] } }, - "embeddedSet": { "@set": "abc123" } + "embeddedSet": { "@set": "abc123" }, + "bytes": { "@bytes": "${testBytesBase64}" } }`; const bugs_mod = new Module("Bugs"); @@ -125,7 +138,9 @@ describe.each` expect(result.measurements[1].time).toBeInstanceOf(TimeStub); expect(result.molecules).toEqual( // eslint-disable-next-line @typescript-eslint/no-loss-of-precision - long_type === "number" ? 999999999999999999 : BigInt("999999999999999999") + long_type === "number" + ? 999999999999999999 + : BigInt("999999999999999999"), ); expect(result.null).toBeNull(); expect(result.mod).toStrictEqual(bugs_mod); @@ -136,6 +151,7 @@ describe.each` expect(result.nullDoc).toStrictEqual(nullDoc); expect(result.page).toStrictEqual(page); expect(result.embeddedSet).toStrictEqual(embeddedSet); + expect(Buffer.from(result.bytes).toString()).toEqual(testBytesString); }); it("can be encoded", () => { @@ -188,14 +204,17 @@ describe.each` }), nullDoc: new NullDocument( new DocumentReference({ coll: bugs_mod, id: "123" }), - "not found" + "not found", ), + bytes_array_buffer: testArrayBufferU8, + bytes_array_buffer_view_u8: testArrayBufferViewU8, + bytes_from_string: testBuffer, // Set types // TODO: uncomment to add test once core accepts `@set` tagged values // page: new Page({ data: ["a", "b"] }), // TODO: uncomment to add test once core accepts `@set` tagged values // page_string: new Page({ after: "abc123" }), - }) + }), ); const backToObj = JSON.parse(result)["@object"]; @@ -225,6 +244,15 @@ describe.each` expect(backToObj.nullDoc).toStrictEqual({ "@ref": { coll: { "@mod": "Bugs" }, id: "123" }, }); + expect(backToObj.bytes_array_buffer).toStrictEqual({ + "@bytes": Buffer.from(testArrayBufferU8).toString("base64"), + }); + expect(backToObj.bytes_array_buffer_view_u8).toStrictEqual({ + "@bytes": Buffer.from(testArrayBufferViewU8).toString("base64"), + }); + expect(backToObj.bytes_from_string).toStrictEqual({ + "@bytes": testBytesBase64, + }); // Set types // TODO: uncomment to add test once core accepts `@set` tagged values // expect(backToObj.page).toStrictEqual({ "@set": { data: ["a", "b"] } }); @@ -264,10 +292,10 @@ describe.each` "@time": new Date("2022-12-02T02:00:00.000Z"), }, }, - }) - ) + }), + ), ).toEqual( - '{"@object":{"@date":{"@object":{"@date":{"@object":{"@time":{"@time":"2022-12-02T02:00:00.000Z"}}}}}}}' + '{"@object":{"@date":{"@object":{"@date":{"@object":{"@time":{"@time":"2022-12-02T02:00:00.000Z"}}}}}}}', ); }); @@ -276,8 +304,8 @@ describe.each` JSON.stringify( TaggedTypeFormat.encode({ "@foo": true, - }) - ) + }), + ), ).toEqual('{"@object":{"@foo":true}}'); }); @@ -318,11 +346,11 @@ describe.each` expect(encodedKey).toEqual(tag); const decoded = TaggedTypeFormat.decode( JSON.stringify(encoded), - decodeOptions + decodeOptions, ); expect(typeof decoded).toBe(expectedType); expect(decoded).toEqual(expected); - } + }, ); it.each` diff --git a/concourse/pipeline.yml b/concourse/pipeline.yml index 591de2e0..9ac007df 100644 --- a/concourse/pipeline.yml +++ b/concourse/pipeline.yml @@ -19,16 +19,16 @@ resources: source: uri: git@github.com:fauna/fauna-js.git branch: main -# tag_filter: v* + # tag_filter: v* private_key: ((github-ssh-key)) - + - name: beta.git type: git icon: github source: uri: git@github.com:fauna/fauna-js.git branch: beta -# tag_filter: v* + # tag_filter: v* private_key: ((github-ssh-key)) - name: testtools-repo @@ -123,7 +123,8 @@ jobs: - task: query-limits-tests privileged: true file: main.git/concourse/tasks/query-limits-tests.yml - input_mapping: {repo.git: main.git, testtools-repo: testtools-repo} + input_mapping: + { repo.git: main.git, testtools-repo: testtools-repo } params: QUERY_LIMITS_DB: limited QUERY_LIMITS_COLL: limitCollection @@ -146,7 +147,7 @@ jobs: - task: integration-tests file: main.git/concourse/tasks/integration-tests.yml - input_mapping: {repo.git: main.git} + input_mapping: { repo.git: main.git } privileged: true on_success: put: notify @@ -159,7 +160,7 @@ jobs: - task: publish file: main.git/concourse/tasks/npm-publish.yml - input_mapping: {repo.git: main.git} + input_mapping: { repo.git: main.git } params: NPM_TOKEN: ((npm_token)) NPM_TAG: latest @@ -220,7 +221,8 @@ jobs: - task: query-limits-tests privileged: true file: beta.git/concourse/tasks/query-limits-tests.yml - input_mapping: {repo.git: beta.git, testtools-repo: testtools-repo} + input_mapping: + { repo.git: beta.git, testtools-repo: testtools-repo } params: QUERY_LIMITS_DB: limited QUERY_LIMITS_COLL: limitCollection @@ -239,24 +241,22 @@ jobs: plan: - get: beta.git passed: - - set-self - -# - task: integration-tests -# file: beta.git/concourse/tasks/integration-tests.yml -# input_mapping: {repo.git: beta.git} -# privileged: true -# on_success: -# put: notify -# params: -# text: "fauna-js driver release passed integration tests" -# on_failure: -# put: notify -# params: -# text: fauna-js driver release failed integration tests + # - task: integration-tests + # file: beta.git/concourse/tasks/integration-tests.yml + # input_mapping: {repo.git: beta.git} + # privileged: true + # on_success: + # put: notify + # params: + # text: "fauna-js driver release passed integration tests" + # on_failure: + # put: notify + # params: + # text: fauna-js driver release failed integration tests - task: publish file: beta.git/concourse/tasks/npm-publish.yml - input_mapping: {repo.git: beta.git} + input_mapping: { repo.git: beta.git } params: NPM_TOKEN: ((npm_token)) NPM_TAG: beta diff --git a/package.json b/package.json index 46fa068f..ee241bb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fauna", - "version": "1.3.1", + "version": "2.0.0", "description": "A driver to query Fauna databases in browsers, Node.js, and other Javascript runtimes", "homepage": "https://fauna.com", "bugs": { @@ -18,23 +18,23 @@ "author": "Fauna", "devDependencies": { "@tsconfig/node18": "^1.0.1", - "@types/jest": "^29.4.0", + "@types/jest": "^29.5.12", "@types/node": "^18.13.0", "@types/serviceworker": "^0.0.67", - "@typescript-eslint/eslint-plugin": "^5.52.0", - "@typescript-eslint/parser": "^5.52.0", + "@typescript-eslint/eslint-plugin": "^7.5.0", + "@typescript-eslint/parser": "^7.5.0", "esbuild": "^0.15.12", - "eslint": "^8.25.0", + "eslint": "^8.57.0", "eslint-plugin-tsdoc": "^0.2.17", "husky": "^8.0.1", "jest": "^29.7.0", "jest-fetch-mock": "^3.0.3", "jest-junit": "^16.0.0", - "prettier": "^2.7.1", - "pretty-quick": "^3.1.3", + "prettier": "^3.2.5", + "pretty-quick": "^4.0.0", "ts-jest": "^29.1.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.4" + "ts-node": "^10.9.2", + "typescript": "^5.4.3" }, "scripts": { "build": "rm -rf dist; yarn build:node; yarn build:browser; yarn build:types", @@ -58,5 +58,8 @@ "suiteNameTemplate": "{filepath}", "classNameTemplate": "{classname}", "titleTemplate": "{title}" + }, + "dependencies": { + "base64-js": "^1.5.1" } } diff --git a/src/client-configuration.ts b/src/client-configuration.ts index 9da4801a..dbeaaf92 100644 --- a/src/client-configuration.ts +++ b/src/client-configuration.ts @@ -1,3 +1,4 @@ +import { HTTPStreamClient } from "./http-client"; import type { ValueFormat } from "./wire-protocol"; /** @@ -155,6 +156,48 @@ export interface Endpoints { [key: string]: URL; } +/** + * Configuration for a streaming client. This typically comes from the `Client` + * instance configuration. + */ +export type StreamClientConfiguration = { + /** + * The underlying {@link HTTPStreamClient} that will execute the actual HTTP calls + */ + httpStreamClient: HTTPStreamClient; + + /** + * Controls what Javascript type to deserialize {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#long | Fauna longs} to. + * + * @see {@link ClientConfiguration.long_type} + */ + long_type: "number" | "bigint"; + + /** + * Max attempts for retryable exceptions. + */ + max_attempts: number; + + /** + * Max backoff between retries. + */ + max_backoff: number; + + /** + * A secret for your Fauna DB, used to authorize your queries. + * @see https://docs.fauna.com/fauna/current/security/keys + */ + secret: string; + + /** + * Indicates if stream should include "status" events, periodic events that + * update the client with the latest valid timestamp (in the event of a + * dropped connection) as well as metrics about about the cost of maintaining + * the stream other than the cost of the received events. + */ + status_events?: boolean; +}; + /** * A extensible set of endpoints for calling Fauna. * @remarks Most clients will will not need to extend this set. diff --git a/src/client.ts b/src/client.ts index 2f5f85d8..986e8e49 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,36 +1,37 @@ -import { ClientConfiguration, endpoints } from "./client-configuration"; import { - AuthenticationError, - AuthorizationError, + ClientConfiguration, + StreamClientConfiguration, + endpoints, +} from "./client-configuration"; +import { ClientClosedError, ClientError, + FaunaError, NetworkError, ProtocolError, - AbortError, - QueryCheckError, - QueryRuntimeError, - QueryTimeoutError, ServiceError, - ServiceInternalError, - ServiceTimeoutError, ThrottlingError, - ContendedTransactionError, - InvalidRequestError, + getServiceError, } from "./errors"; import { + HTTPStreamClient, + StreamAdapter, getDefaultHTTPClient, + isStreamClient, isHTTPResponse, type HTTPClient, } from "./http-client"; import { Query } from "./query-builder"; import { TaggedTypeFormat } from "./tagged-type"; import { getDriverEnv } from "./util/environment"; -import { EmbeddedSet, Page, SetIterator } from "./values"; +import { EmbeddedSet, Page, SetIterator, StreamToken } from "./values"; import { isQueryFailure, isQuerySuccess, QueryInterpolation, - type QueryFailure, + StreamEvent, + StreamEventData, + StreamEventStatus, type QueryOptions, type QuerySuccess, type QueryValue, @@ -80,7 +81,7 @@ export class Client { /** The {@link ClientConfiguration} */ readonly #clientConfiguration: RequiredClientConfig; /** The underlying {@link HTTPClient} client. */ - readonly #httpClient: HTTPClient; + readonly #httpClient: HTTPClient & Partial; /** The last transaction timestamp this client has seen */ #lastTxnTs?: number; /** true if this client is closed false otherwise */ @@ -103,7 +104,7 @@ export class Client { */ constructor( clientConfiguration?: ClientConfiguration, - httpClient?: HTTPClient + httpClient?: HTTPClient, ) { this.#clientConfiguration = { ...DEFAULT_CLIENT_CONFIG, @@ -159,7 +160,7 @@ export class Client { close() { if (this.#isClosed) { throw new ClientClosedError( - "Your client is closed. You cannot close it again." + "Your client is closed. You cannot close it again.", ); } this.#httpClient.close(); @@ -210,7 +211,7 @@ export class Client { */ paginate( iterable: Page | EmbeddedSet | Query, - options?: QueryOptions + options?: QueryOptions, ): SetIterator { if (iterable instanceof Query) { return SetIterator.fromQuery(this, iterable, options); @@ -232,10 +233,7 @@ export class Client { * * @throws {@link ServiceError} Fauna emitted an error. The ServiceError will be * one of ServiceError's child classes if the error can be further categorized, - * or a concrete ServiceError if it cannot. ServiceError child types are - * {@link AuthenticaionError}, {@link AuthorizationError}, {@link QueryCheckError} - * {@link QueryRuntimeError}, {@link QueryTimeoutError}, {@link ServiceInternalError} - * {@link ServiceTimeoutError}, {@link ThrottlingError}. + * or a concrete ServiceError if it cannot. * You can use either the type, or the underlying httpStatus + code to determine * the root cause. * @throws {@link ProtocolError} the client a HTTP error not sent by Fauna. @@ -247,11 +245,11 @@ export class Client { */ async query( query: Query, - options?: QueryOptions + options?: QueryOptions, ): Promise> { if (this.#isClosed) { throw new ClientClosedError( - "Your client is closed. No further requests can be issued." + "Your client is closed. No further requests can be issued.", ); } @@ -264,10 +262,95 @@ export class Client { return this.#queryWithRetries(queryInterpolation, options); } + /** + * Initialize a streaming request to Fauna + * @param query - A string-encoded streaming token, or a {@link Query} + * @returns A {@link StreamClient} that which can be used to listen to a stream + * of events + * + * @example + * ```javascript + * const stream = client.stream(fql`MyCollection.all().toStream()`) + * + * try { + * for await (const event of stream) { + * switch (event.type) { + * case "update": + * case "add": + * case "remove": + * console.log("Stream update:", event); + * // ... + * break; + * } + * } + * } catch (error) { + * // An error will be handled here if Fauna returns a terminal, "error" event, or + * // if Fauna returns a non-200 response when trying to connect, or + * // if the max number of retries on network errors is reached. + * + * // ... handle fatal error + * }; + * ``` + * + * @example + * ```javascript + * const stream = client.stream(fql`MyCollection.all().toStream()`) + * + * stream.start( + * function onEvent(event) { + * switch (event.type) { + * case "update": + * case "add": + * case "remove": + * console.log("Stream update:", event); + * // ... + * break; + * } + * }, + * function onError(error) { + * // An error will be handled here if Fauna returns a terminal, "error" event, or + * // if Fauna returns a non-200 response when trying to connect, or + * // if the max number of retries on network errors is reached. + * + * // ... handle fatal error + * } + * ); + * ``` + */ + stream( + tokenOrQuery: StreamToken | Query, + options?: Partial, + ): StreamClient { + if (this.#isClosed) { + throw new ClientClosedError( + "Your client is closed. No further requests can be issued.", + ); + } + + const streamClient = this.#httpClient; + + if (isStreamClient(streamClient)) { + const streamClientConfig: StreamClientConfiguration = { + ...this.#clientConfiguration, + httpStreamClient: streamClient, + ...options, + }; + + const tokenOrGetToken = + tokenOrQuery instanceof Query + ? () => this.query(tokenOrQuery).then((res) => res.data) + : tokenOrQuery; + + return new StreamClient(tokenOrGetToken, streamClientConfig); + } else { + throw new ClientError("Streaming is not supported by this client."); + } + } + async #queryWithRetries( queryInterpolation: string | QueryInterpolation, options?: QueryOptions, - attempt = 0 + attempt = 0, ): Promise> { const maxBackoff = this.clientConfiguration.max_backoff ?? DEFAULT_CLIENT_CONFIG.max_backoff; @@ -277,16 +360,17 @@ export class Client { const backoffMs = Math.min(Math.random() * 2 ** attempt, maxBackoff) * 1_000; - const wait = (ms: number) => new Promise((r) => setTimeout(r, ms)); attempt += 1; - return this.#query(queryInterpolation, options, attempt).catch((e) => { - if (e instanceof ThrottlingError && attempt < maxAttempts) { - return wait(backoffMs).then(() => - this.#queryWithRetries(queryInterpolation, options, attempt) - ); + + try { + return await this.#query(queryInterpolation, options, attempt); + } catch (error) { + if (error instanceof ThrottlingError && attempt < maxAttempts) { + await wait(backoffMs); + return this.#queryWithRetries(queryInterpolation, options, attempt); } - throw e; - }); + throw error; + } } #getError(e: any): ClientError | NetworkError | ProtocolError | ServiceError { @@ -306,7 +390,7 @@ export class Client { if (isQueryFailure(e.body)) { const failure = e.body; const status = e.status; - return this.#getServiceError(failure, status); + return getServiceError(failure, status); } // we got a different error from the protocol layer @@ -321,7 +405,7 @@ export class Client { "A client level error occurred. Fauna was not called.", { cause: e, - } + }, ); } @@ -342,7 +426,7 @@ export class Client { throw new TypeError( "You must provide a secret to the driver. Set it \ in an environmental variable named FAUNA_SECRET or pass it to the Client\ - constructor." + constructor.", ); } return maybeSecret; @@ -357,7 +441,7 @@ in an environmental variable named FAUNA_SECRET or pass it to the Client\ partialClientConfig.endpoint === undefined ) { throw new TypeError( - `ClientConfiguration option endpoint must be defined.` + `ClientConfiguration option endpoint must be defined.`, ); } @@ -377,48 +461,10 @@ in an environmental variable named FAUNA_SECRET or pass it to the Client\ return partialClientConfig?.endpoint ?? env_endpoint ?? endpoints.default; } - #getServiceError(failure: QueryFailure, httpStatus: number): ServiceError { - switch (httpStatus) { - case 400: - if (QUERY_CHECK_FAILURE_CODES.includes(failure.error.code)) { - return new QueryCheckError(failure, httpStatus); - } - if (failure.error.code === "invalid_request") { - return new InvalidRequestError(failure, httpStatus); - } - if ( - failure.error.code === "abort" && - failure.error.abort !== undefined - ) { - return new AbortError( - failure as QueryFailure & { error: { abort: QueryValue } }, - httpStatus - ); - } - return new QueryRuntimeError(failure, httpStatus); - case 401: - return new AuthenticationError(failure, httpStatus); - case 403: - return new AuthorizationError(failure, httpStatus); - case 409: - return new ContendedTransactionError(failure, httpStatus); - case 429: - return new ThrottlingError(failure, httpStatus); - case 440: - return new QueryTimeoutError(failure, httpStatus); - case 500: - return new ServiceInternalError(failure, httpStatus); - case 503: - return new ServiceTimeoutError(failure, httpStatus); - default: - return new ServiceError(failure, httpStatus); - } - } - async #query( queryInterpolation: string | QueryInterpolation, options?: QueryOptions, - attempt = 0 + attempt = 0, ): Promise> { try { const requestConfig = { @@ -505,12 +551,12 @@ in an environmental variable named FAUNA_SECRET or pass it to the Client\ #setHeaders( fromObject: QueryOptions, - headerObject: Record + headerObject: Record, ): void { const setHeader = ( header: string, value: V | undefined, - transform: (v: V) => string | number = (v) => String(v) + transform: (v: V) => string | number = (v) => String(v), ) => { if (value !== undefined) { headerObject[header] = transform(value); @@ -526,7 +572,7 @@ in an environmental variable named FAUNA_SECRET or pass it to the Client\ setHeader("x-query-tags", fromObject.query_tags, (tags) => Object.entries(tags) .map((tag) => tag.join("=")) - .join(",") + .join(","), ); setHeader("x-last-txn-ts", this.#lastTxnTs, (v) => v); // x-last-txn-ts doesn't get stringified setHeader("x-driver-env", Client.#driverEnvHeader); @@ -544,11 +590,13 @@ in an environmental variable named FAUNA_SECRET or pass it to the Client\ "query_timeout_ms", "fetch_keepalive", "http2_max_streams", + "max_backoff", + "max_attempts", ]; required_options.forEach((option) => { if (config[option] === undefined) { throw new TypeError( - `ClientConfiguration option '${option}' must be defined.` + `ClientConfiguration option '${option}' must be defined.`, ); } }); @@ -559,22 +607,241 @@ in an environmental variable named FAUNA_SECRET or pass it to the Client\ if (config.client_timeout_buffer_ms <= 0) { throw new RangeError( - `'client_timeout_buffer_ms' must be greater than zero.` + `'client_timeout_buffer_ms' must be greater than zero.`, ); } if (config.query_timeout_ms <= 0) { throw new RangeError(`'query_timeout_ms' must be greater than zero.`); } + + if (config.max_backoff <= 0) { + throw new RangeError(`'max_backoff' must be greater than zero.`); + } + + if (config.max_attempts <= 0) { + throw new RangeError(`'max_attempts' must be greater than zero.`); + } + } +} + +/** + * A class to listen to Fauna streams. + */ +export class StreamClient { + /** Whether or not this stream has been closed */ + closed = false; + /** The stream client options */ + #clientConfiguration: StreamClientConfiguration; + /** A tracker for the number of connection attempts */ + #connectionAttempts = 0; + /** A lambda that returns a promise for a {@link StreamToken} */ + #query: () => Promise; + /** The last `txn_ts` value received from events */ + #last_ts?: number; + /** A common interface to operate a stream from any HTTPStreamClient */ + #streamAdapter?: StreamAdapter; + /** A saved copy of the StreamToken once received */ + #streamToken?: StreamToken; + + /** + * + * @param query - A lambda that returns a promise for a {@link StreamToken} + * @param clientConfiguration - The {@link ClientConfiguration} to apply + * @param httpStreamClient - The underlying {@link HTTPStreamClient} that will + * execute the actual HTTP calls + * @example + * ```typescript + * const streamClient = client.stream(streamToken); + * ``` + */ + constructor( + token: StreamToken | (() => Promise), + clientConfiguration: StreamClientConfiguration, + ) { + if (token instanceof StreamToken) { + this.#query = () => Promise.resolve(token); + } else { + this.#query = token; + } + + this.#clientConfiguration = clientConfiguration; + + this.#validateConfiguration(); + } + + /** + * A synchronous method to start listening to the stream and handle events + * using callbacks. + * @param onEvent - A callback function to handle each event + * @param onError - An Optional callback function to handle errors. If none is + * provided, error will not be handled, and the stream will simply end. + */ + start( + onEvent: (event: StreamEventData | StreamEventStatus) => void, + onError?: (error: Error) => void, + ) { + if (typeof onEvent !== "function") { + throw new TypeError( + `Expected a function as the 'onEvent' argument, but received ${typeof onEvent}. Please provide a valid function.`, + ); + } + if (onError && typeof onError !== "function") { + throw new TypeError( + `Expected a function as the 'onError' argument, but received ${typeof onError}. Please provide a valid function.`, + ); + } + const run = async () => { + try { + for await (const event of this) { + onEvent(event); + } + } catch (error) { + if (onError) { + onError(error as Error); + } + } + }; + run(); + } + + async *[Symbol.asyncIterator](): AsyncGenerator< + StreamEventData | StreamEventStatus + > { + if (this.closed) { + throw new ClientError("The stream has been closed and cannot be reused."); + } + + if (!this.#streamToken) { + this.#streamToken = await this.#query().then((maybeStreamToken) => { + if (!(maybeStreamToken instanceof StreamToken)) { + throw new ClientError( + `Error requesting a stream token. Expected a StreamToken as the query result, but received ${typeof maybeStreamToken}. Your query must return the result of '.toStream' or '.changesOn')\n` + + `Query result: ${JSON.stringify(maybeStreamToken, null)}`, + ); + } + return maybeStreamToken; + }); + } + + this.#connectionAttempts = 1; + while (!this.closed) { + const backoffMs = + Math.min( + Math.random() * 2 ** this.#connectionAttempts, + this.#clientConfiguration.max_backoff, + ) * 1_000; + + try { + for await (const event of this.#startStream(this.#last_ts)) { + yield event; + } + } catch (error: any) { + if ( + error instanceof FaunaError || + this.#connectionAttempts >= this.#clientConfiguration.max_attempts + ) { + // A terminal error from Fauna + this.close(); + throw error; + } + + this.#connectionAttempts += 1; + await wait(backoffMs); + } + } + } + + close() { + if (this.#streamAdapter) { + this.#streamAdapter.close(); + this.#streamAdapter = undefined; + } + this.closed = true; + } + + get last_ts(): number | undefined { + return this.#last_ts; + } + + async *#startStream( + start_ts?: number, + ): AsyncGenerator | StreamEventStatus> { + // Safety: This method must only be called after a stream token has been acquired + const streamToken = this.#streamToken as StreamToken; + + const headers = { + Authorization: `Bearer ${this.#clientConfiguration.secret}`, + }; + + const streamAdapter = this.#clientConfiguration.httpStreamClient.stream({ + data: { token: streamToken.token, start_ts }, + headers, + method: "POST", + }); + + this.#streamAdapter = streamAdapter; + + for await (const event of streamAdapter.read) { + // stream events are always tagged + const deserializedEvent: StreamEvent = TaggedTypeFormat.decode(event, { + long_type: this.#clientConfiguration.long_type, + }); + + if (deserializedEvent.type === "error") { + // Errors sent from Fauna are assumed fatal + this.close(); + throw getServiceError(deserializedEvent); + } + + this.#last_ts = deserializedEvent.txn_ts; + + // TODO: remove this once all environments have updated the events to use "status" instead of "start" + if ((deserializedEvent.type as any) === "start") { + deserializedEvent.type = "status"; + } + + if ( + !this.#clientConfiguration.status_events && + deserializedEvent.type === "status" + ) { + continue; + } + + yield deserializedEvent; + } + } + + #validateConfiguration() { + const config = this.#clientConfiguration; + + const required_options: (keyof StreamClientConfiguration)[] = [ + "long_type", + "httpStreamClient", + "max_backoff", + "max_attempts", + "secret", + ]; + required_options.forEach((option) => { + if (config[option] === undefined) { + throw new TypeError( + `ClientConfiguration option '${option}' must be defined.`, + ); + } + }); + + if (config.max_backoff <= 0) { + throw new RangeError(`'max_backoff' must be greater than zero.`); + } + + if (config.max_attempts <= 0) { + throw new RangeError(`'max_attempts' must be greater than zero.`); + } } } // Private types and constants for internal logic. -const QUERY_CHECK_FAILURE_CODES = [ - "invalid_function_definition", - "invalid_identifier", - "invalid_query", - "invalid_syntax", - "invalid_type", -]; +function wait(ms: number) { + return new Promise((r) => setTimeout(r, ms)); +} diff --git a/src/errors.ts b/src/errors.ts index 0a8b4a56..f0947e6f 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -21,7 +21,7 @@ export class ServiceError extends FaunaError { /** * The HTTP Status Code of the error. */ - readonly httpStatus: number; + readonly httpStatus?: number; /** * A code for the error. Codes indicate the cause of the error. * It is safe to write programmatic logic against the code. They are @@ -38,7 +38,7 @@ export class ServiceError extends FaunaError { */ readonly constraint_failures?: Array; - constructor(failure: QueryFailure, httpStatus: number) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure.error.message); // Maintains proper stack trace for where our error was thrown (only available on V8) @@ -69,7 +69,7 @@ export class ServiceError extends FaunaError { * The 'code' field will vary based on the specific error cause. */ export class QueryRuntimeError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 400) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, QueryRuntimeError); @@ -85,7 +85,7 @@ export class QueryRuntimeError extends ServiceError { * failing. */ export class QueryCheckError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 400) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, QueryCheckError); @@ -99,7 +99,7 @@ export class QueryCheckError extends ServiceError { * valid JSON or did not conform to the API specification */ export class InvalidRequestError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 400) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, InvalidRequestError); @@ -108,6 +108,30 @@ export class InvalidRequestError extends ServiceError { } } +/** + * A runtime error due to failing schema constraints. + */ +export class ConstraintFailureError extends ServiceError { + /** + * The list of constraints that failed. + */ + readonly constraint_failures: Array; + + constructor( + failure: QueryFailure & { + error: { constraint_failures: Array }; + }, + httpStatus?: number, + ) { + super(failure, httpStatus); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, QueryCheckError); + } + this.name = "ConstraintFailureError"; + this.constraint_failures = failure.error.constraint_failures; + } +} + /** * An error due to calling the FQL `abort` function. */ @@ -121,7 +145,7 @@ export class AbortError extends ServiceError { constructor( failure: QueryFailure & { error: { abort: QueryValue } }, - httpStatus: 400 + httpStatus?: number, ) { super(failure, httpStatus); if (Error.captureStackTrace) { @@ -137,7 +161,7 @@ export class AbortError extends ServiceError { * used. */ export class AuthenticationError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 401) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, AuthenticationError); @@ -151,7 +175,7 @@ export class AuthenticationError extends ServiceError { * permission to perform the requested action. */ export class AuthorizationError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 403) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, AuthorizationError); @@ -164,7 +188,7 @@ export class AuthorizationError extends ServiceError { * An error due to a contended transaction. */ export class ContendedTransactionError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 409) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, InvalidRequestError); @@ -178,7 +202,7 @@ export class ContendedTransactionError extends ServiceError { * and thus the request could not be served. */ export class ThrottlingError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 429) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, ThrottlingError); @@ -188,11 +212,16 @@ export class ThrottlingError extends ServiceError { } /** - * A failure due to the timeout being exceeded, but the timeout - * was set lower than the query's expected processing time. - * This response is distinguished from a ServiceTimeoutException - * in that a QueryTimeoutError shows Fauna behaving in an expected - * manner. + * A failure due to the query timeout being exceeded. + * + * This error can have one of two sources: + * 1. Fauna is behaving expectedly, but the query timeout provided was too + * aggressive and lower than the query's expected processing time. + * 2. Fauna was not available to service the request before the timeout was + * reached. + * + * In either case, consider increasing the `query_timeout_ms` configuration for + * your client. */ export class QueryTimeoutError extends ServiceError { /** @@ -200,7 +229,7 @@ export class QueryTimeoutError extends ServiceError { */ readonly stats?: { [key: string]: number }; - constructor(failure: QueryFailure, httpStatus: 440) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, QueryTimeoutError); @@ -214,7 +243,7 @@ export class QueryTimeoutError extends ServiceError { * ServiceInternalError indicates Fauna failed unexpectedly. */ export class ServiceInternalError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 500) { + constructor(failure: QueryFailure, httpStatus?: number) { super(failure, httpStatus); if (Error.captureStackTrace) { Error.captureStackTrace(this, ServiceInternalError); @@ -223,20 +252,6 @@ export class ServiceInternalError extends ServiceError { } } -/** - * ServiceTimeoutError indicates Fauna was not available to servce - * the request before the timeout was reached. - */ -export class ServiceTimeoutError extends ServiceError { - constructor(failure: QueryFailure, httpStatus: 503) { - super(failure, httpStatus); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, ServiceTimeoutError); - } - this.name = "ServiceTimeoutError"; - } -} - /** * An error representing a failure internal to the client, itself. * This indicates Fauna was never called - the client failed internally @@ -304,3 +319,58 @@ export class ProtocolError extends FaunaError { this.httpStatus = error.httpStatus; } } + +export const getServiceError = ( + failure: QueryFailure, + httpStatus?: number, +): ServiceError => { + const failureCode = failure.error.code; + + switch (failureCode) { + case "invalid_query": + return new QueryCheckError(failure, httpStatus); + + case "invalid_request": + return new InvalidRequestError(failure, httpStatus); + + case "abort": + if (failure.error.abort !== undefined) { + return new AbortError( + failure as QueryFailure & { error: { abort: QueryValue } }, + httpStatus, + ); + } + break; + + case "constraint_failure": + if (failure.error.constraint_failures !== undefined) { + return new ConstraintFailureError( + failure as QueryFailure & { + error: { constraint_failures: Array }; + }, + httpStatus, + ); + } + break; + + case "unauthorized": + return new AuthenticationError(failure, httpStatus); + + case "forbidden": + return new AuthorizationError(failure, httpStatus); + + case "contended_transaction": + return new ContendedTransactionError(failure, httpStatus); + + case "throttle": + return new ThrottlingError(failure, httpStatus); + + case "time_out": + return new QueryTimeoutError(failure, httpStatus); + + case "internal_error": + return new ServiceInternalError(failure, httpStatus); + } + + return new QueryRuntimeError(failure, httpStatus); +}; diff --git a/src/http-client/fetch-client.ts b/src/http-client/fetch-client.ts index b4c1b721..619807cf 100644 --- a/src/http-client/fetch-client.ts +++ b/src/http-client/fetch-client.ts @@ -1,23 +1,29 @@ /** following reference needed to include types for experimental fetch API in Node */ /// -import { NetworkError } from "../errors"; +import { getServiceError, NetworkError } from "../errors"; +import { QueryFailure } from "../wire-protocol"; import { HTTPClient, HTTPClientOptions, HTTPRequest, HTTPResponse, + HTTPStreamRequest, + HTTPStreamClient, + StreamAdapter, } from "./http-client"; /** * An implementation for {@link HTTPClient} that uses the native fetch API */ -export class FetchClient implements HTTPClient { - #url: string; +export class FetchClient implements HTTPClient, HTTPStreamClient { + #queryURL: string; + #streamURL: string; #keepalive: boolean; constructor({ url, fetch_keepalive }: HTTPClientOptions) { - this.#url = new URL("/query/1", url).toString(); + this.#queryURL = new URL("/query/1", url).toString(); + this.#streamURL = new URL("/stream/1", url).toString(); this.#keepalive = fetch_keepalive; } @@ -38,7 +44,7 @@ export class FetchClient implements HTTPClient { })() : AbortSignal.timeout(client_timeout_ms); - const response = await fetch(this.#url, { + const response = await fetch(this.#queryURL, { method, headers: { ...requestHeaders, "Content-Type": "application/json" }, body: JSON.stringify(data), @@ -64,8 +70,108 @@ export class FetchClient implements HTTPClient { }; } + /** {@inheritDoc HTTPStreamClient.stream} */ + stream({ + data, + headers: requestHeaders, + method, + }: HTTPStreamRequest): StreamAdapter { + const request = new Request(this.#streamURL, { + method, + headers: { ...requestHeaders, "Content-Type": "application/json" }, + body: JSON.stringify(data), + keepalive: this.#keepalive, + }); + + const abortController = new AbortController(); + + const options = { + signal: abortController.signal, + }; + + async function* reader() { + const response = await fetch(request, options).catch((error) => { + throw new NetworkError( + "The network connection encountered a problem.", + { + cause: error, + }, + ); + }); + const status = response.status; + if (!(status >= 200 && status < 400)) { + const failure: QueryFailure = await response.json(); + throw getServiceError(failure, status); + } + + const body = response.body; + if (!body) { + throw new Error("Response body is undefined."); + } + const reader = body.getReader(); + + try { + for await (const line of readLines(reader)) { + yield line; + } + } catch (error) { + throw new NetworkError( + "The network connection encountered a problem while streaming events.", + { cause: error }, + ); + } + } + + return { + read: reader(), + close: () => { + abortController.abort("Stream closed by the client."); + }, + }; + } + /** {@inheritDoc HTTPClient.close} */ close() { // no actions at this time } } + +/** + * Get individual lines from the stream + * + * The stream may be broken into arbitrary chunks, but the events are delimited by a newline character. + * + * @param reader - The stream reader + */ +async function* readLines(reader: ReadableStreamDefaultReader) { + const textDecoder = new TextDecoder(); + let partOfLine = ""; + for await (const chunk of readChunks(reader)) { + const chunkText = textDecoder.decode(chunk); + const chunkLines = (partOfLine + chunkText).split("\n"); + + // Yield all complete lines + for (let i = 0; i < chunkLines.length - 1; i++) { + yield chunkLines[i].trim(); + } + + // Store the partial line + partOfLine = chunkLines[chunkLines.length - 1]; + } + + // Yield the remaining partial line if any + if (partOfLine.trim() !== "") { + yield partOfLine; + } +} + +async function* readChunks(reader: ReadableStreamDefaultReader) { + let done = false; + do { + const readResult = await reader.read(); + if (readResult.value !== undefined) { + yield readResult.value; + } + done = readResult.done; + } while (!done); +} diff --git a/src/http-client/http-client.ts b/src/http-client/http-client.ts index c36711f6..ca800184 100644 --- a/src/http-client/http-client.ts +++ b/src/http-client/http-client.ts @@ -1,6 +1,6 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars import type { Client } from "../client"; -import { QueryRequest } from "../wire-protocol"; +import { QueryRequest, StreamRequest } from "../wire-protocol"; /** * An object representing an http request. @@ -65,3 +65,42 @@ export interface HTTPClient { */ close(): void; } + +/** + * An object representing an http request. + * The {@link Client} provides this to the {@link HTTPStreamClient} implementation. + */ +export type HTTPStreamRequest = { + /** The encoded Fauna query to send */ + // TODO: Allow type to be a QueryRequest once implemented by the db + data: StreamRequest; + + /** Headers in object format */ + headers: Record; + + /** HTTP method to use */ + method: "POST"; +}; + +/** + * A common interface for a StreamClient to operate a stream from any HTTPStreamClient + */ +export interface StreamAdapter { + read: AsyncGenerator; + close: () => void; +} + +/** + * An interface to provide implementation-specific, asyncronous http calls. + * This driver provides default implementations for common environments. Users + * can configure the {@link Client} to use custom implementations if desired. + */ +export interface HTTPStreamClient { + /** + * Makes an HTTP request and returns the response + * @param req - an {@link HTTPStreamRequest} + * @returns A Promise<{@link HTTPResponse}> + * @throws {@link NetworkError} on request timeout or other network issue. + */ + stream(req: HTTPStreamRequest): StreamAdapter; +} diff --git a/src/http-client/index.ts b/src/http-client/index.ts index 4093d3ca..962b8bf5 100644 --- a/src/http-client/index.ts +++ b/src/http-client/index.ts @@ -1,13 +1,19 @@ import { FetchClient } from "./fetch-client"; -import { NodeHTTP2Client } from "./node-http2-client"; import { HTTPClient, HTTPClientOptions, - HTTPRequest, HTTPResponse, + HTTPStreamClient, } from "./http-client"; +import { NodeHTTP2Client } from "./node-http2-client"; + +export * from "./fetch-client"; +export * from "./http-client"; +export * from "./node-http2-client"; -export const getDefaultHTTPClient = (options: HTTPClientOptions): HTTPClient => +export const getDefaultHTTPClient = ( + options: HTTPClientOptions, +): HTTPClient & HTTPStreamClient => nodeHttp2IsSupported() ? NodeHTTP2Client.getClient(options) : new FetchClient(options); @@ -15,7 +21,13 @@ export const getDefaultHTTPClient = (options: HTTPClientOptions): HTTPClient => export const isHTTPResponse = (res: any): res is HTTPResponse => res instanceof Object && "body" in res && "headers" in res && "status" in res; -const nodeHttp2IsSupported = () => { +export const isStreamClient = ( + client: Partial, +): client is HTTPStreamClient => { + return "stream" in client && typeof client.stream === "function"; +}; + +export const nodeHttp2IsSupported = () => { if ( typeof process !== "undefined" && process && @@ -30,5 +42,3 @@ const nodeHttp2IsSupported = () => { } return false; }; - -export { FetchClient, NodeHTTP2Client, HTTPClient, HTTPRequest, HTTPResponse }; diff --git a/src/http-client/node-http2-client.ts b/src/http-client/node-http2-client.ts index ebd61bb6..9f69bedf 100644 --- a/src/http-client/node-http2-client.ts +++ b/src/http-client/node-http2-client.ts @@ -9,8 +9,12 @@ import { HTTPClientOptions, HTTPRequest, HTTPResponse, + HTTPStreamClient, + HTTPStreamRequest, + StreamAdapter, } from "./http-client"; -import { NetworkError } from "../errors"; +import { NetworkError, getServiceError } from "../errors"; +import { QueryFailure } from "../wire-protocol"; // alias http2 types type ClientHttp2Session = any; @@ -22,7 +26,7 @@ type OutgoingHttpHeaders = any; /** * An implementation for {@link HTTPClient} that uses the node http package */ -export class NodeHTTP2Client implements HTTPClient { +export class NodeHTTP2Client implements HTTPClient, HTTPStreamClient { static #clients: Map = new Map(); #http2_session_idle_ms: number; @@ -56,7 +60,7 @@ export class NodeHTTP2Client implements HTTPClient { if (!NodeHTTP2Client.#clients.has(clientKey)) { NodeHTTP2Client.#clients.set( clientKey, - new NodeHTTP2Client(httpClientOptions) + new NodeHTTP2Client(httpClientOptions), ); } // we know that we have a client here @@ -95,7 +99,7 @@ export class NodeHTTP2Client implements HTTPClient { "The network connection encountered a problem.", { cause: error, - } + }, ); } memoizedError = error; @@ -107,6 +111,11 @@ export class NodeHTTP2Client implements HTTPClient { }); } + /** {@inheritDoc HTTPStreamClient.stream} */ + stream(req: HTTPStreamRequest): StreamAdapter { + return this.#doStream(req); + } + /** {@inheritDoc HTTPClient.close} */ close() { // defend against redundant close calls @@ -161,16 +170,16 @@ export class NodeHTTP2Client implements HTTPClient { return new Promise((resolvePromise, rejectPromise) => { let req: ClientHttp2Stream; const onResponse = ( - http2ResponseHeaders: IncomingHttpHeaders & IncomingHttpStatusHeader + http2ResponseHeaders: IncomingHttpHeaders & IncomingHttpStatusHeader, ) => { const status = Number( - http2ResponseHeaders[http2.constants.HTTP2_HEADER_STATUS] + http2ResponseHeaders[http2.constants.HTTP2_HEADER_STATUS], ); let responseData = ""; // append response data to the data string every time we receive new // data chunks in the response - req.on("data", (chunk: any) => { + req.on("data", (chunk: string) => { responseData += chunk; }); @@ -196,7 +205,12 @@ export class NodeHTTP2Client implements HTTPClient { .request(httpRequestHeaders) .setEncoding("utf8") .on("error", (error: any) => { - rejectPromise(error); + rejectPromise( + new NetworkError( + "The network connection encountered a problem while streaming events.", + { cause: error }, + ), + ); }) .on("response", onResponse); @@ -209,8 +223,126 @@ export class NodeHTTP2Client implements HTTPClient { req.end(); } catch (error) { - rejectPromise(error); + rejectPromise( + new NetworkError( + "The network connection encountered a problem while streaming events.", + { cause: error }, + ), + ); } }); } + + /** {@inheritDoc HTTPStreamClient.stream} */ + #doStream({ + data: requestData, + headers: requestHeaders, + method, + }: HTTPStreamRequest): StreamAdapter { + let resolveChunk: (chunk: string[]) => void; + let rejectChunk: (reason: any) => void; + + const setChunkPromise = () => + new Promise((res, rej) => { + resolveChunk = res; + rejectChunk = rej; + }); + + let chunkPromise = setChunkPromise(); + + let req: ClientHttp2Stream; + const onResponse = ( + http2ResponseHeaders: IncomingHttpHeaders & IncomingHttpStatusHeader, + ) => { + const status = Number( + http2ResponseHeaders[http2.constants.HTTP2_HEADER_STATUS], + ); + if (!(status >= 200 && status < 400)) { + // Get the error body and then throw an error + let responseData = ""; + + // append response data to the data string every time we receive new + // data chunks in the response + req.on("data", (chunk: string) => { + responseData += chunk; + }); + + // Once the response is finished, resolve the promise + req.on("end", () => { + try { + const failure: QueryFailure = JSON.parse(responseData); + rejectChunk(getServiceError(failure, status)); + } catch (error) { + rejectChunk( + new NetworkError("Could not process query failure.", { + cause: error, + }), + ); + } + }); + } else { + let partOfLine = ""; + + // append response data to the data string every time we receive new + // data chunks in the response + req.on("data", (chunk: string) => { + const chunkLines = (partOfLine + chunk).split("\n"); + + // Yield all complete lines + resolveChunk(chunkLines.map((s) => s.trim()).slice(0, -1)); + chunkPromise = setChunkPromise(); + + // Store the partial line + partOfLine = chunkLines[chunkLines.length - 1]; + }); + + // Once the response is finished, resolve the promise + req.on("end", () => { + resolveChunk([partOfLine]); + }); + } + }; + + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + + async function* reader(): AsyncGenerator { + const httpRequestHeaders: OutgoingHttpHeaders = { + ...requestHeaders, + [http2.constants.HTTP2_HEADER_PATH]: "/stream/1", + [http2.constants.HTTP2_HEADER_METHOD]: method, + }; + + const session = self.#connect(); + req = session + .request(httpRequestHeaders) + .setEncoding("utf8") + .on("error", (error: any) => { + rejectChunk(error); + }) + .on("response", onResponse); + + const body = JSON.stringify(requestData); + + req.write(body, "utf8"); + + req.end(); + + while (true) { + const chunks = await chunkPromise; + for (const chunk of chunks) { + yield chunk; + } + } + } + + return { + read: reader(), + close: () => { + if (req) { + req.close(); + } + }, + }; + } } diff --git a/src/index.ts b/src/index.ts index 927c7858..7799cc89 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,9 @@ -export { Client } from "./client"; +export { Client, StreamClient } from "./client"; export { endpoints, type ClientConfiguration, type Endpoints, + type StreamClientConfiguration, } from "./client-configuration"; export { AbortError, @@ -10,6 +11,7 @@ export { AuthorizationError, ClientError, ClientClosedError, + ConstraintFailureError, ContendedTransactionError, FaunaError, InvalidRequestError, @@ -20,10 +22,9 @@ export { QueryTimeoutError, ServiceError, ServiceInternalError, - ServiceTimeoutError, ThrottlingError, } from "./errors"; -export { type Query, fql } from "./query-builder"; +export { type Query, type QueryArgument, fql } from "./query-builder"; export { LONG_MAX, LONG_MIN, TaggedTypeFormat } from "./tagged-type"; export { type QueryValueObject, @@ -42,7 +43,6 @@ export { DateStub, Document, DocumentReference, - type DocumentT, EmbeddedSet, Module, NamedDocument, @@ -50,14 +50,19 @@ export { NullDocument, Page, SetIterator, + StreamToken, TimeStub, + type DocumentT, } from "./values"; export { FetchClient, getDefaultHTTPClient, isHTTPResponse, + isStreamClient, NodeHTTP2Client, type HTTPClient, type HTTPRequest, type HTTPResponse, + type HTTPStreamClient, + type StreamAdapter, } from "./http-client"; diff --git a/src/query-builder.ts b/src/query-builder.ts index e8353379..b3c2f838 100644 --- a/src/query-builder.ts +++ b/src/query-builder.ts @@ -7,6 +7,13 @@ import type { QueryOptions, } from "./wire-protocol"; +export type QueryArgument = + | QueryValue + | Query + | Date + | ArrayBuffer + | Uint8Array; + /** * Creates a new Query. Accepts template literal inputs. * @param queryFragments - a {@link TemplateStringsArray} that constitute @@ -25,7 +32,7 @@ import type { */ export function fql( queryFragments: ReadonlyArray, - ...queryArgs: (QueryValue | Query)[] + ...queryArgs: QueryArgument[] ): Query { return new Query(queryFragments, ...queryArgs); } @@ -37,11 +44,11 @@ export function fql( */ export class Query { readonly #queryFragments: ReadonlyArray; - readonly #queryArgs: (QueryValue | Query)[]; + readonly #queryArgs: QueryArgument[]; constructor( queryFragments: ReadonlyArray, - ...queryArgs: (QueryValue | Query)[] + ...queryArgs: QueryArgument[] ) { if ( queryFragments.length === 0 || diff --git a/src/tagged-type.ts b/src/tagged-type.ts index c7f29a87..040c22e3 100644 --- a/src/tagged-type.ts +++ b/src/tagged-type.ts @@ -1,3 +1,5 @@ +import base64 from "base64-js"; + import { ClientError } from "./errors"; import { DateStub, @@ -10,6 +12,7 @@ import { Page, NullDocument, EmbeddedSet, + StreamToken, } from "./values"; import { QueryValueObject, QueryValue } from "./wire-protocol"; @@ -95,6 +98,10 @@ Returning as Number with loss of precision. Use long_type 'bigint' instead.`); return TimeStub.from(value["@time"]); } else if (value["@object"]) { return value["@object"]; + } else if (value["@stream"]) { + return new StreamToken(value["@stream"]); + } else if (value["@bytes"]) { + return base64toBuffer(value["@bytes"]); } return value; @@ -102,6 +109,7 @@ Returning as Number with loss of precision. Use long_type 'bigint' instead.`); } } +type TaggedBytes = { "@bytes": string }; type TaggedDate = { "@date": string }; type TaggedDouble = { "@double": string }; type TaggedInt = { "@int": string }; @@ -124,7 +132,7 @@ const encodeMap = { bigint: (value: bigint): TaggedLong | TaggedInt => { if (value < LONG_MIN || value > LONG_MAX) { throw new RangeError( - "BigInt value exceeds max magnitude for a 64-bit Fauna long. Use a 'number' to represent doubles beyond that limit." + "BigInt value exceeds max magnitude for a 64-bit Fauna long. Use a 'number' to represent doubles beyond that limit.", ); } if (value >= INT_MIN && value <= INT_MAX) { @@ -195,10 +203,10 @@ const encodeMap = { namedDocument: (value: NamedDocument): TaggedRef => ({ "@ref": { name: value.name, coll: { "@mod": value.coll.name } }, }), - // es-lint-disable-next-line @typescript-eslint/no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars set: (value: Page | EmbeddedSet) => { throw new ClientError( - "Page could not be encoded. Fauna does not accept encoded Set values, yet. Use Page.data and Page.after as arguments, instead." + "Page could not be encoded. Fauna does not accept encoded Set values, yet. Use Page.data and Page.after as arguments, instead.", ); // TODO: uncomment to encode Pages once core starts accepting `@set` tagged values // if (value.data === undefined) { @@ -209,6 +217,12 @@ const encodeMap = { // "@set": { data: encodeMap["array"](value.data), after: value.after }, // }; }, + // TODO: encode as a tagged value if provided as a query arg? + // streamToken: (value: StreamToken): TaggedStreamToken => ({ "@stream": value.token }), + streamToken: (value: StreamToken): string => value.token, + bytes: (value: ArrayBuffer | Uint8Array): TaggedBytes => ({ + "@bytes": bufferToBase64(value), + }), }; const encode = (input: QueryValue): QueryValue => { @@ -253,9 +267,28 @@ const encode = (input: QueryValue): QueryValue => { return encodeMap["set"](input); } else if (input instanceof EmbeddedSet) { return encodeMap["set"](input); + } else if (input instanceof StreamToken) { + return encodeMap["streamToken"](input); + } else if (input instanceof Uint8Array || input instanceof ArrayBuffer) { + return encodeMap["bytes"](input); + } else if (ArrayBuffer.isView(input)) { + throw new ClientError( + "Error encoding TypedArray to Fauna Bytes. Convert your TypedArray to Uint8Array or ArrayBuffer before passing it to Fauna. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray", + ); } else { return encodeMap["object"](input); } } // anything here would be unreachable code }; + +function base64toBuffer(value: string): Uint8Array { + return base64.toByteArray(value); +} + +function bufferToBase64(value: ArrayBuffer | Uint8Array): string { + const arr: Uint8Array = + value instanceof Uint8Array ? value : new Uint8Array(value); + + return base64.fromByteArray(arr); +} diff --git a/src/util/package-version.ts b/src/util/package-version.ts index c24da044..e297bbc6 100644 --- a/src/util/package-version.ts +++ b/src/util/package-version.ts @@ -1,4 +1,4 @@ //THIS FILE IS AUTOGENERATED. DO NOT EDIT. SEE .husky/pre-commit /** The current package version. */ -export const packageVersion = "1.3.1"; +export const packageVersion = "2.0.0"; diff --git a/src/values/doc.ts b/src/values/doc.ts index 1fd93221..0e0a2cab 100644 --- a/src/values/doc.ts +++ b/src/values/doc.ts @@ -19,6 +19,8 @@ import { TimeStub } from "./date-time"; * const id = userDocumentReference.id; * id === "101"; // returns true * ``` + * + * @see {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#special} */ export class DocumentReference { readonly coll: Module; @@ -57,9 +59,12 @@ export class DocumentReference { * * @remarks The {@link Document} class cannot be generic because classes cannot * extend generic type arguments. + * + * @see {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#special} */ export class Document extends DocumentReference { readonly ts: TimeStub; + readonly ttl?: TimeStub; constructor(obj: { coll: Module | string; @@ -73,8 +78,8 @@ export class Document extends DocumentReference { Object.assign(this, rest); } - toObject(): { coll: Module; id: string; ts: TimeStub } { - return { ...this } as { coll: Module; id: string; ts: TimeStub }; + toObject(): { coll: Module; id: string; ts: TimeStub; ttl?: TimeStub } { + return { ...this }; } } @@ -96,6 +101,8 @@ export class Document extends DocumentReference { * const collectionName = namedDocumentReference.name; * collectionName === "Users"; // returns true * ``` + * + * @see {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#special} */ export class NamedDocumentReference { readonly coll: Module; @@ -144,9 +151,11 @@ export class NamedDocumentReference { * * const metadata = userCollection.data.metadata; * ``` + * + * @see {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#special} */ export class NamedDocument< - T extends QueryValueObject = Record + T extends QueryValueObject = Record, > extends NamedDocumentReference { readonly ts: TimeStub; readonly data: T; @@ -186,6 +195,8 @@ export class NamedDocument< * `); * const allUserDocuments = response.data; * ``` + * + * @see {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#module} */ export class Module { readonly name: string; @@ -220,6 +231,8 @@ export class Module { * const color = maybeUserDocument.color; * } * ``` + * + * @see {@link https://docs.fauna.com/fauna/current/reference/fql_reference/types#nulldoc} */ export class NullDocument { readonly ref: DocumentReference | NamedDocumentReference; diff --git a/src/values/index.ts b/src/values/index.ts index d31b16c4..fd384678 100644 --- a/src/values/index.ts +++ b/src/values/index.ts @@ -1,3 +1,4 @@ export * from "./date-time"; export * from "./doc"; export * from "./set"; +export * from "./stream"; diff --git a/src/values/stream.ts b/src/values/stream.ts new file mode 100644 index 00000000..544dc68d --- /dev/null +++ b/src/values/stream.ts @@ -0,0 +1,26 @@ +/** + * A token used to initiate a Fauna stream at a particular snapshot in time. + * + * The example below shows how to request a stream token from Fauna and use it + * to establish an event steam. + * + * @example + * ```javascript + * const response = await client.query(fql` + * Messages.byRecipient(User.byId("1234")) + * `); + * const token = response.data; + * + * const stream = client.stream(token) + * .on("add", (event) => console.log("New message", event)) + * + * stream.start(); + * ``` + */ +export class StreamToken { + readonly token: string; + + constructor(token: string) { + this.token = token; + } +} diff --git a/src/wire-protocol.ts b/src/wire-protocol.ts index 06e6f80a..0c830563 100644 --- a/src/wire-protocol.ts +++ b/src/wire-protocol.ts @@ -10,6 +10,7 @@ import { NamedDocumentReference, NullDocument, Page, + StreamToken, TimeStub, } from "./values"; @@ -316,4 +317,29 @@ export type QueryValue = | NamedDocumentReference | NullDocument | Page - | EmbeddedSet; + | EmbeddedSet + | StreamToken + | Uint8Array; + +export type StreamRequest = { + token: string; + start_ts?: number; +}; + +export type StreamEventType = "status" | "add" | "remove" | "update" | "error"; +export type StreamEventStatus = { + type: "status"; + txn_ts: number; + stats: QueryStats; +}; +export type StreamEventData = { + type: "add" | "remove" | "update"; + txn_ts: number; + stats: QueryStats; + data: T; +}; +export type StreamEventError = { type: "error" } & QueryFailure; +export type StreamEvent = + | StreamEventStatus + | StreamEventData + | StreamEventError; diff --git a/yarn.lock b/yarn.lock index 7af97b7f..3bfd655c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,21 +3,14 @@ "@ampproject/remapping@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@babel/highlight" "^7.18.6" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": version "7.24.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== @@ -25,38 +18,12 @@ "@babel/highlight" "^7.24.2" picocolors "^1.0.0" -"@babel/compat-data@^7.20.5": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" - integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== - "@babel/compat-data@^7.23.5": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" - integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.21.0" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-module-transforms" "^7.21.0" - "@babel/helpers" "^7.21.0" - "@babel/parser" "^7.21.0" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" - -"@babel/core@^7.23.9": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.5.tgz#15ab5b98e101972d171aeef92ac70d8d6718f06a" integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== @@ -77,37 +44,16 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.21.0", "@babel/generator@^7.7.2": - version "7.21.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" - integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== - dependencies: - "@babel/types" "^7.21.0" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/generator@^7.24.5": +"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" - integrity "sha1-5a/AaPky8FYWtmcT4o0PBOmdrrM= sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==" + integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== dependencies: "@babel/types" "^7.24.5" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" - integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.21.3" - lru-cache "^5.1.1" - semver "^6.3.0" - "@babel/helper-compilation-targets@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" @@ -119,11 +65,6 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== - "@babel/helper-environment-visitor@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" @@ -144,13 +85,6 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== - dependencies: - "@babel/types" "^7.18.6" - "@babel/helper-module-imports@^7.24.3": version "7.24.3" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" @@ -158,20 +92,6 @@ dependencies: "@babel/types" "^7.24.0" -"@babel/helper-module-transforms@^7.21.0": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" - integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.20.2" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.2" - "@babel/types" "^7.21.2" - "@babel/helper-module-transforms@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz#ea6c5e33f7b262a0ae762fd5986355c45f54a545" @@ -183,17 +103,10 @@ "@babel/helper-split-export-declaration" "^7.24.5" "@babel/helper-validator-identifier" "^7.24.5" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== - -"@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== - dependencies: - "@babel/types" "^7.20.2" +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz#a924607dd254a65695e5bd209b98b902b3b2f11a" + integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== "@babel/helper-simple-access@^7.24.5": version "7.24.5" @@ -202,59 +115,28 @@ dependencies: "@babel/types" "^7.24.5" -"@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== - dependencies: - "@babel/types" "^7.18.6" - "@babel/helper-split-export-declaration@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6" - integrity "sha1-uaZ/BqRrCzOTI2F8jGITuQVaeLY= sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==" + integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== dependencies: "@babel/types" "^7.24.5" -"@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== - "@babel/helper-string-parser@^7.24.1": version "7.24.1" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== -"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - "@babel/helper-validator-identifier@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" - integrity "sha1-kYsaf6IwVmA1BjcAib2ZDYcg22I= sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==" - -"@babel/helper-validator-option@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== + integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== "@babel/helper-validator-option@^7.23.5": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== -"@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== - dependencies: - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" - "@babel/helpers@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.5.tgz#fedeb87eeafa62b621160402181ad8585a22a40a" @@ -264,34 +146,20 @@ "@babel/traverse" "^7.24.5" "@babel/types" "^7.24.5" -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.24.2": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e" - integrity "sha1-vAYT+Y4d0HIOmbKp7jdgGUpwS24= sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==" + integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== dependencies: "@babel/helper-validator-identifier" "^7.24.5" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" - integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== - -"@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" - integrity "sha1-Sk1atDFVeeU5ioLc9jbKgMM5J5A= sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==" + integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -329,11 +197,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -385,22 +253,13 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" - integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - -"@babel/template@^7.20.7", "@babel/template@^7.3.3": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" - integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" + "@babel/helper-plugin-utils" "^7.24.0" -"@babel/template@^7.22.15", "@babel/template@^7.24.0": +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== @@ -409,10 +268,10 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.24.5": +"@babel/traverse@^7.24.5": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" - integrity "sha1-lyqgvEXxaYO/ZKofh3st0O6n5vg= sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==" + integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== dependencies: "@babel/code-frame" "^7.24.2" "@babel/generator" "^7.24.5" @@ -425,19 +284,10 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" - integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== - dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" - to-fast-properties "^2.0.0" - -"@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" - integrity "sha1-dmGTCvxjilOD6wxK7lm3TzjbhNc= sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==" + integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== dependencies: "@babel/helper-string-parser" "^7.24.1" "@babel/helper-validator-identifier" "^7.24.5" @@ -465,14 +315,26 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz#128b76ecb9be48b60cf5cfc1c63a4f00691a3239" integrity sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ== -"@eslint/eslintrc@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff" - integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" + espree "^9.6.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -480,18 +342,18 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.35.0": - version "8.35.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7" - integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw== +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -499,10 +361,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -576,13 +438,6 @@ "@types/node" "*" jest-mock "^29.7.0" -"@jest/expect-utils@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.4.3.tgz#95ce4df62952f071bcd618225ac7c47eaa81431e" - integrity sha512-/6JWbkxHOP8EoS8jeeTd9dTfc9Uawi+43oLKHfp6zzux3U2hqOOVnV3ai4RpDYHOccL6g+5nrxpoc8DmJxtXVQ== - dependencies: - jest-get-type "^29.4.3" - "@jest/expect-utils@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" @@ -650,13 +505,6 @@ strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" - integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== - dependencies: - "@sinclair/typebox" "^0.25.16" - "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -714,18 +562,6 @@ slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.3.tgz#9069145f4ef09adf10cec1b2901b2d390031431f" - integrity sha512-bPYfw8V65v17m2Od1cv44FH+SiKW7w2Xu7trhcdTLUmSv85rfKsP+qXSjO4KGJr4dtPSzl/gvslZBXctf1qGEA== - dependencies: - "@jest/schemas" "^29.4.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - "@jest/types@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" @@ -738,23 +574,6 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -764,32 +583,17 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - "@jridgewell/set-array@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -802,15 +606,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -854,34 +650,29 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@sinclair/typebox@^0.25.16": - version "0.25.24" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" - integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@sinonjs/commons@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" - integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^10.0.2": - version "10.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" - integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: - "@sinonjs/commons" "^2.0.0" + "@sinonjs/commons" "^3.0.0" "@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -894,19 +685,19 @@ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@tsconfig/node18@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node18/-/node18-1.0.1.tgz#ea5b375a9ead6b09ccbd70c3894ea069829ea1bb" - integrity sha512-sNFeK6X2ATlhlvzyH4kKYQlfHXE2f2/wxtB9ClvYXevWpmwkUT7VaSrjIN9E76Qebz8qP5JOJJ9jD3QoD/Z9TA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node18/-/node18-1.0.3.tgz#b14aed11bda116950a57fb5d223dd050e47f4fe1" + integrity sha512-RbwvSJQsuN9TB04AQbGULYfOGE/RnSFk/FLQ5b0NmDf5Kx2q/lABZbHQPKCO1vZ6Fiwkplu+yb9pGdLy1iGseQ== "@types/babel__core@^7.1.14": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" - integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" @@ -915,80 +706,74 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.3.tgz#dfc508a85781e5698d5b33443416b6268c4b3e8d" - integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" + integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== dependencies: - "@babel/types" "^7.3.0" + "@babel/types" "^7.20.7" "@types/graceful-fs@^4.1.3": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.4.0": - version "29.4.0" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.0.tgz#a8444ad1704493e84dbf07bb05990b275b3b9206" - integrity sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ== +"@types/jest@^29.5.12": + version "29.5.12" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: expect "^29.0.0" pretty-format "^29.0.0" -"@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/minimatch@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - -"@types/node@*", "@types/node@^18.13.0": - version "18.14.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.4.tgz#0e64ec0b35a772e1e3d849f9a0ff61782d0cb647" - integrity sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g== +"@types/node@*": + version "20.12.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" + integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== + dependencies: + undici-types "~5.26.4" -"@types/semver@^7.3.12": - version "7.3.13" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" - integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/node@^18.13.0": + version "18.19.33" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.33.tgz#98cd286a1b8a5e11aa06623210240bcc28e95c48" + integrity sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A== + dependencies: + undici-types "~5.26.4" "@types/serviceworker@^0.0.67": version "0.0.67" @@ -996,105 +781,107 @@ integrity sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q== "@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.22" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.22.tgz#7dd37697691b5f17d020f3c63e7a45971ff71e9a" - integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g== + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.52.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz#2c821ad81b2c786d142279a8292090f77d1881f4" - integrity sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw== +"@typescript-eslint/eslint-plugin@^7.5.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz#093b96fc4e342226e65d5f18f9c87081e0b04a31" + integrity sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.9.0" + "@typescript-eslint/type-utils" "7.9.0" + "@typescript-eslint/utils" "7.9.0" + "@typescript-eslint/visitor-keys" "7.9.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^7.5.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.9.0.tgz#fb3ba01b75e0e65cb78037a360961b00301f6c70" + integrity sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ== dependencies: - "@typescript-eslint/scope-manager" "5.54.0" - "@typescript-eslint/type-utils" "5.54.0" - "@typescript-eslint/utils" "5.54.0" - debug "^4.3.4" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - regexpp "^3.2.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.52.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.54.0.tgz#def186eb1b1dbd0439df0dacc44fb6d8d5c417fe" - integrity sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ== - dependencies: - "@typescript-eslint/scope-manager" "5.54.0" - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/typescript-estree" "5.54.0" + "@typescript-eslint/scope-manager" "7.9.0" + "@typescript-eslint/types" "7.9.0" + "@typescript-eslint/typescript-estree" "7.9.0" + "@typescript-eslint/visitor-keys" "7.9.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz#74b28ac9a3fc8166f04e806c957adb8c1fd00536" - integrity sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg== +"@typescript-eslint/scope-manager@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz#1dd3e63a4411db356a9d040e75864851b5f2619b" + integrity sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ== dependencies: - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/visitor-keys" "5.54.0" + "@typescript-eslint/types" "7.9.0" + "@typescript-eslint/visitor-keys" "7.9.0" -"@typescript-eslint/type-utils@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz#390717216eb61393a0cad2995da154b613ba7b26" - integrity sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ== +"@typescript-eslint/type-utils@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz#f523262e1b66ca65540b7a65a1222db52e0a90c9" + integrity sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA== dependencies: - "@typescript-eslint/typescript-estree" "5.54.0" - "@typescript-eslint/utils" "5.54.0" + "@typescript-eslint/typescript-estree" "7.9.0" + "@typescript-eslint/utils" "7.9.0" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/types@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.0.tgz#7d519df01f50739254d89378e0dcac504cab2740" - integrity sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ== +"@typescript-eslint/types@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.9.0.tgz#b58e485e4bfba055659c7e683ad4f5f0821ae2ec" + integrity sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w== -"@typescript-eslint/typescript-estree@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz#f6f3440cabee8a43a0b25fa498213ebb61fdfe99" - integrity sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ== +"@typescript-eslint/typescript-estree@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz#3395e27656060dc313a6b406c3a298b729685e07" + integrity sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg== dependencies: - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/visitor-keys" "5.54.0" + "@typescript-eslint/types" "7.9.0" + "@typescript-eslint/visitor-keys" "7.9.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.0.tgz#3db758aae078be7b54b8ea8ea4537ff6cd3fbc21" - integrity sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw== - dependencies: - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.54.0" - "@typescript-eslint/types" "5.54.0" - "@typescript-eslint/typescript-estree" "5.54.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - semver "^7.3.7" - -"@typescript-eslint/visitor-keys@5.54.0": - version "5.54.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz#846878afbf0cd67c19cfa8d75947383d4490db8f" - integrity sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA== - dependencies: - "@typescript-eslint/types" "5.54.0" - eslint-visitor-keys "^3.3.0" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.9.0.tgz#1b96a34eefdca1c820cb1bbc2751d848b4540899" + integrity sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.9.0" + "@typescript-eslint/types" "7.9.0" + "@typescript-eslint/typescript-estree" "7.9.0" + +"@typescript-eslint/visitor-keys@7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz#82162656e339c3def02895f5c8546f6888d9b9ea" + integrity sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ== + dependencies: + "@typescript-eslint/types" "7.9.0" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== acorn-jsx@^5.3.2: version "5.3.2" @@ -1102,16 +889,16 @@ acorn-jsx@^5.3.2: integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -acorn@^8.4.1, acorn@^8.8.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.4.1, acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== -ajv@^6.10.0, ajv@^6.12.4, ajv@~6.12.6: +ajv@^6.12.4, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1177,21 +964,11 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-differ@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" - integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -arrify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -1257,6 +1034,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1265,6 +1047,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -1272,16 +1061,6 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.21.3: - version "4.21.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== - dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" - browserslist@^4.22.2: version "4.23.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" @@ -1326,17 +1105,12 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001449: - version "1.0.30001458" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001458.tgz#871e35866b4654a7d25eccca86864f411825540c" - integrity sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w== - caniuse-lite@^1.0.30001587: - version "1.0.30001616" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001616.tgz#4342712750d35f71ebba9fcac65e2cf8870013c3" - integrity sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw== + version "1.0.30001620" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz#78bb6f35b8fe315b96b8590597094145d0b146b4" + integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== -chalk@^2.0.0, chalk@^2.4.2: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1345,14 +1119,6 @@ chalk@^2.0.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -1367,14 +1133,14 @@ char-regex@^1.0.2: integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + version "1.3.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== cliui@^8.0.1: version "8.0.1" @@ -1391,9 +1157,9 @@ co@^4.6.0: integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0: version "1.9.3" @@ -1424,11 +1190,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -1453,13 +1214,13 @@ create-require@^1.1.0: integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-fetch@^3.0.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== dependencies: - node-fetch "2.6.7" + node-fetch "^2.6.12" -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1486,20 +1247,15 @@ deep-is@^0.1.3: integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: - version "4.3.0" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.0.tgz#65491893ec47756d44719ae520e0e2609233b59b" - integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" - integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -1524,15 +1280,10 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -electron-to-chromium@^1.4.284: - version "1.4.316" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.316.tgz#7f2cfda199ae1a32a69b3eb9046b8b0640086064" - integrity sha512-9urqVpdeJYAwVL/sBjsX2pSlgYI/b4nOqC6UaNa0xlq1VUbXLRhERWlxcQ4FWfUOQQxSSxN/taFtapEcwg5tVA== - electron-to-chromium@^1.4.668: - version "1.4.759" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.759.tgz#ed7f4d9eed25124708ab0f4422e66b16534648d3" - integrity sha512-qZJc+zsuI+/5UjOSFnpkJBwwLMH1AZgyKqJ7LUNnRsB7v/cDjMu9DvXgp9kH6PTTZxjnPXGp2Uhurw+2Ll4Hjg== + version "1.4.774" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.774.tgz#1017d1758aaeeefe5423aa9d67b4b1e5d1d0a856" + integrity sha512-132O1XCd7zcTkzS3FgkAzKmnBuNJjK8WjcTtNuoylj7MYbqw5eXehjQ5OK91g0zm7OTKIPeaAG4CPoRfD9M1Mg== emittery@^0.13.1: version "0.13.1" @@ -1544,13 +1295,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -1686,12 +1430,7 @@ esbuild@^0.15.12: esbuild-windows-64 "0.15.18" esbuild-windows-arm64 "0.15.18" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escalade@^3.1.2: +escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== @@ -1719,59 +1458,41 @@ eslint-plugin-tsdoc@^0.2.17: "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "0.16.2" -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^8.25.0: - version "8.35.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323" - integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw== - dependencies: - "@eslint/eslintrc" "^2.0.0" - "@eslint/js" "8.35.0" - "@humanwhocodes/config-array" "^0.11.8" +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.57.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1779,33 +1500,29 @@ eslint@^8.25.0: find-up "^5.0.0" glob-parent "^6.0.2" globals "^13.19.0" - grapheme-splitter "^1.0.4" + graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" - js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^8.8.0" + acorn "^8.9.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.1" esprima@^4.0.0: version "4.0.1" @@ -1826,11 +1543,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -1841,22 +1553,7 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -execa@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - -execa@^5.0.0: +execa@^5.0.0, execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -1876,18 +1573,7 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^29.0.0: - version "29.4.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.4.3.tgz#5e47757316df744fe3b8926c3ae8a3ebdafff7fe" - integrity sha512-uC05+Q7eXECFpgDrHdXA4k2rpMyStAYPItEDLyQDo5Ta7fVkJnNA/4zh/OIVkVVNZ1oOK1PipQoyNjuZ6sz6Dg== - dependencies: - "@jest/expect-utils" "^29.4.3" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.4.3" - jest-message-util "^29.4.3" - jest-util "^29.4.3" - -expect@^29.7.0: +expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== @@ -1904,9 +1590,9 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -1925,9 +1611,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" @@ -1969,17 +1655,18 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - flatted "^3.1.0" + flatted "^3.2.9" + keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== fs.realpath@^1.0.0: version "1.0.0" @@ -1987,14 +1674,14 @@ fs.realpath@^1.0.0: integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -2011,13 +1698,6 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-stream@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -2055,9 +1735,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" @@ -2074,14 +1754,14 @@ globby@^11.1.0: slash "^3.0.0" graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== has-flag@^3.0.0: version "3.0.0" @@ -2093,23 +1773,18 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: - function-bind "^1.1.1" + function-bind "^1.1.2" html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -2120,12 +1795,12 @@ husky@^8.0.1: resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== -ignore@^5.1.4, ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.2.0, ignore@^5.3.0, ignore@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -2164,12 +1839,12 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-core-module@^2.1.0, is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== +is-core-module@^2.1.0, is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" is-extglob@^2.1.1: version "2.1.1" @@ -2214,9 +1889,9 @@ isexe@^2.0.0: integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4: version "5.2.1" @@ -2241,12 +1916,12 @@ istanbul-lib-instrument@^6.0.0: semver "^7.5.4" istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" + make-dir "^4.0.0" supports-color "^7.1.0" istanbul-lib-source-maps@^4.0.0: @@ -2259,9 +1934,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.5" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -2346,16 +2021,6 @@ jest-config@^29.7.0: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.4.3.tgz#42f4eb34d0bf8c0fb08b0501069b87e8e84df347" - integrity sha512-YB+ocenx7FZ3T5O9lMVMeLYV4265socJKtkwgk/6YUz/VsEzYDkiMuMhWzZmxm3wDRQvayJu/PjkjjSkjoHsCA== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.4.3" - jest-get-type "^29.4.3" - pretty-format "^29.4.3" - jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -2404,11 +2069,6 @@ jest-fetch-mock@^3.0.3: cross-fetch "^3.0.4" promise-polyfill "^8.1.3" -jest-get-type@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" - integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== - jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" @@ -2451,16 +2111,6 @@ jest-leak-detector@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-matcher-utils@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.4.3.tgz#ea68ebc0568aebea4c4213b99f169ff786df96a0" - integrity sha512-TTciiXEONycZ03h6R6pYiZlSkvYgT0l8aa49z/DLSGYjex4orMUcafuLXYyyEDWB1RKglq00jzwY00Ei7yFNVg== - dependencies: - chalk "^4.0.0" - jest-diff "^29.4.3" - jest-get-type "^29.4.3" - pretty-format "^29.4.3" - jest-matcher-utils@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" @@ -2471,21 +2121,6 @@ jest-matcher-utils@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-message-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.3.tgz#65b5280c0fdc9419503b49d4f48d4999d481cb5b" - integrity sha512-1Y8Zd4ZCN7o/QnWdMmT76If8LuDv23Z1DRovBj/vcSFNlGCJGoO8D1nJDw1AdyAGUk0myDLFGN5RbNeJyCRGCw== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.4.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^29.4.3" - slash "^3.0.0" - stack-utils "^2.0.3" - jest-message-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" @@ -2624,19 +2259,7 @@ jest-snapshot@^29.7.0: pretty-format "^29.7.0" semver "^7.5.3" -jest-util@^29.0.0, jest-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.3.tgz#851a148e23fc2b633c55f6dad2e45d7f4579f496" - integrity sha512-ToSGORAz4SSSoqxDSylWX8JzkOQR7zoBtNRsA7e+1WUX5F8jrOwaNpuh1YfJHJKDHXLHmObv5eOjejUd+/Ws+Q== - dependencies: - "@jest/types" "^29.4.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-util@^29.7.0: +jest-util@^29.0.0, jest-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== @@ -2699,11 +2322,6 @@ jju@~1.4.0: resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== -js-sdsl@^4.1.4: - version "4.3.0" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711" - integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ== - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2729,6 +2347,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -2744,11 +2367,18 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^2.2.2, json5@^2.2.3: +json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -2803,19 +2433,12 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: - semver "^6.0.0" + semver "^7.5.3" make-error@1.x, make-error@^1.1.1: version "1.3.6" @@ -2859,12 +2482,19 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mri@^1.1.5: +mri@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== @@ -2874,31 +2504,15 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -multimatch@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" - integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== - dependencies: - "@types/minimatch" "^3.0.3" - array-differ "^3.0.0" - array-union "^2.1.0" - arrify "^2.0.1" - minimatch "^3.0.4" - -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" @@ -2912,48 +2526,43 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-path@^4.0.0, npm-run-path@^4.0.1: +npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" + word-wrap "^1.2.5" p-limit@^2.2.0: version "2.3.0" @@ -3030,20 +2639,25 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-3.0.1.tgz#817033161def55ec9638567a2f3bbc876b3e7516" + integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== + pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" @@ -3057,21 +2671,12 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.7.1: - version "2.8.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" - integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== +prettier@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== -pretty-format@^29.0.0, pretty-format@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.3.tgz#25500ada21a53c9e8423205cf0337056b201244c" - integrity sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA== - dependencies: - "@jest/schemas" "^29.4.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -pretty-format@^29.7.0: +pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== @@ -3080,17 +2685,18 @@ pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-quick@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-3.1.3.tgz#15281108c0ddf446675157ca40240099157b638e" - integrity sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA== +pretty-quick@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-4.0.0.tgz#ea5cce85a5804bfbec7327b0e064509155d03f39" + integrity sha512-M+2MmeufXb/M7Xw3Afh1gxcYpj+sK0AxEfnfF958ktFeAyi5MsKY5brymVURQLgPLV1QaF5P4pb2oFJ54H3yzQ== dependencies: - chalk "^3.0.0" - execa "^4.0.0" - find-up "^4.1.0" - ignore "^5.1.4" - mri "^1.1.5" - multimatch "^4.0.0" + execa "^5.1.1" + find-up "^5.0.0" + ignore "^5.3.0" + mri "^1.2.0" + picocolors "^1.0.0" + picomatch "^3.0.1" + tslib "^2.6.2" promise-polyfill@^8.1.3: version "8.3.0" @@ -3105,18 +2711,10 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: version "6.1.0" @@ -3129,14 +2727,9 @@ queue-microtask@^1.2.2: integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== require-directory@^2.1.1: version "2.1.1" @@ -3161,16 +2754,16 @@ resolve-from@^5.0.0: integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve.exports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.0.tgz#c1a0028c2d166ec2fbf7d0644584927e76e7400e" - integrity sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.20.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -3201,22 +2794,15 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.7: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" - -semver@^7.5.3, semver@^7.5.4: - version "7.6.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2" - integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA== +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== shebang-command@^2.0.0: version "2.0.0" @@ -3230,7 +2816,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -3304,7 +2890,7 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -3371,6 +2957,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + ts-jest@^29.1.2: version "29.1.2" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.2.tgz#7613d8c81c43c8cb312c6904027257e814c40e09" @@ -3385,10 +2976,10 @@ ts-jest@^29.1.2: semver "^7.5.3" yargs-parser "^21.0.1" -ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -3404,17 +2995,10 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" +tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -3438,26 +3022,23 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typescript@^4.8.4: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.4.3: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== -update-browserslist-db@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== update-browserslist-db@^1.0.13: - version "1.0.15" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz#60ed9f8cba4a728b7ecf7356f641a31e3a691d97" - integrity sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA== + version "1.0.16" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356" + integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== dependencies: escalade "^3.1.2" - picocolors "^1.0.0" + picocolors "^1.0.1" uri-js@^4.2.2: version "4.4.1" @@ -3477,13 +3058,13 @@ v8-compile-cache-lib@^3.0.1: integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-to-istanbul@^9.0.1: - version "9.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" - integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" + convert-source-map "^2.0.0" walker@^1.0.8: version "1.0.8" @@ -3512,7 +3093,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -word-wrap@^1.2.3: +word-wrap@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== @@ -3554,20 +3135,15 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" escalade "^3.1.1"