diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 40e36667415..d60310d0013 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -176,7 +176,7 @@ jobs: - name: Build GTFS GraphQL API documentation run: | - npm install -g @magidoc/cli@6.1.0 + npm install -g @magidoc/cli@6.2.0 magidoc generate --stacktrace - name: Deploy compiled HTML to Github pages diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index ad3b843dd12..1ec537a0b4f 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -88,7 +88,7 @@ jobs: - name: Build graph if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x' run: | - cp application/target/otp-*-SNAPSHOT-shaded.jar otp.jar + cp shaded-jar/target/otp-*-SNAPSHOT-shaded.jar otp.jar java -Xmx32G -jar otp.jar --build --save test/performance/${{ matrix.location }}/ - name: Run speed test diff --git a/DEVELOPMENT_DECISION_RECORDS.md b/DEVELOPMENT_DECISION_RECORDS.md index 2625be325e8..333ac88e1db 100644 --- a/DEVELOPMENT_DECISION_RECORDS.md +++ b/DEVELOPMENT_DECISION_RECORDS.md @@ -110,3 +110,7 @@ Prefer immutable types over mutable. Use builders where appropriate. See [Avoid using records if you cannot encapsulate it properly](doc/dev/decisionrecords/RecordsPOJOsBuilders.md#records) +## GraphQL Best Practices - API Design + +[Follow best practices for designing GraphQL APIs. Our APIs need to be backwards compatible as they are used +by hundreds of clients (web-pages/apps/services).](doc/dev/decisionrecords/APIGraphQLDesign.md) \ No newline at end of file diff --git a/README.md b/README.md index 41d889cf15b..ec66e694e8c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ We run a speed test (included in the code) to measure the performance for every The main Java server code is in `application/src/main/`. OTP also includes a Javascript client based on the MapLibre mapping library in `client/src/`. This client is now used for testing, with most major deployments building custom clients from reusable components. The Maven build produces a unified ("shaded") -JAR file at `application/target/otp-VERSION.jar` containing all necessary code and dependencies to run OpenTripPlanner. +JAR file at `shaded-jar/target/otp-VERSION.jar` containing all necessary code and dependencies to run OpenTripPlanner. Additional information and instructions are available in the [main documentation](http://docs.opentripplanner.org/en/dev-2.x/), including a diff --git a/application/pom.xml b/application/pom.xml index 92313b94304..6f97e3d17e2 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -148,7 +148,7 @@ org.mobilitydata gbfs-java-model - 1.0.7 + 1.0.9 @@ -302,7 +302,7 @@ org.onebusaway onebusaway-gtfs - 3.2.4 + 4.3.0 diff --git a/application/src/client/index.html b/application/src/client/index.html index 391458fba41..23748ea08a7 100644 --- a/application/src/client/index.html +++ b/application/src/client/index.html @@ -4,9 +4,9 @@ - OTP Debug Client - - + OTP Debug + +
diff --git a/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java b/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java index d1e3bd4837c..c819d4abc2e 100644 --- a/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java +++ b/application/src/ext-test/java/org/opentripplanner/ext/fares/impl/OrcaFareServiceTest.java @@ -54,8 +54,7 @@ public class OrcaFareServiceTest { private static final Money ONE_DOLLAR = usDollars(1f); private static final Money TWO_DOLLARS = usDollars(2); - private static final Money FERRY_FARE = usDollars(6.50f); - private static final Money HALF_FERRY_FARE = usDollars(3.25f); + private static final Money HALF_FERRY_FARE = usDollars(1.75f); private static final Money ORCA_SPECIAL_FARE = usDollars(1.00f); public static final Money VASHON_WATER_TAXI_CASH_FARE = usDollars(6.75f); public static final Money WEST_SEATTLE_WATER_TAXI_CASH_FARE = usDollars(5.75f); @@ -219,24 +218,24 @@ void calculateFareThatIncludesNoFreeTransfers() { getLeg(KITSAP_TRANSIT_AGENCY_ID, 121), getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 150, "Fauntleroy-VashonIsland") ); - calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(3).plus(FERRY_FARE)); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE.times(5)); calculateFare( rides, FareType.senior, - ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE).plus(usDollars(0.5f)) + ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE.times(2)).plus(usDollars(0.5f)) ); calculateFare(rides, FareType.youth, Money.ZERO_USD); // We don't get any fares for the skagit transit leg below here because they don't accept ORCA (electronic) - calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR.plus(ONE_DOLLAR).plus(FERRY_FARE)); + calculateFare(rides, FareType.electronicSpecial, ONE_DOLLAR.plus(ONE_DOLLAR).plus(DEFAULT_TEST_RIDE_PRICE.times(2))); calculateFare( rides, FareType.electronicRegular, - DEFAULT_TEST_RIDE_PRICE.times(2).plus(FERRY_FARE) + DEFAULT_TEST_RIDE_PRICE.times(4) ); calculateFare( rides, FareType.electronicSenior, - ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE) + ONE_DOLLAR.plus(ONE_DOLLAR).plus(HALF_FERRY_FARE.times(2)) ); calculateFare(rides, FareType.electronicYouth, ZERO_USD); } @@ -326,11 +325,11 @@ void calculateFareForWSFPtToTahlequah() { List rides = List.of( getLeg(WASHINGTON_STATE_FERRIES_AGENCY_ID, 0, "Point Defiance - Tahlequah") ); - calculateFare(rides, regular, FERRY_FARE); + calculateFare(rides, regular, DEFAULT_TEST_RIDE_PRICE); calculateFare(rides, FareType.senior, HALF_FERRY_FARE); calculateFare(rides, FareType.youth, Money.ZERO_USD); - calculateFare(rides, FareType.electronicSpecial, FERRY_FARE); - calculateFare(rides, FareType.electronicRegular, FERRY_FARE); + calculateFare(rides, FareType.electronicSpecial, DEFAULT_TEST_RIDE_PRICE); + calculateFare(rides, FareType.electronicRegular, DEFAULT_TEST_RIDE_PRICE); calculateFare(rides, FareType.electronicSenior, HALF_FERRY_FARE); calculateFare(rides, FareType.electronicYouth, Money.ZERO_USD); } diff --git a/application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java b/application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java new file mode 100644 index 00000000000..f4cfa8ceb80 --- /dev/null +++ b/application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java @@ -0,0 +1,393 @@ +package org.opentripplanner.ext.siri.updater.azure; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.*; + +import com.azure.core.util.ExpandableStringEnum; +import com.azure.messaging.servicebus.ServiceBusErrorContext; +import com.azure.messaging.servicebus.ServiceBusErrorSource; +import com.azure.messaging.servicebus.ServiceBusException; +import com.azure.messaging.servicebus.ServiceBusFailureReason; +import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.time.Duration; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.opentripplanner.framework.io.OtpHttpClientException; + +class AbstractAzureSiriUpdaterTest { + + private SiriAzureUpdaterParameters mockConfig; + private AbstractAzureSiriUpdater updater; + private AbstractAzureSiriUpdater.CheckedRunnable task; + + @BeforeEach + public void setUp() throws Exception { + mockConfig = mock(SiriAzureUpdaterParameters.class); + when(mockConfig.configRef()).thenReturn("testConfigRef"); + when(mockConfig.getAuthenticationType()).thenReturn(AuthenticationType.SharedAccessKey); + when(mockConfig.getFullyQualifiedNamespace()).thenReturn("testNamespace"); + when(mockConfig.getServiceBusUrl()).thenReturn("testServiceBusUrl"); + when(mockConfig.getTopicName()).thenReturn("testTopic"); + when(mockConfig.getDataInitializationUrl()).thenReturn("http://testurl.com"); + when(mockConfig.getTimeout()).thenReturn(5000); + when(mockConfig.feedId()).thenReturn("testFeedId"); + when(mockConfig.getAutoDeleteOnIdle()).thenReturn(Duration.ofHours(1)); + when(mockConfig.getPrefetchCount()).thenReturn(10); + when(mockConfig.isFuzzyTripMatching()).thenReturn(true); + + // Create a spy on AbstractAzureSiriUpdater with the mock configuration + updater = spy(new AbstractAzureSiriUpdater(mockConfig) { + @Override + protected void messageConsumer(ServiceBusReceivedMessageContext messageContext) { + } + + @Override + protected void errorConsumer(ServiceBusErrorContext errorContext) { + } + + @Override + protected void initializeData(String url, + Consumer consumer + ) throws URISyntaxException { + } + }); + + task = mock(AbstractAzureSiriUpdater.CheckedRunnable.class); + } + + /** + * Tests the retry mechanism when a retryable ServiceBusException is thrown multiple times + * and checks that it follows the backoff sequence. + */ + @Test + void testExecuteWithRetry_FullBackoffSequence() throws Throwable { + final int totalRunCalls = 10; // 9 failures + 1 success + final int totalSleepCalls = 9; // 9 retries + + doNothing().when(updater).sleep(anyInt()); + + // Configure the task to throw a retryable exception for 9 attempts and then succeed + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doNothing() // Succeed on the 10th attempt + .when(task).run(); + + updater.executeWithRetry(task, "Test Task"); + + verify(updater, times(totalSleepCalls)).sleep(anyInt()); + + InOrder inOrder = inOrder(updater); + inOrder.verify(updater).sleep(1000); + inOrder.verify(updater).sleep(2000); + inOrder.verify(updater).sleep(4000); + inOrder.verify(updater).sleep(8000); + inOrder.verify(updater).sleep(16000); + inOrder.verify(updater).sleep(32000); + + for (int i = 0; i < 3; i++) { + inOrder.verify(updater).sleep(60000); + } + + verify(task, times(totalRunCalls)).run(); + } + + /** + * Tests the executeWithRetry method when a non-retryable exception is thrown. + * Ensures that no further retries are attempted and sleep is not called. + */ + @Test + public void testExecuteWithRetry_NonRetryableException() throws Throwable { + doNothing().when(updater).sleep(anyInt()); + + ServiceBusException serviceBusException = createServiceBusException(ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED); + + doThrow(serviceBusException).when(task).run(); + + try { + updater.executeWithRetry(task, "Test Task"); + } catch (ServiceBusException e) { + assertEquals(ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED, e.getReason(), "Exception should have reason MESSAGE_SIZE_EXCEEDED"); + } + + verify(updater, never()).sleep(anyInt()); + verify(task, times(1)).run(); + } + + /** + * Tests the executeWithRetry method when the task fails multiple times with retryable exceptions + * and then succeeds, ensuring that sleep is called the expected number of times with correct durations. + */ + @Test + public void testExecuteWithRetry_MultipleRetriesThenSuccess() throws Throwable { + final int retriesBeforeSuccess = 3; + CountDownLatch latch = new CountDownLatch(retriesBeforeSuccess); + + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doNothing() + .when(task).run(); + + doAnswer(invocation -> { + latch.countDown(); + return null; + }).when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + boolean completed = latch.await(5, TimeUnit.SECONDS); + assertTrue(completed, "Expected sleep calls were not made."); + + ArgumentCaptor sleepCaptor = ArgumentCaptor.forClass(Integer.class); + verify(updater, times(retriesBeforeSuccess)).sleep(sleepCaptor.capture()); + + var sleepDurations = sleepCaptor.getAllValues(); + long[] expectedBackoffSequence = {1000, 2000, 4000}; + + for (int i = 0; i < expectedBackoffSequence.length; i++) { + assertEquals(expectedBackoffSequence[i], Long.valueOf(sleepDurations.get(i)), + "Backoff duration mismatch at retry " + (i + 1)); + } + + verify(task, times(retriesBeforeSuccess + 1)).run(); + } + + /** + * Tests the executeWithRetry method when the task succeeds on the first attempt. + * Ensures that no sleep calls are made. + */ + @Test + public void testExecuteWithRetry_ImmediateSuccess() throws Throwable { + doNothing().when(task).run(); + doNothing().when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + verify(updater, never()).sleep(anyInt()); + verify(task, times(1)).run(); + } + + /** + * Tests the executeWithRetry method when the task fails once with a retryable exception + * and then succeeds on the first retry. + */ + @Test + public void testExecuteWithRetry_OneRetryThenSuccess() throws Throwable { + final int expectedSleepCalls = 1; + CountDownLatch latch = new CountDownLatch(expectedSleepCalls); + + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doNothing() + .when(task).run(); + + doAnswer(invocation -> { + if (invocation.getArgument(0).equals(1000)) { + latch.countDown(); + } + return null; + }).when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + boolean completed = latch.await(5, TimeUnit.SECONDS); + assertTrue(completed, "Expected sleep call was not made."); + + verify(updater, times(expectedSleepCalls)).sleep(1000); + verify(task, times(2)).run(); + } + + /** + * Parameterized test to verify that shouldRetry returns the correct value for each ServiceBusFailureReason. + * + * @param reason The ServiceBusFailureReason to test. + * @param expectedRetry The expected result of shouldRetry. + */ + @ParameterizedTest(name = "shouldRetry with reason {0} should return {1}") + @MethodSource("provideServiceBusFailureReasons") + @DisplayName("Test shouldRetry for all ServiceBusFailureReason values") + void testShouldRetry_ServiceBusFailureReasons(ServiceBusFailureReason reason, boolean expectedRetry) throws Exception { + ServiceBusException serviceBusException = createServiceBusException(reason); + boolean result = updater.shouldRetry(serviceBusException); + assertEquals(expectedRetry, result, "shouldRetry should return " + expectedRetry + " for reason " + reason); + } + + /** + * Test that shouldRetry returns false for non-ServiceBus exceptions. + */ + @Test + @DisplayName("shouldRetry should return false for non-ServiceBus exceptions") + public void testShouldRetry_NonServiceBusException() { + Exception genericException = new Exception("Generic exception"); + boolean result = updater.shouldRetry(genericException); + assertFalse(result, "shouldRetry should return false for non-ServiceBus exceptions"); + } + + /** + * Test that shouldRetry handles all ServiceBusFailureReason values. + * Since enums are closed, this test ensures that the parameterized tests cover all existing values. + */ + @Test + @DisplayName("shouldRetry covers all ServiceBusFailureReason values") + public void testShouldRetry_CoversAllReasons() { + long enumCount = getExpandableStringEnumValues(ServiceBusFailureReason.class).size(); + long testCaseCount = provideServiceBusFailureReasons().count(); + assertEquals(enumCount, testCaseCount, "All ServiceBusFailureReason values should be covered by tests."); + } + + @Test + void testExecuteWithRetry_InterruptedException() throws Throwable { + final int expectedRunCalls = 2; + final int expectedSleepCalls = 1; + + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(new InterruptedException("Sleep interrupted")) + .when(task).run(); + + doNothing().when(updater).sleep(1000); + + InterruptedException thrownException = assertThrows(InterruptedException.class, () -> { + updater.executeWithRetry(task, "Test Task"); + }, "Expected executeWithRetry to throw InterruptedException"); + + assertEquals("Sleep interrupted", thrownException.getMessage(), "Exception message should match"); + verify(updater, times(expectedSleepCalls)).sleep(1000); + verify(task, times(expectedRunCalls)).run(); + assertTrue(Thread.currentThread().isInterrupted(), "Thread should be interrupted"); + } + + @Test + void testExecuteWithRetry_OtpHttpClientException() throws Throwable { + final int retryAttempts = 3; + final int expectedSleepCalls = retryAttempts; + + doThrow(new OtpHttpClientException("could not get historical data")) + .doThrow(new OtpHttpClientException("could not get historical data")) + .doThrow(new OtpHttpClientException("could not get historical data")) + .doNothing() + .when(task).run(); + + doNothing().when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + ArgumentCaptor sleepCaptor = ArgumentCaptor.forClass(Integer.class); + verify(updater, times(expectedSleepCalls)).sleep(sleepCaptor.capture()); + + List sleepDurations = sleepCaptor.getAllValues(); + List expectedBackoffSequence = Arrays.asList(1000, 2000, 4000); + + for (int i = 0; i < retryAttempts; i++) { + assertEquals(expectedBackoffSequence.get(i), sleepDurations.get(i), + "Backoff duration mismatch at retry " + (i + 1)); + } + + verify(task, times(retryAttempts + 1)).run(); + } + + @Test + void testExecuteWithRetry_UnexpectedException() throws Throwable { + doNothing().when(updater).sleep(anyInt()); + + Exception unexpectedException = new NullPointerException("Unexpected null value"); + doThrow(unexpectedException).when(task).run(); + + Exception thrown = assertThrows(NullPointerException.class, () -> { + updater.executeWithRetry(task, "Test Task"); + }, "Expected executeWithRetry to throw NullPointerException"); + + assertEquals("Unexpected null value", thrown.getMessage(), "Exception message should match"); + verify(updater, never()).sleep(anyInt()); + verify(task, times(1)).run(); + } + + /** + * Provides test arguments for each ServiceBusFailureReason and the expected shouldRetry outcome. + * + * @return Stream of Arguments containing ServiceBusFailureReason and expected boolean. + */ + private static Stream provideServiceBusFailureReasons() { + return Stream.of( + // Retryable (Transient) Errors + Arguments.of(ServiceBusFailureReason.SERVICE_BUSY, true), + Arguments.of(ServiceBusFailureReason.SERVICE_TIMEOUT, true), + Arguments.of(ServiceBusFailureReason.SERVICE_COMMUNICATION_ERROR, true), + Arguments.of(ServiceBusFailureReason.MESSAGE_LOCK_LOST, true), + Arguments.of(ServiceBusFailureReason.SESSION_LOCK_LOST, true), + Arguments.of(ServiceBusFailureReason.SESSION_CANNOT_BE_LOCKED, true), + Arguments.of(ServiceBusFailureReason.QUOTA_EXCEEDED, true), + Arguments.of(ServiceBusFailureReason.GENERAL_ERROR, true), + Arguments.of(ServiceBusFailureReason.UNAUTHORIZED, true), + + // Non-Retryable Errors + Arguments.of(ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND, false), + Arguments.of(ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED, false), + Arguments.of(ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED, false), + Arguments.of(ServiceBusFailureReason.MESSAGE_NOT_FOUND, false), + Arguments.of(ServiceBusFailureReason.MESSAGING_ENTITY_ALREADY_EXISTS, false) + ); + } + + /** + * Helper method to create a ServiceBusException with a specified failure reason. + * + * @param reason The ServiceBusFailureReason to set. + * @return A ServiceBusException instance with the specified reason. + */ + private ServiceBusException createServiceBusException(ServiceBusFailureReason reason) { + ServiceBusException exception = new ServiceBusException(new Throwable(), ServiceBusErrorSource.RECEIVE); + try { + Field reasonField = ServiceBusException.class.getDeclaredField("reason"); + reasonField.setAccessible(true); + reasonField.set(exception, reason); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException("Failed to set ServiceBusFailureReason via reflection", e); + } + return exception; + } + + /** + * Helper method to retrieve all instances of an ExpandableStringEnum subclass. + * + * @param clazz The class of the ExpandableStringEnum subclass. + * @param The type parameter extending ExpandableStringEnum. + * @return A Collection of all registered instances. + */ + private static > Collection getExpandableStringEnumValues(Class clazz) { + try { + Method valuesMethod = ExpandableStringEnum.class.getDeclaredMethod("values", Class.class); + valuesMethod.setAccessible(true); + @SuppressWarnings("unchecked") + Collection values = (Collection) valuesMethod.invoke(null, clazz); + return values; + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to retrieve values from ExpandableStringEnum.", e); + } + } +} \ No newline at end of file diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java index c3c1873ad6d..2b732c8dbc4 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -25,7 +25,6 @@ import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; -import org.opentripplanner.transit.model.organization.Agency; public class OrcaFareService extends DefaultFareService { @@ -39,7 +38,7 @@ public class OrcaFareService extends DefaultFareService { public static final String PIERCE_COUNTY_TRANSIT_AGENCY_ID = "3"; public static final String SKAGIT_TRANSIT_AGENCY_ID = "e0e4541a-2714-487b-b30c-f5c6cb4a310f"; public static final String SEATTLE_STREET_CAR_AGENCY_ID = "23"; - public static final String WASHINGTON_STATE_FERRIES_AGENCY_ID = "WSF"; + public static final String WASHINGTON_STATE_FERRIES_AGENCY_ID = "95"; public static final String KITSAP_TRANSIT_AGENCY_ID = "kt"; public static final String WHATCOM_AGENCY_ID = "14"; public static final int ROUTE_TYPE_FERRY = 4; @@ -398,28 +397,11 @@ private Money getWashingtonStateFerriesFare( return defaultFare; } - var longName = routeLongName.toString().replaceAll(" ", ""); - - Map fares = OrcaFaresData.washingtonStateFerriesFares.get(longName); - // WSF doesn't support transfers so we only care about cash fares. - FareType wsfFareType; - if (fareType == FareType.electronicRegular) { - wsfFareType = FareType.regular; - } else if (fareType == FareType.electronicSenior) { - wsfFareType = FareType.senior; - } else if (fareType == FareType.electronicYouth) { - wsfFareType = FareType.youth; - } else if (fareType == FareType.electronicSpecial) { - wsfFareType = FareType.regular; - } else { - wsfFareType = fareType; - } - // WSF is free in one direction on each route - // If a fare is not found in the map, we can assume it's free. - // Route long name is reversed for the reverse direction on a single WSF route - return (fares != null && fares.get(wsfFareType) != null) - ? fares.get(wsfFareType) - : Money.ZERO_USD; + return switch (fareType) { + case youth, electronicYouth -> Money.ZERO_USD; + case regular, electronicRegular, electronicSpecial -> defaultFare; + case senior, electronicSenior -> defaultFare.half().roundDownToNearestFiveMinorUnits(); + }; } /** diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java deleted file mode 100644 index acef59a7c03..00000000000 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.opentripplanner.ext.fares.impl; - -import java.util.Map; -import org.opentripplanner.routing.core.FareType; -import org.opentripplanner.transit.model.basic.Money; - -/** - * Class used to store all the fares for Sounder commuter rail. - * Data comes from a Python script that parses SoundTransit's website. - * A matrix or CSV parser would be a better approach to storing this data, - * but a refactor is unneeded given the proximity of GTFS Fares V2 which will render this redundant. - */ -class OrcaFaresData { - - // Spaces have been removed from the route name because of inconsistencies in the WSF GTFS route dataset. - public static Map> washingtonStateFerriesFares = Map.ofEntries( - sEntry("Seattle-BainbridgeIsland", 9.85f, 4.90f), - sEntry("Seattle-Bremerton", 9.85f, 4.90f), - sEntry("Mukilteo-Clinton", 6f, 3f), - sEntry("Fauntleroy-VashonIsland", 6.50f, 3.25f), - sEntry("Fauntleroy-Southworth", 7.70f, 3.85f), - sEntry("Edmonds-Kingston", 9.85f, 4.90f), - sEntry("PointDefiance-Tahlequah", 6.50f, 3.25f), - sEntry("Anacortes-FridayHarbor", 15.85f, 7.90f), - sEntry("Anacortes-LopezIsland", 15.85f, 7.90f), - sEntry("Anacortes-OrcasIsland", 15.85f, 7.90f), - sEntry("Anacortes-ShawIsland", 15.85f, 7.90f), - sEntry("Coupeville-PortTownsend", 4.10f, 2.05f), - sEntry("PortTownsend-Coupeville", 4.10f, 2.05f), - sEntry("Southworth-VashonIsland", 6.50f, 3.25f) - ); - - private static Map.Entry> sEntry( - String name, - float regularFare, - float seniorFare - ) { - return Map.entry( - name, - Map.of( - FareType.regular, - Money.usDollars(regularFare), - FareType.senior, - Money.usDollars(seniorFare) - ) - ); - } -} diff --git a/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java b/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java index daecb7f6a4e..d420d0e8784 100644 --- a/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java +++ b/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java @@ -121,7 +121,7 @@ private List buildStopClusters(Collection stopL .stream() .collect( Collectors.groupingBy(sl -> - new DeduplicationKey(sl.getName(), sl.getCoordinate().roundToApproximate100m()) + new DeduplicationKey(sl.getName(), sl.getCoordinate().roundToApproximate10m()) ) ) .values() diff --git a/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java b/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java index 7a1b32d36e5..545b216dd56 100644 --- a/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java +++ b/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java @@ -1,5 +1,6 @@ package org.opentripplanner.ext.siri.updater.azure; + import com.azure.identity.DefaultAzureCredentialBuilder; import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.messaging.servicebus.ServiceBusErrorContext; @@ -18,11 +19,14 @@ import java.time.temporal.ChronoUnit; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.opentripplanner.framework.application.ApplicationShutdownSupport; +import org.opentripplanner.framework.io.OtpHttpClientException; import org.opentripplanner.framework.io.OtpHttpClientFactory; import org.opentripplanner.updater.spi.GraphUpdater; import org.opentripplanner.updater.spi.HttpHeaders; @@ -34,6 +38,35 @@ public abstract class AbstractAzureSiriUpdater implements GraphUpdater { + /** + * custom functional interface that allows throwing checked exceptions, thereby + * preserving the exception's intent and type. + */ + @FunctionalInterface + interface CheckedRunnable { + void run() throws Exception; + } + + private static final Set RETRYABLE_REASONS = Set.of( + ServiceBusFailureReason.GENERAL_ERROR, + ServiceBusFailureReason.QUOTA_EXCEEDED, + ServiceBusFailureReason.SERVICE_BUSY, + ServiceBusFailureReason.SERVICE_COMMUNICATION_ERROR, + ServiceBusFailureReason.SERVICE_TIMEOUT, + ServiceBusFailureReason.UNAUTHORIZED, + ServiceBusFailureReason.MESSAGE_LOCK_LOST, + ServiceBusFailureReason.SESSION_LOCK_LOST, + ServiceBusFailureReason.SESSION_CANNOT_BE_LOCKED + ); + + private static final Set NON_RETRYABLE_REASONS = Set.of( + ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND, + ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED, + ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED, + ServiceBusFailureReason.MESSAGE_NOT_FOUND, + ServiceBusFailureReason.MESSAGING_ENTITY_ALREADY_EXISTS + ); + private final Logger LOG = LoggerFactory.getLogger(getClass()); private final AuthenticationType authenticationType; private final String fullyQualifiedNamespace; @@ -64,17 +97,31 @@ public abstract class AbstractAzureSiriUpdater implements GraphUpdater { protected final int timeout; public AbstractAzureSiriUpdater(SiriAzureUpdaterParameters config) { - this.configRef = config.configRef(); - this.authenticationType = config.getAuthenticationType(); - this.fullyQualifiedNamespace = config.getFullyQualifiedNamespace(); - this.serviceBusUrl = config.getServiceBusUrl(); - this.topicName = config.getTopicName(); - this.dataInitializationUrl = config.getDataInitializationUrl(); + this.configRef = Objects.requireNonNull(config.configRef(), "configRef must not be null"); + this.authenticationType = Objects.requireNonNull(config.getAuthenticationType(), "authenticationType must not be null"); + this.topicName = Objects.requireNonNull(config.getTopicName(), "topicName must not be null"); + this.dataInitializationUrl = Objects.requireNonNull(config.getDataInitializationUrl(), "dataInitializationUrl must not be null"); this.timeout = config.getTimeout(); - this.feedId = config.feedId(); + this.feedId = Objects.requireNonNull(config.feedId(), "feedId must not be null"); this.autoDeleteOnIdle = config.getAutoDeleteOnIdle(); this.prefetchCount = config.getPrefetchCount(); this.fuzzyTripMatching = config.isFuzzyTripMatching(); + + if (authenticationType == AuthenticationType.FederatedIdentity) { + this.fullyQualifiedNamespace = Objects.requireNonNull( + config.getFullyQualifiedNamespace(), + "fullyQualifiedNamespace must not be null when using FederatedIdentity authentication" + ); + this.serviceBusUrl = null; + } else if (authenticationType == AuthenticationType.SharedAccessKey) { + this.serviceBusUrl = Objects.requireNonNull( + config.getServiceBusUrl(), + "serviceBusUrl must not be null when using SharedAccessKey authentication" + ); + this.fullyQualifiedNamespace = null; + } else { + throw new IllegalArgumentException("Unsupported authentication type: " + authenticationType); + } } /** @@ -96,10 +143,6 @@ public void setup(WriteToGraphCallback writeToGraphCallback) { @Override public void run() { - Objects.requireNonNull(topicName, "'topic' must be set"); - Objects.requireNonNull(serviceBusUrl, "'servicebus-url' must be set"); - Objects.requireNonNull(feedId, "'feedId' must be set"); - Preconditions.checkState(feedId.length() > 0, "'feedId' must be set"); // In Kubernetes this should be the POD identifier subscriptionName = System.getenv("HOSTNAME"); @@ -107,6 +150,134 @@ public void run() { subscriptionName = "otp-" + UUID.randomUUID(); } + try { + executeWithRetry( + this::setupSubscription, + "Setting up Service Bus subscription to topic" + ); + + executeWithRetry( + () -> initializeData(dataInitializationUrl, messageConsumer), + "Initializing historical Siri data" + ); + + executeWithRetry( + this::startEventProcessor, + "Starting Service Bus event processor" + ); + + setPrimed(); + + ApplicationShutdownSupport.addShutdownHook( + "azure-siri-updater-shutdown", + () -> { + LOG.info("Calling shutdownHook on AbstractAzureSiriUpdater"); + if (eventProcessor != null) { + eventProcessor.close(); + } + if (serviceBusAdmin != null) { + serviceBusAdmin.deleteSubscription(topicName, subscriptionName).block(); + LOG.info("Subscription '{}' deleted on topic '{}'.", subscriptionName, topicName); + } + } + ); + + } catch (ServiceBusException e) { + LOG.error("Service Bus encountered an error during setup: {}", e.getMessage(), e); + } catch (URISyntaxException e) { + LOG.error("Invalid URI provided for Service Bus setup: {}", e.getMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOG.warn("Updater was interrupted during setup."); + } catch (Exception e) { + LOG.error("An unexpected error occurred during setup: {}", e.getMessage(), e); + } + } + + /** + * Sleeps. This is to be able to mock testing + * @param millis number of milliseconds + * @throws InterruptedException if sleep is interrupted + */ + protected void sleep(int millis) throws InterruptedException { + Thread.sleep(millis); + } + + /** + * Executes a task with retry logic. Retries indefinitely for retryable exceptions with exponential backoff. + * Does not retry for InterruptedException and propagates it + * @param task The task to execute. + * @param description A description of the task for logging purposes. + * @throws InterruptedException If the thread is interrupted while waiting between retries. + */ + protected void executeWithRetry(CheckedRunnable task, String description) throws Exception { + int sleepPeriod = 1000; // Start with 1-second delay + int attemptCounter = 1; + + while (true) { + try { + task.run(); + LOG.info("{} succeeded.", description); + return; + } catch (InterruptedException ie) { + LOG.warn("{} was interrupted during execution.", description); + Thread.currentThread().interrupt(); // Restore interrupted status + throw ie; + } catch (Exception e) { + LOG.warn("{} failed. Error: {} (Attempt {})", description, e.getMessage(), attemptCounter); + + if (!shouldRetry(e)) { + LOG.error("{} encountered a non-retryable error: {}.", description, e.getMessage()); + throw e; // Stop retries if the error is non-retryable + } + + LOG.warn("{} will retry in {} ms.", description, sleepPeriod); + attemptCounter++; + try { + sleep(sleepPeriod); + } catch (InterruptedException ie){ + LOG.warn("{} was interrupted during sleep.", description); + Thread.currentThread().interrupt(); // Restore interrupted status + throw ie; + } + sleepPeriod = Math.min(sleepPeriod * 2, 60 * 1000); // Exponential backoff with a cap at 60 seconds + } + } + } + + protected boolean shouldRetry(Exception e) { + if (e instanceof ServiceBusException sbException) { + ServiceBusFailureReason reason = sbException.getReason(); + + if (RETRYABLE_REASONS.contains(reason)) { + + LOG.warn("Transient error encountered: {}. Retrying...", reason); + return true; + + } else if (NON_RETRYABLE_REASONS.contains(reason)) { + + LOG.error("Non-recoverable error encountered: {}. Not retrying.", reason); + return false; + + } else { + LOG.warn("Unhandled ServiceBusFailureReason: {}. Retrying by default.", reason); + return true; + } + } + else if (ExceptionUtils.hasCause(e, OtpHttpClientException.class)){ + // retry for OtpHttpClientException as it is thrown if historical data can't be read at the moment + return true; + } + + LOG.warn("Non-ServiceBus exception encountered: {}. Not retrying.", e.getClass().getName()); + return false; + } + + /** + * Sets up the Service Bus subscription, including checking old subscription, deleting if necessary, + * and creating a new subscription. + */ + private void setupSubscription() throws ServiceBusException, URISyntaxException { // Client with permissions to create subscription if (authenticationType == AuthenticationType.FederatedIdentity) { serviceBusAdmin = @@ -121,40 +292,50 @@ public void run() { } // Set options - var options = new CreateSubscriptionOptions(); - options.setDefaultMessageTimeToLive(Duration.of(25, ChronoUnit.HOURS)); - // Set subscription to be deleted if idle for a certain time, so that orphaned instances doesn't linger. - options.setAutoDeleteOnIdle(autoDeleteOnIdle); + CreateSubscriptionOptions options = new CreateSubscriptionOptions() + .setDefaultMessageTimeToLive(Duration.of(25, ChronoUnit.HOURS)) + .setAutoDeleteOnIdle(autoDeleteOnIdle); // Make sure there is no old subscription on serviceBus - if ( - Boolean.TRUE.equals( - serviceBusAdmin.getSubscriptionExists(topicName, subscriptionName).block() - ) - ) { - LOG.info("Subscription {} already exists", subscriptionName); + if ( Boolean.TRUE.equals( serviceBusAdmin.getSubscriptionExists(topicName, subscriptionName).block())) { + LOG.info("Subscription '{}' already exists. Deleting existing subscription.", subscriptionName); serviceBusAdmin.deleteSubscription(topicName, subscriptionName).block(); LOG.info("Service Bus deleted subscription {}.", subscriptionName); } serviceBusAdmin.createSubscription(topicName, subscriptionName, options).block(); - LOG.info("Service Bus created subscription {}", subscriptionName); + LOG.info("{} created subscription {}", getClass().getSimpleName(), subscriptionName); + } - // Initialize historical Siri data - initializeData(); + /** + * Starts the Service Bus event processor. + */ + private void startEventProcessor() throws ServiceBusException { + ServiceBusClientBuilder clientBuilder = new ServiceBusClientBuilder(); - eventProcessor = - new ServiceBusClientBuilder() - .connectionString(serviceBusUrl) - .processor() - .topicName(topicName) - .subscriptionName(subscriptionName) - .receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .disableAutoComplete() // Receive and delete does not need autocomplete - .prefetchCount(prefetchCount) - .processError(errorConsumer) - .processMessage(messageConsumer) - .buildProcessorClient(); + if (authenticationType == AuthenticationType.FederatedIdentity) { + Preconditions.checkNotNull(fullyQualifiedNamespace, "fullyQualifiedNamespace must be set for FederatedIdentity authentication"); + clientBuilder + .fullyQualifiedNamespace(fullyQualifiedNamespace) + .credential(new DefaultAzureCredentialBuilder().build()); + } else if (authenticationType == AuthenticationType.SharedAccessKey) { + Preconditions.checkNotNull(serviceBusUrl, "serviceBusUrl must be set for SharedAccessKey authentication"); + clientBuilder + .connectionString(serviceBusUrl); + } else { + throw new IllegalArgumentException("Unsupported authentication type: " + authenticationType); + } + + eventProcessor = clientBuilder + .processor() + .topicName(topicName) + .subscriptionName(subscriptionName) + .receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .disableAutoComplete() // Receive and delete does not need autocomplete + .prefetchCount(prefetchCount) + .processError(errorConsumer) + .processMessage(messageConsumer) + .buildProcessorClient(); eventProcessor.start(); LOG.info( @@ -163,20 +344,9 @@ public void run() { subscriptionName, prefetchCount ); - - setPrimed(); - - ApplicationShutdownSupport.addShutdownHook( - "azure-siri-updater-shutdown", - () -> { - LOG.info("Calling shutdownHook on AbstractAzureSiriUpdater"); - eventProcessor.close(); - serviceBusAdmin.deleteSubscription(topicName, subscriptionName).block(); - LOG.info("Subscription '{}' deleted on topic '{}'.", subscriptionName, topicName); - } - ); } + @Override public boolean isPrimed() { return this.isPrimed; @@ -221,37 +391,6 @@ boolean fuzzyTripMatching() { return fuzzyTripMatching; } - /** - * InitializeData - wrapping method that calls an implementation of initialize data - and blocks readiness till finished - */ - private void initializeData() { - int sleepPeriod = 1000; - int attemptCounter = 1; - boolean otpIsShuttingDown = false; - - while (!otpIsShuttingDown) { - try { - initializeData(dataInitializationUrl, messageConsumer); - break; - } catch (Exception e) { - sleepPeriod = Math.min(sleepPeriod * 2, 60 * 1000); - - LOG.warn( - "Caught exception while initializing data will retry after {} ms - attempt {}. ({})", - sleepPeriod, - attemptCounter++, - e.toString() - ); - try { - Thread.sleep(sleepPeriod); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - otpIsShuttingDown = true; - LOG.info("OTP is shutting down, cancelling attempt to initialize Azure SIRI Updater."); - } - } - } - } protected abstract void initializeData( String url, @@ -260,7 +399,7 @@ protected abstract void initializeData( /** * Make some sensible logging on error and if Service Bus is busy, sleep for some time before try again to get messages. - * This code snippet is taken from Microsoft example https://docs.microsoft.com/sv-se/azure/service-bus-messaging/service-bus-java-how-to-use-queues. + * This code snippet is taken from Microsoft example .... * @param errorContext Context for errors handled by the ServiceBusProcessorClient. */ protected void defaultErrorConsumer(ServiceBusErrorContext errorContext) { @@ -270,19 +409,15 @@ protected void defaultErrorConsumer(ServiceBusErrorContext errorContext) { errorContext.getEntityPath() ); - if (!(errorContext.getException() instanceof ServiceBusException)) { + if (!(errorContext.getException() instanceof ServiceBusException e)) { LOG.error("Non-ServiceBusException occurred!", errorContext.getException()); return; } - var e = (ServiceBusException) errorContext.getException(); var reason = e.getReason(); - if ( - reason == ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED || - reason == ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND || - reason == ServiceBusFailureReason.UNAUTHORIZED - ) { + if (reason == ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED || + reason == ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND) { LOG.error( "An unrecoverable error occurred. Stopping processing with reason {} {}", reason, @@ -290,8 +425,9 @@ protected void defaultErrorConsumer(ServiceBusErrorContext errorContext) { ); } else if (reason == ServiceBusFailureReason.MESSAGE_LOCK_LOST) { LOG.error("Message lock lost for message", e); - } else if (reason == ServiceBusFailureReason.SERVICE_BUSY) { - LOG.error("Service Bus is busy, wait and try again"); + } else if (reason == ServiceBusFailureReason.SERVICE_BUSY || + reason == ServiceBusFailureReason.UNAUTHORIZED) { + LOG.error("Service Bus is busy or unauthorized, wait and try again"); try { // Choosing an arbitrary amount of time to wait until trying again. TimeUnit.SECONDS.sleep(5); diff --git a/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java b/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java index 75cd6cb868f..cb774af1619 100644 --- a/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java +++ b/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java @@ -2,7 +2,6 @@ import dagger.Binds; import dagger.Module; -import javax.annotation.Nullable; import org.opentripplanner.ext.stopconsolidation.StopConsolidationRepository; import org.opentripplanner.ext.stopconsolidation.internal.DefaultStopConsolidationRepository; @@ -13,6 +12,5 @@ @Module public interface StopConsolidationRepositoryModule { @Binds - @Nullable - StopConsolidationRepository bindRepository(@Nullable DefaultStopConsolidationRepository repo); + StopConsolidationRepository bindRepository(DefaultStopConsolidationRepository repo); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java index 0060e6ad7e1..f6633818b3d 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java @@ -30,6 +30,11 @@ public DataFetcher latestBookingTime() { return environment -> getSource(environment).getLatestBookingTime(); } + @Override + public DataFetcher maximumBookingNotice() { + return env -> getSource(env).getMaximumBookingNotice().orElse(null); + } + @Override public DataFetcher maximumBookingNoticeSeconds() { return environment -> @@ -41,6 +46,11 @@ public DataFetcher message() { return environment -> getSource(environment).getMessage(); } + @Override + public DataFetcher minimumBookingNotice() { + return env -> getSource(env).getMinimumBookingNotice().orElse(null); + } + @Override public DataFetcher minimumBookingNoticeSeconds() { return environment -> diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index d02d7b59ffa..bb8de508953 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -37,7 +37,6 @@ import org.opentripplanner.ext.fares.impl.DefaultFareService; import org.opentripplanner.ext.fares.impl.GtfsFaresService; import org.opentripplanner.ext.fares.model.FareRuleSet; -import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.DirectionMapper; import org.opentripplanner.model.TripTimeOnDate; @@ -893,11 +892,7 @@ public DataFetcher vehicleRentalStation() { return vehicleRentalStationService .getVehicleRentalStations() .stream() - .filter(vehicleRentalStation -> - OTPFeature.GtfsGraphQlApiRentalStationFuzzyMatching.isOn() - ? stationIdFuzzyMatches(vehicleRentalStation, id) - : stationIdMatches(vehicleRentalStation, id) - ) + .filter(vehicleRentalStation -> stationIdMatches(vehicleRentalStation, id)) .findAny() .orElse(null); }; @@ -968,21 +963,6 @@ private boolean stationIdMatches(VehicleRentalStation station, String feedScoped return station.getId().toString().equals(feedScopedId); } - /** - * This matches station's feedScopedId to the given string if the string is feed scoped (i.e - * contains a `:` separator) or only matches the station's id without the feed to the given - * string. This approach can lead to a random station matching the criteria if there are multiple - * stations with the same id in different feeds. - *

- * TODO this can be potentially removed after a while, only used by Digitransit as of now. - */ - private boolean stationIdFuzzyMatches(VehicleRentalStation station, String idWithoutFeed) { - if (idWithoutFeed != null && idWithoutFeed.contains(":")) { - return stationIdMatches(station, idWithoutFeed); - } - return station.getId().getId().equals(idWithoutFeed); - } - private TransitService getTransitService(DataFetchingEnvironment environment) { return environment.getContext().transitService(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index dd74347b928..6528d8ee286 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -221,10 +221,14 @@ public interface GraphQLBookingInfo { public DataFetcher latestBookingTime(); + public DataFetcher maximumBookingNotice(); + public DataFetcher maximumBookingNoticeSeconds(); public DataFetcher message(); + public DataFetcher minimumBookingNotice(); + public DataFetcher minimumBookingNoticeSeconds(); public DataFetcher pickupMessage(); diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java index fe73e8b9887..66377a56390 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java @@ -2,9 +2,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import graphql.schema.GraphQLSchema; +import graphql.schema.idl.SchemaPrinter; import io.micrometer.core.instrument.Tag; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -31,6 +33,15 @@ @Produces(MediaType.APPLICATION_JSON) public class TransmodelAPI { + // Note, the blank line at the end is intended + private static final String SCHEMA_DOC_HEADER = + """ +# THIS IS NOT INTENDED FOR PRODUCTION USE. We recommend using the GraphQL introspection instead. +# This is intended for the OTP Debug UI and can also be used by humans to get the schema with the +# OTP configured default-values injected. + +"""; + private static final Logger LOG = LoggerFactory.getLogger(TransmodelAPI.class); private static GraphQLSchema schema; @@ -138,6 +149,13 @@ public Response getGraphQL(String query, @Context HttpHeaders headers) { ); } + @GET + @Path("schema.graphql") + public Response getGraphQLSchema() { + var text = SCHEMA_DOC_HEADER + new SchemaPrinter().print(schema); + return Response.ok().encoding("UTF-8").entity(text).build(); + } + private static Iterable getTagsFromHeaders(HttpHeaders headers) { return tracingHeaderTags .stream() diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index f27d252f250..7070f8b486e 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.opentripplanner.apis.vectortiles.model.StyleBuilder; import org.opentripplanner.apis.vectortiles.model.StyleSpec; @@ -14,6 +13,7 @@ import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber; import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber.ZoomStop; import org.opentripplanner.service.vehiclerental.street.StreetVehicleRentalLink; +import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.AreaEdge; import org.opentripplanner.street.model.edge.BoardingLocationToStopLink; @@ -37,13 +37,25 @@ */ public class DebugStyleSpec { - private static final TileSource BACKGROUND_SOURCE = new RasterSource( - "background", + private static final TileSource OSM_BACKGROUND = new RasterSource( + "OSM Carto", List.of("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap Contributors" ); + private static final TileSource POSITRON_BACKGROUND = new RasterSource( + "Positron", + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}{ratio}.png"), + 19, + 256, + "© OpenStreetMap, © CARTO" + ); + + private static final List BACKGROUND_LAYERS = List.of( + OSM_BACKGROUND, + POSITRON_BACKGROUND + ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; private static final String DARK_GREEN = "#136b04"; @@ -92,19 +104,33 @@ static StyleSpec build( VectorSourceLayer areaStops, VectorSourceLayer groupStops, VectorSourceLayer edges, - VectorSourceLayer vertices + VectorSourceLayer vertices, + List extraLayers ) { - var vectorSources = Stream + List vectorSources = Stream .of(regularStops, edges, vertices) - .map(VectorSourceLayer::vectorSource); - var allSources = Stream - .concat(Stream.of(BACKGROUND_SOURCE), vectorSources) - .collect(Collectors.toSet()); + .map(VectorSourceLayer::vectorSource) + .map(TileSource.class::cast) + .toList(); + + List extraRasterSources = extraLayers + .stream() + .map(l -> + (TileSource) new RasterSource( + l.name(), + List.of(l.templateUrl()), + 19, + l.tileSize(), + l.attribution() + ) + ) + .toList(); + var allSources = ListUtils.combine(BACKGROUND_LAYERS, extraRasterSources, vectorSources); return new StyleSpec( "OTP Debug Tiles", allSources, ListUtils.combine( - List.of(StyleBuilder.ofId("background").typeRaster().source(BACKGROUND_SOURCE).minZoom(0)), + backgroundLayers(extraRasterSources), wheelchair(edges), noThruTraffic(edges), traversalPermissions(edges), @@ -115,6 +141,25 @@ static StyleSpec build( ); } + private static List backgroundLayers(List extraLayers) { + return ListUtils + .combine(BACKGROUND_LAYERS, extraLayers) + .stream() + .map(layer -> { + var builder = StyleBuilder + .ofId(layer.id()) + .displayName(layer.name()) + .typeRaster() + .source(layer) + .minZoom(0); + if (!layer.equals(OSM_BACKGROUND)) { + builder.intiallyHidden(); + } + return builder; + }) + .toList(); + } + private static List stops( VectorSourceLayer regularStops, VectorSourceLayer areaStops, diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index d19c25a1f47..0576e91f312 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -147,7 +147,8 @@ public StyleSpec getTileJson(@Context UriInfo uri, @Context HttpHeaders headers) AREA_STOPS.toVectorSourceLayer(stopsSource), GROUP_STOPS.toVectorSourceLayer(stopsSource), EDGES.toVectorSourceLayer(streetSource), - VERTICES.toVectorSourceLayer(streetSource) + VERTICES.toVectorSourceLayer(streetSource), + serverContext.debugUiConfig().additionalBackgroundLayers() ); } diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java index a70acbb8685..4e75f37785d 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java @@ -30,7 +30,7 @@ public class StyleBuilder { private final Map layout = new LinkedHashMap<>(); private final Map metadata = new LinkedHashMap<>(); private final Map line = new LinkedHashMap<>(); - private List filter = List.of(); + private List filter = List.of(); public static StyleBuilder ofId(String id) { return new StyleBuilder(id); @@ -120,6 +120,14 @@ public StyleBuilder group(String group) { return this; } + /** + * A nice human-readable name for the layer. + */ + public StyleBuilder displayName(String name) { + metadata.put("name", name); + return this; + } + public StyleBuilder lineText(String name) { layout.put("symbol-placement", "line-center"); layout.put("symbol-spacing", 1000); diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java index 088ce63d10a..b7f0ce5d048 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.util.List; +import org.opentripplanner.utils.lang.StringUtils; /** * Represent a data source where Maplibre can fetch data for rendering directly in the browser. @@ -12,6 +13,8 @@ public sealed interface TileSource { String id(); + String name(); + /** * Represents a vector tile source which is rendered into a map in the browser. */ @@ -20,17 +23,32 @@ record VectorSource(String id, String url) implements TileSource { public String type() { return "vector"; } + + @Override + public String name() { + return id; + } } /** * Represents a raster-based source for map tiles. These are used mainly for background * map layers with vector data being rendered on top of it. */ - record RasterSource(String id, List tiles, int maxzoom, int tileSize, String attribution) + record RasterSource( + String name, + List tiles, + int maxzoom, + int tileSize, + String attribution + ) implements TileSource { @Override public String type() { return "raster"; } + + public String id() { + return StringUtils.slugify(name); + } } } diff --git a/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java b/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java index 6631287613b..f71283b572e 100644 --- a/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java +++ b/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java @@ -50,11 +50,6 @@ public enum OTPFeature { ), FloatingBike(true, false, "Enable floating bike routing."), GtfsGraphQlApi(true, false, "Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md)."), - GtfsGraphQlApiRentalStationFuzzyMatching( - false, - false, - "Does vehicleRentalStation query also allow ids that are not feed scoped." - ), /** * If this feature flag is switched on, then the minimum transfer time is not the minimum transfer * time, but the definitive transfer time. Use this to override what we think the transfer will diff --git a/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java b/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java index 7b6852cb281..6c3a5b6a007 100644 --- a/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java +++ b/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java @@ -9,16 +9,18 @@ public class OtpFileNames { public static final String OTP_CONFIG_FILENAME = "otp-config.json"; public static final String BUILD_CONFIG_FILENAME = "build-config.json"; public static final String ROUTER_CONFIG_FILENAME = "router-config.json"; + public static final String DEBUG_UI_CONFIG_FILENAME = "debug-ui-config.json"; /** * Check if a file is a config file using the configuration file name. This method returns {@code - * true} if the file match {@code (otp|build|router)-config.json}. + * true} if the file match {@code (otp|build|router|debug-ui)-config.json}. */ public static boolean isConfigFile(String filename) { return ( OTP_CONFIG_FILENAME.equals(filename) || BUILD_CONFIG_FILENAME.equals(filename) || - ROUTER_CONFIG_FILENAME.equals(filename) + ROUTER_CONFIG_FILENAME.equals(filename) || + DEBUG_UI_CONFIG_FILENAME.equals(filename) ); } } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index 75e0965d82f..40695e7c67c 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -1,8 +1,12 @@ package org.opentripplanner.graph_builder.module.osm; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Optional; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; +import org.opentripplanner.graph_builder.issue.api.Issue; import org.opentripplanner.osm.model.OsmWay; import org.opentripplanner.street.model.edge.EscalatorEdge; import org.opentripplanner.street.model.vertex.IntersectionVertex; @@ -13,9 +17,19 @@ class EscalatorProcessor { private final Map intersectionNodes; + private final DataImportIssueStore issueStore; - public EscalatorProcessor(Map intersectionNodes) { + // If an escalator is tagged as moving less than 5 cm/s, or more than 5 m/s, + // assume it's an error and ignore it. + private static final double SLOW_ESCALATOR_ERROR_CUTOFF = 0.05; + private static final double FAST_ESCALATOR_ERROR_CUTOFF = 5.0; + + public EscalatorProcessor( + Map intersectionNodes, + DataImportIssueStore issueStore + ) { this.intersectionNodes = intersectionNodes; + this.issueStore = issueStore; } public void buildEscalatorEdge(OsmWay escalatorWay, double length) { @@ -27,30 +41,58 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { .boxed() .toList(); + Optional duration = escalatorWay.getDuration(v -> + issueStore.add( + Issue.issue( + "InvalidDuration", + "Duration for osm node {} is not a valid duration: '{}'; the value is ignored.", + escalatorWay.url(), + v + ) + ) + ); + if (duration.isPresent()) { + double speed = length / duration.get().toSeconds(); + if (speed < SLOW_ESCALATOR_ERROR_CUTOFF || speed > FAST_ESCALATOR_ERROR_CUTOFF) { + duration = Optional.empty(); + issueStore.add( + Issue.issue( + "InvalidDuration", + "Duration for osm node {} makes implied speed {} be outside acceptable range.", + escalatorWay.url(), + speed + ) + ); + } + } for (int i = 0; i < nodes.size() - 1; i++) { if (escalatorWay.isForwardEscalator()) { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i)), intersectionNodes.get(nodes.get(i + 1)), - length + length, + duration.orElse(null) ); } else if (escalatorWay.isBackwardEscalator()) { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i + 1)), intersectionNodes.get(nodes.get(i)), - length + length, + duration.orElse(null) ); } else { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i)), intersectionNodes.get(nodes.get(i + 1)), - length + length, + duration.orElse(null) ); EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i + 1)), intersectionNodes.get(nodes.get(i)), - length + length, + duration.orElse(null) ); } } diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java index e3618d6f93d..db495905041 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java @@ -259,7 +259,10 @@ private void buildBasicGraph() { long wayCount = osmdb.getWays().size(); ProgressTracker progress = ProgressTracker.track("Build street graph", 5_000, wayCount); LOG.info(progress.startMessage()); - var escalatorProcessor = new EscalatorProcessor(vertexGenerator.intersectionNodes()); + var escalatorProcessor = new EscalatorProcessor( + vertexGenerator.intersectionNodes(), + issueStore + ); WAY:for (OsmWay way : osmdb.getWays()) { WayProperties wayData = way.getOsmProvider().getWayPropertySet().getDataForWay(way); diff --git a/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java b/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java index 30763edca9e..83b677a62ce 100644 --- a/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java +++ b/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java @@ -22,7 +22,10 @@ protected Collection map(Edge input) { List properties = switch (input) { case StreetEdge e -> mapStreetEdge(e); - case EscalatorEdge e -> List.of(kv("distance", e.getDistanceMeters())); + case EscalatorEdge e -> List.of( + kv("distance", e.getDistanceMeters()), + kv("duration", e.getDuration().map(d -> d.toString()).orElse(null)) + ); default -> List.of(); }; return ListUtils.combine(baseProps, properties); diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java index 7b5fbe56748..a620545f521 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java @@ -2,7 +2,10 @@ import gnu.trove.list.TLongList; import gnu.trove.list.array.TLongArrayList; +import java.time.Duration; +import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import org.opentripplanner.graph_builder.module.osm.StreetTraversalPermissionPair; import org.opentripplanner.street.model.StreetTraversalPermission; @@ -130,6 +133,10 @@ public boolean isEscalator() { return (isTag("highway", "steps") && isOneOfTags("conveying", ESCALATOR_CONVEYING_TAGS)); } + public Optional getDuration(Consumer errorHandler) { + return getTagValueAsDuration("duration", errorHandler); + } + public boolean isForwardEscalator() { return isEscalator() && "forward".equals(this.getTag("conveying")); } diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index 67f737e4c79..3f47d4454bd 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -1,5 +1,7 @@ package org.opentripplanner.osm.model; +import java.time.Duration; +import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -221,6 +223,101 @@ public OptionalInt getTagAsInt(String tag, Consumer errorHandler) { return OptionalInt.empty(); } + /** + * Parse an OSM duration tag, which is one of: + * mm + * hh:mm + * hh:mm:ss + * and where the leading value is not limited to any maximum. + * See OSM wiki definition + * of duration. + * + * @param duration string in format mm, hh:mm, or hh:mm:ss + * @return Duration + * @throws DateTimeParseException on bad input + */ + public static Duration parseOsmDuration(String duration) { + // Unfortunately DateFormatParserBuilder doesn't quite do enough for this case. + // It has the capability for expressing optional parts, so it could express hh(:mm(:ss)?)? + // but it cannot express (hh:)?mm(:ss)? where the existence of (:ss) implies the existence + // of (hh:). Even if it did, it would not be able to handle the cases where hours are + // greater than 23 or (if there is no hours part at all) minutes are greater than 59, which + // are both allowed by the spec and exist in OSM data. Durations are not LocalTimes after + // all, in parsing a LocalTime it makes sense and is correct that hours cannot be more than + // 23 or minutes more than 59, but in durations if you have capped the largest unit, it is + // reasonable for the amount of the largest unit to be as large as it needs to be. + int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); + if (colonCount <= 2) { + try { + int i, j; + long hours, minutes, seconds; + // The first :-separated element can be any width, and has no maximum. It still has + // to be non-negative. The following elements must be 2 characters wide, non-negative, + // and less than 60. + switch (colonCount) { + // case "m" + case 0: + minutes = Long.parseLong(duration); + if (minutes >= 0) { + return Duration.ofMinutes(minutes); + } + break; + // case "h:mm" + case 1: + i = duration.indexOf(':'); + hours = Long.parseLong(duration.substring(0, i)); + minutes = Long.parseLong(duration.substring(i + 1)); + if (duration.length() - i == 3 && hours >= 0 && minutes >= 0 && minutes < 60) { + return Duration.ofHours(hours).plusMinutes(minutes); + } + break; + // case "h:mm:ss" + default: + i = duration.indexOf(':'); + j = duration.indexOf(':', i + 1); + hours = Long.parseLong(duration.substring(0, i)); + minutes = Long.parseLong(duration.substring(i + 1, j)); + seconds = Long.parseLong(duration.substring(j + 1)); + if ( + j - i == 3 && + duration.length() - j == 3 && + hours >= 0 && + minutes >= 0 && + minutes < 60 && + seconds >= 0 && + seconds < 60 + ) { + return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds); + } + break; + } + } catch (NumberFormatException e) { + // fallthrough + } + } + throw new DateTimeParseException("Bad OSM duration", duration, 0); + } + + /** + * Gets a tag's value, assumes it is an OSM wiki specified duration, parses and returns it. + * If parsing fails, calls the error handler. + * + * @param key + * @param errorHandler + * @return parsed Duration, or empty + */ + public Optional getTagValueAsDuration(String key, Consumer errorHandler) { + String value = getTag(key); + if (value != null) { + try { + return Optional.of(parseOsmDuration(value)); + } catch (DateTimeParseException e) { + errorHandler.accept(value); + } + } + return Optional.empty(); + } + /** * Some tags are allowed to have values like 55, "true" or "false". *

diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java new file mode 100644 index 00000000000..3c150b43417 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java @@ -0,0 +1,114 @@ +package org.opentripplanner.routing.api.request.preference; + +import static org.opentripplanner.utils.lang.DoubleUtils.doubleEquals; + +import java.io.Serializable; +import java.util.Objects; +import java.util.function.Consumer; +import org.opentripplanner.utils.tostring.ToStringBuilder; + +public class EscalatorPreferences implements Serializable { + + public static final EscalatorPreferences DEFAULT = new EscalatorPreferences(); + + private final double reluctance; + private final double speed; + + /* Using the angle of 30 degrees and a speed of 0.5 m/s gives a horizontal component + * of approx. 0.43 m/s. This is typical of short escalators like those in shopping + * malls. */ + private static final double HORIZONTAL_SPEED = 0.45; + + private EscalatorPreferences() { + this.reluctance = 1.5; + this.speed = HORIZONTAL_SPEED; + } + + private EscalatorPreferences(Builder builder) { + reluctance = builder.reluctance; + speed = builder.speed; + } + + public static Builder of() { + return new Builder(DEFAULT); + } + + public Builder copyOf() { + return new Builder(this); + } + + public double reluctance() { + return reluctance; + } + + public double speed() { + return speed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EscalatorPreferences that = (EscalatorPreferences) o; + return (doubleEquals(that.reluctance, reluctance) && doubleEquals(that.speed, speed)); + } + + @Override + public int hashCode() { + return Objects.hash(speed, reluctance); + } + + @Override + public String toString() { + return ToStringBuilder + .of(EscalatorPreferences.class) + .addNum("speed", speed, DEFAULT.speed) + .addNum("reluctance", reluctance, DEFAULT.reluctance) + .toString(); + } + + public static class Builder { + + private final EscalatorPreferences original; + private double reluctance; + private double speed; + + public Builder(EscalatorPreferences original) { + this.original = original; + this.reluctance = original.reluctance; + this.speed = original.speed; + } + + public EscalatorPreferences original() { + return original; + } + + public double speed() { + return speed; + } + + public Builder withSpeed(double speed) { + this.speed = speed; + return this; + } + + public double reluctance() { + return reluctance; + } + + public Builder withReluctance(double reluctance) { + this.reluctance = reluctance; + return this; + } + + public Builder apply(Consumer body) { + body.accept(this); + return this; + } + + public EscalatorPreferences build() { + var newObj = new EscalatorPreferences(this); + return original.equals(newObj) ? original : newObj; + } + } +} diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java index 4a5969049ba..5bc0a120d32 100644 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java @@ -1,6 +1,7 @@ package org.opentripplanner.routing.api.request.preference; import static org.opentripplanner.utils.lang.DoubleUtils.doubleEquals; +import static org.opentripplanner.utils.lang.ObjectUtils.ifNotNull; import java.io.Serializable; import java.util.Objects; @@ -29,7 +30,7 @@ public final class WalkPreferences implements Serializable { private final double stairsTimeFactor; private final double safetyFactor; - private final double escalatorReluctance; + private final EscalatorPreferences escalator; private WalkPreferences() { this.speed = 1.33; @@ -38,7 +39,7 @@ private WalkPreferences() { this.stairsReluctance = 2.0; this.stairsTimeFactor = 3.0; this.safetyFactor = 1.0; - this.escalatorReluctance = 1.5; + this.escalator = EscalatorPreferences.DEFAULT; } private WalkPreferences(Builder builder) { @@ -48,7 +49,7 @@ private WalkPreferences(Builder builder) { this.stairsReluctance = Units.reluctance(builder.stairsReluctance); this.stairsTimeFactor = Units.reluctance(builder.stairsTimeFactor); this.safetyFactor = Units.reluctance(builder.safetyFactor); - this.escalatorReluctance = Units.reluctance(builder.escalatorReluctance); + this.escalator = builder.escalator; } public static Builder of() { @@ -108,6 +109,10 @@ public double safetyFactor() { return safetyFactor; } + public EscalatorPreferences escalator() { + return escalator; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -120,7 +125,7 @@ public boolean equals(Object o) { doubleEquals(that.stairsReluctance, stairsReluctance) && doubleEquals(that.stairsTimeFactor, stairsTimeFactor) && doubleEquals(that.safetyFactor, safetyFactor) && - doubleEquals(that.escalatorReluctance, escalatorReluctance) + escalator.equals(that.escalator) ); } @@ -133,7 +138,7 @@ public int hashCode() { stairsReluctance, stairsTimeFactor, safetyFactor, - escalatorReluctance + escalator ); } @@ -147,14 +152,10 @@ public String toString() { .addNum("stairsReluctance", stairsReluctance, DEFAULT.stairsReluctance) .addNum("stairsTimeFactor", stairsTimeFactor, DEFAULT.stairsTimeFactor) .addNum("safetyFactor", safetyFactor, DEFAULT.safetyFactor) - .addNum("escalatorReluctance", escalatorReluctance, DEFAULT.escalatorReluctance) + .addObj("escalator", escalator, DEFAULT.escalator) .toString(); } - public double escalatorReluctance() { - return escalatorReluctance; - } - public static class Builder { private final WalkPreferences original; @@ -165,7 +166,7 @@ public static class Builder { private double stairsTimeFactor; private double safetyFactor; - private double escalatorReluctance; + private EscalatorPreferences escalator; public Builder(WalkPreferences original) { this.original = original; @@ -175,7 +176,7 @@ public Builder(WalkPreferences original) { this.stairsReluctance = original.stairsReluctance; this.stairsTimeFactor = original.stairsTimeFactor; this.safetyFactor = original.safetyFactor; - this.escalatorReluctance = original.escalatorReluctance; + this.escalator = original.escalator; } public WalkPreferences original() { @@ -242,12 +243,12 @@ public Builder withSafetyFactor(double safetyFactor) { return this; } - public double escalatorReluctance() { - return escalatorReluctance; + public EscalatorPreferences escalator() { + return escalator; } - public Builder withEscalatorReluctance(double escalatorReluctance) { - this.escalatorReluctance = escalatorReluctance; + public Builder withEscalator(Consumer body) { + this.escalator = ifNotNull(this.escalator, original.escalator).copyOf().apply(body).build(); return this; } diff --git a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java index b5b39ddee18..f088a3de60e 100644 --- a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java +++ b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java @@ -26,6 +26,7 @@ import org.opentripplanner.service.vehicleparking.VehicleParkingService; import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.search.state.State; @@ -127,6 +128,8 @@ default GraphFinder graphFinder() { VectorTileConfig vectorTileConfig(); + DebugUiConfig debugUiConfig(); + /* Sandbox modules */ @Nullable diff --git a/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index c82dd33ddbf..390333f1374 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -49,16 +49,29 @@ public class ConfigModel { */ private RouterConfig routerConfig; - public ConfigModel(OtpConfig otpConfig, BuildConfig buildConfig, RouterConfig routerConfig) { + private final DebugUiConfig debugUiConfig; + + public ConfigModel( + OtpConfig otpConfig, + BuildConfig buildConfig, + RouterConfig routerConfig, + DebugUiConfig debugUiConfig + ) { this.otpConfig = otpConfig; this.buildConfig = buildConfig; this.routerConfig = routerConfig; + this.debugUiConfig = debugUiConfig; initializeOtpFeatures(otpConfig); } public ConfigModel(OtpConfigLoader loader) { - this(loader.loadOtpConfig(), loader.loadBuildConfig(), loader.loadRouterConfig()); + this( + loader.loadOtpConfig(), + loader.loadBuildConfig(), + loader.loadRouterConfig(), + loader.loadDebugUiConfig() + ); } public void updateConfigFromSerializedGraph(BuildConfig buildConfig, RouterConfig routerConfig) { @@ -102,6 +115,10 @@ public RouterConfig routerConfig() { return routerConfig; } + public DebugUiConfig debugUiConfig() { + return debugUiConfig; + } + public static void initializeOtpFeatures(OtpConfig otpConfig) { OTPFeature.enableFeatures(otpConfig.otpFeatures); OTPFeature.logFeatureSetup(); @@ -117,7 +134,8 @@ public void abortOnUnknownParameters() { ( otpConfig.hasUnknownParameters() || buildConfig.hasUnknownParameters() || - routerConfig.hasUnknownParameters() + routerConfig.hasUnknownParameters() || + debugUiConfig.hasUnknownParameters() ) ) { throw new OtpAppException( diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java new file mode 100644 index 00000000000..cca6d2359be --- /dev/null +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -0,0 +1,106 @@ +package org.opentripplanner.standalone.config; + +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.MissingNode; +import java.util.List; +import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is an object representation of the 'debug-ui-config.json'. + */ +public class DebugUiConfig { + + private static final Logger LOG = LoggerFactory.getLogger(DebugUiConfig.class); + + public static final DebugUiConfig DEFAULT = new DebugUiConfig( + MissingNode.getInstance(), + "DEFAULT", + false + ); + + /** + * The node adaptor kept for reference and (de)serialization. + */ + private final NodeAdapter root; + private final List additionalBackgroundLayers; + + public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { + this(new NodeAdapter(node, source), logUnusedParams); + } + + /** protected to give unit-test access */ + DebugUiConfig(NodeAdapter root, boolean logUnusedParams) { + this.root = root; + + this.additionalBackgroundLayers = + root + .of("additionalBackgroundLayers") + .since(V2_7) + .summary("Additional background raster map layers.") + .description( + """ + Add additional background layers that will appear in the Debug UI as one of the choices. + + Currently only raster tile layers are supported. + """ + ) + .asObjects( + List.of(), + node -> + new BackgroundTileLayer( + node + .of("name") + .since(V2_7) + .summary("Name to appear in the layer selector.") + .asString(), + node + .of("templateUrl") + .since(V2_7) + .summary( + """ + The [Maplibre-compatible template URL](https://maplibre.org/maplibre-native/ios/api/tile-url-templates.html) + for the raster layer, for example `https://examples.com/tiles/{z}/{x}/{y}.png`. + """ + ) + .asString(), + node.of("tileSize").since(V2_7).summary("Size of the tile in pixels.").asInt(256), + node + .of("attribution") + .since(V2_7) + .summary("Attribution for the map data.") + .asString("© OpenTripPlanner") + ) + ); + + if (logUnusedParams) { + root.logAllWarnings(LOG::warn); + } + } + + public NodeAdapter asNodeAdapter() { + return root; + } + + public List additionalBackgroundLayers() { + return additionalBackgroundLayers; + } + + /** + * If {@code true} the config is loaded from file, in not the DEFAULT config is used. + */ + public boolean isDefault() { + return root.isEmpty(); + } + + /** + * Checks if any unknown or invalid parameters were encountered while loading the configuration. + */ + public boolean hasUnknownParameters() { + return root.hasUnknownParameters(); + } +} diff --git a/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java b/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java index d5c452b3da7..9e24e56ca12 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java @@ -1,6 +1,7 @@ package org.opentripplanner.standalone.config; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; +import static org.opentripplanner.framework.application.OtpFileNames.DEBUG_UI_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; @@ -105,6 +106,14 @@ public RouterConfig loadRouterConfig() { return new RouterConfig(node, ROUTER_CONFIG_FILENAME, true); } + public DebugUiConfig loadDebugUiConfig() { + JsonNode node = loadFromFile(DEBUG_UI_CONFIG_FILENAME); + if (node.isMissingNode()) { + return DebugUiConfig.DEFAULT; + } + return new DebugUiConfig(node, DEBUG_UI_CONFIG_FILENAME, true); + } + private static void logConfigVersion(String configVersion, String filename) { if (configVersion != null) { LOG.info("{} config-version is {}.", filename, configVersion); diff --git a/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java b/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java index 4f75f3984d5..9a4de91f2ab 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java @@ -8,6 +8,7 @@ import org.opentripplanner.routing.algorithm.raptoradapter.transit.TripSchedule; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; @@ -34,6 +35,11 @@ static RouterConfig provideRouterConfig(ConfigModel model) { return model.routerConfig(); } + @Provides + static DebugUiConfig provideDebugUiConfig(ConfigModel model) { + return model.debugUiConfig(); + } + @Provides @Singleton static RaptorConfig providesRaptorConfig( diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java new file mode 100644 index 00000000000..121debcb40e --- /dev/null +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -0,0 +1,8 @@ +package org.opentripplanner.standalone.config.debuguiconfig; + +public record BackgroundTileLayer( + String name, + String templateUrl, + int tileSize, + String attribution +) {} diff --git a/application/src/main/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirective.java b/application/src/main/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirective.java index f864bc24d99..7389babd7fe 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirective.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirective.java @@ -95,10 +95,12 @@ private String includeFileDirective(String text, String source) { String directive = entry.getKey(); String fileText = loadFile(entry.getValue(), directive, source); - // If the insert text is a legal JSON object "[white-space]{ ... }[white-space]", then + // If the insert text is a legal JSON object or array, then // ignore the optional quotes matched by the directive pattern var json = fileText.trim(); - if (json.startsWith("{") && json.endsWith("}")) { + if ( + (json.startsWith("{") && json.endsWith("}")) || (json.startsWith("[") && json.endsWith("]")) + ) { text = text.replace(entry.getKey(), fileText); } else { // Add back quotes if matched part of directive pattern diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java index ddb6a967f92..28fb7bf9549 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java @@ -33,14 +33,10 @@ public static void populateConfig( .asString(null) ); parameters.setTopicName( - c.of("topic").since(V2_2).summary("Service Bus topic to connect to.").asString(null) + c.of("topic").since(V2_2).summary("Service Bus topic to connect to.").asString() ); parameters.setFeedId( - c - .of("feedId") - .since(V2_2) - .summary("The ID of the feed to apply the updates to.") - .asString(null) + c.of("feedId").since(V2_2).summary("The ID of the feed to apply the updates to.").asString() ); parameters.setAutoDeleteOnIdle( c diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java index d05aee96ccf..454ab29a68c 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java @@ -6,6 +6,7 @@ import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_3; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_4; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_5; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; import static org.opentripplanner.standalone.config.routerequest.ItineraryFiltersConfig.mapItineraryFilterParams; import static org.opentripplanner.standalone.config.routerequest.TransferConfig.mapTransferPreferences; import static org.opentripplanner.standalone.config.routerequest.TriangleOptimizationConfig.mapOptimizationTriangle; @@ -25,6 +26,7 @@ import org.opentripplanner.routing.api.request.preference.AccessEgressPreferences; import org.opentripplanner.routing.api.request.preference.BikePreferences; import org.opentripplanner.routing.api.request.preference.CarPreferences; +import org.opentripplanner.routing.api.request.preference.EscalatorPreferences; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; import org.opentripplanner.routing.api.request.preference.ScooterPreferences; import org.opentripplanner.routing.api.request.preference.StreetPreferences; @@ -736,6 +738,32 @@ private static void mapSystemPreferences(NodeAdapter c, SystemPreferences.Builde } } + private static void mapEscalatorPreferences( + NodeAdapter root, + EscalatorPreferences.Builder escalator + ) { + var dft = escalator.original(); + NodeAdapter c = root.of("escalator").since(V2_7).summary("Escalator preferences.").asObject(); + escalator + .withReluctance( + c + .of("reluctance") + .since(V2_4) + .summary( + "A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time" + ) + .asDouble(dft.reluctance()) + ) + .withSpeed( + c + .of("speed") + .since(V2_7) + .summary("How fast does an escalator move horizontally?") + .description("Horizontal speed of escalator in m/s.") + .asDouble(dft.speed()) + ); + } + private static void mapWalkPreferences(NodeAdapter root, WalkPreferences.Builder walk) { var dft = walk.original(); NodeAdapter c = root.of("walk").since(V2_5).summary("Walking preferences.").asObject(); @@ -809,14 +837,6 @@ private static void mapWalkPreferences(NodeAdapter root, WalkPreferences.Builder ) .asDouble(dft.safetyFactor()) ) - .withEscalatorReluctance( - c - .of("escalatorReluctance") - .since(V2_4) - .summary( - "A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time" - ) - .asDouble(dft.escalatorReluctance()) - ); + .withEscalator(escalator -> mapEscalatorPreferences(c, escalator)); } } diff --git a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java index eb3fae5275f..b4edbb36299 100644 --- a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java +++ b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java @@ -27,6 +27,7 @@ import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.CommandLineParameters; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.GrizzlyServer; @@ -300,6 +301,10 @@ public BuildConfig buildConfig() { return factory.config().buildConfig(); } + public DebugUiConfig debugUiConfig() { + return factory.config().debugUiConfig(); + } + public RaptorConfig raptorConfig() { return factory.raptorConfig(); } diff --git a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java index bbdd39c57d5..42bd8ee4d87 100644 --- a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java +++ b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java @@ -20,6 +20,7 @@ import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.service.StreetLimitationParametersService; @@ -32,6 +33,7 @@ public class ConstructApplicationModule { @Provides OtpServerRequestContext providesServerContext( RouterConfig routerConfig, + DebugUiConfig debugUiConfig, RaptorConfig raptorConfig, Graph graph, TransitService transitService, @@ -69,7 +71,8 @@ OtpServerRequestContext providesServerContext( stopConsolidationService, streetLimitationParametersService, traverseVisitor, - luceneIndex + luceneIndex, + debugUiConfig ); } diff --git a/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java index 1427dcf1971..450b6986cb5 100644 --- a/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java +++ b/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java @@ -26,6 +26,7 @@ import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.standalone.api.HttpRequestScoped; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.routerconfig.TransitRoutingConfig; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.street.service.StreetLimitationParametersService; @@ -57,6 +58,7 @@ public class DefaultServerRequestContext implements OtpServerRequestContext { private final StopConsolidationService stopConsolidationService; private final StreetLimitationParametersService streetLimitationParametersService; private final LuceneIndex luceneIndex; + private final DebugUiConfig debugUiConfig; private RouteRequest defaultRouteRequestWithTimeSet = null; @@ -83,7 +85,8 @@ private DefaultServerRequestContext( StreetLimitationParametersService streetLimitationParametersService, FlexParameters flexParameters, @Nullable TraverseVisitor traverseVisitor, - @Nullable LuceneIndex luceneIndex + @Nullable LuceneIndex luceneIndex, + DebugUiConfig debugUiConfig ) { this.graph = graph; this.transitService = transitService; @@ -105,6 +108,7 @@ private DefaultServerRequestContext( this.stopConsolidationService = stopConsolidationService; this.streetLimitationParametersService = streetLimitationParametersService; this.luceneIndex = luceneIndex; + this.debugUiConfig = debugUiConfig; } /** @@ -129,7 +133,8 @@ public static DefaultServerRequestContext create( @Nullable StopConsolidationService stopConsolidationService, StreetLimitationParametersService streetLimitationParametersService, @Nullable TraverseVisitor traverseVisitor, - @Nullable LuceneIndex luceneIndex + @Nullable LuceneIndex luceneIndex, + DebugUiConfig debugUiConfig ) { return new DefaultServerRequestContext( graph, @@ -151,7 +156,8 @@ public static DefaultServerRequestContext create( streetLimitationParametersService, flexParameters, traverseVisitor, - luceneIndex + luceneIndex, + debugUiConfig ); } @@ -262,6 +268,11 @@ public VectorTileConfig vectorTileConfig() { return vectorTileConfig; } + @Override + public DebugUiConfig debugUiConfig() { + return debugUiConfig; + } + @Nullable @Override public LuceneIndex lucenceIndex() { diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/Edge.java b/application/src/main/java/org/opentripplanner/street/model/edge/Edge.java index 31bff5b1e15..8e4126b4e59 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/Edge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/Edge.java @@ -145,15 +145,17 @@ public String getDefaultName() { */ public abstract I18NString getName(); - // TODO Add comments about what a "bogus name" is. + /** + * Returns true if this edge has a generated name that is derived from its properties, + * like "path", "stairs" or "tunnel". + *

+ * Returns false if the field reflects the real world name, like "Fifth Avenue", + * "Hauptstraße" or "Øvre Holmegate". + */ public boolean hasBogusName() { return false; } - // The next few functions used to live in EdgeNarrative, which has now been - // removed - // @author mattwigway - public LineString getGeometry() { return null; } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 20fae657c78..d44b67568d6 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -1,5 +1,8 @@ package org.opentripplanner.street.model.edge; +import java.time.Duration; +import java.util.Optional; +import javax.annotation.Nullable; import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.i18n.I18NString; @@ -11,16 +14,14 @@ /** Represents an escalator. An escalator edge can only be traversed by walking */ public class EscalatorEdge extends Edge { - /* A quick internet search gives escalator speed range of 0.3-0.6 m/s and angle of 30 degrees. - * Using the angle of 30 degrees and a speed of 0.5 m/s gives a horizontal component - * of approx. 0.43 m/s */ - private static final double HORIZONTAL_SPEED = 0.45; private static final LocalizedString NAME = new LocalizedString("name.escalator"); private final double length; + private final Duration duration; - private EscalatorEdge(Vertex v1, Vertex v2, double length) { + private EscalatorEdge(Vertex v1, Vertex v2, double length, Duration duration) { super(v1, v2); this.length = length; + this.duration = duration; } @Override @@ -28,8 +29,13 @@ public State[] traverse(State s0) { // Only allow traversal by walking if (s0.currentMode() == TraverseMode.WALK && !s0.getRequest().wheelchair()) { var s1 = s0.edit(this); - var time = getDistanceMeters() / HORIZONTAL_SPEED; - s1.incrementWeight(s0.getPreferences().walk().escalatorReluctance() * time); + double time; + if (duration == null) { + time = getDistanceMeters() / s0.getPreferences().walk().escalator().speed(); + } else { + time = duration.toSeconds(); + } + s1.incrementWeight(s0.getPreferences().walk().escalator().reluctance() * time); s1.incrementTimeInSeconds((int) Math.round(time)); s1.incrementWalkDistance(getDistanceMeters()); return s1.makeStateArray(); @@ -46,12 +52,25 @@ public double getDistanceMeters() { return length; } + /** + * Parsed content of duration tag in OSM, if any. Not a calculated value. + * @return Duration, or empty + */ + public Optional getDuration() { + return Optional.ofNullable(duration); + } + @Override public I18NString getName() { return NAME; } - public static EscalatorEdge createEscalatorEdge(Vertex from, Vertex to, double length) { - return connectToGraph(new EscalatorEdge(from, to, length)); + public static EscalatorEdge createEscalatorEdge( + Vertex from, + Vertex to, + double length, + @Nullable Duration duration + ) { + return connectToGraph(new EscalatorEdge(from, to, length, duration)); } } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java index ee24e87f07c..468da359e0a 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/StreetEdge.java @@ -9,9 +9,6 @@ import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; -import javax.annotation.Nullable; import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; import org.opentripplanner.framework.geometry.CompactLineStringUtils; @@ -82,14 +79,14 @@ public class StreetEdge /** * bicycleSafetyWeight = length * bicycleSafetyFactor. For example, a 100m street with a safety - * factor of 2.0 will be considered in term of safety cost as the same as a 200m street with a + * factor of 2.0 will be considered in terms of safety cost as the same as a 200m street with a * safety factor of 1.0. */ private float bicycleSafetyFactor; /** * walkSafetyFactor = length * walkSafetyFactor. For example, a 100m street with a safety - * factor of 2.0 will be considered in term of safety cost as the same as a 200m street with a + * factor of 2.0 will be considered in terms of safety cost as the same as a 200m street with a * safety factor of 1.0. */ private float walkSafetyFactor; @@ -446,8 +443,15 @@ public I18NString getName() { return this.name; } + /** + * Update the name of the edge after it has been constructed. This method also sets the bogusName + * property to false, indicating to the code that maps from edges to steps that this is a real + * street name. + * @see Edge#hasBogusName() + */ public void setName(I18NString name) { this.name = name; + this.flags = BitSetUtils.set(flags, HASBOGUSNAME_FLAG_INDEX, false); } public boolean hasBogusName() { diff --git a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java index 97d6f91be5a..8f28614069c 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java +++ b/application/src/main/java/org/opentripplanner/transit/model/basic/Money.java @@ -147,6 +147,15 @@ public Money half() { return new Money(currency, IntUtils.round(amount / 2f)); } + /** + * Returns the instance rounded down to the nearest multiple of 5 cents + * So $0.14 becomes $0.10 + */ + public Money roundDownToNearestFiveMinorUnits() { + int rounded = (this.minorUnitAmount() / 5) * 5; + return new Money(currency, rounded); + } + /** * Multiplies the amount with the multiplicator. */ diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index a131b95fc8e..f92a8191018 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -279,12 +279,16 @@ type BookingInfo { earliestBookingTime: BookingTime "When is the latest time the service can be booked" latestBookingTime: BookingTime + "Maximum duration before travel to make the request." + maximumBookingNotice: Duration "Maximum number of seconds before travel to make the request" - maximumBookingNoticeSeconds: Long + maximumBookingNoticeSeconds: Long @deprecated(reason : "Use `maximumBookingNotice`") "A general message for those booking the service" message: String + "Minimum duration before travel to make the request" + minimumBookingNotice: Duration "Minimum number of seconds before travel to make the request" - minimumBookingNoticeSeconds: Long + minimumBookingNoticeSeconds: Long @deprecated(reason : "Use `minimumBookingNotice`") "A message specific to the pick up" pickupMessage: String } diff --git a/application/src/test/java/org/opentripplanner/TestServerContext.java b/application/src/test/java/org/opentripplanner/TestServerContext.java index e20720bd7d8..ca818a64a58 100644 --- a/application/src/test/java/org/opentripplanner/TestServerContext.java +++ b/application/src/test/java/org/opentripplanner/TestServerContext.java @@ -21,6 +21,7 @@ import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; import org.opentripplanner.service.worldenvelope.model.WorldEnvelope; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; import org.opentripplanner.standalone.server.DefaultServerRequestContext; @@ -65,7 +66,8 @@ public static OtpServerRequestContext createServerContext( null, createStreetLimitationParametersService(), null, - null + null, + DebugUiConfig.DEFAULT ); creatTransitLayerForRaptor(timetableRepository, routerConfig.transitTuningConfig()); return context; diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java index 1103024aa61..d721a73939b 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java @@ -15,27 +15,40 @@ class BookingInfoImplTest { private static final BookingInfoImpl SUBJECT = new BookingInfoImpl(); private static final Duration TEN_MINUTES = Duration.ofMinutes(10); + private static final BookingInfo WITH_NOTICE_DURATIONS = BookingInfo + .of() + .withMinimumBookingNotice(TEN_MINUTES) + .withMaximumBookingNotice(TEN_MINUTES) + .build(); @Test - void emptyDurations() throws Exception { + void emptyNoticeSeconds() throws Exception { var env = dataFetchingEnvironment(BookingInfo.of().build()); assertNull(SUBJECT.minimumBookingNoticeSeconds().get(env)); assertNull(SUBJECT.maximumBookingNoticeSeconds().get(env)); } @Test - void durations() throws Exception { - var env = dataFetchingEnvironment( - BookingInfo - .of() - .withMinimumBookingNotice(TEN_MINUTES) - .withMaximumBookingNotice(TEN_MINUTES) - .build() - ); + void emptyNoticeDurations() throws Exception { + var env = dataFetchingEnvironment(BookingInfo.of().build()); + assertNull(SUBJECT.minimumBookingNotice().get(env)); + assertNull(SUBJECT.maximumBookingNotice().get(env)); + } + + @Test + void seconds() throws Exception { + var env = dataFetchingEnvironment(WITH_NOTICE_DURATIONS); assertEquals(600, SUBJECT.minimumBookingNoticeSeconds().get(env)); assertEquals(600, SUBJECT.maximumBookingNoticeSeconds().get(env)); } + @Test + void durations() throws Exception { + var env = dataFetchingEnvironment(WITH_NOTICE_DURATIONS); + assertEquals(TEN_MINUTES, SUBJECT.minimumBookingNotice().get(env)); + assertEquals(TEN_MINUTES, SUBJECT.maximumBookingNotice().get(env)); + } + private DataFetchingEnvironment dataFetchingEnvironment(BookingInfo bookingInfo) { var executionContext = newExecutionContextBuilder() .executionId(ExecutionId.from(this.getClass().getName())) diff --git a/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java b/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java index b3c64e0aecb..dc96a094812 100644 --- a/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java +++ b/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java @@ -52,6 +52,7 @@ import org.opentripplanner.service.vehiclerental.internal.DefaultVehicleRentalService; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeRepository; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.model.StreetLimitationParameters; @@ -154,7 +155,8 @@ void setup() { null, new DefaultStreetLimitationParametersService(new StreetLimitationParameters()), null, - null + null, + DebugUiConfig.DEFAULT ), null, transitService diff --git a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index db056050394..26d1044047e 100644 --- a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import org.junit.jupiter.api.Test; import org.opentripplanner.apis.vectortiles.model.TileSource.VectorSource; import org.opentripplanner.apis.vectortiles.model.VectorSourceLayer; @@ -27,7 +28,14 @@ void spec() throws IOException { var groupStops = new VectorSourceLayer(vectorSource, "stops"); var edges = new VectorSourceLayer(vectorSource, "edges"); var vertices = new VectorSourceLayer(vectorSource, "vertices"); - var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices); + var spec = DebugStyleSpec.build( + regularStops, + areaStops, + groupStops, + edges, + vertices, + List.of() + ); var json = ObjectMappers.ignoringExtraFields().valueToTree(spec); try { diff --git a/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java b/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java new file mode 100644 index 00000000000..a5124c0d3e0 --- /dev/null +++ b/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java @@ -0,0 +1,67 @@ +package org.opentripplanner.generate.doc; + +import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; +import static org.opentripplanner.framework.io.FileUtils.readFile; +import static org.opentripplanner.framework.io.FileUtils.writeFile; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.TEMPLATE_PATH; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.USER_DOC_PATH; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceJsonExample; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceParametersDetails; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceParametersTable; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromResource; +import static org.opentripplanner.utils.text.MarkdownFormatter.HEADER_3; + +import java.io.File; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.application.OtpFileNames; +import org.opentripplanner.generate.doc.framework.GeneratesDocumentation; +import org.opentripplanner.generate.doc.framework.ParameterDetailsList; +import org.opentripplanner.generate.doc.framework.ParameterSummaryTable; +import org.opentripplanner.generate.doc.framework.SkipNodes; +import org.opentripplanner.standalone.config.DebugUiConfig; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; + +@GeneratesDocumentation +public class DebugUiConfigurationDocTest { + + private static final String CONFIG_JSON = OtpFileNames.DEBUG_UI_CONFIG_FILENAME; + private static final File TEMPLATE = new File(TEMPLATE_PATH, "DebugUiConfiguration.md"); + private static final File OUT_FILE = new File(USER_DOC_PATH, "DebugUiConfiguration.md"); + + private static final String CONFIG_PATH = "standalone/config/" + CONFIG_JSON; + + /** + * NOTE! This test updates the {@code doc/user/Configuration.md} document based on the latest + * version of the code. + */ + @Test + public void updateDoc() { + NodeAdapter node = readConfig(); + + // Read and close input file (same as output file) + String doc = readFile(TEMPLATE); + String original = readFile(OUT_FILE); + + doc = replaceParametersTable(doc, getParameterSummaryTable(node)); + doc = replaceParametersDetails(doc, getParameterDetailsTable(node)); + doc = replaceJsonExample(doc, node, CONFIG_JSON); + + writeFile(OUT_FILE, doc); + + assertFileEquals(original, OUT_FILE); + } + + private NodeAdapter readConfig() { + var json = jsonNodeFromResource(CONFIG_PATH); + var conf = new DebugUiConfig(json, CONFIG_PATH, true); + return conf.asNodeAdapter(); + } + + private String getParameterSummaryTable(NodeAdapter node) { + return new ParameterSummaryTable(SkipNodes.of().build()).createTable(node).toMarkdownTable(); + } + + private String getParameterDetailsTable(NodeAdapter node) { + return ParameterDetailsList.listParametersWithDetails(node, SkipNodes.of().build(), HEADER_3); + } +} diff --git a/application/src/test/java/org/opentripplanner/graph_builder/module/osm/naming/SidewalkNamerTest.java b/application/src/test/java/org/opentripplanner/graph_builder/module/osm/naming/SidewalkNamerTest.java index 465eeb32ba2..cbfb7b76c6f 100644 --- a/application/src/test/java/org/opentripplanner/graph_builder/module/osm/naming/SidewalkNamerTest.java +++ b/application/src/test/java/org/opentripplanner/graph_builder/module/osm/naming/SidewalkNamerTest.java @@ -58,6 +58,7 @@ void postprocess() { assertNotEquals(sidewalk.edge.getName(), pryorStreet.edge.getName()); builder.postProcess(new SidewalkNamer()); assertEquals(sidewalk.edge.getName(), pryorStreet.edge.getName()); + assertFalse(sidewalk.edge.hasBogusName()); } private static class ModelBuilder { diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java index a89f8612040..84b74b8f655 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java @@ -5,9 +5,11 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.OptionalInt; import java.util.Set; import org.junit.jupiter.api.Test; @@ -298,4 +300,32 @@ void parseIntOrBoolean(String value, OptionalInt expected) { var maybeInt = way.parseIntOrBoolean(key, i -> {}); assertEquals(expected, maybeInt); } + + private static List parseTagAsDurationCases() { + return List.of( + Arguments.of("00:11", Optional.of(Duration.ofMinutes(11))), + Arguments.of("11", Optional.of(Duration.ofMinutes(11))), + Arguments.of("1:22:33", Optional.of(Duration.ofHours(1).plusMinutes(22).plusSeconds(33))), + Arguments.of("82", Optional.of(Duration.ofMinutes(82))), + Arguments.of("25:00", Optional.of(Duration.ofHours(25))), + Arguments.of("25:00:00", Optional.of(Duration.ofHours(25))), + Arguments.of("22:60", Optional.empty()), + Arguments.of("10:61:40", Optional.empty()), + Arguments.of("10:59:60", Optional.empty()), + Arguments.of("1:12:34", Optional.of(Duration.ofHours(1).plusMinutes(12).plusSeconds(34))), + Arguments.of("1:2:34", Optional.empty()), + Arguments.of("1:12:3", Optional.empty()), + Arguments.of("1:2", Optional.empty()) + ); + } + + @ParameterizedTest + @MethodSource("parseTagAsDurationCases") + void parseTagAsDuration(String value, Optional expected) { + var way = new OsmWithTags(); + var key = "duration"; + way.addTag(key, value); + var duration = way.getTagValueAsDuration(key, i -> {}); + assertEquals(expected, duration); + } } diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapperTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapperTest.java index 6e41f6ddf2b..de9fe21718a 100644 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapperTest.java +++ b/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/StatesToWalkStepsMapperTest.java @@ -42,7 +42,7 @@ void enterStation() { var walkSteps = buildWalkSteps(builder); assertEquals(2, walkSteps.size()); var enter = walkSteps.get(1); - assertEquals(enter.getRelativeDirection(), ENTER_STATION); + assertEquals(ENTER_STATION, enter.getRelativeDirection()); } @Test @@ -54,7 +54,7 @@ void exitStation() { var walkSteps = buildWalkSteps(builder); assertEquals(3, walkSteps.size()); var enter = walkSteps.get(2); - assertEquals(enter.getRelativeDirection(), EXIT_STATION); + assertEquals(EXIT_STATION, enter.getRelativeDirection()); } @Test @@ -64,7 +64,7 @@ void signpostedPathway() { var walkSteps = buildWalkSteps(builder); assertEquals(2, walkSteps.size()); var step = walkSteps.get(1); - assertEquals(step.getRelativeDirection(), FOLLOW_SIGNS); + assertEquals(FOLLOW_SIGNS, step.getRelativeDirection()); assertEquals(sign, step.getDirectionText().toString()); } diff --git a/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java b/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java index a61a0558bb1..785b130ca7a 100644 --- a/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java +++ b/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java @@ -88,7 +88,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); var secondEqual = WalkPreferences @@ -97,7 +97,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertEqualsAndHashCode(firstEqual, secondEqual); @@ -110,7 +110,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentSpeedPreferences); @@ -123,7 +123,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(notSameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentReluctancePreferences); @@ -136,7 +136,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(notSameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentStairsReluctancePreferences); @@ -149,7 +149,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(notSameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentSafetyFactorPreferences); @@ -162,7 +162,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(notSameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(notSameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentEscalatorReluctancePreferences); @@ -175,7 +175,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(notSameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentBoardCostPreferences); diff --git a/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java b/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java index 01392e64493..4fdb74d5340 100644 --- a/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java +++ b/application/src/test/java/org/opentripplanner/routing/core/MoneyTest.java @@ -91,6 +91,12 @@ void half() { assertEquals(Money.usDollars(0.38f), Money.usDollars(0.75f).half()); } + @Test + void roundDownToNearestFiveMinorUnits() { + assertEquals(Money.usDollars(0.1f), Money.usDollars(0.11f).roundDownToNearestFiveMinorUnits()); + assertEquals(Money.usDollars(0.5f), Money.usDollars(0.54f).roundDownToNearestFiveMinorUnits()); + } + @Test void greaterThan() { assertTrue(twoDollars.greaterThan(oneDollar)); diff --git a/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java b/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java index 06b0d8ed592..934da6f923d 100644 --- a/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java +++ b/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; +import static org.opentripplanner.framework.application.OtpFileNames.DEBUG_UI_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; @@ -60,6 +61,17 @@ void otpConfig(Path filename) { testConfig(filename, nodeAdapter -> new OtpConfig(nodeAdapter, true)); } + @FilePatternSource( + pattern = { + "doc/user/examples/**/" + DEBUG_UI_CONFIG_FILENAME, + "application/src/test/resources/standalone/config/" + DEBUG_UI_CONFIG_FILENAME, + } + ) + @ParameterizedTest(name = "Check validity of {0}") + void debugUiConfig(Path filename) { + testConfig(filename, nodeAdapter -> new DebugUiConfig(nodeAdapter, true)); + } + @FilePatternSource( pattern = { "application/src/test/resources/standalone/config/invalid-config.json" } ) diff --git a/application/src/test/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirectiveTest.java b/application/src/test/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirectiveTest.java index 0fc1199236d..0628b610216 100644 --- a/application/src/test/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirectiveTest.java +++ b/application/src/test/java/org/opentripplanner/standalone/config/framework/file/IncludeFileDirectiveTest.java @@ -45,6 +45,17 @@ void includeFileWithQuotesAndProperJsonInput() throws IOException { assertEquals(json("{ 'key' : \t {\n 'foo' : 'bar' \n }\n}"), result); } + @Test + void includeFileWithQuotesAndJsonArrayInput() throws IOException { + savePartialFile(json("\t [\n 'foo', 'bar' \n ]\n")); + String result = IncludeFileDirective.includeFileDirective( + CONFIG_DIR, + json("{ 'key' : '${includeFile:" + PART_FILE_NAME + "}'}"), + PART_FILE_NAME + ); + assertEquals(json("{ 'key' : \t [\n 'foo', 'bar' \n ]\n}"), result); + } + @Test void includeFileWithQuotesWithNoJsonInput() throws IOException { savePartialFile("value"); diff --git a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java index 1cfff635c45..23ae7a567f8 100644 --- a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java +++ b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java @@ -3,6 +3,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.time.Duration; import java.util.Locale; import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -27,20 +28,31 @@ static Stream args() { @ParameterizedTest(name = "escalatorReluctance of {0} should lead to traversal costs of {1}") @MethodSource("args") void testWalking(double escalatorReluctance, double expectedWeight) { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 45); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, null); var req = StreetSearchRequest .of() - .withPreferences(p -> p.withWalk(w -> w.withEscalatorReluctance(escalatorReluctance))) + .withPreferences(p -> + p.withWalk(w -> w.withEscalator(escalator -> escalator.withReluctance(escalatorReluctance))) + ) .withMode(StreetMode.WALK); var res = edge.traverse(new State(from, req.build()))[0]; - assertEquals(res.weight, expectedWeight); - assertEquals(res.getTimeDeltaSeconds(), 100); + assertEquals(expectedWeight, res.weight); + assertEquals(100, res.getTimeDeltaSeconds()); + } + + @Test + void testDuration() { + // If duration is given, length does not affect timeDeltaSeconds, only duration does. + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, Duration.ofSeconds(60)); + var req = StreetSearchRequest.of().withMode(StreetMode.WALK); + var res = edge.traverse(new State(from, req.build()))[0]; + assertEquals(60, res.getTimeDeltaSeconds()); } @Test void testCycling() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); var req = StreetSearchRequest.of().withMode(StreetMode.BIKE); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -48,7 +60,7 @@ void testCycling() { @Test void testWheelchair() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); var req = StreetSearchRequest.of().withMode(StreetMode.WALK).withWheelchair(true); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -56,14 +68,14 @@ void testWheelchair() { @Test void name() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); assertEquals("Rolltreppe", edge.getName().toString(Locale.GERMANY)); assertEquals("escalator", edge.getName().toString(Locale.ENGLISH)); } @Test void geometry() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); assertThat(edge.getGeometry().getCoordinates()).isNotEmpty(); } } diff --git a/application/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java b/application/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java index 7de7b0c7ce6..ef2bacb91dd 100644 --- a/application/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java +++ b/application/src/test/java/org/opentripplanner/street/model/edge/StreetEdgeTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; import static org.opentripplanner.street.model._data.StreetModelForTest.intersectionVertex; import static org.opentripplanner.street.model._data.StreetModelForTest.streetEdge; import static org.opentripplanner.street.model._data.StreetModelForTest.streetEdgeBuilder; @@ -17,6 +18,8 @@ import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.impl.PackedCoordinateSequence; +import org.opentripplanner.framework.geometry.GeometryUtils; +import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.routing.api.request.StreetMode; import org.opentripplanner.routing.core.VehicleRoutingOptimizeType; import org.opentripplanner.routing.util.ElevationUtils; @@ -43,7 +46,7 @@ public class StreetEdgeTest { private StreetSearchRequest proto; @BeforeEach - public void before() { + void before() { v0 = intersectionVertex("maple_0th", 0.0, 0.0); // label, X, Y v1 = intersectionVertex("maple_1st", 2.0, 2.0); v2 = intersectionVertex("maple_2nd", 2.0, 1.0); @@ -64,9 +67,9 @@ public void before() { } @Test - public void testInAndOutAngles() { + void testInAndOutAngles() { // An edge heading straight West - StreetEdge e1 = streetEdge(v1, v2, 1.0, StreetTraversalPermission.ALL); + StreetEdge e1 = streetEdge(v1, v2, 1.0, ALL); // Edge has same first and last angle. assertEquals(90, e1.getInAngle()); @@ -77,7 +80,7 @@ public void testInAndOutAngles() { StreetVertex v = intersectionVertex("test2", 2.0, 2.0); // Second edge, heading straight North - StreetEdge e2 = streetEdge(u, v, 1.0, StreetTraversalPermission.ALL); + StreetEdge e2 = streetEdge(u, v, 1.0, ALL); // 180 degrees could be expressed as 180 or -180. Our implementation happens to use -180. assertEquals(180, Math.abs(e2.getInAngle())); @@ -85,10 +88,8 @@ public void testInAndOutAngles() { } @Test - public void testTraverseAsPedestrian() { - StreetEdge e1 = streetEdgeBuilder(v1, v2, 100.0, StreetTraversalPermission.ALL) - .withCarSpeed(10.0f) - .buildAndConnect(); + void testTraverseAsPedestrian() { + StreetEdge e1 = streetEdgeBuilder(v1, v2, 100.0, ALL).withCarSpeed(10.0f).buildAndConnect(); StreetSearchRequest options = StreetSearchRequest .copyOf(proto) @@ -106,10 +107,8 @@ public void testTraverseAsPedestrian() { } @Test - public void testTraverseAsCar() { - StreetEdge e1 = streetEdgeBuilder(v1, v2, 100.0, StreetTraversalPermission.ALL) - .withCarSpeed(10.0f) - .buildAndConnect(); + void testTraverseAsCar() { + StreetEdge e1 = streetEdgeBuilder(v1, v2, 100.0, ALL).withCarSpeed(10.0f).buildAndConnect(); State s0 = new State(v1, StreetSearchRequest.copyOf(proto).withMode(StreetMode.CAR).build()); State s1 = e1.traverse(s0)[0]; @@ -122,8 +121,8 @@ public void testTraverseAsCar() { } @Test - public void testModeSetCanTraverse() { - StreetEdge e = streetEdge(v1, v2, 1.0, StreetTraversalPermission.ALL); + void testModeSetCanTraverse() { + StreetEdge e = streetEdge(v1, v2, 1.0, ALL); TraverseModeSet modes = TraverseModeSet.allModes(); assertTrue(e.canTraverse(modes)); @@ -146,7 +145,7 @@ public void testModeSetCanTraverse() { * correctly during turn cost computation. 4. Traffic light wait time is taken into account. */ @Test - public void testTraverseModeSwitchBike() { + void testTraverseModeSwitchBike() { var vWithTrafficLight = new LabelledIntersectionVertex("maple_1st", 2.0, 2.0, false, true); StreetEdge e0 = streetEdge(v0, vWithTrafficLight, 50.0, StreetTraversalPermission.PEDESTRIAN); StreetEdge e1 = streetEdge( @@ -183,7 +182,7 @@ public void testTraverseModeSwitchBike() { * the bike walking speed on the walking speed. 4. Traffic light wait time is taken into account. */ @Test - public void testTraverseModeSwitchWalk() { + void testTraverseModeSwitchWalk() { var vWithTrafficLight = new LabelledIntersectionVertex("maple_1st", 2.0, 2.0, false, true); StreetEdge e0 = streetEdge( v0, @@ -214,7 +213,7 @@ public void testTraverseModeSwitchWalk() { * Test the bike switching penalty feature, both its cost penalty and its separate time penalty. */ @Test - public void testBikeSwitch() { + void testBikeSwitch() { StreetEdge e0 = streetEdge(v0, v1, 0.0, StreetTraversalPermission.PEDESTRIAN); StreetEdge e1 = streetEdge(v1, v2, 0.0, StreetTraversalPermission.BICYCLE); StreetEdge e2 = streetEdge(v2, v0, 0.0, StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE); @@ -271,9 +270,9 @@ public void testBikeSwitch() { } @Test - public void testTurnRestriction() { - StreetEdge e0 = streetEdge(v0, v1, 50.0, StreetTraversalPermission.ALL); - StreetEdge e1 = streetEdge(v1, v2, 18.4, StreetTraversalPermission.ALL); + void testTurnRestriction() { + StreetEdge e0 = streetEdge(v0, v1, 50.0, ALL); + StreetEdge e1 = streetEdge(v1, v2, 18.4, ALL); StreetSearchRequestBuilder streetSearchRequestBuilder = StreetSearchRequest.copyOf(proto); streetSearchRequestBuilder.withArriveBy(true); StreetSearchRequest request = streetSearchRequestBuilder.withMode(StreetMode.WALK).build(); @@ -285,13 +284,13 @@ public void testTurnRestriction() { } @Test - public void testElevationProfile() { + void testElevationProfile() { var elevationProfile = new PackedCoordinateSequence.Double( new double[] { 0, 10, 50, 12 }, 2, 0 ); - var edge = streetEdge(v0, v1, 50.0, StreetTraversalPermission.ALL); + var edge = streetEdge(v0, v1, 50.0, ALL); StreetElevationExtensionBuilder .of(edge) .withElevationProfile(elevationProfile) @@ -306,7 +305,7 @@ public void testElevationProfile() { } @Test - public void testBikeOptimizeTriangle() { + void testBikeOptimizeTriangle() { // This test does not depend on the setup method - and can probably be simplified Coordinate c1 = new Coordinate(-122.575033, 45.456773); @@ -326,7 +325,7 @@ public void testBikeOptimizeTriangle() { .withGeometry(geometry) .withName("Test Lane") .withMeterLength(length) - .withPermission(StreetTraversalPermission.ALL) + .withPermission(ALL) .withBack(false) // a safe street .withBicycleSafetyFactor(0.74f) @@ -400,4 +399,25 @@ public void testBikeOptimizeTriangle() { double expectedWeight = timeWeight * 0.33 + slopeWeight * 0.33 + safetyWeight * 0.34; assertEquals(expectedWeight, result.getWeight(), DELTA); } + + @Test + void setName() { + var path = I18NString.of("path"); + var edge = new StreetEdgeBuilder<>() + .withFromVertex(v0) + .withToVertex(v1) + .withPermission(ALL) + .withGeometry(GeometryUtils.makeLineString(v0.getCoordinate(), v1.getCoordinate())) + .withName(path) + .withBogusName(true) + .buildAndConnect(); + + assertEquals(path, edge.getName()); + assertTrue(edge.hasBogusName()); + + var mainStreet = I18NString.of("Main Street"); + edge.setName(mainStreet); + assertEquals(mainStreet, edge.getName()); + assertFalse(edge.hasBogusName()); + } } diff --git a/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java b/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java index c55ddff854f..ca4e85eed84 100644 --- a/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java +++ b/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java @@ -29,6 +29,7 @@ import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfigLoader; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; @@ -130,7 +131,8 @@ public SpeedTest( null, TestServerContext.createStreetLimitationParametersService(), null, - null + null, + DebugUiConfig.DEFAULT ); // Creating transitLayerForRaptor should be integrated into the TimetableRepository, but for now // we do it manually here diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index b08a225fde3..66858390ab5 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,28 +1,52 @@ { "name": "OTP Debug Tiles", "sources": { - "background": { - "id": "background", - "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], + "positron": { + "name": "Positron", + "tiles": [ + "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}{ratio}.png" + ], "maxzoom": 19, "tileSize": 256, - "attribution": "© OpenStreetMap Contributors", + "attribution": "© OpenStreetMap, © CARTO", "type": "raster" }, "vectorSource": { "id": "vectorSource", "url": "https://example.com", "type": "vector" + }, + "osm-carto": { + "name": "OSM Carto", + "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], + "maxzoom": 19, + "tileSize": 256, + "attribution": "© OpenStreetMap Contributors", + "type": "raster" } }, "layers": [ { - "id": "background", + "id": "osm-carto", "type": "raster", - "source": "background", + "source": "osm-carto", "minzoom": 0, "metadata": { - "group": "Other" + "group": "Other", + "name": "OSM Carto" + } + }, + { + "id": "positron", + "type": "raster", + "source": "positron", + "minzoom": 0, + "layout": { + "visibility": "none" + }, + "metadata": { + "group": "Other", + "name": "Positron" } }, { diff --git a/application/src/test/resources/standalone/config/debug-ui-config.json b/application/src/test/resources/standalone/config/debug-ui-config.json new file mode 100644 index 00000000000..1ae690a4d37 --- /dev/null +++ b/application/src/test/resources/standalone/config/debug-ui-config.json @@ -0,0 +1,9 @@ +{ + "additionalBackgroundLayers": [ + { + "name": "TriMet aerial photos", + "templateUrl": "https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials", + "attribution": "© TriMet" + } + ] +} diff --git a/application/src/test/resources/standalone/config/router-config.json b/application/src/test/resources/standalone/config/router-config.json index 4b6cf30f45d..3616007c087 100644 --- a/application/src/test/resources/standalone/config/router-config.json +++ b/application/src/test/resources/standalone/config/router-config.json @@ -75,7 +75,10 @@ "reluctance": 4.0, "stairsReluctance": 1.65, "boardCost": 600, - "escalatorReluctance": 1.5 + "escalator": { + "reluctance": 1.5, + "speed": 0.45 + } }, "waitReluctance": 1.0, "otherThanPreferredRoutesPenalty": 300, diff --git a/client/index.html b/client/index.html index 77eb289e595..f09832636f0 100644 --- a/client/index.html +++ b/client/index.html @@ -4,7 +4,7 @@ - OTP Debug Client + OTP Debug

diff --git a/client/package-lock.json b/client/package-lock.json index bbed0b8e4fa..52d93d9d4cf 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,9 +14,9 @@ "graphql": "16.9.0", "graphql-request": "7.1.2", "maplibre-gl": "4.7.1", - "react": "18.3.1", + "react": "19.0.0", "react-bootstrap": "2.10.6", - "react-dom": "18.3.1", + "react-dom": "19.0.0", "react-map-gl": "7.1.7" }, "devDependencies": { @@ -24,9 +24,9 @@ "@graphql-codegen/client-preset": "4.5.1", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", - "@testing-library/react": "16.0.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", + "@testing-library/react": "16.1.0", + "@types/react": "19.0.1", + "@types/react-dom": "19.0.1", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "4.3.4", @@ -45,15 +45,6 @@ "vitest": "2.1.8" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -229,9 +220,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", "dev": true, "engines": { "node": ">=6.9.0" @@ -268,13 +259,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -284,12 +275,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -312,19 +303,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { @@ -334,37 +323,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", - "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", - "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -401,12 +367,12 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -422,14 +388,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", - "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -438,40 +404,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -518,12 +458,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "dev": true, "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -582,12 +522,12 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", - "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", + "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -597,12 +537,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", - "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -612,12 +552,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -639,12 +579,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", - "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -654,12 +594,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", - "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -669,12 +609,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -684,18 +624,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", - "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -706,13 +644,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", - "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/template": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -722,12 +660,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", - "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -737,13 +675,13 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", - "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.9.tgz", + "integrity": "sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-flow": "^7.24.1" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-flow": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -753,13 +691,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", - "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -769,14 +707,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", - "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -786,12 +724,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", - "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -801,12 +739,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", - "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -816,14 +754,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", - "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-simple-access": "^7.22.5" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -833,13 +770,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", - "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -849,12 +786,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", - "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -864,12 +801,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", - "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -879,12 +816,12 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", - "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -894,16 +831,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -943,12 +880,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", - "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -958,13 +895,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", - "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -974,12 +911,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", - "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -992,7 +929,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", - "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1015,16 +951,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", + "@babel/types": "^7.26.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1033,9 +969,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -1436,24 +1372,27 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1536,7 +1475,6 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1551,7 +1489,6 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-5.0.3.tgz", "integrity": "sha512-SxXPmramkth8XtBlAHu4H4jYcYXM/o3p01+psU+0NADQowA8jtYkK6MW5rV6T+CxkEaNZItfSmZRPgIuypcqnA==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", "tslib": "~2.6.0" @@ -1560,12 +1497,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/add/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/cli": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.3.tgz", "integrity": "sha512-ULpF6Sbu2d7vNEOgBtE9avQp2oMgcPY/QBYcCqk0Xru5fz+ISjcovQX29V7CS7y5wWBRzNLoXwJQGeEyWbl05g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/generator": "^7.18.13", "@babel/template": "^7.18.10", @@ -1627,7 +1569,6 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.5.1.tgz", "integrity": "sha512-UE2/Kz2eaxv35HIXFwlm2QwoUH77am6+qp54aeEWYq+T+WPwmIc6+YzqtGiT/VcaXgoOUSgidREGm9R6jKcf9g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", @@ -1650,6 +1591,12 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/client-preset/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/core": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-4.0.2.tgz", @@ -1665,12 +1612,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/core/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/gql-tag-operations": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.12.tgz", "integrity": "sha512-v279i49FJ5dMmQXIGUgm6FtnnkxtJjVJWDNYh9JK4ppvOixdHp+PmEzW227DkLN6avhVxNnYdp/1gdRBwdWypw==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/visitor-plugin-common": "5.6.0", @@ -1685,6 +1637,12 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/gql-tag-operations/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/introspection": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-4.0.3.tgz", @@ -1699,12 +1657,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/introspection/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/plugin-helpers": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.1.0.tgz", "integrity": "sha512-Y7cwEAkprbTKzVIe436TIw4w03jorsMruvCvu0HJkavaKMQbWY+lQ1RIuROgszDbxAyM35twB5/sUvYG5oW+yg==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-tools/utils": "^10.0.0", "change-case-all": "1.0.15", @@ -1720,12 +1683,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/schema-ast": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-4.1.0.tgz", "integrity": "sha512-kZVn0z+th9SvqxfKYgztA6PM7mhnSZaj4fiuBWvMTqA+QqQ9BBed6Pz41KuD/jr0gJtnlr2A4++/0VlpVbCTmQ==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", "@graphql-tools/utils": "^10.0.0", @@ -1735,12 +1703,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/schema-ast/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/typed-document-node": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.12.tgz", "integrity": "sha512-Wsbc1AqC+MFp3maWPzrmmyHLuWCPB63qBBFLTKtO6KSsnn0KnLocBp475wkfBZnFISFvzwpJ0e6LV71gKfTofQ==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/visitor-plugin-common": "5.6.0", @@ -1755,12 +1728,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/typescript": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.1.2.tgz", "integrity": "sha512-GhPgfxgWEkBrvKR2y77OThus3K8B6U3ESo68l7+sHH1XiL2WapK5DdClViblJWKQerJRjfJu8tcaxQ8Wpk6Ogw==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/schema-ast": "^4.0.2", @@ -1780,7 +1758,6 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.4.0.tgz", "integrity": "sha512-oVlos2ySx8xIbbe8r5ZI6mOpI+OTeP14RmS2MchBJ6DL+S9G16O6+9V3Y8V22fTnmBTZkTfAAaBv4HYhhDGWVA==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/typescript": "^4.1.2", @@ -1795,12 +1772,23 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/typescript-operations/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@graphql-codegen/typescript/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/visitor-plugin-common": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.6.0.tgz", "integrity": "sha512-PowcVPJbUqMC9xTJ/ZRX1p/fsdMZREc+69CM1YY+AlFng2lL0zsdBskFJSRoviQk2Ch9IPhKGyHxlJCy9X22tg==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-tools/optimize": "^2.0.0", @@ -1820,15 +1808,21 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-tools/apollo-engine-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.1.tgz", - "integrity": "sha512-NaPeVjtrfbPXcl+MLQCJLWtqe2/E4bbAqcauEOQ+3sizw1Fc2CNmhHRF8a6W4D0ekvTRRXAMptXYgA2uConbrA==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.7.tgz", + "integrity": "sha512-jyQU4ZhbkUM7C3V+m15K3ch7BSCTdWw/bthjhYhMkiMoFGL/ClNL5+fCIFMcQi5xSxPPmwkBkxzQ8u8UoNPMAg==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", - "@graphql-tools/utils": "^10.0.13", - "@whatwg-node/fetch": "^0.9.0", + "@graphql-tools/utils": "^10.6.2", + "@whatwg-node/fetch": "^0.10.0", "tslib": "^2.4.0" }, "engines": { @@ -1838,32 +1832,60 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/batch-execute": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.4.tgz", - "integrity": "sha512-kkebDLXgDrep5Y0gK1RN3DMUlLqNhg60OAz0lTCqrYeja6DshxLtLkj+zV4mVbBA4mQOEoBmw6g1LZs3dA84/w==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.10.tgz", + "integrity": "sha512-nCRNFq2eqy+ONDknd8DfqidY/Ljgyq67Q0Hb9SMJ3FOWpKrApqmNT9J1BA3JW4r+/zIGtM1VKi+P9FYu3zMHHA==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", - "dataloader": "^2.2.2", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "@graphql-tools/utils": "^10.6.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/code-file-loader": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.1.tgz", - "integrity": "sha512-q4KN25EPSUztc8rA8YUU3ufh721Yk12xXDbtUA+YstczWS7a1RJlghYMFEfR1HsHSYbF7cUqkbnTKSGM3o52bQ==", + "version": "8.1.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.8.tgz", + "integrity": "sha512-b8BTP0cVTgWgc60H7LNfY7dZcEJVsgyCm52BsWOggwWapKAdli1T7ZaLJvnTAbVd8EY8+k4OAO1Z/ti1iirVOA==", "dev": true, "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.3.0", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/graphql-tag-pluck": "8.3.7", + "@graphql-tools/utils": "^10.6.2", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -1876,29 +1898,31 @@ } }, "node_modules/@graphql-tools/delegate": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.0.4.tgz", - "integrity": "sha512-WswZRbQZMh/ebhc8zSomK9DIh6Pd5KbuiMsyiKkKz37TWTrlCOe+4C/fyrBFez30ksq6oFyCeSKMwfrCbeGo0Q==", + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.2.7.tgz", + "integrity": "sha512-cHNRguTi/RGxLttmDR5F4698kVtoPnYCFjgEZh/sg8MGrejTiCpQeg+aXUqcj0efWmnKIkeia5JaqqbTGpc0xA==", "dev": true, "dependencies": { - "@graphql-tools/batch-execute": "^9.0.4", - "@graphql-tools/executor": "^1.2.1", - "@graphql-tools/schema": "^10.0.3", - "@graphql-tools/utils": "^10.0.13", - "dataloader": "^2.2.2", - "tslib": "^2.5.0" + "@graphql-tools/batch-execute": "^9.0.10", + "@graphql-tools/executor": "^1.3.6", + "@graphql-tools/schema": "^10.0.11", + "@graphql-tools/utils": "^10.6.2", + "@repeaterjs/repeater": "^3.0.6", + "dataloader": "^2.2.3", + "dset": "^3.1.2", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/documents": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/documents/-/documents-1.0.0.tgz", - "integrity": "sha512-rHGjX1vg/nZ2DKqRGfDPNC55CWZBMldEVcH+91BThRa6JeT80NqXknffLLEZLRUxyikCfkwMsk6xR3UNMqG0Rg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/documents/-/documents-1.0.1.tgz", + "integrity": "sha512-aweoMH15wNJ8g7b2r4C4WRuJxZ0ca8HtNO54rkye/3duxTkW4fGBEutCx03jCIr5+a1l+4vFJNP859QnAVBVCA==", "dev": true, "dependencies": { "lodash.sortby": "^4.7.0", @@ -1912,12 +1936,12 @@ } }, "node_modules/@graphql-tools/executor": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.2.4.tgz", - "integrity": "sha512-aCO/5LEAwyTWObAAfpLlwAjaOjTxRX6YNXcGW62mglQhPBy+j0fTc4desci/4nJ49l8FWETaTG0MZ1G/PqQslg==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.3.6.tgz", + "integrity": "sha512-ZmWsWdUhTez2b4w9NkmL4wpPb8n8WZmLOMIPTXH2A2yEe2nHrK/tk653JZXvZFtx2HrBIcoZD4Fe/STYWIR74Q==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.1.1", + "@graphql-tools/utils": "^10.6.2", "@graphql-typed-document-node/core": "3.2.0", "@repeaterjs/repeater": "^3.0.4", "tslib": "^2.4.0", @@ -1931,57 +1955,87 @@ } }, "node_modules/@graphql-tools/executor-graphql-ws": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.1.2.tgz", - "integrity": "sha512-+9ZK0rychTH1LUv4iZqJ4ESbmULJMTsv3XlFooPUngpxZkk00q6LqHKJRrsLErmQrVaC7cwQCaRBJa0teK17Lg==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.3.5.tgz", + "integrity": "sha512-8BZf9a9SkaJAkF5Byb4ZdiwzCNoTrfl515m206XvCkCHM7dM1AwvX1rYZTrnJWgXgQUxhPjvll5vgciOe1APaA==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", - "@types/ws": "^8.0.0", + "@graphql-tools/utils": "^10.6.2", + "@whatwg-node/disposablestack": "^0.0.5", "graphql-ws": "^5.14.0", "isomorphic-ws": "^5.0.0", - "tslib": "^2.4.0", - "ws": "^8.13.0" + "tslib": "^2.8.1", + "ws": "^8.17.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/executor-http": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.0.9.tgz", - "integrity": "sha512-+NXaZd2MWbbrWHqU4EhXcrDbogeiCDmEbrAN+rMn4Nu2okDjn2MTFDbTIab87oEubQCH4Te1wDkWPKrzXup7+Q==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.1.14.tgz", + "integrity": "sha512-y/j+fOTgkYSEDzLQ7xMErSfg6kgejVhG4yieKy1PXBaiDNN8t9MOUxEJDDtRDr/pFnvjTtm78UFo04I7S+m7BA==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "@repeaterjs/repeater": "^3.0.4", - "@whatwg-node/fetch": "^0.9.0", + "@whatwg-node/disposablestack": "^0.0.5", + "@whatwg-node/fetch": "^0.10.1", "extract-files": "^11.0.0", "meros": "^1.2.1", - "tslib": "^2.4.0", + "tslib": "^2.8.1", "value-or-promise": "^1.0.12" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/executor-legacy-ws": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.6.tgz", - "integrity": "sha512-lDSxz9VyyquOrvSuCCnld3256Hmd+QI2lkmkEv7d4mdzkxkK4ddAWW1geQiWrQvWmdsmcnGGlZ7gDGbhEExwqg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.1.5.tgz", + "integrity": "sha512-iqN3NYpv4mGTOUUkhNOL0v9kskVHXl1BrzueRtDFaWznjO7qpwAUwCAih3AMHDNadLQdppkjIhOJB+YU8KCfsQ==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "@types/ws": "^8.0.0", "isomorphic-ws": "^5.0.0", "tslib": "^2.4.0", - "ws": "^8.15.0" + "ws": "^8.17.1" }, "engines": { "node": ">=16.0.0" @@ -1991,15 +2045,15 @@ } }, "node_modules/@graphql-tools/git-loader": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.5.tgz", - "integrity": "sha512-P97/1mhruDiA6D5WUmx3n/aeGPLWj2+4dpzDOxFGGU+z9NcI/JdygMkeFpGZNHeJfw+kHfxgPcMPnxHcyhAoVA==", + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.12.tgz", + "integrity": "sha512-B65UbwMeR6TWwTzz5OS6iGuqSa1za/lbLO3buSwDs8+zxTpqrJljeKllG2EFk7g7D2OtTt3Tu9+itWkuIbqOUw==", "dev": true, "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.3.0", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/graphql-tag-pluck": "8.3.7", + "@graphql-tools/utils": "^10.6.2", "is-glob": "4.0.3", - "micromatch": "^4.0.4", + "micromatch": "^4.0.8", "tslib": "^2.4.0", "unixify": "^1.0.0" }, @@ -2011,16 +2065,16 @@ } }, "node_modules/@graphql-tools/github-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.1.tgz", - "integrity": "sha512-W4dFLQJ5GtKGltvh/u1apWRFKBQOsDzFxO9cJkOYZj1VzHCpRF43uLST4VbCfWve+AwBqOuKr7YgkHoxpRMkcg==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.7.tgz", + "integrity": "sha512-p7aGLbOkwLTCKk/hSEJJgrSIhbwNS7SBhtYFPMa1uoga4I10xDJuGrUl8l9Jq2y953rtJA6/aGyVJs87Yn2hwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", - "@graphql-tools/executor-http": "^1.0.9", - "@graphql-tools/graphql-tag-pluck": "^8.0.0", - "@graphql-tools/utils": "^10.0.13", - "@whatwg-node/fetch": "^0.9.0", + "@graphql-tools/executor-http": "^1.1.9", + "@graphql-tools/graphql-tag-pluck": "^8.3.7", + "@graphql-tools/utils": "^10.6.2", + "@whatwg-node/fetch": "^0.10.0", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, @@ -2031,14 +2085,43 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/graphql-file-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.1.tgz", - "integrity": "sha512-7gswMqWBabTSmqbaNyWSmRRpStWlcCkBc73E6NZNlh4YNuiyKOwbvSkOUYFOqFMfEL+cFsXgAvr87Vz4XrYSbA==", + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.6.tgz", + "integrity": "sha512-nLOvotKcvZLXQWryYl34vHI4Fr+VTA/y6WHcZ73gXBQ//8oGKgnuDNoAdi4rXgk4iGyIMvRxZpYU27k6Z4acBw==", "dev": true, "dependencies": { - "@graphql-tools/import": "7.0.1", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/import": "7.0.6", + "@graphql-tools/utils": "^10.6.2", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2051,9 +2134,9 @@ } }, "node_modules/@graphql-tools/graphql-tag-pluck": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.0.tgz", - "integrity": "sha512-gNqukC+s7iHC7vQZmx1SEJQmLnOguBq+aqE2zV2+o1hxkExvKqyFli1SY/9gmukFIKpKutCIj+8yLOM+jARutw==", + "version": "8.3.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.7.tgz", + "integrity": "sha512-QoGf/8oVzhMZW+EbgpkM7zUxlNyv60Twb254R0D8TxS19OznoMMZMiDJdoID/k42QRoJ7o1V/yEOHgJFcqYHVw==", "dev": true, "dependencies": { "@babel/core": "^7.22.9", @@ -2061,7 +2144,7 @@ "@babel/plugin-syntax-import-assertions": "^7.20.0", "@babel/traverse": "^7.16.8", "@babel/types": "^7.16.8", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0" }, "engines": { @@ -2072,12 +2155,12 @@ } }, "node_modules/@graphql-tools/import": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.0.1.tgz", - "integrity": "sha512-935uAjAS8UAeXThqHfYVr4HEAp6nHJ2sximZKO1RzUTq5WoALMAhhGARl0+ecm6X+cqNUwIChJbjtaa6P/ML0w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.0.6.tgz", + "integrity": "sha512-F28lG9w3gckZ+ubnq3jM2s2OiyH+cVZZXvOZ8RO/EJQ0dS+BE/S9zzvpCTuOWyuZvcLvbYBDjliZTOmeSQUhMg==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "resolve-from": "5.0.0", "tslib": "^2.4.0" }, @@ -2089,12 +2172,12 @@ } }, "node_modules/@graphql-tools/json-file-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.1.tgz", - "integrity": "sha512-lAy2VqxDAHjVyqeJonCP6TUemrpYdDuKt25a10X6zY2Yn3iFYGnuIDQ64cv3ytyGY6KPyPB+Kp+ZfOkNDG3FQA==", + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.6.tgz", + "integrity": "sha512-mjZFVMtBL9fcvovwCoXKjZxXqr92/dcPZmHlQsW9jUC9WW6KfmolwtyvRxy9CcOjjh1HDTPcNoDgW05iI1CFYQ==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2107,13 +2190,13 @@ } }, "node_modules/@graphql-tools/load": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.2.tgz", - "integrity": "sha512-S+E/cmyVmJ3CuCNfDuNF2EyovTwdWfQScXv/2gmvJOti2rGD8jTt9GYVzXaxhblLivQR9sBUCNZu/w7j7aXUCA==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.7.tgz", + "integrity": "sha512-1JmZaMxs9LOyyq7XF/knBxY+Uejnc68+nILCFYwsts9KTUOZHpJqjleIIDf7Il1yHDaujjThX4Xqg2Dwhdb/bw==", "dev": true, "dependencies": { - "@graphql-tools/schema": "^10.0.3", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/schema": "^10.0.11", + "@graphql-tools/utils": "^10.6.2", "p-limit": "3.1.0", "tslib": "^2.4.0" }, @@ -2125,12 +2208,12 @@ } }, "node_modules/@graphql-tools/merge": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.3.tgz", - "integrity": "sha512-FeKv9lKLMwqDu0pQjPpF59GY3HReUkWXKsMIuMuJQOKh9BETu7zPEFUELvcw8w+lwZkl4ileJsHXC9+AnsT2Lw==", + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.12.tgz", + "integrity": "sha512-ECkUdgWkizhzQ6JJg16MCYnIN2r2+q/vP5smzi3YeeJkZ/3f9ynFDkaqoMg0Ddg9MugR03hMiQQrssk5f0389Q==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0" }, "engines": { @@ -2156,16 +2239,15 @@ } }, "node_modules/@graphql-tools/prisma-loader": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.3.tgz", - "integrity": "sha512-oZhxnMr3Jw2WAW1h9FIhF27xWzIB7bXWM8olz4W12oII4NiZl7VRkFw9IT50zME2Bqi9LGh9pkmMWkjvbOpl+Q==", + "version": "8.0.17", + "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.17.tgz", + "integrity": "sha512-fnuTLeQhqRbA156pAyzJYN0KxCjKYRU5bz1q/SKOwElSnAU4k7/G1kyVsWLh7fneY78LoMNH5n+KlFV8iQlnyg==", "dev": true, "dependencies": { - "@graphql-tools/url-loader": "^8.0.2", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/url-loader": "^8.0.15", + "@graphql-tools/utils": "^10.5.6", "@types/js-yaml": "^4.0.0", - "@types/json-stable-stringify": "^1.0.32", - "@whatwg-node/fetch": "^0.9.0", + "@whatwg-node/fetch": "^0.10.0", "chalk": "^4.1.0", "debug": "^4.3.1", "dotenv": "^16.0.0", @@ -2174,7 +2256,6 @@ "https-proxy-agent": "^7.0.0", "jose": "^5.0.0", "js-yaml": "^4.0.0", - "json-stable-stringify": "^1.0.1", "lodash": "^4.17.20", "scuid": "^1.1.0", "tslib": "^2.4.0", @@ -2187,12 +2268,40 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/prisma-loader/node_modules/graphql-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", "cross-fetch": "^3.1.5" @@ -2202,13 +2311,13 @@ } }, "node_modules/@graphql-tools/relay-operation-optimizer": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.1.tgz", - "integrity": "sha512-y0ZrQ/iyqWZlsS/xrJfSir3TbVYJTYmMOu4TaSz6F4FRDTQ3ie43BlKkhf04rC28pnUOS4BO9pDcAo1D30l5+A==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.6.tgz", + "integrity": "sha512-hzzH1flmvL0o7tczQbnGVmsaLruhl8rxoqszo6uBjjjPxppoT0vwqIvU5X+lGJi2U+/fv3Q2FV3XALQB5Pmeaw==", "dev": true, "dependencies": { "@ardatan/relay-compiler": "12.0.0", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0" }, "engines": { @@ -2219,13 +2328,13 @@ } }, "node_modules/@graphql-tools/schema": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.3.tgz", - "integrity": "sha512-p28Oh9EcOna6i0yLaCFOnkcBDQECVf3SCexT6ktb86QNj9idnkhI+tCxnwZDh58Qvjd2nURdkbevvoZkvxzCog==", + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.11.tgz", + "integrity": "sha512-cYr/7SJSKtdwPByTKHlBr0tYGf7/sYNyzKlPhPMHWoYyGxtn8ytbfF6wEUcxuaOoqksIFxOGr+WOJh1WvShb6A==", "dev": true, "dependencies": { - "@graphql-tools/merge": "^9.0.3", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/merge": "^9.0.12", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, @@ -2237,24 +2346,23 @@ } }, "node_modules/@graphql-tools/url-loader": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.2.tgz", - "integrity": "sha512-1dKp2K8UuFn7DFo1qX5c1cyazQv2h2ICwA9esHblEqCYrgf69Nk8N7SODmsfWg94OEaI74IqMoM12t7eIGwFzQ==", + "version": "8.0.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.18.tgz", + "integrity": "sha512-gz6oRoZzUJyBDIVMBKFa35InRqzq3FOb/kEb+8T3/DrDZCIxFlmLBZzy9ANjKmF3ctLn0WQXopRSaG/Wq7NEwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", - "@graphql-tools/delegate": "^10.0.4", - "@graphql-tools/executor-graphql-ws": "^1.1.2", - "@graphql-tools/executor-http": "^1.0.9", - "@graphql-tools/executor-legacy-ws": "^1.0.6", - "@graphql-tools/utils": "^10.0.13", - "@graphql-tools/wrap": "^10.0.2", + "@graphql-tools/executor-graphql-ws": "^1.3.2", + "@graphql-tools/executor-http": "^1.1.9", + "@graphql-tools/executor-legacy-ws": "^1.1.5", + "@graphql-tools/utils": "^10.6.2", + "@graphql-tools/wrap": "^10.0.16", "@types/ws": "^8.0.0", - "@whatwg-node/fetch": "^0.9.0", + "@whatwg-node/fetch": "^0.10.0", "isomorphic-ws": "^5.0.0", "tslib": "^2.4.0", "value-or-promise": "^1.0.11", - "ws": "^8.12.0" + "ws": "^8.17.1" }, "engines": { "node": ">=16.0.0" @@ -2263,14 +2371,43 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/utils": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.1.2.tgz", - "integrity": "sha512-fX13CYsDnX4yifIyNdiN0cVygz/muvkreWWem6BBw130+ODbRRgfiVveL0NizCEnKXkpvdeTy9Bxvo9LIKlhrw==", + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.6.2.tgz", + "integrity": "sha512-ABZHTpwiVR8oE2//NI/nnU3nNhbBpqMlMYyCF5cnqjLfhlyOdFfoRuhYEATEsmMfDg0ijGreULywK/SmepVGfw==", "dev": true, "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", - "cross-inspect": "1.0.0", + "cross-inspect": "1.0.1", "dset": "^3.1.2", "tslib": "^2.4.0" }, @@ -2282,19 +2419,18 @@ } }, "node_modules/@graphql-tools/wrap": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.5.tgz", - "integrity": "sha512-Cbr5aYjr3HkwdPvetZp1cpDWTGdD1Owgsb3z/ClzhmrboiK86EnQDxDvOJiQkDCPWE9lNBwj8Y4HfxroY0D9DQ==", + "version": "10.0.25", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.25.tgz", + "integrity": "sha512-51Koxi6IZHF4Ns7c6jvLU2x7GJyGGDL7V6e0u4J6ci/0vSCqLBwT3YYutDlZ7uJTpbLjEbjl0R0+1fOerdIkOQ==", "dev": true, "dependencies": { - "@graphql-tools/delegate": "^10.0.4", - "@graphql-tools/schema": "^10.0.3", - "@graphql-tools/utils": "^10.1.1", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "@graphql-tools/delegate": "^10.2.7", + "@graphql-tools/schema": "^10.0.11", + "@graphql-tools/utils": "^10.6.2", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" @@ -2314,7 +2450,6 @@ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -2364,15 +2499,13 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2386,11 +2519,10 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2403,7 +2535,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2416,7 +2547,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2434,7 +2564,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2450,7 +2579,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2508,8 +2636,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -2537,8 +2664,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/@kamilkisiela/fast-url-parser/-/fast-url-parser-1.1.4.tgz", "integrity": "sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@mapbox/geojson-rewind": { "version": "0.5.2", @@ -2592,10 +2718,9 @@ } }, "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.3.1.tgz", - "integrity": "sha512-5ueL4UDitzVtceQ8J4kY+Px3WK+eZTsmGwha3MBKHKqiHvKrjWWwBCIl1K8BuJSc5OFh83uI8IFNoFvQxX2uUw==", - "license": "ISC", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", + "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", @@ -2603,7 +2728,6 @@ "minimist": "^1.2.8", "quickselect": "^2.0.0", "rw": "^1.3.3", - "sort-object": "^3.0.3", "tinyqueue": "^3.0.0" }, "bin": { @@ -2612,6 +2736,11 @@ "gl-style-validate": "dist/gl-style-validate.mjs" } }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2653,7 +2782,6 @@ "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", "dev": true, "hasInstallScript": true, - "license": "MIT", "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", @@ -2691,7 +2819,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -2712,7 +2839,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2733,7 +2859,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2754,7 +2879,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -2775,7 +2899,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2796,7 +2919,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2817,7 +2939,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2838,7 +2959,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2859,7 +2979,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2880,7 +2999,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2901,7 +3019,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2922,7 +3039,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2943,7 +3059,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2961,7 +3076,6 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -2977,9 +3091,9 @@ } }, "node_modules/@react-aria/ssr": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.2.tgz", - "integrity": "sha512-0gKkgDYdnq1w+ey8KzG9l+H5Z821qh9vVjztk55rUg71vTk/Eaebeir+WtzcLLwTjw3m/asIjx8Y59y1lJZhBw==", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.7.tgz", + "integrity": "sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg==", "dependencies": { "@swc/helpers": "^0.5.0" }, @@ -2987,13 +3101,13 @@ "node": ">= 12" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@repeaterjs/repeater": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.5.tgz", - "integrity": "sha512-l3YHBLAol6d/IKnB9LhpD0cEZWAoe3eFKUyTYWmFmCO2Q/WOckxLQAUyMZWwZV2M/m3+4vgRoaolFqaII82/TA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz", + "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==", "dev": true }, "node_modules/@restart/hooks": { @@ -3011,7 +3125,6 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.1.tgz", "integrity": "sha512-qghR21ynHiUrpcIkKCoKYB+3rJtezY5Y7ikrwradCL+7hZHdQ2Ozc5ffxtpmpahoAGgc31gyXaSx2sXXaThmqA==", - "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", "@popperjs/core": "^2.11.8", @@ -3032,7 +3145,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.0.tgz", "integrity": "sha512-wS+h6IusJCPjTkmOOrRZxIPICD/mtFA3PRZviutoM23/b7akyDGfZF/WS+nIFk27u7JDhPE2+0GBdZxjSqHZkg==", - "license": "MIT", "dependencies": { "dequal": "^2.0.3" }, @@ -3049,9 +3161,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", - "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz", + "integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==", "cpu": [ "arm" ], @@ -3062,9 +3174,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", - "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz", + "integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==", "cpu": [ "arm64" ], @@ -3075,9 +3187,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", - "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz", + "integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==", "cpu": [ "arm64" ], @@ -3088,9 +3200,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", - "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz", + "integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==", "cpu": [ "x64" ], @@ -3101,9 +3213,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", - "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz", + "integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==", "cpu": [ "arm64" ], @@ -3114,9 +3226,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", - "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz", + "integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==", "cpu": [ "x64" ], @@ -3127,9 +3239,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", - "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz", + "integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==", "cpu": [ "arm" ], @@ -3140,9 +3252,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", - "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz", + "integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==", "cpu": [ "arm" ], @@ -3153,9 +3265,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", - "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz", + "integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==", "cpu": [ "arm64" ], @@ -3166,9 +3278,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", - "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz", + "integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==", "cpu": [ "arm64" ], @@ -3178,10 +3290,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz", + "integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", - "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz", + "integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==", "cpu": [ "ppc64" ], @@ -3192,9 +3317,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", - "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz", + "integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==", "cpu": [ "riscv64" ], @@ -3205,9 +3330,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", - "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz", + "integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==", "cpu": [ "s390x" ], @@ -3218,9 +3343,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", - "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz", + "integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==", "cpu": [ "x64" ], @@ -3231,9 +3356,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", - "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz", + "integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==", "cpu": [ "x64" ], @@ -3244,9 +3369,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", - "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz", + "integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==", "cpu": [ "arm64" ], @@ -3257,9 +3382,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", - "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz", + "integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==", "cpu": [ "ia32" ], @@ -3270,9 +3395,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", - "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz", + "integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==", "cpu": [ "x64" ], @@ -3286,21 +3411,20 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@swc/helpers": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.7.tgz", - "integrity": "sha512-BVvNZhx362+l2tSwSuyEUV4h7+jk9raNdoTSdLfwTshXJSaGmYKluGRJznziCI3KX02Z19DdsQrdfrpXAU3Hfg==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "node_modules/@testing-library/dom": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz", - "integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, "peer": true, "dependencies": { @@ -3318,11 +3442,10 @@ } }, "node_modules/@testing-library/react": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", - "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.1.0.tgz", + "integrity": "sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" }, @@ -3331,10 +3454,10 @@ }, "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" + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3385,9 +3508,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -3400,9 +3523,9 @@ "dev": true }, "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + "version": "7946.0.15", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz", + "integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==" }, "node_modules/@types/geojson-vt": { "version": "3.2.5", @@ -3418,12 +3541,6 @@ "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true }, - "node_modules/@types/json-stable-stringify": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.36.tgz", - "integrity": "sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==", - "dev": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -3446,20 +3563,20 @@ } }, "node_modules/@types/mapbox-gl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.1.0.tgz", - "integrity": "sha512-hI6cQDjw1bkJw7MC/eHMqq5TWUamLwsujnUUeiIX2KDRjxRNSYMjnHz07+LATz9I9XIsKumOtUz4gRYnZOJ/FA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.4.1.tgz", + "integrity": "sha512-NsGKKtgW93B+UaLPti6B7NwlxYlES5DpV5Gzj9F75rK5ALKsqSk15CiEHbOnTr09RGbr6ZYiCdI+59NNNcAImg==", "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/node": { - "version": "20.11.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", - "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.20.0" } }, "node_modules/@types/pbf": { @@ -3467,35 +3584,27 @@ "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==" }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" - }, "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "license": "MIT", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.1.tgz", + "integrity": "sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.1.tgz", + "integrity": "sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } @@ -3514,9 +3623,9 @@ "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", "dev": true, "dependencies": { "@types/node": "*" @@ -3527,7 +3636,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -3561,7 +3669,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -3590,7 +3697,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" @@ -3608,7 +3714,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", @@ -3636,7 +3741,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -3650,7 +3754,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", @@ -3679,7 +3782,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3692,7 +3794,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -3715,7 +3816,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" @@ -3729,9 +3829,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "dev": true }, "node_modules/@vitejs/plugin-react": { @@ -3758,7 +3858,6 @@ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz", "integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^0.2.3", @@ -3791,7 +3890,6 @@ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz", "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/spy": "2.1.8", "@vitest/utils": "2.1.8", @@ -3807,7 +3905,6 @@ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", "dev": true, - "license": "MIT", "dependencies": { "tinyrainbow": "^1.2.0" }, @@ -3820,7 +3917,6 @@ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz", "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/utils": "2.1.8", "pathe": "^1.1.2" @@ -3834,7 +3930,6 @@ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz", "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/pretty-format": "2.1.8", "magic-string": "^0.30.12", @@ -3849,7 +3944,6 @@ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz", "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==", "dev": true, - "license": "MIT", "dependencies": { "tinyspy": "^3.0.2" }, @@ -3862,7 +3956,6 @@ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/pretty-format": "2.1.8", "loupe": "^3.1.2", @@ -3872,14 +3965,25 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@whatwg-node/disposablestack": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.5.tgz", + "integrity": "sha512-9lXugdknoIequO4OYvIjhygvfSEgnO8oASLqLelnDhkRjgBZhc39shC3QSlZuyDO9bgYSIVa2cHAiN+St3ty4w==", + "dev": true, + "dependencies": { + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@whatwg-node/fetch": { - "version": "0.9.21", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.21.tgz", - "integrity": "sha512-Wt0jPb+04JjobK0pAAN7mEHxVHcGA9HoP3OyCsZtyAecNQeADXCZ1MihFwVwjsgaRYuGVmNlsCmLxlG6mor8Gw==", + "version": "0.9.23", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.23.tgz", + "integrity": "sha512-7xlqWel9JsmxahJnYVUj/LLxWcnA93DR4c9xlw3U814jWTiYalryiH1qToik1hOxweKKRLi4haXHM5ycRksPBA==", "dev": true, - "license": "MIT", "dependencies": { - "@whatwg-node/node-fetch": "^0.5.23", + "@whatwg-node/node-fetch": "^0.6.0", "urlpattern-polyfill": "^10.0.0" }, "engines": { @@ -3887,11 +3991,10 @@ } }, "node_modules/@whatwg-node/node-fetch": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.26.tgz", - "integrity": "sha512-4jXDeZ4IH4bylZ6wu14VEx0aDXXhrN4TC279v9rPmn08g4EYekcYf8wdcOOnS9STjDkb6x77/6xBUTqxGgjr8g==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.6.0.tgz", + "integrity": "sha512-tcZAhrpx6oVlkEsRngeTEEE7I5/QdLjeEz4IlekabGaESP7+Dkm/6a9KcF1KdCBB7mO9PXtBkwCuTCt8+UPg8Q==", "dev": true, - "license": "MIT", "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", "busboy": "^1.6.0", @@ -3902,17 +4005,10 @@ "node": ">=18.0.0" } }, - "node_modules/@whatwg-node/node-fetch/node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true, - "license": "0BSD" - }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3931,13 +4027,10 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } @@ -4160,7 +4253,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -4205,7 +4297,6 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -4267,11 +4358,10 @@ } }, "node_modules/axe-core": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", - "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", "dev": true, - "license": "MPL-2.0", "engines": { "node": ">=4" } @@ -4281,7 +4371,6 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -4390,27 +4479,26 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -4426,12 +4514,11 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -4512,22 +4599,34 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/callsites": { @@ -4559,9 +4658,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "version": "1.0.30001687", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz", + "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==", "dev": true, "funding": [ { @@ -4576,8 +4675,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/capital-case": { "version": "1.0.4", @@ -4595,7 +4693,6 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", "dev": true, - "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -4672,7 +4769,6 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 16" } @@ -4884,9 +4980,9 @@ } }, "node_modules/cross-inspect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.0.tgz", - "integrity": "sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.1.tgz", + "integrity": "sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==", "dev": true, "dependencies": { "tslib": "^2.4.0" @@ -4896,9 +4992,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -4914,7 +5010,6 @@ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "dev": true, - "license": "MIT", "dependencies": { "rrweb-cssom": "^0.7.1" }, @@ -4998,9 +5093,9 @@ } }, "node_modules/dataloader": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", - "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", + "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", "dev": true }, "node_modules/debounce": { @@ -5010,11 +5105,10 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -5047,7 +5141,6 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5202,9 +5295,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, "engines": { "node": ">=12" @@ -5214,33 +5307,44 @@ } }, "node_modules/dset": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", - "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", "dev": true, "engines": { "node": ">=4" } }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/earcut": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==", - "license": "ISC" + "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.5.40", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.40.tgz", - "integrity": "sha512-LYm78o6if4zTasnYclgQzxEcgMoIcybWOhkATWepN95uwVVWV0/IW10v+2sIeHE+bIYWipLneTftVyQm45UY7g==", - "dev": true, - "license": "ISC" + "version": "1.5.71", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz", + "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==", + "dev": true }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -5270,11 +5374,10 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", + "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -5291,7 +5394,7 @@ "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", @@ -5307,10 +5410,10 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", + "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.9", @@ -5331,13 +5434,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -5352,11 +5452,10 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", - "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", + "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -5366,6 +5465,7 @@ "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "globalthis": "^1.0.4", + "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", @@ -5381,8 +5481,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/es-object-atoms": { "version": "1.0.0", @@ -5420,14 +5519,14 @@ } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -5480,7 +5579,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5501,8 +5599,8 @@ "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -5590,7 +5688,6 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -5617,7 +5714,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, - "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -5651,7 +5747,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5662,7 +5757,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -5672,7 +5766,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5685,7 +5778,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5698,7 +5790,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, - "license": "MIT", "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -5728,7 +5819,6 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -5738,7 +5828,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5749,7 +5838,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5762,7 +5850,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", "dev": true, - "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -5795,7 +5882,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -5808,7 +5894,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.16.tgz", "integrity": "sha512-slterMlxAhov/DZO8NScf6mEeMBBXodFUolijDvrtTxyezyLoTQaa73FyYus/VbTdftd8wBgBxPMRk3poleXNQ==", "dev": true, - "license": "MIT", "peerDependencies": { "eslint": ">=8.40" } @@ -5818,7 +5903,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5829,7 +5913,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5842,7 +5925,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5855,7 +5937,6 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -5901,7 +5982,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5912,7 +5992,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -5928,7 +6007,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5941,7 +6019,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -5967,9 +6044,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -6022,7 +6099,6 @@ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } @@ -6068,8 +6144,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -6122,7 +6197,6 @@ "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", "dev": true, - "license": "MIT", "dependencies": { "fast-decode-uri-component": "^1.0.1" } @@ -6203,9 +6277,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -6245,9 +6319,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true }, "node_modules/for-each": { @@ -6260,11 +6334,10 @@ } }, "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, - "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -6281,7 +6354,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC", "engines": { "node": ">=14" }, @@ -6290,9 +6362,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "dependencies": { "asynckit": "^0.4.0", @@ -6371,8 +6443,7 @@ "node_modules/geojson-vt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", - "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", - "license": "ISC" + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==" }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -6384,16 +6455,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.5.tgz", + "integrity": "sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6447,6 +6521,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -6501,7 +6576,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", - "license": "MIT", "dependencies": { "ini": "^4.1.3", "kind-of": "^6.0.3", @@ -6515,7 +6589,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", "engines": { "node": ">=16" } @@ -6524,7 +6597,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -6549,7 +6621,6 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -6582,12 +6653,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6603,7 +6674,6 @@ "version": "16.9.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -6613,7 +6683,6 @@ "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-5.1.3.tgz", "integrity": "sha512-RBhejsPjrNSuwtckRlilWzLVt2j8itl74W9Gke1KejDTz7oaA5kVd6wRn9zK9TS5mcmIYGxf7zN7a1ORMdxp1Q==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-tools/graphql-file-loader": "^8.0.0", "@graphql-tools/json-file-loader": "^8.0.0", @@ -6641,11 +6710,10 @@ } }, "node_modules/graphql-config/node_modules/jiti": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.3.3.tgz", - "integrity": "sha512-EX4oNDwcXSivPrw2qKH2LB5PoFxEvgtv2JgwW0bU858HoLQ+kutSvjLMUqBd0PeJYEinLWhoI9Ol0eYMqj/wNQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.1.tgz", + "integrity": "sha512-yPBThwecp1wS9DmoA4x4KR2h3QoslacnDR8ypuFM962kI4/456Iy1oHx2RAgh4jfZNdn0bctsdadceiBUgpU1g==", "dev": true, - "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -6654,7 +6722,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-7.1.2.tgz", "integrity": "sha512-+XE3iuC55C2di5ZUrB4pjgwe+nIQBuXVIK9J98wrVwojzDW3GMdSBZfxUk8l4j9TieIpjpggclxhNEU9ebGF8w==", - "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, @@ -6678,9 +6745,9 @@ } }, "node_modules/graphql-ws": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.15.0.tgz", - "integrity": "sha512-xWGAtm3fig9TIhSaNsg0FaDZ8Pyn/3re3RFlP4rhQcmjRDIPpk1EhRuNB+YSJtLzttyuToaDiNhwT1OMoGnJnw==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", + "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", "dev": true, "engines": { "node": ">=10" @@ -6720,10 +6787,13 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -6732,9 +6802,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -6812,13 +6882,12 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, - "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -6857,9 +6926,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" @@ -6933,6 +7002,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -6949,7 +7019,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7042,7 +7111,6 @@ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -7054,25 +7122,28 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz", + "integrity": "sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7098,7 +7169,6 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -7157,13 +7227,15 @@ } }, "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz", + "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7183,7 +7255,6 @@ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -7258,12 +7329,13 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.0.tgz", + "integrity": "sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7299,13 +7371,15 @@ "dev": true }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz", + "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "gopd": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -7354,12 +7428,13 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.0.tgz", + "integrity": "sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7369,12 +7444,14 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.0.tgz", + "integrity": "sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "call-bind": "^1.0.7", + "has-symbols": "^1.0.3", + "safe-regex-test": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -7537,7 +7614,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", @@ -7565,7 +7641,6 @@ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "get-intrinsic": "^1.2.1", @@ -7582,7 +7657,6 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7594,18 +7668,18 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "dev": true, "bin": { "jiti": "bin/jiti.js" } }, "node_modules/jose": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz", - "integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==", + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/panva" @@ -7638,7 +7712,6 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, - "license": "MIT", "dependencies": { "cssstyle": "^4.1.0", "data-urls": "^5.0.0", @@ -7679,7 +7752,6 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -7705,24 +7777,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/json-stable-stringify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", - "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "isarray": "^2.0.5", - "jsonify": "^0.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -7759,15 +7813,6 @@ "node": ">=6" } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -7806,9 +7851,9 @@ } }, "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", "dev": true }, "node_modules/language-tags": { @@ -7985,8 +8030,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/lower-case": { "version": "2.0.2", @@ -8026,11 +8070,10 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.14", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", + "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -8040,7 +8083,6 @@ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", @@ -8062,26 +8104,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -8089,12 +8116,6 @@ "node": ">=10" } }, - "node_modules/make-dir/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -8108,7 +8129,6 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", - "license": "BSD-3-Clause", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -8145,12 +8165,6 @@ "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" } }, - "node_modules/maplibre-gl/node_modules/quickselect": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", - "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", - "license": "ISC" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -8178,12 +8192,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -8225,7 +8239,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8249,7 +8262,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -8258,8 +8270,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/murmurhash-js": { "version": "1.0.0", @@ -8307,13 +8318,10 @@ } }, "node_modules/node-addon-api": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", - "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==", - "dev": true, - "engines": { - "node": "^16 || ^18 || >= 20" - } + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true }, "node_modules/node-fetch": { "version": "2.7.0", @@ -8367,8 +8375,7 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/normalize-path": { "version": "2.1.1", @@ -8389,11 +8396,10 @@ "dev": true }, "node_modules/nwsapi": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", - "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", - "dev": true, - "license": "MIT" + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "dev": true }, "node_modules/object-assign": { "version": "4.1.1", @@ -8404,10 +8410,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8527,17 +8536,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -8630,11 +8639,10 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true, - "license": "BlueOak-1.0.0" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true }, "node_modules/param-case": { "version": "3.0.4", @@ -8691,12 +8699,12 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -8781,7 +8789,6 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -8797,8 +8804,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -8820,7 +8826,6 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 14.16" } @@ -8829,7 +8834,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", - "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -8912,7 +8916,6 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -8997,6 +9000,15 @@ "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9018,17 +9030,14 @@ ] }, "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", "engines": { "node": ">=0.10.0" } @@ -9037,7 +9046,6 @@ "version": "2.10.6", "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.6.tgz", "integrity": "sha512-fNvKytSp0nHts1WRnRBJeBEt+I9/ZdrnhIjWOucEduRNvFRU1IXjZueDdWnBiqsTSJ7MckQJi9i/hxGolaRq+g==", - "license": "MIT", "dependencies": { "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", @@ -9064,15 +9072,14 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.25.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.0.0" } }, "node_modules/react-is": { @@ -9138,7 +9145,6 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9173,19 +9179,19 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz", + "integrity": "sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", + "dunder-proto": "^1.0.0", + "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" + "gopd": "^1.2.0", + "which-builtin-type": "^1.2.0" }, "engines": { "node": ">= 0.4" @@ -9200,15 +9206,15 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -9322,15 +9328,16 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -9343,9 +9350,9 @@ } }, "node_modules/rollup": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", - "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz", + "integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==", "dev": true, "dependencies": { "@types/estree": "1.0.6" @@ -9358,24 +9365,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.27.4", - "@rollup/rollup-android-arm64": "4.27.4", - "@rollup/rollup-darwin-arm64": "4.27.4", - "@rollup/rollup-darwin-x64": "4.27.4", - "@rollup/rollup-freebsd-arm64": "4.27.4", - "@rollup/rollup-freebsd-x64": "4.27.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", - "@rollup/rollup-linux-arm-musleabihf": "4.27.4", - "@rollup/rollup-linux-arm64-gnu": "4.27.4", - "@rollup/rollup-linux-arm64-musl": "4.27.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", - "@rollup/rollup-linux-riscv64-gnu": "4.27.4", - "@rollup/rollup-linux-s390x-gnu": "4.27.4", - "@rollup/rollup-linux-x64-gnu": "4.27.4", - "@rollup/rollup-linux-x64-musl": "4.27.4", - "@rollup/rollup-win32-arm64-msvc": "4.27.4", - "@rollup/rollup-win32-ia32-msvc": "4.27.4", - "@rollup/rollup-win32-x64-msvc": "4.27.4", + "@rollup/rollup-android-arm-eabi": "4.28.1", + "@rollup/rollup-android-arm64": "4.28.1", + "@rollup/rollup-darwin-arm64": "4.28.1", + "@rollup/rollup-darwin-x64": "4.28.1", + "@rollup/rollup-freebsd-arm64": "4.28.1", + "@rollup/rollup-freebsd-x64": "4.28.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.28.1", + "@rollup/rollup-linux-arm-musleabihf": "4.28.1", + "@rollup/rollup-linux-arm64-gnu": "4.28.1", + "@rollup/rollup-linux-arm64-musl": "4.28.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.28.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.28.1", + "@rollup/rollup-linux-riscv64-gnu": "4.28.1", + "@rollup/rollup-linux-s390x-gnu": "4.28.1", + "@rollup/rollup-linux-x64-gnu": "4.28.1", + "@rollup/rollup-linux-x64-musl": "4.28.1", + "@rollup/rollup-win32-arm64-msvc": "4.28.1", + "@rollup/rollup-win32-ia32-msvc": "4.28.1", + "@rollup/rollup-win32-x64-msvc": "4.28.1", "fsevents": "~2.3.2" } }, @@ -9383,8 +9391,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/run-async": { "version": "2.4.1", @@ -9506,12 +9513,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==" }, "node_modules/scuid": { "version": "1.1.0", @@ -9619,10 +9623,13 @@ } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9733,7 +9740,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -9791,8 +9797,7 @@ "version": "3.8.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/streamsearch": { "version": "1.1.0", @@ -9838,7 +9843,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9852,8 +9856,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", @@ -9866,7 +9869,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -9907,7 +9909,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -9980,7 +9981,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10061,7 +10061,6 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^10.4.1", @@ -10076,7 +10075,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -10108,22 +10106,19 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tinyexec": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tinypool": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", - "integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" } @@ -10131,15 +10126,13 @@ "node_modules/tinyqueue": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", - "license": "ISC" + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" }, "node_modules/tinyrainbow": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -10149,7 +10142,6 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -10164,24 +10156,22 @@ } }, "node_modules/tldts": { - "version": "6.1.52", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.52.tgz", - "integrity": "sha512-fgrDJXDjbAverY6XnIt0lNfv8A0cf7maTEaZxNykLGsLG7XP+5xhjBTrt/ieAsFjAlZ+G5nmXomLcZDkxXnDzw==", + "version": "6.1.66", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.66.tgz", + "integrity": "sha512-l3ciXsYFel/jSRfESbyKYud1nOw7WfhrBEF9I3UiarYk/qEaOOwu3qXNECHw4fHGHGTEOuhf/VdKgoDX5M/dhQ==", "dev": true, - "license": "MIT", "dependencies": { - "tldts-core": "^6.1.52" + "tldts-core": "^6.1.66" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.52", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.52.tgz", - "integrity": "sha512-j4OxQI5rc1Ve/4m/9o2WhWSC4jGc4uVbCINdOEJRAraCi0YqTqgMcxUx7DbmuP0G3PCixoof/RZB0Q5Kh9tagw==", - "dev": true, - "license": "MIT" + "version": "6.1.66", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.66.tgz", + "integrity": "sha512-s07jJruSwndD2X8bVjwioPfqpIc1pDTzszPe9pL1Skbh4bjytL85KNQ3tolqLbCvpQHawIsGfFi9dgerWjqW4g==", + "dev": true }, "node_modules/tmp": { "version": "0.0.33", @@ -10212,7 +10202,6 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "tldts": "^6.1.32" }, @@ -10232,19 +10221,10 @@ "node": ">=18" } }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "engines": { "node": ">=16" @@ -10254,9 +10234,9 @@ } }, "node_modules/ts-log": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", - "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.7.tgz", + "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==", "dev": true }, "node_modules/tsconfig-paths": { @@ -10284,9 +10264,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/type-check": { "version": "0.4.0", @@ -10346,9 +10326,9 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz", + "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -10356,7 +10336,8 @@ "for-each": "^0.3.3", "gopd": "^1.0.1", "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.13", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -10366,17 +10347,17 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -10390,7 +10371,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10413,9 +10393,9 @@ "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==" }, "node_modules/ua-parser-js": { - "version": "1.0.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", - "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.39.tgz", + "integrity": "sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==", "dev": true, "funding": [ { @@ -10431,6 +10411,9 @@ "url": "https://github.com/sponsors/faisalman" } ], + "bin": { + "ua-parser-js": "script/cli.js" + }, "engines": { "node": "*" } @@ -10474,9 +10457,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.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true }, "node_modules/union-value": { @@ -10524,7 +10507,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.0" @@ -10563,21 +10545,11 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/urlpattern-polyfill": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/util-deprecate": { "version": "1.0.2", @@ -10599,7 +10571,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.2.tgz", "integrity": "sha512-XdQ+VsY2tJpBsKGs0wf3U/+azx8BBpYRHFAyKm5VeEZNOJZRB63q7Sc8Iup3k0TrN3KO6QgyzFf+opSbfY1y0g==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.24.0", "postcss": "^8.4.49", @@ -10671,7 +10642,6 @@ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz", "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==", "dev": true, - "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", @@ -11159,7 +11129,6 @@ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz", "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/expect": "2.1.8", "@vitest/mocker": "2.1.8", @@ -11228,7 +11197,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -11245,7 +11213,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -11262,7 +11229,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -11279,7 +11245,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -11296,7 +11261,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -11313,7 +11277,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -11330,7 +11293,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -11347,7 +11309,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -11364,7 +11325,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11381,7 +11341,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11398,7 +11357,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11415,7 +11373,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11432,7 +11389,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11449,7 +11405,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11466,7 +11421,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11483,7 +11437,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11500,7 +11453,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11517,7 +11469,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -11534,7 +11485,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -11551,7 +11501,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -11568,7 +11517,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -11585,7 +11533,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -11602,7 +11549,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -11616,7 +11562,6 @@ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz", "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/spy": "2.1.8", "estree-walker": "^3.0.3", @@ -11644,7 +11589,6 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -11682,7 +11626,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -11819,9 +11762,9 @@ } }, "node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dev": true, "dependencies": { "tr46": "^5.0.0", @@ -11847,33 +11790,36 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.0.tgz", + "integrity": "sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==", "dev": true, "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.0", + "is-number-object": "^1.1.0", + "is-string": "^1.1.0", + "is-symbol": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz", + "integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==", "dev": true, - "license": "MIT", "dependencies": { + "call-bind": "^1.0.7", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", + "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.1.4", "is-weakref": "^1.0.2", @@ -11914,9 +11860,9 @@ "dev": true }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz", + "integrity": "sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -11937,7 +11883,6 @@ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "license": "MIT", "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" @@ -11949,6 +11894,15 @@ "node": ">=8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -11969,7 +11923,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -11993,7 +11946,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/client/package.json b/client/package.json index f930bcd67d5..92747c2fbb7 100644 --- a/client/package.json +++ b/client/package.json @@ -23,9 +23,9 @@ "graphql": "16.9.0", "graphql-request": "7.1.2", "maplibre-gl": "4.7.1", - "react": "18.3.1", + "react": "19.0.0", "react-bootstrap": "2.10.6", - "react-dom": "18.3.1", + "react-dom": "19.0.0", "react-map-gl": "7.1.7" }, "devDependencies": { @@ -33,9 +33,9 @@ "@graphql-codegen/client-preset": "4.5.1", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", - "@testing-library/react": "16.0.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", + "@testing-library/react": "16.1.0", + "@types/react": "19.0.1", + "@types/react-dom": "19.0.1", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "4.3.4", diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index 61dd48e4a34..43b0258662d 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -26,49 +26,92 @@ class LayerControl implements IControl { this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group layer-select'; map.on('load', () => { - // clean on + // clean on rerender while (this.container.firstChild) { this.container.removeChild(this.container.firstChild); } - const title = document.createElement('h4'); - title.textContent = 'Debug layers'; - this.container.appendChild(title); - - const groups: Record = {}; - map - .getLayersOrder() - .map((l) => map.getLayer(l)) - .filter((layer) => !!layer) - .filter((layer) => this.layerInteractive(layer)) - .reverse() - .forEach((layer) => { - if (layer) { - const meta: { group: string } = layer.metadata as { group: string }; - - let groupName: string = 'Misc'; - if (meta.group) { - groupName = meta.group; - } - - const layerDiv = this.buildLayerDiv(layer as TypedStyleLayer, map); - - if (groups[groupName]) { - groups[groupName]?.appendChild(layerDiv); - } else { - const groupDiv = this.buildGroupDiv(groupName, layerDiv); - groups[groupName] = groupDiv; - this.container.appendChild(groupDiv); - } - } - }); - // initialize clickable layers (initially stops) - this.updateInteractiveLayerIds(map); + this.buildBackgroundLayers(map); + this.buildDebugLayers(map); }); return this.container; } + private buildBackgroundLayers(map: Map) { + const title = document.createElement('h4'); + title.textContent = 'Background'; + this.container.appendChild(title); + + const select = document.createElement('select'); + this.container.appendChild(select); + + const rasterLayers = map + .getLayersOrder() + .map((l) => map.getLayer(l)) + .filter((layer) => !!layer) + .filter((layer) => layer?.type == 'raster'); + + rasterLayers.forEach((layer) => { + if (layer) { + const option = document.createElement('option'); + const meta = layer.metadata as { name: string }; + option.textContent = meta.name; + option.id = layer.id; + option.value = layer.id; + + select.appendChild(option); + } + }); + select.onchange = () => { + const layerId = select.value; + const layer = map.getLayer(layerId); + if (layer) { + rasterLayers.forEach((l) => { + map.setLayoutProperty(l?.id, 'visibility', 'none'); + }); + + map.setLayoutProperty(layer.id, 'visibility', 'visible'); + } + }; + } + + private buildDebugLayers(map: Map) { + const title = document.createElement('h4'); + title.textContent = 'Debug layers'; + this.container.appendChild(title); + + const groups: Record = {}; + map + .getLayersOrder() + .map((l) => map.getLayer(l)) + .filter((layer) => !!layer) + .filter((layer) => this.layerInteractive(layer)) + .reverse() + .forEach((layer) => { + if (layer) { + const meta: { group: string } = layer.metadata as { group: string }; + + let groupName: string = 'Misc'; + if (meta.group) { + groupName = meta.group; + } + + const layerDiv = this.buildLayerDiv(layer as TypedStyleLayer, map); + + if (groups[groupName]) { + groups[groupName]?.appendChild(layerDiv); + } else { + const groupDiv = this.buildGroupDiv(groupName, layerDiv); + groups[groupName] = groupDiv; + this.container.appendChild(groupDiv); + } + } + }); + // initialize clickable layers (initially stops) + this.updateInteractiveLayerIds(map); + } + private updateInteractiveLayerIds(map: Map) { const visibleInteractiveLayerIds = map .getLayersOrder() diff --git a/client/src/components/SearchBar/SearchBar.tsx b/client/src/components/SearchBar/SearchBar.tsx index 47781532179..e90a54eab80 100644 --- a/client/src/components/SearchBar/SearchBar.tsx +++ b/client/src/components/SearchBar/SearchBar.tsx @@ -34,7 +34,7 @@ export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables,
setShowServerInfo((v) => !v)}>
- OTP Debug Client + OTP Debug {showServerInfo && }
diff --git a/client/src/style.css b/client/src/style.css index c33f5dff711..f838dce2c7b 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -181,6 +181,10 @@ margin-left: 6px; } +.maplibregl-ctrl-group.layer-select select { + margin-bottom: 14px; +} + .maplibregl-ctrl-group.layer-select h4 { font-size: 17px; } diff --git a/doc/dev/decisionrecords/APIGraphQLDesign.md b/doc/dev/decisionrecords/APIGraphQLDesign.md new file mode 100644 index 00000000000..c4dfc6fbd5e --- /dev/null +++ b/doc/dev/decisionrecords/APIGraphQLDesign.md @@ -0,0 +1,33 @@ +# GraphQL Best Practices - API Design + +Follow best practices for designing GraphQL APIs. Our APIs need to be backwards compatible as they +are used by hundreds of clients (web-pages/apps/services). A good reference used by several +of the OTP developers is the Production Ready GraphQL book by Marc-André Giroux. + + +## Pagination + +We use the [pagination](https://graphql.org/learn/pagination/) (a.k. Relay) specification for paging over entities like stations, +stops, trips and routes. Very often OTP has a _finite_ list of entities in memory. + + +## Refetching + +We often use `type(id)` format queries for fetching or refetching entities or value objects of type by id. Additionally, +the GTFS GraphQL API has a node interface and query for refetching objects which follow the +[GraphQL Global Object Identification Specification](https://relay.dev/graphql/objectidentification.htm). We should not use the +node interface or query for non-entities (such as Itineraries and Legs) which do not always have an ID and/or which IDs are not +trivial to reconstruct. + + +## Consistency + +Unfortunately, part of the GraphQL API is old and does not follow best practices. So, when adding +new features, consider what is best; To follow the existing style or follow the best practice. + + +### Context and Problem Statement + +Our APIs need to be backwards compatible as they are used by hundreds of clients (web-pages/apps/services) +Correcting mistakes may not be possible or may take a long time. + diff --git a/doc/dev/decisionrecords/_TEMPLATE.md b/doc/dev/decisionrecords/_TEMPLATE.md index 88c492ca2df..7ac4a960126 100644 --- a/doc/dev/decisionrecords/_TEMPLATE.md +++ b/doc/dev/decisionrecords/_TEMPLATE.md @@ -6,9 +6,6 @@ document later. --> -Original pull request: {#NNNN} - - ### Context and Problem Statement + +# Debug UI configuration + +The Debug UI is the standard interface that is bundled with OTP and available by visiting +[`http://localhost:8080`](http://localhost:8080). This page list the configuration options available +by placing a file `debug-ui-config.json` into OTP's working directory. + + + + +## Parameter Details + + + +## Config Example + + diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index f6f9a55fb77..decbb0a2d4b 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -57,6 +57,10 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Make `motorroad=yes` car-only [#6288](https://github.com/opentripplanner/OpenTripPlanner/pull/6288) - Add decision record for analysis and design documentation [#6281](https://github.com/opentripplanner/OpenTripPlanner/pull/6281) - Switch GTFS flex `safe_duration_offset` back to seconds [#6298](https://github.com/opentripplanner/OpenTripPlanner/pull/6298) +- Remove unused GtfsGraphQlApiRentalStationFuzzyMatching feature [#6282](https://github.com/opentripplanner/OpenTripPlanner/pull/6282) +- Make debug UI background layers configurable with new file `debug-ui-config.json` [#6295](https://github.com/opentripplanner/OpenTripPlanner/pull/6295) +- Better escalator duration control: specific duration from OSM duration tag, default speed from build-config.json [#6268](https://github.com/opentripplanner/OpenTripPlanner/pull/6268) +- Detect JSON array in addition to JSON objects when including a file in the config. [#6307](https://github.com/opentripplanner/OpenTripPlanner/pull/6307) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) diff --git a/doc/user/Configuration.md b/doc/user/Configuration.md index f80966b8cb3..bec637fe51c 100644 --- a/doc/user/Configuration.md +++ b/doc/user/Configuration.md @@ -41,9 +41,9 @@ default behavior of scanning the base directory for input files. Scanning is ove independently for each file type, and can point to remote cloud storage with arbitrary URIs. See [the storage section](Configuration.md#Storage) for further details. -## Three Scopes of Configuration +## Four scopes of configuration -OTP is configured via three configuration JSON files which are read from the directory specified on +OTP is configured via four configuration JSON files which are read from the directory specified on its command line. We try to provide sensible defaults for every option, so all three of these files are optional, as are all the options within each file. Each configuration file corresponds to options that are relevant at a particular phase of OTP usage. @@ -51,7 +51,8 @@ options that are relevant at a particular phase of OTP usage. Options and parameters that are taken into account during the graph building process will be "baked into" the graph, and cannot be changed later in a running server. These are specified in `build-config.json`. Other details of OTP operation can be modified without rebuilding the graph. -These run-time configuration options are found in `router-config.json`. Finally, `otp-config.json` +These run-time configuration options are found in `router-config.json`. If you want to configure +the built-in debug UI add `debug-ui-config.json`. Finally, `otp-config.json` contains simple switches that enable or disable system-wide features. ## Configuration types @@ -168,7 +169,8 @@ directory. Relative paths are not supported. To allow both files (the configuration file and the injected file) to be valid JSON files, a special case is supported. If the include file directive is quoted, then the quotes are removed, if the -text inserted is valid JSON (starts with `{` and ends with `}`). +text inserted is valid JSON object (starts with `{` and ends with `}`) or valid JSON array +(starts with `[` and ends with `]`). Variable substitution is performed on configuration file after the include file directive; Hence variable substitution is also performed on the text in the injected file. @@ -219,40 +221,39 @@ Here is a list of all features which can be toggled on/off and their default val -| Feature | Description | Enabled by default | Sandbox | -|--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------:|:-------:| -| `APIBikeRental` | Enable the bike rental endpoint. | ✓️ | | -| `APIServerInfo` | Enable the server info endpoint. | ✓️ | | -| `APIUpdaterStatus` | Enable endpoint for graph updaters status. | ✓️ | | -| `IncludeEmptyRailStopsInTransfers` | Turning this on guarantees that Rail stops without scheduled departures still get included when generating transfers using `ConsiderPatternsForDirectTransfers`. It is common for stops to be assign at real-time for Rail. Turning this on will help to avoid dropping transfers which are needed, when the stop is in use later. Turning this on, if ConsiderPatternsForDirectTransfers is off has no effect. | | | -| `ConsiderPatternsForDirectTransfers` | Enable limiting transfers so that there is only a single transfer to each pattern. | ✓️ | | -| `DebugUi` | Enable the debug GraphQL client and web UI and located at the root of the web server as well as the debug map tiles it uses. Be aware that the map tiles are not a stable API and can change without notice. Use the [vector tiles feature if](sandbox/MapboxVectorTilesApi.md) you want a stable map tiles API. | ✓️ | | -| `ExtraTransferLegOnSameStop` | Should there be a transfer leg when transferring on the very same stop. Note that for in-seat/interlined transfers no transfer leg will be generated. | | | -| `FloatingBike` | Enable floating bike routing. | ✓️ | | -| `GtfsGraphQlApi` | Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md). | ✓️ | | -| `GtfsGraphQlApiRentalStationFuzzyMatching` | Does vehicleRentalStation query also allow ids that are not feed scoped. | | | -| `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | | -| `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | | -| `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | | -| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | | -| `TransmodelGraphQlApi` | Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md). | ✓️ | ✓️ | -| `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ | -| `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | | -| `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ | -| `DataOverlay` | Enable usage of data overlay when calculating costs for the street network. | | ✓️ | -| `FaresV2` | Enable import of GTFS-Fares v2 data. | | ✓️ | -| `FlexRouting` | Enable FLEX routing. | | ✓️ | -| `GoogleCloudStorage` | Enable Google Cloud Storage integration. | | ✓️ | -| `LegacyRestApi` | Enable legacy REST API. This API will be removed in the future. | | ✓️ | -| `MultiCriteriaGroupMaxFilter` | Keep the best itinerary with respect to each criteria used in the transit-routing search. For example the itinerary with the lowest cost, fewest transfers, and each unique transit-group (transit-group-priority) is kept, even if the max-limit is exceeded. This is turned off by default for now, until this feature is well tested. | | | -| `RealtimeResolver` | When routing with ignoreRealtimeUpdates=true, add an extra step which populates results with real-time data | | ✓️ | -| `ReportApi` | Enable the report API. | | ✓️ | -| `RestAPIPassInDefaultConfigAsJson` | Enable a default RouteRequest to be passed in as JSON on the REST API - FOR DEBUGGING ONLY! | | | -| `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ | -| `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ | -| `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ | -| `Sorlandsbanen` | Include train Sørlandsbanen in results when searching in south of Norway. Only relevant in Norway. | | ✓️ | -| `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ | +| Feature | Description | Enabled by default | Sandbox | +|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------:|:-------:| +| `APIBikeRental` | Enable the bike rental endpoint. | ✓️ | | +| `APIServerInfo` | Enable the server info endpoint. | ✓️ | | +| `APIUpdaterStatus` | Enable endpoint for graph updaters status. | ✓️ | | +| `IncludeEmptyRailStopsInTransfers` | Turning this on guarantees that Rail stops without scheduled departures still get included when generating transfers using `ConsiderPatternsForDirectTransfers`. It is common for stops to be assign at real-time for Rail. Turning this on will help to avoid dropping transfers which are needed, when the stop is in use later. Turning this on, if ConsiderPatternsForDirectTransfers is off has no effect. | | | +| `ConsiderPatternsForDirectTransfers` | Enable limiting transfers so that there is only a single transfer to each pattern. | ✓️ | | +| `DebugUi` | Enable the debug GraphQL client and web UI and located at the root of the web server as well as the debug map tiles it uses. Be aware that the map tiles are not a stable API and can change without notice. Use the [vector tiles feature if](sandbox/MapboxVectorTilesApi.md) you want a stable map tiles API. | ✓️ | | +| `ExtraTransferLegOnSameStop` | Should there be a transfer leg when transferring on the very same stop. Note that for in-seat/interlined transfers no transfer leg will be generated. | | | +| `FloatingBike` | Enable floating bike routing. | ✓️ | | +| `GtfsGraphQlApi` | Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md). | ✓️ | | +| `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | | +| `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | | +| `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | | +| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | | +| `TransmodelGraphQlApi` | Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md). | ✓️ | ✓️ | +| `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ | +| `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | | +| `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ | +| `DataOverlay` | Enable usage of data overlay when calculating costs for the street network. | | ✓️ | +| `FaresV2` | Enable import of GTFS-Fares v2 data. | | ✓️ | +| `FlexRouting` | Enable FLEX routing. | | ✓️ | +| `GoogleCloudStorage` | Enable Google Cloud Storage integration. | | ✓️ | +| `LegacyRestApi` | Enable legacy REST API. This API will be removed in the future. | | ✓️ | +| `MultiCriteriaGroupMaxFilter` | Keep the best itinerary with respect to each criteria used in the transit-routing search. For example the itinerary with the lowest cost, fewest transfers, and each unique transit-group (transit-group-priority) is kept, even if the max-limit is exceeded. This is turned off by default for now, until this feature is well tested. | | | +| `RealtimeResolver` | When routing with ignoreRealtimeUpdates=true, add an extra step which populates results with real-time data | | ✓️ | +| `ReportApi` | Enable the report API. | | ✓️ | +| `RestAPIPassInDefaultConfigAsJson` | Enable a default RouteRequest to be passed in as JSON on the REST API - FOR DEBUGGING ONLY! | | | +| `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ | +| `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ | +| `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ | +| `Sorlandsbanen` | Include train Sørlandsbanen in results when searching in south of Norway. Only relevant in Norway. | | ✓️ | +| `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ | diff --git a/doc/user/DebugUiConfiguration.md b/doc/user/DebugUiConfiguration.md new file mode 100644 index 00000000000..a1657796fe0 --- /dev/null +++ b/doc/user/DebugUiConfiguration.md @@ -0,0 +1,66 @@ + + +# Debug UI configuration + +The Debug UI is the standard interface that is bundled with OTP and available by visiting +[`http://localhost:8080`](http://localhost:8080). This page list the configuration options available +by placing a file `debug-ui-config.json` into OTP's working directory. + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|-----------------------------------------------------------|:----------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------:|-----------------------|:-----:| +| [additionalBackgroundLayers](#additionalBackgroundLayers) | `object[]` | Additional background raster map layers. | *Optional* | | 2.7 | +|       attribution | `string` | Attribution for the map data. | *Optional* | `"© OpenTripPlanner"` | 2.7 | +|       name | `string` | Name to appear in the layer selector. | *Required* | | 2.7 | +|       templateUrl | `string` | The [Maplibre-compatible template URL](https://maplibre.org/maplibre-native/ios/api/tile-url-templates.html) for the raster layer, for example `https://examples.com/tiles/{z}/{x}/{y}.png`. | *Required* | | 2.7 | +|       tileSize | `integer` | Size of the tile in pixels. | *Optional* | `256` | 2.7 | + + + + +## Parameter Details + + + + +

additionalBackgroundLayers

+ +**Since version:** `2.7` ∙ **Type:** `object[]` ∙ **Cardinality:** `Optional` +**Path:** / + +Additional background raster map layers. + +Add additional background layers that will appear in the Debug UI as one of the choices. + +Currently only raster tile layers are supported. + + + + + +## Config Example + + + + +```JSON +// debug-ui-config.json +{ + "additionalBackgroundLayers" : [ + { + "name" : "TriMet aerial photos", + "templateUrl" : "https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials", + "attribution" : "© TriMet" + } + ] +} +``` + + diff --git a/doc/user/Getting-OTP.md b/doc/user/Getting-OTP.md index 92f1e7298fc..ea0bac0df90 100644 --- a/doc/user/Getting-OTP.md +++ b/doc/user/Getting-OTP.md @@ -65,7 +65,7 @@ OTP. If all goes well you should see a success message like the following: ``` This build process should produce a JAR file called `otp-x.y.z-shaded.jar` in the -`application/target/` directory which contains all the compiled OTP classes and their dependencies +`shaded-jar/target/` directory which contains all the compiled OTP classes and their dependencies (the external libraries they use). The shell script called 'otp' in the root of the cloned repository will start the main class of that JAR file under a Java virtual machine, so after the Maven build completes you should be able to run `./otp --help` and see an OTP help message including command line diff --git a/doc/user/RouteRequest.md b/doc/user/RouteRequest.md index ea3d0d12c74..5b428ff9175 100644 --- a/doc/user/RouteRequest.md +++ b/doc/user/RouteRequest.md @@ -155,12 +155,14 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe |    [routes](#rd_unpreferred_routes) | `feed-scoped-id[]` | The ids of the routes that incur an extra cost when being used. Format: `FeedId:RouteId` | *Optional* | | 2.2 | | walk | `object` | Walking preferences. | *Optional* | | 2.5 | |    boardCost | `integer` | Prevents unnecessary transfers by adding a cost for boarding a vehicle. This is the cost that is used when boarding while walking. | *Optional* | `600` | 2.0 | -|    escalatorReluctance | `double` | A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time | *Optional* | `1.5` | 2.4 | |    [reluctance](#rd_walk_reluctance) | `double` | A multiplier for how bad walking is, compared to being in transit for equal lengths of time. | *Optional* | `2.0` | 2.0 | |    [safetyFactor](#rd_walk_safetyFactor) | `double` | Factor for how much the walk safety is considered in routing. | *Optional* | `1.0` | 2.2 | |    speed | `double` | The user's walking speed in meters/second. | *Optional* | `1.33` | 2.0 | |    stairsReluctance | `double` | Used instead of walkReluctance for stairs. | *Optional* | `2.0` | 2.0 | |    [stairsTimeFactor](#rd_walk_stairsTimeFactor) | `double` | How much more time does it take to walk a flight of stairs compared to walking a similar horizontal length. | *Optional* | `3.0` | 2.1 | +|    escalator | `object` | Escalator preferences. | *Optional* | | 2.7 | +|       reluctance | `double` | A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time | *Optional* | `1.5` | 2.4 | +|       [speed](#rd_walk_escalator_speed) | `double` | How fast does an escalator move horizontally? | *Optional* | `0.45` | 2.7 | | wheelchairAccessibility | `object` | See [Wheelchair Accessibility](Accessibility.md) | *Optional* | | 2.2 | |    enabled | `boolean` | Enable wheelchair accessibility. | *Optional* | `false` | 2.0 | |    inaccessibleStreetReluctance | `double` | The factor to multiply the cost of traversing a street edge that is not wheelchair-accessible. | *Optional* | `25.0` | 2.2 | @@ -1105,6 +1107,15 @@ Default value is based on: Fujiyama, T., & Tyler, N. (2010). Predicting the walk speed of pedestrians on stairs. Transportation Planning and Technology, 33(2), 177–202. +

speed

+ +**Since version:** `2.7` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.45` +**Path:** /routingDefaults/walk/escalator + +How fast does an escalator move horizontally? + +Horizontal speed of escalator in m/s. +

maxSlope

**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.083` @@ -1214,7 +1225,10 @@ include stairs as a last result. "reluctance" : 4.0, "stairsReluctance" : 1.65, "boardCost" : 600, - "escalatorReluctance" : 1.5 + "escalator" : { + "reluctance" : 1.5, + "speed" : 0.45 + } }, "waitReluctance" : 1.0, "otherThanPreferredRoutesPenalty" : 300, diff --git a/doc/user/RouterConfiguration.md b/doc/user/RouterConfiguration.md index 6dbd1174397..7dae97fd74c 100644 --- a/doc/user/RouterConfiguration.md +++ b/doc/user/RouterConfiguration.md @@ -528,7 +528,10 @@ Used to group requests when monitoring OTP. "reluctance" : 4.0, "stairsReluctance" : 1.65, "boardCost" : 600, - "escalatorReluctance" : 1.5 + "escalator" : { + "reluctance" : 1.5, + "speed" : 0.45 + } }, "waitReluctance" : 1.0, "otherThanPreferredRoutesPenalty" : 300, diff --git a/doc/user/sandbox/siri/SiriAzureUpdater.md b/doc/user/sandbox/siri/SiriAzureUpdater.md index c8e7f4d9255..898e70d7b84 100644 --- a/doc/user/sandbox/siri/SiriAzureUpdater.md +++ b/doc/user/sandbox/siri/SiriAzureUpdater.md @@ -28,12 +28,12 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro | [authenticationType](#u__11__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | | autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 | | [customMidnight](#u__11__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | -| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.2 | | [fullyQualifiedNamespace](#u__11__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | | fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 | | prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 | | [servicebus-url](#u__11__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | -| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 | +| topic | `string` | Service Bus topic to connect to. | *Required* | | 2.2 | | history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 | |    fromDateTime | `string` | Datetime boundary for historical data | *Optional* | `"-P1D"` | 2.2 | |    timeout | `integer` | Timeout in milliseconds | *Optional* | `300000` | na | @@ -116,12 +116,12 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima | [authenticationType](#u__10__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | | autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 | | [customMidnight](#u__10__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | -| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.2 | | [fullyQualifiedNamespace](#u__10__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | | fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 | | prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 | | [servicebus-url](#u__10__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | -| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 | +| topic | `string` | Service Bus topic to connect to. | *Required* | | 2.2 | | history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 | |    fromDateTime | `string` | Datetime boundary for historical data. | *Optional* | `"-P1D"` | 2.2 | |    timeout | `integer` | Timeout in milliseconds | *Optional* | `300000` | na | diff --git a/mkdocs.yml b/mkdocs.yml index b40f77ff3c0..51245f6c3b8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,6 +82,7 @@ nav: - Router: 'RouterConfiguration.md' - "Route Request": 'RouteRequest.md' - "Realtime Updaters": 'UpdaterConfig.md' + - "Debug UI": 'DebugUiConfiguration.md' - "Migrating between versions/builds": 'Migrating-Configuration.md' - Features explained: - "Routing modes": 'RoutingModes.md' diff --git a/pom.xml b/pom.xml index c1027be78b0..64a3b5eae2c 100644 --- a/pom.xml +++ b/pom.xml @@ -58,14 +58,14 @@ - 174 + 175 32.1 - 2.52 + 2.53 2.18.2 3.1.9 5.11.3 - 1.13.7 + 1.14.1 5.6.0 1.5.12 9.12.0 diff --git a/renovate.json5 b/renovate.json5 index a5838fb3ff0..557857bf54c 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -149,7 +149,8 @@ "com.fasterxml.jackson:{/,}**", "com.fasterxml.jackson.datatype::{/,}**" ], - "minimumReleaseAge": "1 week" + "minimumReleaseAge": "1 week", + "schedule": "on the 13th through 14th day of the month" }, { "description": "Geotools takes a while to publish a changelog and since it pulls in JTS it can change the serialization of the graph", diff --git a/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java b/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java index 72eb2638c13..c1a2219da72 100644 --- a/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java @@ -132,6 +132,14 @@ public static String kebabCase(String input) { return input.toLowerCase().replace('_', '-'); } + /** + * Create a URL-friendly "slug" version of the string, so "Entur Routebanken" becomes + * "entur-routebanken". + */ + public static String slugify(String input) { + return input.toLowerCase().replace('_', '-').replaceAll("\\s+", "-"); + } + /** * Detects unprintable control characters like newlines, tabs and invisible whitespace * like 'ZERO WIDTH SPACE' (U+200B) that don't have an immediate visual representation. diff --git a/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java b/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java index 7e8f0a6217b..dda9248468e 100644 --- a/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java +++ b/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java @@ -100,4 +100,10 @@ void containsInvisibleChars(String input) { void noInvisibleChars(String input) { assertFalse(StringUtils.containsInvisibleCharacters(input)); } + + @ParameterizedTest + @ValueSource(strings = { "AAA Bbb", "aAa bbb", "aaa bbb", "aaa bbb", "AAA_BBB" }) + void slugify(String input) { + assertEquals("aaa-bbb", StringUtils.slugify(input)); + } }