From c4590bef0d8db64cb14b91e52263fe33b618817c Mon Sep 17 00:00:00 2001 From: taefi Date: Mon, 19 Aug 2024 21:27:55 +0300 Subject: [PATCH 1/7] feat: add automatic subscribe/unsubscribe to signals Fixes #2621 --- .../core/registry/SecureSignalsRegistry.java | 9 ++ .../hilla/signals/handler/SignalsHandler.java | 3 +- .../spring/react-signals/package-lock.json | 2 +- .../tests/spring/react-signals/package.json | 2 +- .../ts/react-signals/src/FullStackSignal.ts | 83 +++++++++++++++---- 5 files changed, 80 insertions(+), 19 deletions(-) diff --git a/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistry.java b/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistry.java index ac5cea34ac..f3b6879167 100644 --- a/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistry.java +++ b/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistry.java @@ -51,6 +51,15 @@ public synchronized void register(String clientSignalId, delegate.register(clientSignalId, signal); } + public synchronized void unsubscribe(String clientSignalId) { + var endpointMethodInfo = endpointMethods.get(clientSignalId); + if (endpointMethodInfo == null) { + return; + } + delegate.removeClientSignalToSignalMapping(clientSignalId); + endpointMethods.remove(clientSignalId); + } + public synchronized NumberSignal get(String clientSignalId) throws EndpointInvocationException.EndpointAccessDeniedException, EndpointInvocationException.EndpointNotFoundException { diff --git a/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/handler/SignalsHandler.java b/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/handler/SignalsHandler.java index 4e241aa13e..beedeb5acb 100644 --- a/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/handler/SignalsHandler.java +++ b/packages/java/endpoint/src/main/java/com/vaadin/hilla/signals/handler/SignalsHandler.java @@ -41,7 +41,8 @@ public Flux subscribe(String providerEndpoint, } registry.register(clientSignalId, providerEndpoint, providerMethod); - return registry.get(clientSignalId).subscribe(); + return registry.get(clientSignalId).subscribe() + .doFinally((event) -> registry.unsubscribe(clientSignalId)); } catch (Exception e) { return Flux.error(e); } diff --git a/packages/java/tests/spring/react-signals/package-lock.json b/packages/java/tests/spring/react-signals/package-lock.json index cb9d0b7c70..878ed79a83 100644 --- a/packages/java/tests/spring/react-signals/package-lock.json +++ b/packages/java/tests/spring/react-signals/package-lock.json @@ -30,7 +30,7 @@ "lit": "3.2.0", "react": "18.3.1", "react-dom": "18.3.1", - "react-router-dom": "^6.26.0" + "react-router-dom": "^6.26.1" }, "devDependencies": { "@babel/preset-react": "7.24.7", diff --git a/packages/java/tests/spring/react-signals/package.json b/packages/java/tests/spring/react-signals/package.json index bc36135887..244f4324a9 100644 --- a/packages/java/tests/spring/react-signals/package.json +++ b/packages/java/tests/spring/react-signals/package.json @@ -26,7 +26,7 @@ "lit": "3.2.0", "react": "18.3.1", "react-dom": "18.3.1", - "react-router-dom": "^6.26.0" + "react-router-dom": "^6.26.1" }, "devDependencies": { "@babel/preset-react": "7.24.7", diff --git a/packages/ts/react-signals/src/FullStackSignal.ts b/packages/ts/react-signals/src/FullStackSignal.ts index ea68f45b9e..11607d4ec5 100644 --- a/packages/ts/react-signals/src/FullStackSignal.ts +++ b/packages/ts/react-signals/src/FullStackSignal.ts @@ -22,6 +22,41 @@ export type StateEvent = Readonly<{ value: T; }>; +abstract class DependencyTrackingSignal extends Signal { + readonly #onSubscribe: () => void; + readonly #onUnsubscribe: () => void; + + // -1 means to ignore the first subscription that is created internally in the + // FullStackSignal constructor. + #subscribeCount = -1; + + protected constructor(value: T | undefined, onSubscribe: () => void, onUnsubscribe: () => void) { + super(value); + this.#onSubscribe = onSubscribe; + this.#onUnsubscribe = onUnsubscribe; + } + + protected S(node: unknown): void { + // @ts-expect-error: We use the protected method from the base class. + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + super.S(node); + if (this.#subscribeCount === 0) { + this.#onSubscribe(); + } + this.#subscribeCount += 1; + } + + protected U(node: unknown): void { + // @ts-expect-error: We use the protected method from the base class. + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + super.U(node); + this.#subscribeCount -= 1; + if (this.#subscribeCount === 0) { + this.#onUnsubscribe(); + } + } +} + /** * An object that describes a data object to connect to the signal provider * service. @@ -93,7 +128,7 @@ class ServerConnection { * * @internal */ -export abstract class FullStackSignal extends Signal { +export abstract class FullStackSignal extends DependencyTrackingSignal { /** * The unique identifier of the signal necessary to communicate with the * server. @@ -118,24 +153,20 @@ export abstract class FullStackSignal extends Signal { readonly #pending = signal(false); readonly #error = signal(undefined); + // Paused at the very start to prevent the signal from sending the initial + // value to the server. + #paused = true; + constructor(value: T | undefined, config: ServerConnectionConfig) { - super(value); + super( + value, + () => this.#connect(), + () => this.#disconnect(), + ); this.server = new ServerConnection(this.id, config); - // Paused at the very start to prevent the signal from sending the initial - // value to the server. - let paused = true; - - this.server.connect().onNext((event: StateEvent) => { - if (event.type === StateEventType.SNAPSHOT) { - paused = true; - this.value = event.value; - paused = false; - } - }); - this.subscribe((v) => { - if (!paused) { + if (!this.#paused) { this.#pending.value = true; this.#error.value = undefined; this.server @@ -153,6 +184,26 @@ export abstract class FullStackSignal extends Signal { } }); - paused = false; + this.#paused = false; + } + + #connect() { + if (this.server.subscription !== undefined) { + return; + } + this.server.connect().onNext((event: StateEvent) => { + if (event.type === StateEventType.SNAPSHOT) { + this.#paused = true; + this.value = event.value; + this.#paused = false; + } + }); + } + + #disconnect() { + if (this.server.subscription === undefined) { + return; + } + this.server.disconnect(); } } From 8179c45966126a187df1c477e4308dcdbda6be1c Mon Sep 17 00:00:00 2001 From: taefi Date: Mon, 19 Aug 2024 22:36:36 +0300 Subject: [PATCH 2/7] adopt changes in the tests --- .../test/FullStackSignal.spec.tsx | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/ts/react-signals/test/FullStackSignal.spec.tsx b/packages/ts/react-signals/test/FullStackSignal.spec.tsx index 344bd81705..bb609f1037 100644 --- a/packages/ts/react-signals/test/FullStackSignal.spec.tsx +++ b/packages/ts/react-signals/test/FullStackSignal.spec.tsx @@ -60,7 +60,12 @@ describe('@vaadin/hilla-react-signals', () => { expect(signal.value).to.be.undefined; }); - it('should subscribe to signal provider endpoint', () => { + it('should subscribe to signal provider endpoint only after being rendered', async () => { + expect(client.subscribe).not.to.have.been.called; + + render(Value is {signal}); + await nextFrame(); + expect(client.subscribe).to.be.have.been.calledOnce; expect(client.subscribe).to.have.been.calledWith('SignalsHandler', 'subscribe', { clientSignalId: signal.id, @@ -79,9 +84,12 @@ describe('@vaadin/hilla-react-signals', () => { }); }); - it("should update signal's value based on the received event", () => { + it("should update signal's value based on the received event", async () => { expect(signal.value).to.be.undefined; + render(Value is {signal}); + await nextFrame(); + // Simulate the event received from the server: const snapshotEvent: StateEvent = { id: 'someId', type: StateEventType.SNAPSHOT, value: 42 }; simulateReceivedChange(subscription, snapshotEvent); @@ -92,9 +100,12 @@ describe('@vaadin/hilla-react-signals', () => { it('should render the updated value', async () => { const numberSignal = signal; + + let result = render(Value is {numberSignal}); + await nextFrame(); simulateReceivedChange(subscription, { id: 'someId', type: StateEventType.SNAPSHOT, value: 42 }); - const result = render(Value is {numberSignal}); + result = render(Value is {numberSignal}); await nextFrame(); expect(result.container.textContent).to.equal('Value is 42'); @@ -103,7 +114,10 @@ describe('@vaadin/hilla-react-signals', () => { expect(result.container.textContent).to.equal('Value is 99'); }); - it('should subscribe using client', () => { + it('should subscribe using client', async () => { + render(Value is {signal}); + await nextFrame(); + expect(client.subscribe).to.be.have.been.calledOnce; expect(client.subscribe).to.have.been.calledWith('SignalsHandler', 'subscribe', { clientSignalId: signal.id, @@ -159,11 +173,16 @@ describe('@vaadin/hilla-react-signals', () => { expect(signal.pending).to.be.like({ value: false }); }); - it('should provide an internal server subscription', () => { + it('should provide an internal server subscription', async () => { + render(Value is {signal}); + await nextFrame(); expect(signal.server.subscription).to.equal(subscription); }); - it('should disconnect from the server', () => { + it('should disconnect from the server', async () => { + render(Value is {signal}); + await nextFrame(); + signal.server.disconnect(); expect(subscription.cancel).to.have.been.calledOnce; }); From ce820990381e643c86a0bcb912532adcf81f4dd2 Mon Sep 17 00:00:00 2001 From: taefi Date: Tue, 20 Aug 2024 00:00:51 +0300 Subject: [PATCH 3/7] add tests --- .../registry/SecureSignalsRegistryTest.java | 23 ++++++++++++++++ .../spring/react-signals/package-lock.json | 24 ++++++++--------- .../tests/spring/react-signals/package.json | 2 +- .../ts/react-signals/src/FullStackSignal.ts | 3 +-- .../test/FullStackSignal.spec.tsx | 27 +++++++++++++++++-- 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/packages/java/endpoint/src/test/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistryTest.java b/packages/java/endpoint/src/test/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistryTest.java index d8f5a64815..6834e2e6c5 100644 --- a/packages/java/endpoint/src/test/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistryTest.java +++ b/packages/java/endpoint/src/test/java/com/vaadin/hilla/signals/core/registry/SecureSignalsRegistryTest.java @@ -42,6 +42,29 @@ public void when_accessToEndpointIsAllowed_signalInstanceIsRegistered() } } + @Test + public void when_unsubscribedIsCalled_underlyingRegistryRemovesClientSignalToSignalMapping() + throws Exception { + NumberSignal signal = new NumberSignal(); + EndpointInvoker invoker = mockEndpointInvokerThatGrantsAccess(signal); + + AtomicReference signalsRegistry = new AtomicReference<>(); + try (var dummy = Mockito.mockConstruction(SignalsRegistry.class, + (mockSignalRegistry, context) -> { + when(mockSignalRegistry.get("clientSignalId")) + .thenReturn(signal); + signalsRegistry.set(mockSignalRegistry); + })) { + SecureSignalsRegistry secureSignalsRegistry = new SecureSignalsRegistry( + invoker); + secureSignalsRegistry.register("clientSignalId", "endpoint", + "method"); + secureSignalsRegistry.unsubscribe("clientSignalId"); + verify(signalsRegistry.get(), times(1)) + .removeClientSignalToSignalMapping("clientSignalId"); + } + } + @Test public void when_accessToEndpointIsRejected_register_throws() throws Exception { diff --git a/packages/java/tests/spring/react-signals/package-lock.json b/packages/java/tests/spring/react-signals/package-lock.json index 878ed79a83..4d66f80534 100644 --- a/packages/java/tests/spring/react-signals/package-lock.json +++ b/packages/java/tests/spring/react-signals/package-lock.json @@ -3118,9 +3118,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", - "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz", + "integrity": "sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==", "engines": { "node": ">=14.0.0" } @@ -7569,11 +7569,11 @@ } }, "node_modules/react-router": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz", - "integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==", + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.1.tgz", + "integrity": "sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==", "dependencies": { - "@remix-run/router": "1.19.0" + "@remix-run/router": "1.19.1" }, "engines": { "node": ">=14.0.0" @@ -7583,12 +7583,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.0.tgz", - "integrity": "sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==", + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.1.tgz", + "integrity": "sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==", "dependencies": { - "@remix-run/router": "1.19.0", - "react-router": "6.26.0" + "@remix-run/router": "1.19.1", + "react-router": "6.26.1" }, "engines": { "node": ">=14.0.0" diff --git a/packages/java/tests/spring/react-signals/package.json b/packages/java/tests/spring/react-signals/package.json index 244f4324a9..c30b11cded 100644 --- a/packages/java/tests/spring/react-signals/package.json +++ b/packages/java/tests/spring/react-signals/package.json @@ -117,7 +117,7 @@ "workbox-core": "7.1.0", "workbox-precaching": "7.1.0" }, - "hash": "380838fd2237f6d269693eac27d292fa25ba2920ad38b53d8ebcfb27a20b5ace" + "hash": "8587dd57f1366294a48aaf55834f4b03439212337f749df1d38ec198ca284dec" }, "overrides": { "@vaadin/common-frontend": "$@vaadin/common-frontend", diff --git a/packages/ts/react-signals/src/FullStackSignal.ts b/packages/ts/react-signals/src/FullStackSignal.ts index 11607d4ec5..5e0d101b6a 100644 --- a/packages/ts/react-signals/src/FullStackSignal.ts +++ b/packages/ts/react-signals/src/FullStackSignal.ts @@ -1,7 +1,6 @@ -import { computed, signal } from '@preact/signals-react'; import type { ConnectClient, Subscription } from '@vaadin/hilla-frontend'; import { nanoid } from 'nanoid'; -import { Signal } from './core.js'; +import { computed, signal, Signal } from './core.js'; const ENDPOINT = 'SignalsHandler'; diff --git a/packages/ts/react-signals/test/FullStackSignal.spec.tsx b/packages/ts/react-signals/test/FullStackSignal.spec.tsx index bb609f1037..ce753ec6c3 100644 --- a/packages/ts/react-signals/test/FullStackSignal.spec.tsx +++ b/packages/ts/react-signals/test/FullStackSignal.spec.tsx @@ -5,7 +5,7 @@ import { ConnectClient, type Subscription } from '@vaadin/hilla-frontend'; import sinon from 'sinon'; import sinonChai from 'sinon-chai'; import { type StateEvent, StateEventType } from '../src/FullStackSignal.js'; -import { NumberSignal } from '../src/index.js'; +import { computed, NumberSignal } from '../src/index.js'; import { nextFrame } from './utils.js'; use(sinonChai); @@ -60,7 +60,11 @@ describe('@vaadin/hilla-react-signals', () => { expect(signal.value).to.be.undefined; }); - it('should subscribe to signal provider endpoint only after being rendered', async () => { + it('should not subscribe to signal provider endpoint before being subscribed to', () => { + expect(client.subscribe).not.to.have.been.called; + }); + + it('should subscribe to signal provider endpoint only after being subscribed to', async () => { expect(client.subscribe).not.to.have.been.called; render(Value is {signal}); @@ -74,6 +78,25 @@ describe('@vaadin/hilla-react-signals', () => { }); }); + it('should not call client subscribe after being connected to the server instance', async () => { + render(Value is {signal}); + await nextFrame(); + + expect(client.subscribe).to.be.have.been.calledOnce; + expect(client.subscribe).to.have.been.calledWith('SignalsHandler', 'subscribe', { + clientSignalId: signal.id, + providerEndpoint: 'TestEndpoint', + providerMethod: 'testMethod', + }); + + const dependentSignal = computed(() => signal.value); + expect(client.subscribe).to.be.have.been.calledOnce; + + render(Value is {dependentSignal}); + await nextFrame(); + expect(client.subscribe).to.be.have.been.calledOnce; + }); + it('should publish updates to signals handler endpoint', () => { signal.value = 42; From 507e1629b0f7b9d8697c1daa518abac8e9a598e9 Mon Sep 17 00:00:00 2001 From: taefi Date: Tue, 20 Aug 2024 00:30:50 +0300 Subject: [PATCH 4/7] add tests --- .../ts/react-signals/src/FullStackSignal.ts | 8 +++- .../test/FullStackSignal.spec.tsx | 41 ++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/ts/react-signals/src/FullStackSignal.ts b/packages/ts/react-signals/src/FullStackSignal.ts index 5e0d101b6a..93313d9ca3 100644 --- a/packages/ts/react-signals/src/FullStackSignal.ts +++ b/packages/ts/react-signals/src/FullStackSignal.ts @@ -21,7 +21,13 @@ export type StateEvent = Readonly<{ value: T; }>; -abstract class DependencyTrackingSignal extends Signal { +/** + * An abstraction of a signal that tracks the number of subscribers, and calls + * the provided `onSubscribe` and `onUnsubscribe` callbacks for the first + * subscription and the last unsubscription, respectively. + * @internal + */ +export abstract class DependencyTrackingSignal extends Signal { readonly #onSubscribe: () => void; readonly #onUnsubscribe: () => void; diff --git a/packages/ts/react-signals/test/FullStackSignal.spec.tsx b/packages/ts/react-signals/test/FullStackSignal.spec.tsx index ce753ec6c3..0b0fc81f6f 100644 --- a/packages/ts/react-signals/test/FullStackSignal.spec.tsx +++ b/packages/ts/react-signals/test/FullStackSignal.spec.tsx @@ -4,13 +4,50 @@ import { render } from '@testing-library/react'; import { ConnectClient, type Subscription } from '@vaadin/hilla-frontend'; import sinon from 'sinon'; import sinonChai from 'sinon-chai'; -import { type StateEvent, StateEventType } from '../src/FullStackSignal.js'; +import { DependencyTrackingSignal, type StateEvent, StateEventType } from '../src/FullStackSignal.js'; import { computed, NumberSignal } from '../src/index.js'; import { nextFrame } from './utils.js'; use(sinonChai); describe('@vaadin/hilla-react-signals', () => { + describe('DependencyTrackingSignal', () => { + class TestSignal extends DependencyTrackingSignal { + constructor(value: T | undefined, onSubscribe: () => void, onUnsubscribe: () => void) { + super(value, onSubscribe, onUnsubscribe); + this.subscribe(() => {}); // Ignores the internal subscription. + } + } + + let onSubscribe: () => void; + let onUnsubscribe: () => void; + let signal: TestSignal; + + beforeEach(() => { + onSubscribe = sinon.spy(); + onUnsubscribe = sinon.spy(); + signal = new TestSignal(undefined, onSubscribe, onUnsubscribe); + }); + + afterEach(() => { + sinon.resetHistory(); + }); + + it('should call onSubscribe when the first subscription is created', () => { + expect(onSubscribe).not.to.have.been.called; + signal.subscribe(() => {}); + expect(onSubscribe).to.have.been.calledOnce; + }); + + it('should call onUnsubscribe when the last subscription is removed', () => { + expect(onUnsubscribe).not.to.have.been.called; + const subscriptionDisposeFnc = signal.subscribe(() => {}); + expect(onUnsubscribe).not.to.have.been.called; + subscriptionDisposeFnc(); + expect(onUnsubscribe).to.have.been.calledOnce; + }); + }); + describe('FullStackSignal', () => { function simulateReceivedChange( connectSubscriptionMock: sinon.SinonSpiedInstance>>, @@ -92,7 +129,7 @@ describe('@vaadin/hilla-react-signals', () => { const dependentSignal = computed(() => signal.value); expect(client.subscribe).to.be.have.been.calledOnce; - render(Value is {dependentSignal}); + render(Value is {dependentSignal.value}); await nextFrame(); expect(client.subscribe).to.be.have.been.calledOnce; }); From 70a05f5083f26f0d4d576c2f8edb9465ab2f871b Mon Sep 17 00:00:00 2001 From: taefi Date: Tue, 20 Aug 2024 11:33:05 +0300 Subject: [PATCH 5/7] apply suggestions from code review --- .../ts/react-signals/src/FullStackSignal.ts | 17 +++++++--------- .../test/FullStackSignal.spec.tsx | 20 +++++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/packages/ts/react-signals/src/FullStackSignal.ts b/packages/ts/react-signals/src/FullStackSignal.ts index 93313d9ca3..f10a29d9f1 100644 --- a/packages/ts/react-signals/src/FullStackSignal.ts +++ b/packages/ts/react-signals/src/FullStackSignal.ts @@ -28,17 +28,17 @@ export type StateEvent = Readonly<{ * @internal */ export abstract class DependencyTrackingSignal extends Signal { - readonly #onSubscribe: () => void; - readonly #onUnsubscribe: () => void; + readonly #onFirstSubscribe: () => void; + readonly #onLastUnsubscribe: () => void; // -1 means to ignore the first subscription that is created internally in the // FullStackSignal constructor. #subscribeCount = -1; - protected constructor(value: T | undefined, onSubscribe: () => void, onUnsubscribe: () => void) { + protected constructor(value: T | undefined, onFirstSubscribe: () => void, onLastUnsubscribe: () => void) { super(value); - this.#onSubscribe = onSubscribe; - this.#onUnsubscribe = onUnsubscribe; + this.#onFirstSubscribe = onFirstSubscribe; + this.#onLastUnsubscribe = onLastUnsubscribe; } protected S(node: unknown): void { @@ -46,7 +46,7 @@ export abstract class DependencyTrackingSignal extends Signal { // eslint-disable-next-line @typescript-eslint/no-unsafe-call super.S(node); if (this.#subscribeCount === 0) { - this.#onSubscribe(); + this.#onFirstSubscribe(); } this.#subscribeCount += 1; } @@ -57,7 +57,7 @@ export abstract class DependencyTrackingSignal extends Signal { super.U(node); this.#subscribeCount -= 1; if (this.#subscribeCount === 0) { - this.#onUnsubscribe(); + this.#onLastUnsubscribe(); } } } @@ -193,9 +193,6 @@ export abstract class FullStackSignal extends DependencyTrackingSignal { } #connect() { - if (this.server.subscription !== undefined) { - return; - } this.server.connect().onNext((event: StateEvent) => { if (event.type === StateEventType.SNAPSHOT) { this.#paused = true; diff --git a/packages/ts/react-signals/test/FullStackSignal.spec.tsx b/packages/ts/react-signals/test/FullStackSignal.spec.tsx index 0b0fc81f6f..8e039fe541 100644 --- a/packages/ts/react-signals/test/FullStackSignal.spec.tsx +++ b/packages/ts/react-signals/test/FullStackSignal.spec.tsx @@ -19,14 +19,14 @@ describe('@vaadin/hilla-react-signals', () => { } } - let onSubscribe: () => void; - let onUnsubscribe: () => void; + let onFirstSubscribe: sinon.SinonSpy; + let onLastUnsubscribe: sinon.SinonSpy; let signal: TestSignal; beforeEach(() => { - onSubscribe = sinon.spy(); - onUnsubscribe = sinon.spy(); - signal = new TestSignal(undefined, onSubscribe, onUnsubscribe); + onFirstSubscribe = sinon.spy(); + onLastUnsubscribe = sinon.spy(); + signal = new TestSignal(undefined, onFirstSubscribe, onLastUnsubscribe); }); afterEach(() => { @@ -34,17 +34,17 @@ describe('@vaadin/hilla-react-signals', () => { }); it('should call onSubscribe when the first subscription is created', () => { - expect(onSubscribe).not.to.have.been.called; + expect(onFirstSubscribe).not.to.have.been.called; signal.subscribe(() => {}); - expect(onSubscribe).to.have.been.calledOnce; + expect(onFirstSubscribe).to.have.been.calledOnce; }); it('should call onUnsubscribe when the last subscription is removed', () => { - expect(onUnsubscribe).not.to.have.been.called; + expect(onLastUnsubscribe).not.to.have.been.called; const subscriptionDisposeFnc = signal.subscribe(() => {}); - expect(onUnsubscribe).not.to.have.been.called; + expect(onLastUnsubscribe).not.to.have.been.called; subscriptionDisposeFnc(); - expect(onUnsubscribe).to.have.been.calledOnce; + expect(onLastUnsubscribe).to.have.been.calledOnce; }); }); From 2ce954d934b8e8bcaf3e61439b4f7f70c58b4005 Mon Sep 17 00:00:00 2001 From: taefi Date: Tue, 20 Aug 2024 13:43:34 +0300 Subject: [PATCH 6/7] fix @remix-run/router version --- package-lock.json | 780 ++++++++++++++++++++-------------------------- 1 file changed, 335 insertions(+), 445 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d454b243f..80ecc3ea48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3487,9 +3487,9 @@ } }, "node_modules/@preact/signals-react": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-2.1.0.tgz", - "integrity": "sha512-jWq2ldDWXdbKpg+aMGuOZfj9tS5JkVlGJ5hGNzNe1Zfe7RLFfvldBEfNe6ZT7KZddecAxKhyoxSsEypgbfx/Gw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-2.2.0.tgz", + "integrity": "sha512-EPYlhXqqcOUxz2gTQGt4rtK6X7Jr04517DcJVZ4I5a7Gxy39haK24uFeVWtiU/tnEReRFcxpQN6poYra1jf68A==", "dependencies": { "@preact/signals-core": "^1.7.0", "use-sync-external-store": "^1.2.0" @@ -3524,17 +3524,17 @@ } }, "node_modules/@remix-run/router": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", - "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz", + "integrity": "sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==", "engines": { "node": ">=14.0.0" } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", - "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz", + "integrity": "sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==", "cpu": [ "arm" ], @@ -3544,9 +3544,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", - "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz", + "integrity": "sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==", "cpu": [ "arm64" ], @@ -3556,9 +3556,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz", + "integrity": "sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==", "cpu": [ "arm64" ], @@ -3568,9 +3568,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", - "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz", + "integrity": "sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==", "cpu": [ "x64" ], @@ -3580,9 +3580,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", - "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz", + "integrity": "sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==", "cpu": [ "arm" ], @@ -3592,9 +3592,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", - "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz", + "integrity": "sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==", "cpu": [ "arm" ], @@ -3604,9 +3604,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", - "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz", + "integrity": "sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==", "cpu": [ "arm64" ], @@ -3616,9 +3616,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", - "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz", + "integrity": "sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==", "cpu": [ "arm64" ], @@ -3628,9 +3628,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", - "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz", + "integrity": "sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==", "cpu": [ "ppc64" ], @@ -3640,9 +3640,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", - "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz", + "integrity": "sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==", "cpu": [ "riscv64" ], @@ -3652,9 +3652,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", - "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz", + "integrity": "sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==", "cpu": [ "s390x" ], @@ -3664,9 +3664,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz", + "integrity": "sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==", "cpu": [ "x64" ], @@ -3676,9 +3676,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz", + "integrity": "sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==", "cpu": [ "x64" ], @@ -3688,9 +3688,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz", + "integrity": "sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==", "cpu": [ "arm64" ], @@ -3700,9 +3700,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz", + "integrity": "sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==", "cpu": [ "ia32" ], @@ -3712,9 +3712,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz", + "integrity": "sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==", "cpu": [ "x64" ], @@ -3786,9 +3786,9 @@ } }, "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", "dev": true }, "node_modules/@socket.io/component-emitter": { @@ -3919,189 +3919,30 @@ } }, "node_modules/@testing-library/react": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz", - "integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", + "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", "dev": true, "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^9.0.0", - "@types/react-dom": "^18.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", "react": "^18.0.0", "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "9.3.4", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", - "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@testing-library/react/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/react/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/@testing-library/react/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/react/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/react/node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@testing-library/react/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/@testing-library/react/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/react/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@testing-library/react/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, "node_modules/@testing-library/user-event": { @@ -4495,12 +4336,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", - "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", + "version": "20.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.1.tgz", + "integrity": "sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/parse-json": { @@ -6702,9 +6543,9 @@ } }, "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true }, "node_modules/async-arrays": { @@ -6781,9 +6622,9 @@ } }, "node_modules/axios": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", - "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -7200,9 +7041,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001650", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001650.tgz", - "integrity": "sha512-fgEc7hP/LB7iicdXHUI9VsBsMZmUmlVJeQP2qqQW+3lkqVhbmjEU8zp+h5stWeilX+G7uXuIUIIlWlDw9jdt8g==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true, "funding": [ { @@ -7297,7 +7138,6 @@ "resolved": "https://registry.npmjs.org/chai-like/-/chai-like-1.1.1.tgz", "integrity": "sha512-VKa9z/SnhXhkT1zIjtPACFWSoWsqVoaz1Vg+ecrKo5DCKVlgL30F/pEyEvXPBOVwCgLZcWUleCM/C1okaKdTTA==", "dev": true, - "license": "MIT", "peerDependencies": { "chai": "2 - 4" } @@ -8489,10 +8329,36 @@ } }, "node_modules/deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==", - "dev": true + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/deep-equal-in-any-order": { "version": "2.0.6", @@ -8504,6 +8370,12 @@ "sort-any": "^2.0.0" } }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -8923,9 +8795,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.12.tgz", + "integrity": "sha512-tIhPkdlEoCL1Y+PToq3zRNehUaKp3wBX/sr7aclAWdIWjvqAe/Im/H0SiCM4c1Q8BLPHCdoJTol+ZblflydehA==", "dev": true }, "node_modules/emoji-regex": { @@ -10429,9 +10301,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.0", @@ -10952,6 +10824,12 @@ "node": ">= 0.8" } }, + "node_modules/http-assert/node_modules/deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==", + "dev": true + }, "node_modules/http-assert/node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -11087,9 +10965,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" @@ -11777,7 +11655,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/iterator-helpers-polyfill/-/iterator-helpers-polyfill-3.0.1.tgz", "integrity": "sha512-9uSoKErC0+TG7uoXlv5k7rs196/l/VGr9hb9KbptpMhszsSksxJCwetp0p7FvgM3SwxlxgEkvokmeOi02PARlQ==", - "license": "MIT", "engines": { "chrome": ">=63", "firefox": ">=57", @@ -12646,9 +12523,9 @@ } }, "node_modules/lint-staged": { - "version": "15.2.8", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.8.tgz", - "integrity": "sha512-PUWFf2zQzsd9EFU+kM1d7UP+AZDbKFKuj+9JNVTBkhUFhbg4MAt6WfyMMwBfM4lYqd4D2Jwac5iuTu9rVj4zCQ==", + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", + "integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", "dev": true, "dependencies": { "chalk": "~5.3.0", @@ -13381,9 +13258,9 @@ } }, "node_modules/mocha": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz", - "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", @@ -13625,9 +13502,9 @@ } }, "node_modules/monocart-coverage-reports": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/monocart-coverage-reports/-/monocart-coverage-reports-2.10.1.tgz", - "integrity": "sha512-BYjyBxxcg+qoSWtZBN6yeFi9HoySHzsNB9vxUvjpFe63FdnN2olbsvmG64hC5K3mE9y/Ptb75KNNOA0O55ITgQ==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/monocart-coverage-reports/-/monocart-coverage-reports-2.10.3.tgz", + "integrity": "sha512-CVBjRABy5ygNMVnk5IOVZyB2gfiCUG2xxZuFd5D3nuiP/ja2XWC9GJ8ddgr4fXwrbm8vMkSjOxXs/mfvgP9pSA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", @@ -13638,7 +13515,7 @@ "commander": "^12.1.0", "console-grid": "^2.2.2", "eight-colors": "^1.3.0", - "foreground-child": "^3.2.1", + "foreground-child": "^3.3.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.1.7", @@ -15234,9 +15111,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -15541,11 +15418,11 @@ } }, "node_modules/react-router": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz", - "integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==", + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.1.tgz", + "integrity": "sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==", "dependencies": { - "@remix-run/router": "1.19.0" + "@remix-run/router": "1.19.1" }, "engines": { "node": ">=14.0.0" @@ -15555,12 +15432,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.0.tgz", - "integrity": "sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==", + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.1.tgz", + "integrity": "sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==", "dependencies": { - "@remix-run/router": "1.19.0", - "react-router": "6.26.0" + "@remix-run/router": "1.19.1", + "react-router": "6.26.1" }, "engines": { "node": ">=14.0.0" @@ -15931,9 +15808,9 @@ } }, "node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.0.tgz", + "integrity": "sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==", "dependencies": { "@types/estree": "1.0.5" }, @@ -15945,22 +15822,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", + "@rollup/rollup-android-arm-eabi": "4.21.0", + "@rollup/rollup-android-arm64": "4.21.0", + "@rollup/rollup-darwin-arm64": "4.21.0", + "@rollup/rollup-darwin-x64": "4.21.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.0", + "@rollup/rollup-linux-arm-musleabihf": "4.21.0", + "@rollup/rollup-linux-arm64-gnu": "4.21.0", + "@rollup/rollup-linux-arm64-musl": "4.21.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.0", + "@rollup/rollup-linux-riscv64-gnu": "4.21.0", + "@rollup/rollup-linux-s390x-gnu": "4.21.0", + "@rollup/rollup-linux-x64-gnu": "4.21.0", + "@rollup/rollup-linux-x64-musl": "4.21.0", + "@rollup/rollup-win32-arm64-msvc": "4.21.0", + "@rollup/rollup-win32-ia32-msvc": "4.21.0", + "@rollup/rollup-win32-x64-msvc": "4.21.0", "fsevents": "~2.3.2" } }, @@ -17143,12 +17020,12 @@ } }, "node_modules/tsx": { - "version": "4.16.5", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.5.tgz", - "integrity": "sha512-ArsiAQHEW2iGaqZ8fTA1nX0a+lN5mNTyuGRRO6OW3H/Yno1y9/t1f9YOI1Cfoqz63VAthn++ZYcbDP7jPflc+A==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.17.0.tgz", + "integrity": "sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==", "dev": true, "dependencies": { - "esbuild": "~0.21.5", + "esbuild": "~0.23.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -17183,9 +17060,9 @@ } }, "node_modules/type-fest": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz", - "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.25.0.tgz", + "integrity": "sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==", "dev": true, "engines": { "node": ">=16" @@ -17337,9 +17214,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -18690,6 +18567,154 @@ "react": "^18" } }, + "packages/ts/models/node_modules/@testing-library/dom": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "packages/ts/models/node_modules/@testing-library/react": { + "version": "14.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz", + "integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^9.0.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "packages/ts/models/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/ts/models/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "packages/ts/models/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/ts/models/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "packages/ts/models/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "packages/ts/models/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "packages/ts/models/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "packages/ts/models/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/ts/models/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "packages/ts/models/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "packages/ts/react-auth": { "name": "@vaadin/hilla-react-auth", "version": "24.5.0-alpha9", @@ -18720,33 +18745,6 @@ "react-router-dom": "^6" } }, - "packages/ts/react-auth/node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "packages/ts/react-crud": { "name": "@vaadin/hilla-react-crud", "version": "24.5.0-alpha9", @@ -18782,33 +18780,6 @@ "react-dom": "^18" } }, - "packages/ts/react-crud/node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "packages/ts/react-form": { "name": "@vaadin/hilla-react-form", "version": "24.5.0-alpha9", @@ -18839,33 +18810,6 @@ "react": "^18" } }, - "packages/ts/react-form/node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "packages/ts/react-i18n": { "name": "@vaadin/hilla-react-i18n", "version": "24.5.0-alpha9", @@ -18899,33 +18843,6 @@ "react": "^18" } }, - "packages/ts/react-i18n/node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "packages/ts/react-signals": { "name": "@vaadin/hilla-react-signals", "version": "24.5.0-alpha9", @@ -18962,33 +18879,6 @@ "react-router-dom": "^6" } }, - "packages/ts/react-signals/node_modules/@testing-library/react": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", - "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "packages/ts/react-signals/node_modules/nanoid": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", From 34f3e962e8462170674b0ba54bd30d0256153809 Mon Sep 17 00:00:00 2001 From: taefi Date: Tue, 20 Aug 2024 15:20:15 +0300 Subject: [PATCH 7/7] apply suggestions from code review --- packages/ts/react-signals/test/FullStackSignal.spec.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ts/react-signals/test/FullStackSignal.spec.tsx b/packages/ts/react-signals/test/FullStackSignal.spec.tsx index 8e039fe541..4155b5a0aa 100644 --- a/packages/ts/react-signals/test/FullStackSignal.spec.tsx +++ b/packages/ts/react-signals/test/FullStackSignal.spec.tsx @@ -19,13 +19,13 @@ describe('@vaadin/hilla-react-signals', () => { } } - let onFirstSubscribe: sinon.SinonSpy; - let onLastUnsubscribe: sinon.SinonSpy; + let onFirstSubscribe: sinon.SinonStub; + let onLastUnsubscribe: sinon.SinonStub; let signal: TestSignal; beforeEach(() => { - onFirstSubscribe = sinon.spy(); - onLastUnsubscribe = sinon.spy(); + onFirstSubscribe = sinon.stub(); + onLastUnsubscribe = sinon.stub(); signal = new TestSignal(undefined, onFirstSubscribe, onLastUnsubscribe); });