From e9cece5277a30dd9992ecdd4e3748d7f33251a5c Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Mon, 2 Sep 2024 11:31:09 +0200 Subject: [PATCH 01/64] [CP-3095] 2.3.1-mockdev.70 requests not existing app update (#2045) --- .../settings/actions/load-settings.action.ts | 5 ++++- libs/core/utils/get-base-bersion.ts | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 libs/core/utils/get-base-bersion.ts diff --git a/libs/core/settings/actions/load-settings.action.ts b/libs/core/settings/actions/load-settings.action.ts index e31a1467bc..f8f4e9287b 100644 --- a/libs/core/settings/actions/load-settings.action.ts +++ b/libs/core/settings/actions/load-settings.action.ts @@ -12,6 +12,7 @@ import logger from "Core/__deprecated__/main/utils/logger" import { getConfiguration } from "Core/settings/requests" import packageInfo from "../../../../apps/mudita-center/package.json" import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import getBaseVersion from "Core/utils/get-base-bersion" export const loadSettings = createAsyncThunk< void, @@ -23,9 +24,11 @@ export const loadSettings = createAsyncThunk< const configuration = await getConfiguration() try { + const packageInfoBaseVersion = getBaseVersion(packageInfo.version) as string + updateRequired = isVersionGreater( configuration.centerVersion, - packageInfo.version + packageInfoBaseVersion ) // AUTO DISABLED - fix me if you like :) // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/libs/core/utils/get-base-bersion.ts b/libs/core/utils/get-base-bersion.ts new file mode 100644 index 0000000000..b6ff64af6d --- /dev/null +++ b/libs/core/utils/get-base-bersion.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import semver from "semver/preload" + +const getBaseVersion = (version = "") => { + const baseVersion = semver.parse(version); + if (baseVersion) { + return `${baseVersion.major}.${baseVersion.minor}.${baseVersion.patch}`; + } + + return null; +}; + +export default getBaseVersion From 3e7f5554679c43a368204db38837d957d8b1dc7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kurczewski?= Date: Thu, 5 Sep 2024 13:02:03 +0200 Subject: [PATCH 02/64] [CP-3037] Implemented APIEntitiesService (#2047) --- libs/device/feature/src/index.ts | 1 + .../lib/api-entities/api-entities.service.ts | 76 ++++++++ .../get-api-entities-config.request.ts | 16 ++ .../feature/src/lib/api-entities/index.ts | 7 + libs/device/feature/src/lib/api-module.ts | 4 + libs/device/models/src/index.ts | 1 + .../src/lib/api-config/api-config.test.ts | 6 + .../models/src/lib/api-config/api-config.ts | 1 + .../models/src/lib/api-request.model.ts | 2 + .../entities/entity-config.validator.test.ts | 76 ++++++++ .../lib/entities/entity-config.validator.ts | 164 +++++++++++++++++ .../flatten-entity-configuration.test.ts | 170 ++++++++++++++++++ .../helpers/flatten-entity-configuration.ts | 44 +++++ libs/device/models/src/lib/entities/index.ts | 6 + libs/device/models/src/lib/general-error.ts | 4 + .../api-entities-service-events.ts | 8 + .../src/lib/renderer-to-main-events/index.ts | 1 + 17 files changed, 587 insertions(+) create mode 100644 libs/device/feature/src/lib/api-entities/api-entities.service.ts create mode 100644 libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts create mode 100644 libs/device/feature/src/lib/api-entities/index.ts create mode 100644 libs/device/models/src/lib/entities/entity-config.validator.test.ts create mode 100644 libs/device/models/src/lib/entities/entity-config.validator.ts create mode 100644 libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts create mode 100644 libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.ts create mode 100644 libs/device/models/src/lib/entities/index.ts create mode 100644 libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts diff --git a/libs/device/feature/src/index.ts b/libs/device/feature/src/index.ts index d91fba1db0..5a3ad9f197 100644 --- a/libs/device/feature/src/index.ts +++ b/libs/device/feature/src/index.ts @@ -7,6 +7,7 @@ export * from "./lib/api-config" export * from "./lib/api-device" export * from "./lib/api-module" export * from "./lib/api-features" +export * from "./lib/api-entities" export * from "./lib/outbox" export * from "./lib/menu" export * from "./lib/server" diff --git a/libs/device/feature/src/lib/api-entities/api-entities.service.ts b/libs/device/feature/src/lib/api-entities/api-entities.service.ts new file mode 100644 index 0000000000..714d9ac1d9 --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/api-entities.service.ts @@ -0,0 +1,76 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { DeviceProtocol } from "device-protocol/feature" +import { DeviceId } from "Core/device/constants/device-id" +import { Result, ResultObject } from "Core/core/builder" +import { AppError, AppErrorType } from "Core/core/errors" +import { + entityConfigValidator, + EntitiesError, + EntityConfig, + GeneralError, + APIEntitiesServiceEvents, +} from "device/models" +import { SafeParseSuccess } from "zod" +import { IpcEvent } from "Core/core/decorators" + +export class APIEntitiesService { + constructor(private deviceProtocol: DeviceProtocol) {} + + private getDevice = (deviceId?: DeviceId) => { + return deviceId + ? this.deviceProtocol.getAPIDeviceById(deviceId) + : this.deviceProtocol.apiDevice + } + + private handleError(responseStatus: AppErrorType) { + if (EntitiesError[responseStatus as EntitiesError]) { + return Result.failed( + new AppError( + responseStatus, + EntitiesError[responseStatus as EntitiesError] + ) + ) + } else { + return Result.failed(new AppError(GeneralError.IncorrectResponse, "")) + } + } + + private handleSuccess(response: SafeParseSuccess) { + return Result.success(response.data) + } + + @IpcEvent(APIEntitiesServiceEvents.EntityConfig) + public async getEntityConfiguration({ + entityType, + deviceId, + }: { + entityType: string + deviceId?: DeviceId + }): Promise> { + const device = this.getDevice(deviceId) + if (!device) { + return Result.failed(new AppError(GeneralError.NoDevice, "")) + } + + const response = await device.request({ + endpoint: "ENTITY_CONFIGURATION", + method: "GET", + body: { + type: entityType, + }, + }) + if (!response.ok) { + return this.handleError(response.error.type) + } + + const apiConfig = entityConfigValidator.safeParse(response.data.body) + if (!apiConfig.success) { + return this.handleError(response.data.status) + } + return this.handleSuccess(apiConfig) + } +} diff --git a/libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts b/libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts new file mode 100644 index 0000000000..8c18dedf7f --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ipcRenderer } from "electron-better-ipc" +import { ResultObject } from "Core/core/builder" +import { DeviceId } from "Core/device/constants/device-id" +import { APIEntitiesServiceEvents, EntityConfig } from "device/models" + +export const getAPIEntitiesConfigRequest = (data: { + entityType: string + deviceId?: DeviceId +}): Promise> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntityConfig, data) +} diff --git a/libs/device/feature/src/lib/api-entities/index.ts b/libs/device/feature/src/lib/api-entities/index.ts new file mode 100644 index 0000000000..743f3ba553 --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/index.ts @@ -0,0 +1,7 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +export * from "./api-entities.service" +export * from "./get-api-entities-config.request" diff --git a/libs/device/feature/src/lib/api-module.ts b/libs/device/feature/src/lib/api-module.ts index 4341dfe354..1bb94ca5ec 100644 --- a/libs/device/feature/src/lib/api-module.ts +++ b/libs/device/feature/src/lib/api-module.ts @@ -17,6 +17,7 @@ import { SystemUtilsModule } from "system-utils/feature" import { APIRestoreService } from "./restore" import { DeviceSystemActionsService } from "./device-system-actions/device-system-actions.service" import { APIDataTransferService } from "./data-transfer" +import { APIEntitiesService } from "./api-entities" import { ISettingsService } from "shared/utils" export class APIModule { @@ -24,6 +25,7 @@ export class APIModule { private apiFeaturesService: APIFeaturesService private apiOutboxService: APIOutboxService private apiMenuService: APIMenuService + private apiEntitiesService: APIEntitiesService private serverService: ServerService private backupService: APIBackupService private restoreService: APIRestoreService @@ -43,6 +45,7 @@ export class APIModule { this.apiFeaturesService = new APIFeaturesService(deviceProtocol) this.apiOutboxService = new APIOutboxService(deviceProtocol) this.apiMenuService = new APIMenuService(deviceProtocol) + this.apiEntitiesService = new APIEntitiesService(deviceProtocol) this.serverService = new ServerService() this.backupService = new APIBackupService(deviceProtocol) this.apiDataTransferService = new APIDataTransferService(deviceProtocol) @@ -72,6 +75,7 @@ export class APIModule { this.apiFeaturesService, this.apiOutboxService, this.apiMenuService, + this.apiEntitiesService, this.serverService, this.backupService, this.restoreService, diff --git a/libs/device/models/src/index.ts b/libs/device/models/src/index.ts index f808d8a139..eb55aff648 100644 --- a/libs/device/models/src/index.ts +++ b/libs/device/models/src/index.ts @@ -18,3 +18,4 @@ export * from "./lib/restore" export * from "./lib/feature" export * from "./lib/import-contacts" export * from "./lib/data-transfer" +export * from "./lib/entities" diff --git a/libs/device/models/src/lib/api-config/api-config.test.ts b/libs/device/models/src/lib/api-config/api-config.test.ts index b676fc5732..68ea8bfb0f 100644 --- a/libs/device/models/src/lib/api-config/api-config.test.ts +++ b/libs/device/models/src/lib/api-config/api-config.test.ts @@ -35,6 +35,12 @@ describe("APIConfigValidator", () => { const result = ApiConfigValidator.safeParse(apiConfig) expect(result.success).toBeFalsy() }) + it("should return fail when entityTypes array is empty", () => { + const apiConfig = { ...minimumApiConfig, entityTypes: [] } + + const result = ApiConfigValidator.safeParse(apiConfig) + expect(result.success).toBeFalsy() + }) it.each(["apiVersion", "productId", "vendorId"])( "should return fail when %s is missing", (fieldName) => { diff --git a/libs/device/models/src/lib/api-config/api-config.ts b/libs/device/models/src/lib/api-config/api-config.ts index e4d990a1b7..95f134ee64 100644 --- a/libs/device/models/src/lib/api-config/api-config.ts +++ b/libs/device/models/src/lib/api-config/api-config.ts @@ -17,6 +17,7 @@ export const ApiConfigValidator = z.object({ vendorId: z.string(), serialNumber: z.string().optional(), features: z.array(z.string()).min(1), + entityTypes: z.array(z.string()).min(1).optional(), }) export type ApiConfig = z.infer diff --git a/libs/device/models/src/lib/api-request.model.ts b/libs/device/models/src/lib/api-request.model.ts index 9bca8acd77..b7e7826c5f 100644 --- a/libs/device/models/src/lib/api-request.model.ts +++ b/libs/device/models/src/lib/api-request.model.ts @@ -19,6 +19,7 @@ export const APIEndpoints = [ "SYSTEM", "PRE_DATA_TRANSFER", "DATA_TRANSFER", + "ENTITY_CONFIGURATION", ] as const export type APIEndpointType = (typeof APIEndpoints)[number] @@ -43,6 +44,7 @@ const APIRequests = { SYSTEM: ["POST"], PRE_DATA_TRANSFER: ["POST"], DATA_TRANSFER: ["POST", "GET", "DELETE"], + ENTITY_CONFIGURATION: ["GET"], } as const interface APIRequestConfig< diff --git a/libs/device/models/src/lib/entities/entity-config.validator.test.ts b/libs/device/models/src/lib/entities/entity-config.validator.test.ts new file mode 100644 index 0000000000..654094c580 --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-config.validator.test.ts @@ -0,0 +1,76 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { EntityConfig, entityConfigValidator } from "./entity-config.validator" +import { ZodError } from "zod" + +describe("entityConfigValidator", () => { + it("validates a correct entity configuration", () => { + const validConfig: EntityConfig = { + globalValidators: { + requiredFieldsCombinations: [ + { + fields: ["field1", "field2", "field3.field3a", "field4[]"], + countLogic: "gt", + fieldsCount: 1, + }, + ], + }, + fields: { + field1: { type: "id" }, + field2: { type: "string", validators: [{ pattern: "/abc/" }] }, + field3: { type: "object", fields: { field3a: { type: "string" } } }, + field4: { type: "array", items: { type: "string" } }, + }, + } + expect(() => entityConfigValidator.parse(validConfig)).not.toThrow() + }) + + it("throws an error when 'requiredFieldsCombinations' uses wrong fields", () => { + const invalidConfig: EntityConfig = { + globalValidators: { + requiredFieldsCombinations: [ + { + fields: ["field1", "field2.field3a", "field3"], + countLogic: "gt", + fieldsCount: 1, + }, + ], + }, + fields: { + field1: { type: "id" }, + field2: { + type: "array", + items: { + type: "object", + fields: { + field3a: { type: "string" }, + }, + }, + }, + }, + } + const result = () => entityConfigValidator.parse(invalidConfig) + expect(result).toThrow() + + try { + result() + } catch (error) { + expect((error as ZodError).errors).toEqual([ + { + code: "custom", + message: + "global validators are mentioning fields not defined in the 'fields' object", + path: [ + "globalValidators", + "requiredFieldsCombinations[0]", + "fields", + "[field2.field3a, field3]", + ], + }, + ]) + } + }) +}) diff --git a/libs/device/models/src/lib/entities/entity-config.validator.ts b/libs/device/models/src/lib/entities/entity-config.validator.ts new file mode 100644 index 0000000000..90a78b6aae --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-config.validator.ts @@ -0,0 +1,164 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" +import { flattenEntityConfiguration } from "./helpers/flatten-entity-configuration" +import { difference } from "lodash" + +// FIELDS SCHEMA +const validatorErrorSchema = z.string().optional() + +const patternValidatorSchema = z.object({ + pattern: z + .string() + .regex( + /^\/.+\/[gmiyuvsd]*$/m, + "Regex must be in format /regex/ or /regex/flags" + ), + negatePattern: z.boolean().optional(), + error: validatorErrorSchema, +}) + +const uniqueValidatorSchema = z.object({ + unique: z.boolean(), + error: validatorErrorSchema, +}) + +const requiredValidatorSchema = z.object({ + required: z.boolean(), + error: validatorErrorSchema, +}) + +const fieldValidatorsSchema = z + .array( + z.union([ + patternValidatorSchema, + uniqueValidatorSchema, + requiredValidatorSchema, + ]) + ) + .optional() + +const idFieldSchema = z.object({ + type: z.literal("id"), +}) + +const primitiveFieldSchema = z.object({ + type: z.enum(["string", "number", "boolean"]), + validators: fieldValidatorsSchema, +}) + +const basicFieldSchema = z.discriminatedUnion("type", [ + idFieldSchema, + primitiveFieldSchema, +]) + +const nestedArrayFieldSchema = z.object({ + type: z.literal("array"), + items: basicFieldSchema, + validators: fieldValidatorsSchema, +}) + +const nestedObjectFieldSchema = z.object({ + type: z.literal("object"), + fields: z.record(z.string(), basicFieldSchema), + validators: fieldValidatorsSchema, +}) + +const arrayFieldSchema = z.object({ + type: z.literal("array"), + items: z.union([ + basicFieldSchema, + nestedArrayFieldSchema, + nestedObjectFieldSchema, + ]), + validators: fieldValidatorsSchema, +}) + +const objectFieldSchema = z.object({ + type: z.literal("object"), + fields: z.record( + z.string(), + z.union([basicFieldSchema, nestedArrayFieldSchema, nestedObjectFieldSchema]) + ), + validators: fieldValidatorsSchema, +}) + +const fieldSchema = z.union([ + idFieldSchema, + primitiveFieldSchema, + arrayFieldSchema, + objectFieldSchema, + arrayFieldSchema, +]) + +// GLOBAL VALIDATORS SCHEMA +const requiredFieldsCombinationsSchema = z.object({ + fields: z.array(z.string()).min(1), + countLogic: z.enum(["gt", "lt", "eq"]), + fieldsCount: z.number().nonnegative(), + error: z.string().optional(), +}) + +const globalValidatorSchema = z + .object({ + requiredFieldsCombinations: z + .array(requiredFieldsCombinationsSchema) + .optional(), + }) + .optional() + +export const entityConfigValidator = z + .object({ + fields: z.record(z.string(), fieldSchema), + globalValidators: globalValidatorSchema, + metadata: z.unknown().optional(), + }) + .refine( + (data) => { + const requiredFieldsCombinations = + data.globalValidators?.requiredFieldsCombinations + if (!requiredFieldsCombinations) return true + + const availableKeys = flattenEntityConfiguration(data.fields) + + return Object.values(data.globalValidators || {}).every((validator) => { + return validator.every((combination) => { + return combination.fields.every((field) => field in availableKeys) + }) + }) + }, + (data) => { + let failedValidator: string[] = [] + const availableFields = flattenEntityConfiguration(data.fields) + + for (const [validatorKey, validators] of Object.entries( + data.globalValidators || {} + )) { + if (failedValidator.length) break + for (const [validatorIndex, validator] of validators.entries()) { + if (failedValidator.length) break + if (!validator.fields.every((field) => field in availableFields)) { + failedValidator = [ + "globalValidators", + `${validatorKey}[${validatorIndex}]`, + `fields`, + `[${difference( + validator.fields, + Object.keys(availableFields) + ).join(", ")}]`, + ] + break + } + } + } + return { + message: `global validators are mentioning fields not defined in the 'fields' object`, + path: failedValidator, + } + } + ) + +export type EntityConfig = z.infer diff --git a/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts b/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts new file mode 100644 index 0000000000..6a3853dfc9 --- /dev/null +++ b/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts @@ -0,0 +1,170 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { flattenEntityConfiguration } from "./flatten-entity-configuration" +import { EntityConfig } from "device/models" + +describe("flattenEntityConfiguration", () => { + it("handles objects with non-object values correctly", () => { + const input: EntityConfig["fields"] = { + a: { + type: "id", + }, + b: { + type: "string", + }, + c: { + type: "number", + }, + d: { + type: "boolean", + }, + } + expect(flattenEntityConfiguration(input)).toEqual({ + a: "id", + b: "string", + c: "number", + d: "boolean", + }) + }) + + it("converts a simple nested object to dot notation correctly", () => { + const input: EntityConfig["fields"] = { + a: { + type: "object", + fields: { + b: { + type: "object", + fields: { + c: { + type: "string", + }, + }, + }, + }, + }, + } + expect(flattenEntityConfiguration(input)).toEqual({ + a: "object", + "a.b": "object", + "a.b.c": "string", + }) + }) + + it("handles objects with nested arrays correctly", () => { + const input: EntityConfig["fields"] = { + a: { + type: "object", + fields: { + b: { + type: "array", + items: { + type: "string", + }, + }, + }, + }, + } + expect(flattenEntityConfiguration(input)).toEqual({ + a: "object", + "a.b": "array", + "a.b[]": "string", + }) + }) + + it("handles arrays with nested arrays correctly", () => { + const input: EntityConfig["fields"] = { + a: { + type: "array", + items: { + type: "array", + items: { + type: "string", + }, + }, + }, + } + expect(flattenEntityConfiguration(input)).toEqual({ + a: "array", + "a[]": "array", + "a[][]": "string", + }) + }) + + it("handles arrays with nested objects correctly", () => { + const input: EntityConfig["fields"] = { + a: { + type: "array", + items: { + type: "object", + fields: { + b: { + type: "string", + }, + }, + }, + }, + } + expect(flattenEntityConfiguration(input)).toEqual({ + a: "array", + "a[]": "object", + "a[].b": "string", + }) + }) + + it("excludes 'validators' key", () => { + const input: EntityConfig["fields"] = { + a: { + type: "string", + validators: [], + }, + b: { + type: "object", + validators: [], + fields: { + c: { + type: "string", + validators: [], + }, + }, + }, + } + expect(flattenEntityConfiguration(input, "")).toEqual({ + a: "string", + b: "object", + "b.c": "string", + }) + }) + + it("handles empty objects correctly", () => { + const input: EntityConfig["fields"] = {} + expect(flattenEntityConfiguration(input)).toEqual({}) + }) + + it("handles nested objects with mixed types", () => { + const input: EntityConfig["fields"] = { + a: { + type: "object", + fields: { + b: { + type: "string", + }, + c: { + type: "number", + }, + d: { + type: "boolean", + }, + }, + }, + } + expect(flattenEntityConfiguration(input)).toEqual({ + a: "object", + "a.b": "string", + "a.c": "number", + "a.d": "boolean", + }) + }) +}) diff --git a/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.ts b/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.ts new file mode 100644 index 0000000000..fa0aadbc59 --- /dev/null +++ b/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +export const flattenEntityConfiguration = ( + obj: Record, + prefix: string = "" +): Record => { + const result: Record = {} + + for (const key in obj) { + if ( + !Object.prototype.hasOwnProperty.call(obj, key) || + ["validators"].includes(key) + ) { + continue + } + let currentKey = key + switch (key) { + case "items": + currentKey = "[]" + break + case "fields": + currentKey = "." + break + case "type": + currentKey = "" + } + const value = obj[key] + const newKey = prefix ? `${prefix}${currentKey}` : currentKey + + if (typeof value === "object" && value !== null && !Array.isArray(value)) { + Object.assign( + result, + flattenEntityConfiguration(value as Record, newKey) + ) + } else { + result[newKey] = value + } + } + + return result +} diff --git a/libs/device/models/src/lib/entities/index.ts b/libs/device/models/src/lib/entities/index.ts new file mode 100644 index 0000000000..22b0994766 --- /dev/null +++ b/libs/device/models/src/lib/entities/index.ts @@ -0,0 +1,6 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +export * from "./entity-config.validator" diff --git a/libs/device/models/src/lib/general-error.ts b/libs/device/models/src/lib/general-error.ts index 608722f08f..0c8ea12b6c 100644 --- a/libs/device/models/src/lib/general-error.ts +++ b/libs/device/models/src/lib/general-error.ts @@ -22,3 +22,7 @@ export enum ApiFileTransferError { Unknown = 500, NotEnoughSpace = 507, } + +export enum EntitiesError { + EntityTypeNotSupported = 406 +} diff --git a/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts b/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts new file mode 100644 index 0000000000..e513bdc23e --- /dev/null +++ b/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts @@ -0,0 +1,8 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +export enum APIEntitiesServiceEvents { + EntityConfig = "apiservice_entity-config", +} diff --git a/libs/device/models/src/lib/renderer-to-main-events/index.ts b/libs/device/models/src/lib/renderer-to-main-events/index.ts index 9cae09872d..f39c013746 100644 --- a/libs/device/models/src/lib/renderer-to-main-events/index.ts +++ b/libs/device/models/src/lib/renderer-to-main-events/index.ts @@ -14,3 +14,4 @@ export * from "./api-file-transfer-service-events" export * from "./file-manager-service-events" export * from "./device-system-actions-service-events" export * from "./api-data-transfer-service-events" +export * from "./api-entities-service-events" From bb41f8c7a97fb78ef7aa2a5a09780af28e2f2be3 Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Tue, 17 Sep 2024 10:30:32 +0200 Subject: [PATCH 03/64] [CP-3093] Add data-testid to Success modal for Contact Support Form sending (#2054) --- ...ontact-support-modal-success.component.tsx | 14 +++++++---- libs/e2e-test-ids/.eslintrc.json | 18 +++++++++++++++ libs/e2e-test-ids/README.md | 7 ++++++ libs/e2e-test-ids/project.json | 23 +++++++++++++++++++ libs/e2e-test-ids/src/e2e-test-ids.ts | 14 +++++++++++ libs/e2e-test-ids/src/index.ts | 6 +++++ libs/e2e-test-ids/tsconfig.json | 16 +++++++++++++ libs/e2e-test-ids/tsconfig.lib.json | 9 ++++++++ .../theme/src/lib/generic-theme-provider.tsx | 2 +- .../modal/helpers/modal-close-button.tsx | 9 ++++---- nx.json | 5 ++++ tsconfig.base.json | 1 + 12 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 libs/e2e-test-ids/.eslintrc.json create mode 100644 libs/e2e-test-ids/README.md create mode 100644 libs/e2e-test-ids/project.json create mode 100644 libs/e2e-test-ids/src/e2e-test-ids.ts create mode 100644 libs/e2e-test-ids/src/index.ts create mode 100644 libs/e2e-test-ids/tsconfig.json create mode 100644 libs/e2e-test-ids/tsconfig.lib.json diff --git a/libs/core/contact-support/components/contact-support-modal-success.component.tsx b/libs/core/contact-support/components/contact-support-modal-success.component.tsx index f51cd23ee1..911630a3e1 100644 --- a/libs/core/contact-support/components/contact-support-modal-success.component.tsx +++ b/libs/core/contact-support/components/contact-support-modal-success.component.tsx @@ -5,11 +5,12 @@ import React from "react" import { defineMessages } from "react-intl" -import { FunctionComponent } from "Core/core/types/function-component.interface" +import { ContactSupportModalTestIds } from "e2e-test-ids" import { Modal } from "generic-view/ui" +import { IconType } from "generic-view/utils" +import { FunctionComponent } from "Core/core/types/function-component.interface" import { intl } from "Core/__deprecated__/renderer/utils/intl" import { ButtonSecondary } from "../../../generic-view/ui/src/lib/buttons/button-secondary" -import { IconType } from "generic-view/utils" const messages = defineMessages({ title: { id: "component.supportModalSuccessTitle" }, @@ -26,10 +27,15 @@ export const ContactSupportModalSuccess: FunctionComponent = ({ }) => ( <> - {intl.formatMessage(messages.title)} -

{intl.formatMessage(messages.body)}

+ + {intl.formatMessage(messages.title)} + +

+ {intl.formatMessage(messages.body)} +

` box-shadow: 0 2rem 10rem 0 ${({ theme }) => theme.color.black + "26"}; } - .modal-close-button:nth-child(2) { + .modal-close-icon-button:nth-child(2) { display: none; } * { diff --git a/libs/generic-view/ui/src/lib/interactive/modal/helpers/modal-close-button.tsx b/libs/generic-view/ui/src/lib/interactive/modal/helpers/modal-close-button.tsx index 3bd02fa7d7..590d9493df 100644 --- a/libs/generic-view/ui/src/lib/interactive/modal/helpers/modal-close-button.tsx +++ b/libs/generic-view/ui/src/lib/interactive/modal/helpers/modal-close-button.tsx @@ -5,24 +5,25 @@ import React from "react" import styled, { css } from "styled-components" +import { ModalCloseButtonTestIds } from "e2e-test-ids" import { APIFC, IconType } from "generic-view/utils" +import { ModalCloseButtonConfig } from "generic-view/models" import { ButtonBase } from "../../../buttons/button-base/button-base" import { iconButtonStyles } from "../../../shared/button" import { Icon } from "../../../icon/icon" -import { ModalCloseButtonConfig } from "generic-view/models" export const ModalCloseButton: APIFC = ({ data, config, - className, + className = "", ...rest }) => { if (!config?.action) return null return ( diff --git a/nx.json b/nx.json index 1ee96c524d..4267796381 100644 --- a/nx.json +++ b/nx.json @@ -39,5 +39,10 @@ } } } + }, + "pluginsConfig": { + "@nx/js": { + "analyzeSourceFiles": true + } } } diff --git a/tsconfig.base.json b/tsconfig.base.json index 8cb30bec95..1a11ab9e48 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -46,6 +46,7 @@ "e2e-mock-client": ["libs/e2e-mock/client/src/index.ts"], "e2e-mock-responses": ["libs/e2e-mock/responses/src/index.ts"], "e2e-mock-server": ["libs/e2e-mock/server/src/index.ts"], + "e2e-test-ids": ["libs/e2e-test-ids/src/index.ts"], "electron/application-updater": [ "libs/electron/application-updater/src/index.ts" ], From 58709c8790d3b569be90632275854dc427cc948b Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Tue, 17 Sep 2024 15:14:12 +0200 Subject: [PATCH 04/64] [CP-3108] Add data-testid to Backup modals (#2055) --- libs/e2e-test-ids/src/e2e-test-ids.ts | 16 +++++++++++++ .../lib/interactive/form/input/text-input.tsx | 24 ++++++++++++++----- .../lib/predefined/backup/backup-password.tsx | 9 +++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/libs/e2e-test-ids/src/e2e-test-ids.ts b/libs/e2e-test-ids/src/e2e-test-ids.ts index 3d7bc89b59..fa38cbdbf6 100644 --- a/libs/e2e-test-ids/src/e2e-test-ids.ts +++ b/libs/e2e-test-ids/src/e2e-test-ids.ts @@ -7,6 +7,22 @@ export enum ModalCloseButtonTestIds { IconButton = "modal-close-button-icon-button", } +export enum InteractiveTextInputTestIds { + Text = "interactive-text-input-text", + Input = "interactive-text-input-input", + IconButton = "interactive-text-input-icon-button", + ErrorText = "interactive-text-input-error-text", +} + +export enum PredefinedBackupPasswordTestIds { + Title = "predefined-backup-password-title", + Description = "predefined-backup-password-description", + PasswordPlaceholder = "predefined-backup-password-placeholder", + PasswordRepeatPlaceholder = "predefined-backup-password-repeat-placeholder", + ConfirmButton = "predefined-backup-password-confirm-button", + SkipButton = "predefined-backup-password-skip-button", +} + export enum ContactSupportModalTestIds { Title = "contact-support-modal-success-title", Description = "contact-support-modal-success-description", diff --git a/libs/generic-view/ui/src/lib/interactive/form/input/text-input.tsx b/libs/generic-view/ui/src/lib/interactive/form/input/text-input.tsx index 3ec4d5ac2d..06025e14cb 100644 --- a/libs/generic-view/ui/src/lib/interactive/form/input/text-input.tsx +++ b/libs/generic-view/ui/src/lib/interactive/form/input/text-input.tsx @@ -4,16 +4,18 @@ */ import React, { useEffect, useId, useState } from "react" -import { APIFC, IconType } from "generic-view/utils" import styled, { css } from "styled-components" -import { IconButton } from "../../../shared/button" -import { Icon } from "../../../icon/icon" import { useFormContext } from "react-hook-form" +import { InteractiveTextInputTestIds } from "e2e-test-ids" +import { APIFC, IconType } from "generic-view/utils" import { FormTextInputConfig, FormTextInputData } from "generic-view/models" +import { IconButton } from "../../../shared/button" +import { Icon } from "../../../icon/icon" export const TextInput: APIFC = ({ data, config, + ...props }) => { const id = useId() const { @@ -40,8 +42,9 @@ export const TextInput: APIFC = ({ }, [config.name, data?.value, setValue]) return ( - + {config.type === "password" && value.length > 0 && ( - + = ({ )} - {error && {error?.message?.toString()}} + {error && ( + + {error?.message?.toString()} + + )} ) } diff --git a/libs/generic-view/ui/src/lib/predefined/backup/backup-password.tsx b/libs/generic-view/ui/src/lib/predefined/backup/backup-password.tsx index f23d4615eb..15062b83ba 100644 --- a/libs/generic-view/ui/src/lib/predefined/backup/backup-password.tsx +++ b/libs/generic-view/ui/src/lib/predefined/backup/backup-password.tsx @@ -13,6 +13,7 @@ import { Modal } from "../../interactive/modal" import { defineMessages } from "react-intl" import { intl } from "Core/__deprecated__/renderer/utils/intl" import { Form } from "../../interactive/form/form" +import { PredefinedBackupPasswordTestIds } from "e2e-test-ids" const messages = defineMessages({ title: { @@ -66,17 +67,18 @@ export const BackupPassword: FunctionComponent = ({ type: IconType.Settings, }} /> - + {intl.formatMessage(messages.title)} {intl.formatMessage(messages.subtitle)} - + {intl.formatMessage(messages.description)} {intl.formatMessage(messages.description2)} = ({ }} /> = ({ /> = ({ }} /> Date: Tue, 17 Sep 2024 16:30:10 +0200 Subject: [PATCH 05/64] [CP-2870] Improper handling of an incorrectly entered passcode (#2056) --- .../components/passcode-modal/passcode-modal.component.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/core/device-initialization/components/passcode-modal/passcode-modal.component.tsx b/libs/core/device-initialization/components/passcode-modal/passcode-modal.component.tsx index b6a64af321..a711cadaa8 100644 --- a/libs/core/device-initialization/components/passcode-modal/passcode-modal.component.tsx +++ b/libs/core/device-initialization/components/passcode-modal/passcode-modal.component.tsx @@ -11,9 +11,10 @@ import { AppError } from "Core/core/errors" import { ModalDialogProps } from "Core/ui" import { ModalLayers } from "Core/modals-manager/constants/modal-layers.enum" import { useHelpShortcut } from "help/store" +import { UnlockStatus } from "Core/device" export type UnlockDeviceReturnType = Promise< - PayloadAction + PayloadAction > interface Props extends Omit { @@ -79,7 +80,7 @@ const PasscodeModal: FunctionComponent = ({ return } - if (!unlockDeviceStatus.payload) { + if (unlockDeviceStatus.payload !== "UNLOCKED") { setErrorState(ErrorState.BadPasscode) return } From 59f288e564c2995c86b04ed9ccb2790dbd57de9f Mon Sep 17 00:00:00 2001 From: robertmudi <158469469+robertmudi@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:04:15 +0200 Subject: [PATCH 06/64] CP-2919-pause-fix added loop and pause (#2065) --- .../specs/stress-tests/device-drawer-stress-test.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/mudita-center-e2e/src/specs/stress-tests/device-drawer-stress-test.ts b/apps/mudita-center-e2e/src/specs/stress-tests/device-drawer-stress-test.ts index 0c6c5a17cb..c688cd46b1 100644 --- a/apps/mudita-center-e2e/src/specs/stress-tests/device-drawer-stress-test.ts +++ b/apps/mudita-center-e2e/src/specs/stress-tests/device-drawer-stress-test.ts @@ -46,7 +46,8 @@ describe("Kompakt switching devices", () => { }, ] - for (const device of devices) { + for (let i = 0; i < devices.length; i++) { + const device = devices[i] E2EMockClient.mockResponse({ path: device.path, body: device.body, @@ -59,7 +60,12 @@ describe("Kompakt switching devices", () => { serialNumber: device.serialNumber, }) - await browser.pause(6000) + // Add a 4-second wait after adding the first device + if (i === 0) { + await browser.pause(10000) + } else { + await browser.pause(6000) + } } }) From 567d58fac88284a84ec9d48c72e707b38e8e4553 Mon Sep 17 00:00:00 2001 From: MateuszMudita Date: Wed, 18 Sep 2024 14:58:58 +0200 Subject: [PATCH 07/64] Added data-testid to Backup Modal --- libs/e2e-test-ids/src/e2e-test-ids.ts | 11 ++++++++++ .../ui/src/lib/interactive/modal/modal.tsx | 8 ++++++- .../lib/predefined/backup/backup-features.tsx | 21 +++++++++++++++---- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/libs/e2e-test-ids/src/e2e-test-ids.ts b/libs/e2e-test-ids/src/e2e-test-ids.ts index fa38cbdbf6..e59041910c 100644 --- a/libs/e2e-test-ids/src/e2e-test-ids.ts +++ b/libs/e2e-test-ids/src/e2e-test-ids.ts @@ -28,3 +28,14 @@ export enum ContactSupportModalTestIds { Description = "contact-support-modal-success-description", CloseButton = "contact-support-modal-success-close-button", } + +export enum BackupModalTestIds { + Title = "backup-features-modal-title", + Description = "backup-features-modal-description", + FeatureElementActive = "backup-features-modal-element-active", + FeatureElementInactive = "backup-features-modal-element-inactive", +} + +export enum ModalTestIds { + Modal = "modal-content", +} diff --git a/libs/generic-view/ui/src/lib/interactive/modal/modal.tsx b/libs/generic-view/ui/src/lib/interactive/modal/modal.tsx index 016dad7869..28dbef35cc 100644 --- a/libs/generic-view/ui/src/lib/interactive/modal/modal.tsx +++ b/libs/generic-view/ui/src/lib/interactive/modal/modal.tsx @@ -16,6 +16,7 @@ import { ModalScrollableContent } from "./helpers/modal-scrollable-content" import { ModalContent } from "./helpers/modal-content" import { ModalConfig } from "generic-view/models" import { ModalVisibilityController } from "./helpers/modal-visibility-controller" +import { ModalTestIds } from "e2e-test-ids" export const Modal: BaseGenericComponent< undefined, @@ -48,7 +49,12 @@ export const Modal: BaseGenericComponent< {config.closeButtonAction && ( )} - {children} + + {children} + ) } diff --git a/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx b/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx index a5c18dbb90..1d06819449 100644 --- a/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx +++ b/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx @@ -12,6 +12,7 @@ import { Modal } from "../../interactive/modal" import { defineMessages } from "react-intl" import { intl } from "Core/__deprecated__/renderer/utils/intl" import { BackupFeature } from "generic-view/models" +import { BackupModalTestIds } from "e2e-test-ids" const messages = defineMessages({ title: { @@ -57,17 +58,29 @@ export const BackupFeatures: FunctionComponent = ({ return ( <> - {intl.formatMessage(messages.title)} + + {intl.formatMessage(messages.title)} +
-

{intl.formatMessage(messages.description)}

+

+ {intl.formatMessage(messages.description)} +

    {features.map((feature, index) => ( -
  • {feature.label}
  • +
  • + {feature.label} +
  • ))} {Object.entries(comingSoonMessages).map(([key, message], index) => { return ( - + {intl.formatMessage(message)} ) From fdb8b3ff1f30a5d283b2c821bc5bec5bd36bb16f Mon Sep 17 00:00:00 2001 From: MateuszMudita Date: Wed, 18 Sep 2024 15:55:11 +0200 Subject: [PATCH 08/64] Fixed test --- .../containers/contact-support-flow.container.test.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/core/contact-support/containers/contact-support-flow.container.test.tsx b/libs/core/contact-support/containers/contact-support-flow.container.test.tsx index 4b2412b54a..5eb53540ae 100644 --- a/libs/core/contact-support/containers/contact-support-flow.container.test.tsx +++ b/libs/core/contact-support/containers/contact-support-flow.container.test.tsx @@ -15,6 +15,14 @@ jest.mock("Core/settings/store/schemas/generate-application-id", () => ({ generateApplicationId: () => "123", })) +jest.mock("e2e-test-ids", () => { + return { + ModalTestIds: { + Modal: "modal-content", + }, + } +}) + type Props = ComponentProps const defaultProps: Props = {} From b6606038a2527069fdc4995c76252a7bc2f5b793 Mon Sep 17 00:00:00 2001 From: MateuszMudita Date: Thu, 19 Sep 2024 11:15:32 +0200 Subject: [PATCH 09/64] Added data testid to Create Backup Action --- libs/e2e-test-ids/src/e2e-test-ids.ts | 1 + .../ui/src/lib/predefined/backup/backup-features.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/e2e-test-ids/src/e2e-test-ids.ts b/libs/e2e-test-ids/src/e2e-test-ids.ts index e59041910c..b281207187 100644 --- a/libs/e2e-test-ids/src/e2e-test-ids.ts +++ b/libs/e2e-test-ids/src/e2e-test-ids.ts @@ -34,6 +34,7 @@ export enum BackupModalTestIds { Description = "backup-features-modal-description", FeatureElementActive = "backup-features-modal-element-active", FeatureElementInactive = "backup-features-modal-element-inactive", + CreateBackupAction = "backup-features-modal-create-action", } export enum ModalTestIds { diff --git a/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx b/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx index 1d06819449..3d2b09cf69 100644 --- a/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx +++ b/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx @@ -100,6 +100,7 @@ export const BackupFeatures: FunctionComponent = ({ text: intl.formatMessage(messages.createButtonLabel), action: nextAction, }} + data-testid={BackupModalTestIds.CreateBackupAction} /> From a3483822b82e8a45a93e46df559151e2b9a30f7e Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Fri, 20 Sep 2024 09:15:07 +0200 Subject: [PATCH 10/64] [CP-2634] Update webdriverIO from 7.16 to 8.6+ (#2057) --- .../src/page-objects/contacts.page.ts | 153 +- .../src/page-objects/help-modal.page.ts | 37 +- .../src/page-objects/help.page.ts | 1 - .../messages-browse-contacts-modal.page.ts | 21 +- .../messages-conversation.page.ts | 89 +- .../page-objects/messages-templates.page.ts | 21 +- .../src/page-objects/messages.page.ts | 85 +- .../page-objects/modal-backup-restore.page.ts | 37 +- .../src/page-objects/modal-contacts.page.ts | 35 +- .../src/page-objects/modal-general.page.ts | 25 +- .../src/page-objects/modal-messages.page.ts | 9 +- .../src/page-objects/news.page.ts | 1 - .../src/page-objects/tabs.page.ts | 1 - .../connected-devices-stress-test.ts | 7 +- apps/mudita-center-e2e/tsconfig.json | 7 +- apps/mudita-center-e2e/wdio.conf.ts | 4 + package-lock.json | 7797 +++++++++++++---- package.json | 18 +- 18 files changed, 6081 insertions(+), 2267 deletions(-) diff --git a/apps/mudita-center-e2e/src/page-objects/contacts.page.ts b/apps/mudita-center-e2e/src/page-objects/contacts.page.ts index a92ed4d1c5..80b5027262 100644 --- a/apps/mudita-center-e2e/src/page-objects/contacts.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/contacts.page.ts @@ -3,14 +3,11 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class ContactsPage extends Page { /**[Selector] New contact button on Contacts screen */ - public get newContactButton(): ChainablePromiseElement< - Promise - > { + public get newContactButton() { return $('[data-testid="new-contact-button"]') } @@ -21,23 +18,17 @@ class ContactsPage extends Page { } /**[Selector] Import button on Contacts screen*/ - public get importButton(): ChainablePromiseElement< - Promise - > { + public get importButton() { return $('[data-testid="import-button"]') } /**[Selector] Search contacts input*/ - public get searchContactsInput(): ChainablePromiseElement< - Promise - > { + public get searchContactsInput() { return $('[data-testid="contact-input-select-input"]') } /**[Selector] First name input*/ - public get firstNameInput(): ChainablePromiseElement< - Promise - > { + public get firstNameInput() { return $('[data-testid="first-name"]') } /**Insert provided text to First Name input field*/ @@ -47,9 +38,7 @@ class ContactsPage extends Page { } /**[Selector] Last name input*/ - public get lastNameInput(): ChainablePromiseElement< - Promise - > { + public get lastNameInput() { return $('[data-testid="second-name"]') } @@ -60,9 +49,7 @@ class ContactsPage extends Page { } /**[Selector] Primary phone number input*/ - public get primaryPhoneNumberInput(): ChainablePromiseElement< - Promise - > { + public get primaryPhoneNumberInput() { return $('[data-testid="primary-number"]') } @@ -73,9 +60,7 @@ class ContactsPage extends Page { } /**[Selector] Secondary phone number input*/ - public get secondaryPhoneNumberInput(): ChainablePromiseElement< - Promise - > { + public get secondaryPhoneNumberInput() { return $('[data-testid="secondary-number"]') } @@ -85,9 +70,7 @@ class ContactsPage extends Page { await this.secondaryPhoneNumberInput.setValue(textValue) } /**[Selector] Adress first line input*/ - public get addressFirstLineInput(): ChainablePromiseElement< - Promise - > { + public get addressFirstLineInput() { return $('[data-testid="first-address-line"]') } @@ -98,9 +81,7 @@ class ContactsPage extends Page { } /**[Selector] Adress second line input*/ - public get addressSecondLineInput(): ChainablePromiseElement< - Promise - > { + public get addressSecondLineInput() { return $('[data-testid="second-address-line"]') } @@ -111,9 +92,7 @@ class ContactsPage extends Page { } /**[Selector] Close button on contact detail screen*/ - public get closeButton(): ChainablePromiseElement< - Promise - > { + public get closeButton() { return $('[data-testid="icon-Close"]') } @@ -123,22 +102,16 @@ class ContactsPage extends Page { await this.closeButton.click() } /**[Selector] add to favourites checkbox*/ - public get addToFavouritessCheckbox(): ChainablePromiseElement< - Promise - > { + public get addToFavouritessCheckbox() { return $('[name*="favourite"]') } /**[Selector] Cancel button on add/edit contact screen*/ - public get cancelButton(): ChainablePromiseElement< - Promise - > { + public get cancelButton() { return $("p*=Cancel") } /** [Selector] Save contact button*/ - public get saveContactButton(): ChainablePromiseElement< - Promise - > { + public get saveContactButton() { return $('[data-testid="save-button"]') } /** Click on Save contact button */ @@ -147,9 +120,7 @@ class ContactsPage extends Page { await this.saveContactButton.click() } - public get noContactsTextLabel(): ChainablePromiseElement< - Promise - > { + public get noContactsTextLabel() { return $('[data-testid="contact-list-no-result"]') } @@ -157,21 +128,15 @@ class ContactsPage extends Page { return $$('[data-testid="virtualized-contact-list-item-contact-row"]') } - public get singleContactRow(): ChainablePromiseElement< - Promise - > { + public get singleContactRow() { return $('[data-testid="virtualized-contact-list-item-contact-row"]') } - public get phoneNumberOnContactList(): ChainablePromiseElement< - Promise - > { + public get phoneNumberOnContactList() { return $('[data-testid="virtualized-contact-phone-number"]') } - public get optionsButtonOnContactList(): ChainablePromiseElement< - Promise - > { + public get optionsButtonOnContactList() { return $('[data-testid="icon-More"]') } async optionsButtonOnContactListClick() { @@ -179,69 +144,47 @@ class ContactsPage extends Page { await this.optionsButtonOnContactList.click() } - public get editContactOptionMenu(): ChainablePromiseElement< - Promise - > { + public get editContactOptionMenu() { return $('[data-testid="icon-Edit"]') } - public get exportAsVCardOptionMenu(): ChainablePromiseElement< - Promise - > { + public get exportAsVCardOptionMenu() { return $('[data-testid="icon-UploadDark"]') } - public get deleteContactOptionMenu(): ChainablePromiseElement< - Promise - > { + public get deleteContactOptionMenu() { return $('[data-testid="icon-Delete"]') } - public get nameOnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get nameOnContactDetailScreen() { return $('[data-testid="name"]') } - public get phoneNumber1OnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get phoneNumber1OnContactDetailScreen() { return $('[data-testid="primary-phone-input"]') } - public get phoneNumber2OnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get phoneNumber2OnContactDetailScreen() { return $('[data-testid="secondary-phone-input"]') } - public get addressOnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get addressOnContactDetailScreen() { return $('[data-testid="address-details"]') } - public get buttonDeleteOnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get buttonDeleteOnContactDetailScreen() { return $('[data-testid="icon-Delete"]') } - public get buttonExportOnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get buttonExportOnContactDetailScreen() { return $('[data-testid="icon-UploadDark"]') } - public get editButtonOnContactDetailScreen(): ChainablePromiseElement< - Promise - > { + public get editButtonOnContactDetailScreen() { return $('[data-testid="icon-Edit"]') } - public get checkboxSingleContact(): ChainablePromiseElement< - Promise - > { + public get checkboxSingleContact() { return $('[type="checkbox"]') } @@ -249,57 +192,39 @@ class ContactsPage extends Page { return $$('[type="checkbox"]') } - public get checkboxSelectAll(): ChainablePromiseElement< - Promise - > { + public get checkboxSelectAll() { return $('[data-testid="selection-manager"]').$('[type="checkbox"]') } - public get textSummaryOfContactsSelected(): ChainablePromiseElement< - Promise - > { + public get textSummaryOfContactsSelected() { return $('[data-testid="info"]') } - public get buttonDeleteSelectionManager(): ChainablePromiseElement< - Promise - > { + public get buttonDeleteSelectionManager() { return $("p*=Delete") } - public get inputHiddenVcfFile(): ChainablePromiseElement< - Promise - > { + public get inputHiddenVcfFile() { return $('[data-testid="file-input"]') } - public get buttonContinueWithGoogle(): ChainablePromiseElement< - Promise - > { + public get buttonContinueWithGoogle() { return $('[data-testid="google-button"]') } - public get buttonOutlookImport(): ChainablePromiseElement< - Promise - > { + public get buttonOutlookImport() { return $('[data-testid="outlook-button"]') } - public get buttonImportFromVCFFileImport(): ChainablePromiseElement< - Promise - > { + public get buttonImportFromVCFFileImport() { return $('[data-testid="icon-Upload"]') } - public get inputSearch(): ChainablePromiseElement< - Promise - > { + public get inputSearch() { return $('[data-testid="contact-input-select-input"]') } - public get dropDownSearchResultList(): ChainablePromiseElement< - Promise - > { + public get dropDownSearchResultList() { return $('[data-testid="input-select-list"]') } @@ -310,9 +235,7 @@ class ContactsPage extends Page { ) } - public get contactDetailsFavouritesIcon(): ChainablePromiseElement< - Promise - > { + public get contactDetailsFavouritesIcon() { return $('[data-testid="icon-Favourites"]') } } diff --git a/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts b/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts index ff1d6d1529..9dcfb00b17 100644 --- a/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts @@ -3,38 +3,27 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class HelpModalPage extends Page { /**[Selector] Modal close button */ - public get closeModalButton(): ChainablePromiseElement< - Promise - > { + public get closeModalButton() { return $('[data-testid="close-modal-button"]') } /**[Selector] Modal title */ - public get modalHeader(): ChainablePromiseElement< - Promise - > { + public get modalHeader() { return $('[data-testid="modal-header"]') } /**[Selector] Contact support email input */ - public get emailInput(): ChainablePromiseElement< - Promise - > { + public get emailInput() { return $('[data-testid="email-input"]') } /**[Selector] Contact support message input */ - public get descriptionInput(): ChainablePromiseElement< - Promise - > { + public get descriptionInput() { return $('[data-testid="description-input"]') } /**[Selector] Send button */ - public get sendButton(): ChainablePromiseElement< - Promise - > { + public get sendButton() { return $('[data-testid="submit-button"]') } @@ -43,26 +32,18 @@ class HelpModalPage extends Page { return $('[data-testid="file-list"]').$$('[data-testid="file-list-file"]') } /**[Selector] single attachment element */ - public get singleAttachment(): ChainablePromiseElement< - Promise - > { + public get singleAttachment() { return $('[data-testid="file-list-file"]') } /**[Selector] Success sent message modal */ - public get sentSuccessModal(): ChainablePromiseElement< - Promise - > { + public get sentSuccessModal() { return $('[data-testid="contact-support-modal-success"]') } /**[Selector] Close bottom button */ - public get closeBottomButton(): ChainablePromiseElement< - Promise - > { + public get closeBottomButton() { return $('[data-testid="close-bottom-button"]') } - public get invalidEmailTextElement(): ChainablePromiseElement< - Promise - > { + public get invalidEmailTextElement() { return $('//input[@data-testid="email-input"]/following-sibling::*[1]') } } diff --git a/apps/mudita-center-e2e/src/page-objects/help.page.ts b/apps/mudita-center-e2e/src/page-objects/help.page.ts index 38b7fdaf70..59106add62 100644 --- a/apps/mudita-center-e2e/src/page-objects/help.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help.page.ts @@ -3,7 +3,6 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class HelpPage extends Page { diff --git a/apps/mudita-center-e2e/src/page-objects/messages-browse-contacts-modal.page.ts b/apps/mudita-center-e2e/src/page-objects/messages-browse-contacts-modal.page.ts index 831ca34c8d..ec28d22c17 100644 --- a/apps/mudita-center-e2e/src/page-objects/messages-browse-contacts-modal.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/messages-browse-contacts-modal.page.ts @@ -3,39 +3,28 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import ModalPage from "./modal.page" class BrowseContactsModal extends ModalPage { - public get emptyContactList(): ChainablePromiseElement< - Promise - > { + public get emptyContactList() { return $('[data-testid="empty-content"]') } - public get searchInput(): ChainablePromiseElement< - Promise - > { + public get searchInput() { return $('[data-testid="contact-input-select-input"]') } - public get modalContactNameText(): ChainablePromiseElement< - Promise - > { + public get modalContactNameText() { return $( '[data-testid="contact-simple-list-phone-selection-item-avatar-column"]' ) } - public get modalContactPrimaryNumberText(): ChainablePromiseElement< - Promise - > { + public get modalContactPrimaryNumberText() { return $( '[data-testid="contact-simple-list-phone-selection-item-primary-phone-field"]' ) } - public get modalContactSecondaryNumberText(): ChainablePromiseElement< - Promise - > { + public get modalContactSecondaryNumberText() { return $( '[data-testid="contact-simple-list-phone-selection-item-secondary-phone-field"]' ) diff --git a/apps/mudita-center-e2e/src/page-objects/messages-conversation.page.ts b/apps/mudita-center-e2e/src/page-objects/messages-conversation.page.ts index 50bb470e9c..ca9852fdf3 100644 --- a/apps/mudita-center-e2e/src/page-objects/messages-conversation.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/messages-conversation.page.ts @@ -3,90 +3,65 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class MessagesConversationPage extends Page { /** [Selector] NEW MESSAGE button selector */ - public get newMessageButton(): ChainablePromiseElement< - Promise - > { + public get newMessageButton() { return $('[data-testid="message-panel-new-message-button"]') } /** [Selector] Search Contacts input field (visible after NEW MESSAGE button is clicked) */ - public get searchContactsInput(): ChainablePromiseElement< - Promise - > { + public get searchContactsInput() { return $('[data-testid="receiver-input-select-input"]') } /** [Selector] Input field for message text */ - public get messageTextInput(): ChainablePromiseElement< - Promise - > { + public get messageTextInput() { return $('[data-testid="thread-details-text-area-input"]') } /** [Selector] Send message button (visible after message text is entered) */ - public get sendMessageButton(): ChainablePromiseElement< - Promise - > { + public get sendMessageButton() { return $('[data-testid="thread-details-text-area-send-button"]') } /** [Selector] Message not sent icon displayed next to the message */ - public get messageNotSentIcon(): ChainablePromiseElement< - Promise - > { + public get messageNotSentIcon() { return $('[data-testid="message-bubble-not-send-icon"]') } /** [Selector] Delete button visible on open thread (thread details) screen*/ - public get threadDetailScreenDeleteButton(): ChainablePromiseElement< - Promise - > { + public get threadDetailScreenDeleteButton() { return $('[data-testid="right-sidebar-delete-button"]') } /** [Selector] Add contact button visible on open thread (thread details) screen*/ - public get threadDetailScreenAddContactButton(): ChainablePromiseElement< - Promise - > { + public get threadDetailScreenAddContactButton() { return $('[data-testid="right-sidebar-contact-button"]') } /** [Selector] Close button visible on open thread (thread details) screen*/ - public get threadDetailScreenCloseButton(): ChainablePromiseElement< - Promise - > { + public get threadDetailScreenCloseButton() { return $('[data-testid="table-sidebar-close"]') } /** [Selector] Mark as unread button visible on open thread (thread details) screen*/ - public get threadDetailScreenMarkAsUnreadButton(): ChainablePromiseElement< - Promise - > { + public get threadDetailScreenMarkAsUnreadButton() { return $('[data-testid="right-sidebar-mark-as-unread-button"]') } /** [Selector] Single sending status */ - public get sendingStatusIcon(): ChainablePromiseElement< - Promise - > { + public get sendingStatusIcon() { return $('[data-testid="dot"]') } /** [Selector] Single message container */ - public get messageContainer(): ChainablePromiseElement< - Promise - > { + public get messageContainer() { return $('[data-testid="message-bubble-container"]') } /** [Selector] Single message content element*/ - public get messageContent(): ChainablePromiseElement< - Promise - > { + public get messageContent() { return $('[data-testid="message-bubble-message-content"]') } /** Hover over Message content element to display options button*/ @@ -96,18 +71,14 @@ class MessagesConversationPage extends Page { } /** [Selector] Single message options button (...) visible on hover over message. Same purpose as messageDropdownIcon */ - public get messageDropdownButton(): ChainablePromiseElement< - Promise - > { + public get messageDropdownButton() { return this.messageContainer.$( '[data-testid="message-bubble-dropdown-action-button"]' ) } /** [Selector] Single message options icon (...) visible on hover over message*/ - public get messageDropdownIcon(): ChainablePromiseElement< - Promise - > { + public get messageDropdownIcon() { return this.messageContainer.$('[data-testid="icon-More"]') } @@ -118,16 +89,12 @@ class MessagesConversationPage extends Page { } /** Dropdown element displayed after message options button/icon is clicked*/ - public get messageDropdown(): ChainablePromiseElement< - Promise - > { + public get messageDropdown() { return $('[data-testid="dropdown"]') } /** [Selector] Delete message button on message dropodown list */ - public get messageDropdownDeleteButton(): ChainablePromiseElement< - Promise - > { + public get messageDropdownDeleteButton() { return this.messageDropdown.$( '[data-testid="message-bubble-delete-message-button"]' ) @@ -182,37 +149,27 @@ class MessagesConversationPage extends Page { } /** [Selector] Thread details top level element*/ - public get threadDetailsContainer(): ChainablePromiseElement< - Promise - > { + public get threadDetailsContainer() { return $('[data-testid="messages-thread-details"]') } /** [Selector] Browse contacts button*/ - public get browseContactsButton(): ChainablePromiseElement< - Promise - > { + public get browseContactsButton() { return $('[data-testid="new-message-form-browse-contacts"]') } /** [Selector] Conversation recipient name text*/ - public get conversationRecipientNameText(): ChainablePromiseElement< - Promise - > { + public get conversationRecipientNameText() { return $('[data-testid="sidebar-fullname"]') } /** [Selector] Conversation recipient number text*/ - public get conversationRecipientPhoneText(): ChainablePromiseElement< - Promise - > { + public get conversationRecipientPhoneText() { return $('[data-testid="sidebar-phone-number"]') } /** [Selector] Contact search result item*/ - public get contactSearchResultItem(): ChainablePromiseElement< - Promise - > { + public get contactSearchResultItem() { return $('[data-testid="input-select-list-item"]') } /** [Selector] Returns list of multiple elements - contact icon for threads with matching contact in phonebok */ @@ -220,9 +177,7 @@ class MessagesConversationPage extends Page { return this.messageContent.$(`strong*=${text}`) } /** [Selector] Delete message button on message dropodown list */ - public get messageDropdownResendButton(): ChainablePromiseElement< - Promise - > { + public get messageDropdownResendButton() { return this.messageDropdown.$( '[data-testid="message-bubble-resend-message-button"]' ) diff --git a/apps/mudita-center-e2e/src/page-objects/messages-templates.page.ts b/apps/mudita-center-e2e/src/page-objects/messages-templates.page.ts index e07ea5ff4f..ce3fe5c377 100644 --- a/apps/mudita-center-e2e/src/page-objects/messages-templates.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/messages-templates.page.ts @@ -3,25 +3,18 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import ModalPage from "./modal.page" class TemplatesPage extends ModalPage { - public get newTemplateButton(): ChainablePromiseElement< - Promise - > { + public get newTemplateButton() { return $('[data-testid="templates-panel-button"]') } - public get templateTextInputForm(): ChainablePromiseElement< - Promise - > { + public get templateTextInputForm() { return $('[data-testid="template-form-text-filed"]') } - public get saveButton(): ChainablePromiseElement< - Promise - > { + public get saveButton() { return $('[data-testid="template-form-save-button"]') } @@ -31,15 +24,11 @@ class TemplatesPage extends ModalPage { await this.templateTextInputForm.setValue(inputText) } - public get templateCheckbox(): ChainablePromiseElement< - Promise - > { + public get templateCheckbox() { return $('[data-testid="template-checkbox"]') } - public get selectAllTemplatesCheckbox(): ChainablePromiseElement< - Promise - > { + public get selectAllTemplatesCheckbox() { return $('[data-testid="checkbox"]') } diff --git a/apps/mudita-center-e2e/src/page-objects/messages.page.ts b/apps/mudita-center-e2e/src/page-objects/messages.page.ts index b35a16aa9a..1131afbf6d 100644 --- a/apps/mudita-center-e2e/src/page-objects/messages.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/messages.page.ts @@ -3,46 +3,35 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" const backspaceKey = "\ue003" class MessagesPage extends Page { /** [Selector] NEW MESSAGE button selector */ - public get newMessageButton(): ChainablePromiseElement< - Promise - > { + public get newMessageButton() { return $('[data-testid="message-panel-new-message-button"]') } /** [Selector] Message not sent icon displayed on the thread list */ - public get messageNotSentThreadIcon(): ChainablePromiseElement< - Promise - > { + public get messageNotSentThreadIcon() { return $('[data-testid="thread-not-send-message-icon"]') } /** Empty thread list screen: * You don't have any messages yet * Don’t hesitate - let your friends know you’re thinking about them */ - public get threadScreenEmptyList(): ChainablePromiseElement< - Promise - > { + public get threadScreenEmptyList() { return $('[data-testid="messages-empty-thread-list-state"]') } /** [Selector] Thread options icon (...) */ - public get threadDropdownIcon(): ChainablePromiseElement< - Promise - > { + public get threadDropdownIcon() { return $('[data-testid="icon-More"]') } /** [Selector] Thread options icon (...) */ - public get threadDropdownButton(): ChainablePromiseElement< - Promise - > { + public get threadDropdownButton() { return $('[data-testid="thread-row-toggler"]') } /** Click Thread options button*/ @@ -52,9 +41,7 @@ class MessagesPage extends Page { } /** [Selector] Delete conversation button on therad dropodown list */ - public get threadDropdownDeleteButton(): ChainablePromiseElement< - Promise - > { + public get threadDropdownDeleteButton() { return $('[data-testid="dropdown-delete"]') } @@ -77,9 +64,7 @@ class MessagesPage extends Page { } /** [Selector] Thread row element */ - public get threadRow(): ChainablePromiseElement< - Promise - > { + public get threadRow() { return $('[data-testid="message-row"]') } @@ -90,9 +75,7 @@ class MessagesPage extends Page { } /** [Selector] Thread checkbox*/ - public get threadCheckbox(): ChainablePromiseElement< - Promise - > { + public get threadCheckbox() { return $('[data-testid="checkbox"]') } @@ -103,9 +86,7 @@ class MessagesPage extends Page { } /** [Selector] Delete button available when selection manager is active */ - public get selectionManagerIconDelete(): ChainablePromiseElement< - Promise - > { + public get selectionManagerIconDelete() { return $('[data-testid="icon-Delete"]') } @@ -116,16 +97,12 @@ class MessagesPage extends Page { } /** [Selector] Thread details top level element*/ - public get threadDetailsContainer(): ChainablePromiseElement< - Promise - > { + public get threadDetailsContainer() { return $('[data-testid="messages-thread-details"]') } /** [Selector] Mark as read on thread dropdown */ - public get threadDropdownMarkAsReadButton(): ChainablePromiseElement< - Promise - > { + public get threadDropdownMarkAsReadButton() { return $('[data-testid="dropdown-mark-as-read"]') } @@ -138,9 +115,7 @@ class MessagesPage extends Page { } /** [Selector] Text of dropdownMarkAsReadButton, depending on the message status can be 'Mark as read' or 'Mark as unread' */ - public get textOptionMarkAsReadDropdown(): ChainablePromiseElement< - Promise - > { + public get textOptionMarkAsReadDropdown() { return this.threadDropdownMarkAsReadButton.$("p") } /** Returns list of last message text displayed on the conversation list and true/false depending on message unread/read status*/ @@ -172,9 +147,7 @@ class MessagesPage extends Page { return result } /** [Selector] Messages search input */ - public get searchInput(): ChainablePromiseElement< - Promise - > { + public get searchInput() { return $('[data-testid="input-search"]') } @@ -190,21 +163,15 @@ class MessagesPage extends Page { } /** [Selector] Search result overlay list */ - public get searchResultsOverlayList(): ChainablePromiseElement< - Promise - > { + public get searchResultsOverlayList() { return $('[data-testid="input-select-list"]') } /** [Selector] empty search results overlay list */ - public get emptySearchResultsOverlayList(): ChainablePromiseElement< - Promise - > { + public get emptySearchResultsOverlayList() { return this.searchResultsOverlayList.$("li*=No results found") } /** [Selector] See all button on search results overlay */ - public get seeAllSearchResultsButton(): ChainablePromiseElement< - Promise - > { + public get seeAllSearchResultsButton() { return $("button*=See all") } @@ -218,24 +185,18 @@ class MessagesPage extends Page { return $$('[data-testid="avatar-text"]') } /** [Selector] Selection manager- select all checkbox */ - public get selectAllCheckbox(): ChainablePromiseElement< - Promise - > { + public get selectAllCheckbox() { return $('[data-testid="message-panel-selection-manager"]').$( '[type="checkbox"]' ) } /** [Selector] Selection manager- select all checkbox */ - public get selectionManagerDeleteButton(): ChainablePromiseElement< - Promise - > { + public get selectionManagerDeleteButton() { return $('[data-testid="message-panel-selection-manager"]').$("p*=Delete") } /** [Selector] Search results for ' ' text displayed above the thread list*/ - public get searchResultsForText(): ChainablePromiseElement< - Promise - > { + public get searchResultsForText() { return $("h4*=Search results") } @@ -268,16 +229,12 @@ class MessagesPage extends Page { } /** [Selector] Element containing contact number/name displayed on Search results for '' list */ - public get nameFieldOnSearchResultsConversationList(): ChainablePromiseElement< - Promise - > { + public get nameFieldOnSearchResultsConversationList() { return $('[data-testid="name-field"]') } /** [Selector] Templates tab */ - public get templatesTab(): ChainablePromiseElement< - Promise - > { + public get templatesTab() { return $("p*=Templates") } } diff --git a/apps/mudita-center-e2e/src/page-objects/modal-backup-restore.page.ts b/apps/mudita-center-e2e/src/page-objects/modal-backup-restore.page.ts index 24da798641..eb729c8b94 100644 --- a/apps/mudita-center-e2e/src/page-objects/modal-backup-restore.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/modal-backup-restore.page.ts @@ -3,19 +3,14 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class ModalBackupRestorePage extends Page { - public get failModalIcon(): ChainablePromiseElement< - Promise - > { + public get failModalIcon() { return $('[data-testid="icon-Fail"]') } - public get checkCircleIcon(): ChainablePromiseElement< - Promise - > { + public get checkCircleIcon() { return $('[data-testid="icon-CheckCircle"]') } @@ -23,45 +18,31 @@ class ModalBackupRestorePage extends Page { return $$('[data-testid="restore-available-backup-modal-body-row"]') } - public get restoreButton(): ChainablePromiseElement< - Promise - > { + public get restoreButton() { return $('[data-testid="modal-action-button"]*=Restore') } - public get restorePasswordInput(): ChainablePromiseElement< - Promise - > { + public get restorePasswordInput() { return $('[name="secretKey"]') } - public get restoreSubmitButton(): ChainablePromiseElement< - Promise - > { + public get restoreSubmitButton() { return $('[type="submit"]*=Confirm') } //BACKUP modal objects - public get createBackupModalButton(): ChainablePromiseElement< - Promise - > { + public get createBackupModalButton() { return $('[data-testid="modal-action-button"]') } - public get backupPasswordFirstInput(): ChainablePromiseElement< - Promise - > { + public get backupPasswordFirstInput() { return $('[data-testid="backup-first-input"]') } - public get backupPasswordSecondInput(): ChainablePromiseElement< - Promise - > { + public get backupPasswordSecondInput() { return $('[data-testid="backup-second-input"]') } - public get backupSubmitButton(): ChainablePromiseElement< - Promise - > { + public get backupSubmitButton() { return $('[data-testid="backup-submit-button"]') } } diff --git a/apps/mudita-center-e2e/src/page-objects/modal-contacts.page.ts b/apps/mudita-center-e2e/src/page-objects/modal-contacts.page.ts index 0883164726..4e3a30733a 100644 --- a/apps/mudita-center-e2e/src/page-objects/modal-contacts.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/modal-contacts.page.ts @@ -3,13 +3,10 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class ModalContacts extends Page { - public get iconClose(): ChainablePromiseElement< - Promise - > { + public get iconClose() { return $('[data-testid="icon-Close"]') } async buttonCloseClick() { @@ -21,27 +18,19 @@ class ModalContacts extends Page { } } - public get modalContent(): ChainablePromiseElement< - Promise - > { + public get modalContent() { return $('[data-testid="delete-modal-content"]') } - public get textOnModal(): ChainablePromiseElement< - Promise - > { + public get textOnModal() { return $('[data-testid="delete-modal-content"]').$("p") } - public get iconDelete(): ChainablePromiseElement< - Promise - > { + public get iconDelete() { return $('[data-testid="icon-DeleteBig"]') } - public get buttonConfirmDelete(): ChainablePromiseElement< - Promise - > { + public get buttonConfirmDelete() { return $('[data-testid="modal-action-button"]*=Delete') } async buttonConfirmDeleteClick() { @@ -49,28 +38,22 @@ class ModalContacts extends Page { await this.buttonConfirmDelete.click() } - public get buttonCancel(): ChainablePromiseElement< - Promise - > { + public get buttonCancel() { return $('[data-testid="close-bottom-button"]') } async cancelModalButtonClick() { await this.buttonCancel.click() } - public get buttonImport(): ChainablePromiseElement< - Promise - > { + public get buttonImport() { return $('[data-testid="modal-action-button"]*=Import') } - public get textSavingCompleted(): ChainablePromiseElement< - Promise - > { + public get textSavingCompleted() { return $("h4*=Saving completed") } - public get buttonOK(): ChainablePromiseElement> { + public get buttonOK() { return $('[data-testid="modal-action-button"]*=OK') } } diff --git a/apps/mudita-center-e2e/src/page-objects/modal-general.page.ts b/apps/mudita-center-e2e/src/page-objects/modal-general.page.ts index b51f2a4494..35a106955a 100644 --- a/apps/mudita-center-e2e/src/page-objects/modal-general.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/modal-general.page.ts @@ -3,13 +3,10 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class ModalGeneralPage extends Page { - public get closeIcon(): ChainablePromiseElement< - Promise - > { + public get closeIcon() { return $('[data-testid="icon-Close"]') } async closeModalButtonClick() { @@ -20,15 +17,11 @@ class ModalGeneralPage extends Page { console.log(error) } } - public get modalHeader(): ChainablePromiseElement< - Promise - > { + public get modalHeader() { return $('[data-testid="modal-header"]') } - public get updateAvailableModalCloseButton(): ChainablePromiseElement< - Promise - > { + public get updateAvailableModalCloseButton() { return this.modalHeader.$('[data-testid="icon-Close"]') } @@ -42,9 +35,7 @@ class ModalGeneralPage extends Page { console.log(error) } } - public get closeModalBackgroundUpdateAvailableFailed(): ChainablePromiseElement< - Promise - > { + public get closeModalBackgroundUpdateAvailableFailed() { return $('[data-testid="update-os-flow-check-for-update-failed-modal"]').$( '[data-testid="icon-Close"]' ) @@ -61,15 +52,11 @@ class ModalGeneralPage extends Page { } } - public get updateNotAvailableModal(): ChainablePromiseElement< - Promise - > { + public get updateNotAvailableModal() { return $('[data-testid="update-os-flow-update-not-available-modal"]') } - public get closeModalButton(): ChainablePromiseElement< - Promise - > { + public get closeModalButton() { return $('[data-testid="close-modal-button"]') } diff --git a/apps/mudita-center-e2e/src/page-objects/modal-messages.page.ts b/apps/mudita-center-e2e/src/page-objects/modal-messages.page.ts index 47b912ea56..559ee6de6a 100644 --- a/apps/mudita-center-e2e/src/page-objects/modal-messages.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/modal-messages.page.ts @@ -3,13 +3,10 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class ModalMessages extends Page { - public get iconClose(): ChainablePromiseElement< - Promise - > { + public get iconClose() { return $('[data-testid="icon-Close"]') } async buttonCloseClick() { @@ -21,9 +18,7 @@ class ModalMessages extends Page { } } - public get confirmDeleteButton(): ChainablePromiseElement< - Promise - > { + public get confirmDeleteButton() { return $('[data-testid="modal-action-button"]*=Delete') } async clickConfirmDeleteButton() { diff --git a/apps/mudita-center-e2e/src/page-objects/news.page.ts b/apps/mudita-center-e2e/src/page-objects/news.page.ts index 5b91e12e42..a85e660248 100644 --- a/apps/mudita-center-e2e/src/page-objects/news.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/news.page.ts @@ -3,7 +3,6 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class NewsPage extends Page { diff --git a/apps/mudita-center-e2e/src/page-objects/tabs.page.ts b/apps/mudita-center-e2e/src/page-objects/tabs.page.ts index 795cb7a1d1..1bdd187478 100644 --- a/apps/mudita-center-e2e/src/page-objects/tabs.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/tabs.page.ts @@ -3,7 +3,6 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { ChainablePromiseElement } from "webdriverio" import Page from "./page" class NavigationTabs extends Page { diff --git a/apps/mudita-center-e2e/src/specs/stress-tests/connected-devices-stress-test.ts b/apps/mudita-center-e2e/src/specs/stress-tests/connected-devices-stress-test.ts index 8fdb23453c..4d2c6b8e90 100644 --- a/apps/mudita-center-e2e/src/specs/stress-tests/connected-devices-stress-test.ts +++ b/apps/mudita-center-e2e/src/specs/stress-tests/connected-devices-stress-test.ts @@ -70,8 +70,11 @@ describe("Kompakt switching devices", () => { "Select a device to continue" ) - const availableDevices = selectDevicePage.availableDevices - await expect(availableDevices).toBeDisplayed() + const availableDevices = await selectDevicePage.availableDevices + + for (const device of availableDevices) { + await expect(device).toBeDisplayed(); + } const firstDeviceOnSelectModal = await selectDevicePage.getDeviceOnSelectModal(1) diff --git a/apps/mudita-center-e2e/tsconfig.json b/apps/mudita-center-e2e/tsconfig.json index aae4540887..865837d96d 100644 --- a/apps/mudita-center-e2e/tsconfig.json +++ b/apps/mudita-center-e2e/tsconfig.json @@ -3,15 +3,16 @@ "compilerOptions": { "types": [ "node", - "webdriverio/async", + "@wdio/globals/types", "@wdio/mocha-framework", "expect-webdriverio" ], "resolveJsonModule": true, "esModuleInterop": true, "target": "es5", - "outDir": "./dist" + "outDir": "./dist", + "typeRoots": ["./node_modules/@types", "./typings"] }, - "include": ["src/**/*"], + "include": ["src/**/*", "./wdio.conf.ts"], "exclude": ["node_modules"] } diff --git a/apps/mudita-center-e2e/wdio.conf.ts b/apps/mudita-center-e2e/wdio.conf.ts index 2da0d93030..2c8ab5a6c3 100644 --- a/apps/mudita-center-e2e/wdio.conf.ts +++ b/apps/mudita-center-e2e/wdio.conf.ts @@ -4,6 +4,7 @@ */ import type { Options } from "@wdio/types" +import path from "path" import * as dotenv from "dotenv" import { TestFilesPaths, toRelativePath } from "./src/test-filenames" @@ -173,6 +174,9 @@ export const config: Options.Testrunner = { binary: process.env.TEST_BINARY_PATH, args: [], }, + 'wdio:chromedriverOptions': { + binary: path.resolve(__dirname, '..', '..', 'node_modules', 'chromedriver', 'bin', 'chromedriver') + } // If outputDir is provided WebdriverIO can capture driver session logs // it is possible to configure which logTypes to include/exclude. // excludeDriverLogs: ['*'], // pass '*' to exclude all driver session logs diff --git a/package-lock.json b/package-lock.json index 8f6bcf7342..10ca251a71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "@contentful/rich-text-plain-text-renderer": "^16.2.6", "@orama/orama": "^2.0.22", "@vscode/sudo-prompt": "^9.3.1", + "@wdio/json-reporter": "^8.40.3", "crypto-js": "^4.2.0", "js-crc": "^0.2.0", "jschardet": "^3.1.2", @@ -69,6 +70,7 @@ "@types/elasticlunr": "^0.9.5", "@types/electron-devtools-installer": "^2.2.2", "@types/electron-localshortcut": "^3.1.0", + "@types/fs-extra": "^11.0.4", "@types/history": "^4.7.9", "@types/jest": "^29.5.6", "@types/js-crc": "^0.2.3", @@ -107,12 +109,12 @@ "@types/webpack-env": "^1.17.0", "@typescript-eslint/eslint-plugin": "^ 6.7.4", "@typescript-eslint/parser": "^ 6.7.4", - "@wdio/cli": "^7.16.13", - "@wdio/local-runner": "^7.16.13", - "@wdio/mocha-framework": "^7.16.13", - "@wdio/reporter": "^7.16.14", - "@wdio/spec-reporter": "^7.16.14", - "@wdio/types": "^8.31.0", + "@wdio/cli": "^8.40.5", + "@wdio/local-runner": "^8.40.5", + "@wdio/mocha-framework": "^8.40.3", + "@wdio/reporter": "^8.40.3", + "@wdio/spec-reporter": "^8.40.3", + "@wdio/types": "^8.40.3", "archiver": "^5.3.1", "async-mutex": "^0.4.0", "axios": "^0.27.2", @@ -230,7 +232,6 @@ "uuid": "^9.0.1", "vcf": "^2.1.2", "wdio-chromedriver-service": "^8.1.1", - "wdio-json-reporter": "^3.0.0", "wdio-wait-for": "^2.2.1", "webpack": "^5.74.0", "webpack-cli": "^4.10.0", @@ -4558,9 +4559,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "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 }, "node_modules/@jridgewell/trace-mapping": { @@ -4585,6 +4586,18 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/@malept/cross-spawn-promise": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", @@ -5708,6 +5721,68 @@ } } }, + "node_modules/@promptbook/utils": { + "version": "0.70.0-1", + "resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.70.0-1.tgz", + "integrity": "sha512-qd2lLRRN+sE6UuNMi2tEeUUeb4zmXnxY5EMdfHVXNE+bqBDpUC7/aEfXgA3jnUXEr+xFjQ8PTFQgWvBMaKvw0g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://buymeacoffee.com/hejny" + }, + { + "type": "github", + "url": "https://github.com/webgptorg/promptbook/blob/main/README.md#%EF%B8%8F-contributing" + } + ], + "dependencies": { + "spacetrim": "0.11.39" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", + "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", + "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.1", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/@radix-ui/number": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz", @@ -9432,6 +9507,12 @@ "node": ">= 10" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -9606,28 +9687,12 @@ "integrity": "sha512-Rf3/lB9WkDfIL9eEKaSYKc+1L/rNVYBjThk22JTqQw0YozXarX8YljFAz+HCoC6h4B4KwCMsBPZHaFezwT4BNA==", "dev": true }, - "node_modules/@types/diff": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.0.9.tgz", - "integrity": "sha512-RWVEhh/zGXpAVF/ZChwNnv7r4rvqzJ7lYNSmZSVTxjV0PBLf6Qu7RNg+SUtkpzxmiNkjCx0Xn2tPp7FIkshJwQ==", - "dev": true - }, "node_modules/@types/doctrine": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.3.tgz", "integrity": "sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==", "dev": true }, - "node_modules/@types/easy-table": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/easy-table/-/easy-table-1.2.0.tgz", - "integrity": "sha512-gVQkR2G/q6UK3wQT+waY9tCrbFauzMoBfJpMxHSuemHLQ8HpHdUIQ9YyRwYMfNX4CfoAoj/eJATyECGkFr65Pg==", - "deprecated": "This is a stub types definition. easy-table provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "easy-table": "*" - } - }, "node_modules/@types/ejs": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", @@ -9811,16 +9876,6 @@ "@types/node": "*" } }, - "node_modules/@types/inquirer": { - "version": "8.2.10", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.10.tgz", - "integrity": "sha512-IdD5NmHyVjWM8SHWo/kPBgtzXatwPkfwzyP3fN1jF2g9BWt5WO+8hL2F4o2GKIYsU40PpqeevuUWvkS/roXJkA==", - "dev": true, - "dependencies": { - "@types/through": "*", - "rxjs": "^7.2.0" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -9934,33 +9989,6 @@ "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", "dev": true }, - "node_modules/@types/lodash.flattendeep": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/@types/lodash.flattendeep/-/lodash.flattendeep-4.4.9.tgz", - "integrity": "sha512-Oacs/ZMuMvVWkhMqvj+Spad457Beln5pnkauif+6s65fE2cSL7J7NoMfwkxjuQsOsr4DUCDH/iDbmuZo81Nypw==", - "dev": true, - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/lodash.pickby": { - "version": "4.6.9", - "resolved": "https://registry.npmjs.org/@types/lodash.pickby/-/lodash.pickby-4.6.9.tgz", - "integrity": "sha512-SPI248FYnyd3jOxDeJq2vX2UKQnDzqacuqdeOVqwE1MPSk8gN8TA3FcHSMQWLlpBnuHgXvgKInvywbOFbidpJA==", - "dev": true, - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/lodash.union": { - "version": "4.6.9", - "resolved": "https://registry.npmjs.org/@types/lodash.union/-/lodash.union-4.6.9.tgz", - "integrity": "sha512-l/GEj9Xp2DptsfFYZ1JUczg6W/6JGbbDi0mVK8urg8XLUMguNJ2L1ya0QJzMctrtlP9+t5lfyL4QLF6P9/6ssQ==", - "dev": true, - "dependencies": { - "@types/lodash": "*" - } - }, "node_modules/@types/mdast": { "version": "3.0.15", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", @@ -10060,12 +10088,6 @@ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, - "node_modules/@types/object-inspect": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/@types/object-inspect/-/object-inspect-1.8.4.tgz", - "integrity": "sha512-2yh72JxmDney1h7LQvkyO8p8FOmNMQXGs8HjuXS3SXvE/dLydLLjBqKCdHqcTUo66CQVHfn7yFR680bvi9jlVw==", - "dev": true - }, "node_modules/@types/papaparse": { "version": "5.3.14", "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", @@ -10257,15 +10279,6 @@ "@types/node": "*" } }, - "node_modules/@types/recursive-readdir": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.4.tgz", - "integrity": "sha512-84REEGT3lcgopvpkmGApzmU5UEG0valme5rQS/KGiguTkJ70/Au8UYZTyrzoZnY9svuX9351+1uvrRPzWDD/uw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/redux-logger": { "version": "3.0.11", "resolved": "https://registry.npmjs.org/@types/redux-logger/-/redux-logger-3.0.11.tgz", @@ -10390,15 +10403,6 @@ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, - "node_modules/@types/stream-buffers": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.7.tgz", - "integrity": "sha512-azOCy05sXVXrO+qklf0c/B07H/oHaIuDDAiHPVwlk3A9Ek+ksHyTeMajLZl3r76FxpPpxem//4Te61G1iW3Giw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/styled-components": { "version": "5.1.34", "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz", @@ -10410,12 +10414,6 @@ "csstype": "^3.0.2" } }, - "node_modules/@types/supports-color": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.3.tgz", - "integrity": "sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==", - "dev": true - }, "node_modules/@types/tar-stream": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-2.2.3.tgz", @@ -10431,21 +10429,6 @@ "integrity": "sha512-0vQ4fz9TTM4bCdllYWEJ2JHBUXR9xqPtc70dJ7BMRDVfvZyYdrgey3nP5RRcVj+qAgnHJM8r9fvgrfnPMxdnhA==", "dev": true }, - "node_modules/@types/through": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", - "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/tmp": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", - "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==", - "dev": true - }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -10763,185 +10746,252 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.0.tgz", + "integrity": "sha512-7sxf2F3DNYatgmzXXcTh6cq+/fxwB47RIQqZJFoSH883wnVAoccSRT6g+dTKemUBo8Q5N4OYYj1EBXLuRKvp3Q==", + "dev": true, + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.0.tgz", + "integrity": "sha512-x69CygGMzt9VCO283K2/FYQ+nBrOj66OTKpsPykjCR4Ac3lLV+m85hj9reaIGmjBSsKzVvbxWmjWE3kF5ha3uQ==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.0", + "magic-string": "^0.30.11", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@vscode/sudo-prompt": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/@vscode/sudo-prompt/-/sudo-prompt-9.3.1.tgz", "integrity": "sha512-9ORTwwS74VaTn38tNbQhsA5U44zkJfcb0BdTSyyG6frP4e8KMtHuTXYmwefe5dpL8XB1aGSIVTaLjD3BbWb5iA==" }, "node_modules/@wdio/cli": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-7.33.0.tgz", - "integrity": "sha512-S5Iy4AVcbcJDMhAP4k/Yf18mKma9NGFM8A5bafcGRpFlIj97rpnb0/cpmJVVEr4v/wr3XCu0k38ooJw0B/D3nw==", - "dev": true, - "dependencies": { - "@types/ejs": "^3.0.5", - "@types/fs-extra": "^11.0.1", - "@types/inquirer": "^8.1.2", - "@types/lodash.flattendeep": "^4.4.6", - "@types/lodash.pickby": "^4.6.6", - "@types/lodash.union": "^4.6.6", - "@types/node": "^18.0.0", - "@types/recursive-readdir": "^2.2.0", - "@wdio/config": "7.33.0", - "@wdio/logger": "7.26.0", - "@wdio/protocols": "7.27.0", - "@wdio/types": "7.33.0", - "@wdio/utils": "7.33.0", + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.40.5.tgz", + "integrity": "sha512-DtWbZnC6q5tv7TZpXD+lRno5eRa3LIysfvofnEwatMI6fibdLMnh6xJmTwzcDXhET965n+RUEQ1vnXcEscJ3jA==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0", + "@vitest/snapshot": "^2.0.4", + "@wdio/config": "8.40.3", + "@wdio/globals": "8.40.5", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", "async-exit-hook": "^2.0.1", - "chalk": "^4.0.0", - "chokidar": "^3.0.0", - "cli-spinners": "^2.1.0", - "ejs": "^3.0.1", - "fs-extra": "^11.1.1", - "inquirer": "8.2.4", + "chalk": "^5.2.0", + "chokidar": "^3.5.3", + "cli-spinners": "^2.9.0", + "dotenv": "^16.3.1", + "ejs": "^3.1.9", + "execa": "^8.0.1", + "import-meta-resolve": "^4.0.0", + "inquirer": "9.2.12", "lodash.flattendeep": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.union": "^4.6.0", - "mkdirp": "^3.0.0", - "recursive-readdir": "^2.2.2", - "webdriverio": "7.33.0", - "yargs": "^17.0.0", - "yarn-install": "^1.0.0" + "read-pkg-up": "10.0.0", + "recursive-readdir": "^2.2.3", + "webdriverio": "8.40.5", + "yargs": "^17.7.2" }, "bin": { "wdio": "bin/wdio.js" }, "engines": { - "node": ">=12.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/cli/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "dev": true, - "dependencies": { - "@types/node": "^18.0.0", - "got": "^11.8.1" - }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "^4.6.2" + "node": ">=14.16" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@wdio/cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@wdio/cli/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "defer-to-connect": "^2.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=14.16" } }, - "node_modules/@wdio/cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@wdio/cli/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/cli/node_modules/@types/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/cli/node_modules/@wdio/config": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.3.tgz", + "integrity": "sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==", + "dev": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "node_modules/@wdio/cli/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=14.14" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@wdio/cli/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/@wdio/repl": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.40.3.tgz", + "integrity": "sha512-mWEiBbaC7CgxvSd2/ozpbZWebnRIc8KRu/J81Hlw/txUWio27S7IpXBlZGVvhEsNzq0+cuxB/8gDkkXvMPbesw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@types/node": "^22.2.0" }, "engines": { - "node": ">=8" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/cli/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/cli/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", "dev": true, - "optional": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=4.2.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/config": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.33.0.tgz", - "integrity": "sha512-SaCZNKrDtBghf7ujyaxTiU4pBW+1Kms32shSoXpJ/wFop6/MiA7nb19qpUPoJtEDw5/NOKevUKz8nBMBXphiew==", + "node_modules/@wdio/cli/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@wdio/cli/node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, "dependencies": { - "@types/glob": "^8.1.0", - "@wdio/logger": "7.26.0", - "@wdio/types": "7.33.0", - "@wdio/utils": "7.33.0", - "deepmerge": "^4.0.0", - "glob": "^8.0.3" + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" }, "engines": { - "node": ">=12.0.0" + "node": ">= 14" } }, - "node_modules/@wdio/config/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/cli/node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, "dependencies": { - "@types/node": "^18.0.0", - "got": "^11.8.1" + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "^4.6.2" + "node": ">= 14" + } + }, + "node_modules/@wdio/cli/node_modules/archiver-utils/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/config/node_modules/brace-expansion": { + "node_modules/@wdio/cli/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", @@ -10950,486 +11000,3448 @@ "balanced-match": "^1.0.0" } }, - "node_modules/@wdio/config/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "node_modules/@wdio/cli/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "node_modules/@wdio/config/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/@wdio/cli/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, "engines": { - "node": ">=10" + "node": ">=8.0.0" } }, - "node_modules/@wdio/config/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/cli/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", "dev": true, - "optional": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, "engines": { - "node": ">=4.2.0" + "node": ">=14.16" } }, - "node_modules/@wdio/local-runner": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-7.33.0.tgz", - "integrity": "sha512-oZLLyOizlX2mV3FIxRLWgN0J2sDL+6LhC71CwFxcV8iVjXvp16my9jbKrgtkIgdo1BsaWIqq+tZlCr9e9NUUjA==", + "node_modules/@wdio/cli/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dev": true, "dependencies": { - "@types/stream-buffers": "^3.0.3", - "@wdio/logger": "7.26.0", - "@wdio/repl": "7.33.0", - "@wdio/runner": "7.33.0", - "@wdio/types": "7.33.0", - "async-exit-hook": "^2.0.1", - "split2": "^4.0.0", - "stream-buffers": "^3.0.2" + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@wdio/cli": "^7.0.0" + "node": ">=14.16" } }, - "node_modules/@wdio/local-runner/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/cli/node_modules/cacheable-request/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "@types/node": "^18.0.0", - "got": "^11.8.1" - }, "engines": { - "node": ">=12.0.0" + "node": ">=10" }, - "peerDependencies": { - "typescript": "^4.6.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@wdio/local-runner/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/cli/node_modules/chrome-launcher": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, "optional": true, "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "print-chrome-path": "bin/print-chrome-path.js" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.13.0" } }, - "node_modules/@wdio/logger": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.26.0.tgz", - "integrity": "sha512-kQj9s5JudAG9qB+zAAcYGPHVfATl2oqKgqj47yjehOQ1zzG33xmtL1ArFbQKWhDG32y1A8sN6b0pIqBEIwgg8Q==", + "node_modules/@wdio/cli/node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "loglevel": "^1.6.0", - "loglevel-plugin-prefix": "^0.8.4", - "strip-ansi": "^6.0.0" + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">= 14" } }, - "node_modules/@wdio/logger/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@wdio/cli/node_modules/compress-commons/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/logger/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@wdio/cli/node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 14" } }, - "node_modules/@wdio/logger/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@wdio/cli/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/cli/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/mocha-framework": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-7.33.0.tgz", - "integrity": "sha512-y6+iBF+QrqeiXC+mNwW/o0vRsB+qaRznxoh+ds6Xz9V0tui55cn4kl2gYkBu3oHX8h+9R52ykLyaY9wv+r2aeg==", + "node_modules/@wdio/cli/node_modules/devtools": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.40.2.tgz", + "integrity": "sha512-DR/P5LEdxTJO5tVGW4UtjMKKpZbg3g8+VmLQWwq5Lz7pMP1I83G2PlQ3JrRJGDTx9ur52/1QLYHuDrhxYjCMCA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@types/mocha": "^10.0.0", - "@wdio/logger": "7.26.0", - "@wdio/types": "7.33.0", - "@wdio/utils": "7.33.0", - "expect-webdriverio": "^3.0.0", - "mocha": "^10.0.0" + "@types/node": "^20.1.0", + "@wdio/config": "8.40.2", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "chrome-launcher": "^1.0.0", + "edge-paths": "^3.0.5", + "import-meta-resolve": "^4.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.37", + "uuid": "^10.0.0", + "which": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/mocha-framework/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/cli/node_modules/devtools-protocol": { + "version": "0.0.1232444", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", + "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/devtools/node_modules/@types/node": { + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@types/node": "^18.0.0", - "got": "^11.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "^4.6.2" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "undici-types": "~6.19.2" } }, - "node_modules/@wdio/mocha-framework/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/cli/node_modules/devtools/node_modules/@wdio/config": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.2.tgz", + "integrity": "sha512-RED2vcdX5Zdd6r+K+aWcjK4douxjJY4LP/8YvvavgqM0TURd5PDI0Y7IEz7+BIJOT4Uh+3atZawIN9/3yWFeag==", "dev": true, "optional": true, "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" }, "engines": { - "node": ">=4.2.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/protocols": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.27.0.tgz", - "integrity": "sha512-hT/U22R5i3HhwPjkaKAG0yd59eaOaZB0eibRj2+esCImkb5Y6rg8FirrlYRxIGFVBl0+xZV0jKHzR5+o097nvg==", + "node_modules/@wdio/cli/node_modules/devtools/node_modules/@wdio/protocols": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.38.0.tgz", + "integrity": "sha512-7BPi7aXwUtnXZPeWJRmnCNFjyDvGrXlBmN9D4Pi58nILkyjVRQKEY9/qv/pcdyB0cvmIvw++Kl/1Lg+RxG++UA==", "dev": true, - "engines": { - "node": ">=12.0.0" - } + "optional": true, + "peer": true }, - "node_modules/@wdio/repl": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.33.0.tgz", - "integrity": "sha512-17KM9NCg+UVpZNbS8koT/917vklF5M8IQnw0kGwmJEo444ifTMxmLwQymbS2ovQKAKAQxlfdM7bpqMeI15kzsQ==", + "node_modules/@wdio/cli/node_modules/devtools/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@wdio/utils": "7.33.0" + "@types/node": "^20.1.0" }, "engines": { - "node": ">=12.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/reporter": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-7.33.0.tgz", - "integrity": "sha512-iL3SwP+hVmu1qj54YPwRCK+ZpVN75xpltYihjpuZCWZKJ0qpQuE2oBlNauFQWgrrd74ta20EDV4mSIhXm9lX6g==", + "node_modules/@wdio/cli/node_modules/devtools/node_modules/@wdio/utils": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.2.tgz", + "integrity": "sha512-leYcCUSaAdLUCVKqRKNgMCASPOUo/VvOTKETiZ/qpdY2azCBt/KnLugtiycCzakeYg6Kp+VIjx5fkm0M7y4qhA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@types/diff": "^5.0.0", - "@types/node": "^18.0.0", - "@types/object-inspect": "^1.8.0", - "@types/supports-color": "^8.1.0", - "@types/tmp": "^0.2.0", - "@wdio/types": "7.33.0", - "diff": "^5.0.0", - "fs-extra": "^11.1.1", - "object-inspect": "^1.10.3", - "supports-color": "8.1.1" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": ">=12.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/reporter/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/cli/node_modules/devtools/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, - "dependencies": { + "optional": true, + "peer": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/edge-paths": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/which": "^2.0.1", + "which": "^2.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/shirshak55" + } + }, + "node_modules/@wdio/cli/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@wdio/cli/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/get-port": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/@wdio/cli/node_modules/got/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/@wdio/cli/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@wdio/cli/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wdio/cli/node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/ky": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz", + "integrity": "sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/@wdio/cli/node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/@wdio/cli/node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/cli/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/cli/node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/@wdio/cli/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/parse-json": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", + "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/puppeteer-core": { + "version": "21.11.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.11.0.tgz", + "integrity": "sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "1.9.1", + "chromium-bidi": "0.5.8", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1232444", + "ws": "8.16.0" + }, + "engines": { + "node": ">=16.13.2" + } + }, + "node_modules/@wdio/cli/node_modules/read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/read-pkg-up": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.0.0.tgz", + "integrity": "sha512-jgmKiS//w2Zs+YbX039CorlkOp8FIVbSAN8r8GJHDsGlmNPXo+VeHkqAwCiQVTTx5/LwLZTcEw59z3DvcLbr0g==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^8.0.0", + "type-fest": "^3.12.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/read-pkg/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/serialize-error": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "dev": true, + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/serialize-error/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/cli/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@wdio/cli/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/@wdio/cli/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "optional": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/cli/node_modules/webdriver": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.40.3.tgz", + "integrity": "sha512-mc/pxLpgAQphnIaWvix/QXzp9CJpEvIA3YeF9t5plPaTbvbEaCAYYWkTP6e3vYPYWvx57krjGaYkNUnDCBNolA==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0", + "@types/ws": "^8.5.3", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "deepmerge-ts": "^5.1.0", + "got": "^12.6.1", + "ky": "^0.33.0", + "ws": "^8.8.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.40.5.tgz", + "integrity": "sha512-fKzaAF8lbgVFWIP8i0eGk22MpjactVVTWP8qtUXDob5Kdo8ffrg1lCKP8mcyrz6fiZM1OY1m6dvkbFelf23Nxw==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/repl": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "archiver": "^7.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools-protocol": "^0.0.1342118", + "grapheme-splitter": "^1.0.2", + "import-meta-resolve": "^4.0.0", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "minimatch": "^9.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^11.0.1", + "webdriver": "8.40.3" + }, + "engines": { + "node": "^16.13 || >=18" + }, + "peerDependencies": { + "devtools": "^8.14.0" + }, + "peerDependenciesMeta": { + "devtools": { + "optional": true + } + } + }, + "node_modules/@wdio/cli/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", + "dev": true + }, + "node_modules/@wdio/cli/node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/cli/node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/config": { + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-7.33.0.tgz", + "integrity": "sha512-SaCZNKrDtBghf7ujyaxTiU4pBW+1Kms32shSoXpJ/wFop6/MiA7nb19qpUPoJtEDw5/NOKevUKz8nBMBXphiew==", + "dev": true, + "dependencies": { + "@types/glob": "^8.1.0", + "@wdio/logger": "7.26.0", + "@wdio/types": "7.33.0", + "@wdio/utils": "7.33.0", + "deepmerge": "^4.0.0", + "glob": "^8.0.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/config/node_modules/@wdio/types": { + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", + "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "dev": true, + "dependencies": { "@types/node": "^18.0.0", "got": "^11.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.2" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@wdio/config/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@wdio/config/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/config/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wdio/config/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@wdio/globals": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.40.5.tgz", + "integrity": "sha512-pHWNDhAO25BqfuxXmEwBceUeGzfEjkym9I4EzfUlPpoi39BRasDXbWSpX3us/5snUv5Xk+NWMDv4aTpTxfDQrA==", + "dev": true, + "engines": { + "node": "^16.13 || >=18" + }, + "optionalDependencies": { + "expect-webdriverio": "^4.11.2", + "webdriverio": "8.40.5" + } + }, + "node_modules/@wdio/globals/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@wdio/globals/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "optional": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/globals/node_modules/@types/node": { + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/globals/node_modules/@types/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/globals/node_modules/@wdio/config": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.2.tgz", + "integrity": "sha512-RED2vcdX5Zdd6r+K+aWcjK4douxjJY4LP/8YvvavgqM0TURd5PDI0Y7IEz7+BIJOT4Uh+3atZawIN9/3yWFeag==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/@wdio/config/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "optional": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/@wdio/protocols": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.38.0.tgz", + "integrity": "sha512-7BPi7aXwUtnXZPeWJRmnCNFjyDvGrXlBmN9D4Pi58nILkyjVRQKEY9/qv/pcdyB0cvmIvw++Kl/1Lg+RxG++UA==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/globals/node_modules/@wdio/repl": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.40.3.tgz", + "integrity": "sha512-mWEiBbaC7CgxvSd2/ozpbZWebnRIc8KRu/J81Hlw/txUWio27S7IpXBlZGVvhEsNzq0+cuxB/8gDkkXvMPbesw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "^22.2.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/@wdio/repl/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "optional": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/globals/node_modules/@wdio/utils": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.2.tgz", + "integrity": "sha512-leYcCUSaAdLUCVKqRKNgMCASPOUo/VvOTKETiZ/qpdY2azCBt/KnLugtiycCzakeYg6Kp+VIjx5fkm0M7y4qhA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/@wdio/utils/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@wdio/globals/node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "optional": true, + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/globals/node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "optional": true, + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/globals/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@wdio/globals/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@wdio/globals/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@wdio/globals/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/globals/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/globals/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/globals/node_modules/chrome-launcher": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/@wdio/globals/node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dev": true, + "optional": true, + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/globals/node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, + "optional": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/globals/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "optional": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/globals/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/devtools": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.40.2.tgz", + "integrity": "sha512-DR/P5LEdxTJO5tVGW4UtjMKKpZbg3g8+VmLQWwq5Lz7pMP1I83G2PlQ3JrRJGDTx9ur52/1QLYHuDrhxYjCMCA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/config": "8.40.2", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "chrome-launcher": "^1.0.0", + "edge-paths": "^3.0.5", + "import-meta-resolve": "^4.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.37", + "uuid": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/devtools-protocol": { + "version": "0.0.1232444", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", + "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==", + "dev": true, + "optional": true + }, + "node_modules/@wdio/globals/node_modules/devtools/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/devtools/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@wdio/globals/node_modules/edge-paths": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/which": "^2.0.1", + "which": "^2.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/shirshak55" + } + }, + "node_modules/@wdio/globals/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/get-port": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "optional": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/@wdio/globals/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "optional": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/@wdio/globals/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wdio/globals/node_modules/ky": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz", + "integrity": "sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/@wdio/globals/node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/@wdio/globals/node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@wdio/globals/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "optional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wdio/globals/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/globals/node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "optional": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/@wdio/globals/node_modules/puppeteer-core": { + "version": "21.11.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.11.0.tgz", + "integrity": "sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==", + "dev": true, + "optional": true, + "dependencies": { + "@puppeteer/browsers": "1.9.1", + "chromium-bidi": "0.5.8", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1232444", + "ws": "8.16.0" + }, + "engines": { + "node": ">=16.13.2" + } + }, + "node_modules/@wdio/globals/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, + "optional": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@wdio/globals/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "optional": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/serialize-error": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "dev": true, + "optional": true, + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/globals/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "optional": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@wdio/globals/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "optional": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/@wdio/globals/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "optional": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/globals/node_modules/webdriver": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.40.3.tgz", + "integrity": "sha512-mc/pxLpgAQphnIaWvix/QXzp9CJpEvIA3YeF9t5plPaTbvbEaCAYYWkTP6e3vYPYWvx57krjGaYkNUnDCBNolA==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "^22.2.0", + "@types/ws": "^8.5.3", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "deepmerge-ts": "^5.1.0", + "got": "^12.6.1", + "ky": "^0.33.0", + "ws": "^8.8.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/webdriver/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "optional": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/globals/node_modules/webdriver/node_modules/@wdio/config": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.3.tgz", + "integrity": "sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==", + "dev": true, + "optional": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/webdriver/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", + "dev": true, + "optional": true + }, + "node_modules/@wdio/globals/node_modules/webdriver/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", + "dev": true, + "optional": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.40.5.tgz", + "integrity": "sha512-fKzaAF8lbgVFWIP8i0eGk22MpjactVVTWP8qtUXDob5Kdo8ffrg1lCKP8mcyrz6fiZM1OY1m6dvkbFelf23Nxw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "^22.2.0", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/repl": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "archiver": "^7.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools-protocol": "^0.0.1342118", + "grapheme-splitter": "^1.0.2", + "import-meta-resolve": "^4.0.0", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "minimatch": "^9.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^11.0.1", + "webdriver": "8.40.3" + }, + "engines": { + "node": "^16.13 || >=18" + }, + "peerDependencies": { + "devtools": "^8.14.0" + }, + "peerDependenciesMeta": { + "devtools": { + "optional": true + } + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "optional": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/@wdio/config": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.3.tgz", + "integrity": "sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==", + "dev": true, + "optional": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", + "dev": true, + "optional": true + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", + "dev": true, + "optional": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/globals/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", + "dev": true, + "optional": true + }, + "node_modules/@wdio/globals/node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "optional": true, + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/json-reporter": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/json-reporter/-/json-reporter-8.40.3.tgz", + "integrity": "sha512-Guu8zGFohJj2q6FUHsGJw1qZ1/T/gDu6v10DaqvmviRon4GXTg5nibtnK3uAGnkhGgzHjYKosq/jWoOsFmhEZg==", + "dependencies": { + "@wdio/reporter": "8.40.3", + "@wdio/types": "8.40.3" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/local-runner": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.40.5.tgz", + "integrity": "sha512-/0RXdFU4OH/FZgRGgVYpYWfJIk5ht6VqF2hwuVtS8URBv2riDUKa+Hl+fu5Y8GUQzAs2reNPG0ES2OyNjXxugw==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0", + "@wdio/logger": "8.38.0", + "@wdio/repl": "8.40.3", + "@wdio/runner": "8.40.5", + "@wdio/types": "8.40.3", + "async-exit-hook": "^2.0.1", + "split2": "^4.1.0", + "stream-buffers": "^3.0.2" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/local-runner/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/local-runner/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/local-runner/node_modules/@wdio/repl": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.40.3.tgz", + "integrity": "sha512-mWEiBbaC7CgxvSd2/ozpbZWebnRIc8KRu/J81Hlw/txUWio27S7IpXBlZGVvhEsNzq0+cuxB/8gDkkXvMPbesw==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/local-runner/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@wdio/local-runner/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/local-runner/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@wdio/logger": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-7.26.0.tgz", + "integrity": "sha512-kQj9s5JudAG9qB+zAAcYGPHVfATl2oqKgqj47yjehOQ1zzG33xmtL1ArFbQKWhDG32y1A8sN6b0pIqBEIwgg8Q==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/logger/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@wdio/logger/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/logger/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wdio/mocha-framework": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.40.3.tgz", + "integrity": "sha512-u8toUYRroA5MgCQZPHiQQv88RbeLjJFXSeowXQX6hwMTLurqDLfrqKtaTweFO6QJRFROeq/M0iNJbK008EXXMQ==", + "dev": true, + "dependencies": { + "@types/mocha": "^10.0.0", + "@types/node": "^22.2.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "mocha": "^10.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/get-port": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/mocha-framework/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@wdio/protocols": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-7.27.0.tgz", + "integrity": "sha512-hT/U22R5i3HhwPjkaKAG0yd59eaOaZB0eibRj2+esCImkb5Y6rg8FirrlYRxIGFVBl0+xZV0jKHzR5+o097nvg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/repl": { + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-7.33.0.tgz", + "integrity": "sha512-17KM9NCg+UVpZNbS8koT/917vklF5M8IQnw0kGwmJEo444ifTMxmLwQymbS2ovQKAKAQxlfdM7bpqMeI15kzsQ==", + "dev": true, + "dependencies": { + "@wdio/utils": "7.33.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@wdio/reporter": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-8.40.3.tgz", + "integrity": "sha512-icoUnlyIqLKgxB215OPdDTHG+hlu+U+t/sO6S9eI0ZTYBYaDIQBWVCilkUWRvgfcNSiXYo+1VlVt6waIgIHKwQ==", + "dependencies": { + "@types/node": "^22.2.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "diff": "^5.0.0", + "object-inspect": "^1.12.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/reporter/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/reporter/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/reporter/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@wdio/reporter/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/reporter/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@wdio/runner": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.40.5.tgz", + "integrity": "sha512-5sKORwwps0fvuPDfBbBz+jm8RV2xBV4xBGOLHiad6Mpruzc7+uDwxz6ILkE+CErQhJoNdB99YOOm2foh+aO4Ww==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0", + "@wdio/config": "8.40.3", + "@wdio/globals": "8.40.5", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "deepmerge-ts": "^5.1.0", + "expect-webdriverio": "^4.12.0", + "gaze": "^1.1.3", + "webdriver": "8.40.3", + "webdriverio": "8.40.5" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/runner/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/runner/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/runner/node_modules/@types/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/runner/node_modules/@wdio/config": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.3.tgz", + "integrity": "sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==", + "dev": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/runner/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/runner/node_modules/@wdio/protocols": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.38.0.tgz", + "integrity": "sha512-7BPi7aXwUtnXZPeWJRmnCNFjyDvGrXlBmN9D4Pi58nILkyjVRQKEY9/qv/pcdyB0cvmIvw++Kl/1Lg+RxG++UA==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/runner/node_modules/@wdio/repl": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.40.3.tgz", + "integrity": "sha512-mWEiBbaC7CgxvSd2/ozpbZWebnRIc8KRu/J81Hlw/txUWio27S7IpXBlZGVvhEsNzq0+cuxB/8gDkkXvMPbesw==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/runner/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/runner/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/runner/node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/runner/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@wdio/runner/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/runner/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/runner/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "peerDependencies": { - "typescript": "^4.6.2" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/chrome-launcher": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" } }, - "node_modules/@wdio/reporter/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "node_modules/@wdio/runner/node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">=14.14" + "node": ">= 14" } }, - "node_modules/@wdio/reporter/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/runner/node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/runner/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@wdio/runner/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/devtools": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.40.2.tgz", + "integrity": "sha512-DR/P5LEdxTJO5tVGW4UtjMKKpZbg3g8+VmLQWwq5Lz7pMP1I83G2PlQ3JrRJGDTx9ur52/1QLYHuDrhxYjCMCA==", "dev": true, "optional": true, "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/config": "8.40.2", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "chrome-launcher": "^1.0.0", + "edge-paths": "^3.0.5", + "import-meta-resolve": "^4.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.37", + "uuid": "^10.0.0", + "which": "^4.0.0" }, "engines": { - "node": ">=4.2.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-7.33.0.tgz", - "integrity": "sha512-3B+29EanAdRFh4vT3E4XnHQga/apdLIDZq5pGEbqnDA5LarbIvsNWbJjeJzWM6XaZmEwrPfjOunjOevJt5yvdg==", + "node_modules/@wdio/runner/node_modules/devtools-protocol": { + "version": "0.0.1232444", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", + "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/devtools/node_modules/@types/node": { + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@wdio/config": "7.33.0", - "@wdio/logger": "7.26.0", - "@wdio/types": "7.33.0", - "@wdio/utils": "7.33.0", - "deepmerge": "^4.0.0", - "gaze": "^1.1.2", - "webdriver": "7.33.0", - "webdriverio": "7.33.0" + "undici-types": "~6.19.2" + } + }, + "node_modules/@wdio/runner/node_modules/devtools/node_modules/@wdio/config": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.2.tgz", + "integrity": "sha512-RED2vcdX5Zdd6r+K+aWcjK4douxjJY4LP/8YvvavgqM0TURd5PDI0Y7IEz7+BIJOT4Uh+3atZawIN9/3yWFeag==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" }, "engines": { - "node": ">=12.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/runner/node_modules/devtools/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@types/node": "^18.0.0", - "got": "^11.8.1" + "@types/node": "^20.1.0" }, "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "^4.6.2" + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/runner/node_modules/devtools/node_modules/@wdio/utils": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.2.tgz", + "integrity": "sha512-leYcCUSaAdLUCVKqRKNgMCASPOUo/VvOTKETiZ/qpdY2azCBt/KnLugtiycCzakeYg6Kp+VIjx5fkm0M7y4qhA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/runner/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/runner/node_modules/devtools/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "optional": true, "peer": true, + "dependencies": { + "isexe": "^3.1.1" + }, "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "node-which": "bin/which.js" }, "engines": { - "node": ">=4.2.0" + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@wdio/spec-reporter": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-7.33.0.tgz", - "integrity": "sha512-+BTJE6p82EaQMK+2t3lmXlpxF0Q72EJwUSEqY6RPyPUZL7fB+AZdHKQcxcmCR8bYyOUp68H45Yj4PuCKRS6hAg==", + "node_modules/@wdio/runner/node_modules/edge-paths": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@types/easy-table": "^1.2.0", - "@wdio/reporter": "7.33.0", - "@wdio/types": "7.33.0", - "chalk": "^4.0.0", - "easy-table": "^1.1.1", - "pretty-ms": "^7.0.0" + "@types/which": "^2.0.1", + "which": "^2.0.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, - "peerDependencies": { - "@wdio/cli": "^7.0.0" + "funding": { + "url": "https://github.com/sponsors/shirshak55" } }, - "node_modules/@wdio/spec-reporter/node_modules/@wdio/types": { - "version": "7.33.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.33.0.tgz", - "integrity": "sha512-tNcuN5Kl+i5CffaeTYV1omzAo4rVjiI1m9raIA8ph6iVteWdCzYv2/ImpGgFiBPb7Mf6VokU3+q9Slh5Jitaww==", + "node_modules/@wdio/runner/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/get-port": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", "dev": true, "dependencies": { - "@types/node": "^18.0.0", - "got": "^11.8.1" + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.16" }, - "peerDependencies": { - "typescript": "^4.6.2" + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=10.19.0" } }, - "node_modules/@wdio/spec-reporter/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@wdio/runner/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wdio/runner/node_modules/ky": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz", + "integrity": "sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/@wdio/runner/node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "ms": "2.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/spec-reporter/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@wdio/runner/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@wdio/spec-reporter/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@wdio/runner/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@wdio/runner/node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/@wdio/runner/node_modules/puppeteer-core": { + "version": "21.11.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.11.0.tgz", + "integrity": "sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@puppeteer/browsers": "1.9.1", + "chromium-bidi": "0.5.8", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1232444", + "ws": "8.16.0" }, "engines": { - "node": ">=8" + "node": ">=16.13.2" } }, - "node_modules/@wdio/spec-reporter/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "node_modules/@wdio/runner/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@wdio/runner/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/serialize-error": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "dev": true, + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/runner/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@wdio/runner/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/@wdio/runner/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "optional": true, "peer": true, "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wdio/runner/node_modules/webdriver": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.40.3.tgz", + "integrity": "sha512-mc/pxLpgAQphnIaWvix/QXzp9CJpEvIA3YeF9t5plPaTbvbEaCAYYWkTP6e3vYPYWvx57krjGaYkNUnDCBNolA==", + "dev": true, + "dependencies": { + "@types/node": "^22.2.0", + "@types/ws": "^8.5.3", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "deepmerge-ts": "^5.1.0", + "got": "^12.6.1", + "ky": "^0.33.0", + "ws": "^8.8.0" }, "engines": { - "node": ">=4.2.0" + "node": "^16.13 || >=18" } }, - "node_modules/@wdio/types": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.31.0.tgz", - "integrity": "sha512-uHAeJ5JMHCOkLXdwht+uS4QC7Pz3piEcEKGzsz6TJzvTgZLhxRlUfYkkxogbae05DZBHnRKfZD+XWH92cjgsIg==", + "node_modules/@wdio/runner/node_modules/webdriver/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/webdriverio": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.40.5.tgz", + "integrity": "sha512-fKzaAF8lbgVFWIP8i0eGk22MpjactVVTWP8qtUXDob5Kdo8ffrg1lCKP8mcyrz6fiZM1OY1m6dvkbFelf23Nxw==", "dev": true, "dependencies": { - "@types/node": "^20.1.0" + "@types/node": "^22.2.0", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/repl": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "archiver": "^7.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools-protocol": "^0.0.1342118", + "grapheme-splitter": "^1.0.2", + "import-meta-resolve": "^4.0.0", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "minimatch": "^9.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^11.0.1", + "webdriver": "8.40.3" }, "engines": { "node": "^16.13 || >=18" + }, + "peerDependencies": { + "devtools": "^8.14.0" + }, + "peerDependenciesMeta": { + "devtools": { + "optional": true + } } }, - "node_modules/@wdio/types/node_modules/@types/node": { - "version": "20.11.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", - "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", + "dev": true + }, + "node_modules/@wdio/runner/node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@wdio/spec-reporter": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-8.40.3.tgz", + "integrity": "sha512-Qp8hI4ZqxOLQAeqpt1wmOzR0QgarsoT35NOVfEA7gSy8FcF+H/axrPwEToOLRSQIU4bKEh5/khJ7j81GaVqtVg==", + "dev": true, + "dependencies": { + "@wdio/reporter": "8.40.3", + "@wdio/types": "8.40.3", + "chalk": "^5.1.2", + "easy-table": "^1.2.0", + "pretty-ms": "^7.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/spec-reporter/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wdio/types": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.40.3.tgz", + "integrity": "sha512-zK17uyON3Ise3m+XwiF5VrrdZcXXmvqB8AWXoKe88DiksFUPMVoCOuVL2SSX1KnA2YLlZBA55qcFZT99GORVKQ==", "dependencies": { - "undici-types": "~5.26.4" + "@types/node": "^22.2.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/@wdio/types/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": { + "undici-types": "~6.19.2" } }, "node_modules/@wdio/utils": { @@ -11779,6 +14791,17 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@zip.js/zip.js": { + "version": "2.7.52", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.52.tgz", + "integrity": "sha512-+5g7FQswvrCHwYKNMd/KFxZSObctLSsQOgqBSi0LzwHo3li9Eh1w5cF5ndjQw9Zbr3ajVnd2+XyiX85gAetx1Q==", + "dev": true, + "engines": { + "bun": ">=0.7.0", + "deno": ">=1.0.0", + "node": ">=16.5.0" + } + }, "node_modules/@zkochan/js-yaml": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", @@ -12330,23 +15353,13 @@ "deep-equal": "^2.0.5" } }, - "node_modules/arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -12409,15 +15422,6 @@ "node": ">=8" } }, - "node_modules/array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array.prototype.flat": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", @@ -12749,6 +15753,12 @@ "dequal": "^2.0.3" } }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", @@ -14913,6 +17923,53 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.4.tgz", + "integrity": "sha512-7YyxitZEq0ey5loOF5gdo1fZQFF7290GziT+VbAJ+JbYTJYaPZwuEz2r/Nq23sm4fjyTgUf2uJI2gkT3xAuSYA==", + "dev": true, + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" + } + }, + "node_modules/bare-os": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.3.tgz", + "integrity": "sha512-FjkNiU3AwTQNQkcxFOmDcCfoN1LjjtU+ofGJh5DymZZLTqdw2i/CzV7G0h3snvh6G8jrWtdmNSgZPH4L2VOAsQ==", + "dev": true, + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "dev": true, + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, + "node_modules/bare-stream": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", + "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", + "dev": true, + "optional": true, + "dependencies": { + "b4a": "^1.6.6", + "streamx": "^2.20.0" + } + }, "node_modules/base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", @@ -14985,6 +18042,15 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -15021,6 +18087,19 @@ "node": "*" } }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -15417,12 +18496,30 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, "node_modules/builder-util": { "version": "24.9.4", "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.9.4.tgz", @@ -15527,194 +18624,6 @@ "node": ">= 0.8" } }, - "node_modules/cac": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", - "integrity": "sha512-hq4rxE3NT5PlaEiVV39Z45d6MoFcQZG5dsgJqtAUeOz3408LEQAElToDkf9i5IYSCOmK0If/81dLg7nKxqPR0w==", - "dev": true, - "dependencies": { - "camelcase-keys": "^3.0.0", - "chalk": "^1.1.3", - "indent-string": "^3.0.0", - "minimist": "^1.2.0", - "read-pkg-up": "^1.0.1", - "suffix": "^0.1.0", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cac/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/camelcase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", - "integrity": "sha512-U4E6A6aFyYnNW+tDt5/yIUKQURKXe3WMFPfX4FxrQFcwZ/R08AUk1xWcUtlr7oq6CV07Ji+aa69V2g7BSpblnQ==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cac/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cac/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/cacache": { "version": "18.0.1", "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.1.tgz", @@ -15812,14 +18721,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15940,6 +18854,27 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chainsaw/node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -16137,6 +19072,19 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/chromium-bidi": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.8.tgz", + "integrity": "sha512-blqh+1cEQbHBKmok3rVJkBlBxt9beKBgOsxbFgs7UJcoVbbeZ+K7+6liAsjgpc8l1Xd55cQUy14fXZdGSb4zIw==", + "dev": true, + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/chromium-pickle-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", @@ -16319,12 +19267,12 @@ } }, "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/cliui": { @@ -17650,6 +20598,15 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -17873,6 +20830,15 @@ "node": ">=0.10.0" } }, + "node_modules/deepmerge-ts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz", + "integrity": "sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/default-browser-id": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", @@ -17923,17 +20889,20 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-lazy-prop": { @@ -17983,6 +20952,32 @@ "integrity": "sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==", "dev": true }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/degenerator/node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/del": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", @@ -18375,7 +21370,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true, "engines": { "node": ">=0.3.1" } @@ -18673,6 +21667,51 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -18757,6 +21796,179 @@ "which": "^2.0.2" } }, + "node_modules/edgedriver": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-5.6.1.tgz", + "integrity": "sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@wdio/logger": "^8.38.0", + "@zip.js/zip.js": "^2.7.48", + "decamelize": "^6.0.0", + "edge-paths": "^3.0.5", + "fast-xml-parser": "^4.4.1", + "node-fetch": "^3.3.2", + "which": "^4.0.0" + }, + "bin": { + "edgedriver": "bin/edgedriver.js" + } + }, + "node_modules/edgedriver/node_modules/@types/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", + "dev": true + }, + "node_modules/edgedriver/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/edgedriver/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/edgedriver/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/edgedriver/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/edgedriver/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/edgedriver/node_modules/edge-paths": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", + "dev": true, + "dependencies": { + "@types/which": "^2.0.1", + "which": "^2.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/shirshak55" + } + }, + "node_modules/edgedriver/node_modules/edge-paths/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/edgedriver/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/edgedriver/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/edgedriver/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/edgedriver/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -19268,6 +22480,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-get-iterator": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", @@ -20312,490 +23545,1177 @@ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { - "estraverse": "^5.2.0" + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-pubsub": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-5.0.3.tgz", + "integrity": "sha512-2QiHxshejKgJrYMzSI9MEHrvhmzxBL+eLyiM5IiyjDBySkgwS2+tdtnO3gbx8pEisu/yOFCIhfCb63gCEu0yBQ==", + "dependencies": { + "copyfiles": "^2.4.0", + "strong-type": "^0.1.3" + }, + "engines": { + "node": ">=13.0.0" + } + }, + "node_modules/event-pubsub/node_modules/strong-type": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/strong-type/-/strong-type-0.1.6.tgz", + "integrity": "sha512-eJe5caH6Pi5oMMeQtIoBPpvNu/s4jiyb63u5tkHNnQXomK+puyQ5i+Z5iTLBr/xUz/pIcps0NSfzzFI34+gAXg==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/exec-sh": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execall": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", + "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", + "dev": true, + "dependencies": { + "clone-regexp": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==", + "dev": true + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect-webdriverio": { + "version": "4.15.4", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-4.15.4.tgz", + "integrity": "sha512-Op1xZoevlv1pohCq7g2Og5Gr3xP2NhY7MQueOApmopVxgweoJ/BqJxyvMNP0A//QsMg8v0WsN/1j81Sx2er9Wg==", + "dev": true, + "dependencies": { + "@vitest/snapshot": "^2.0.3", + "expect": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">=16 || >=18 || >=20" + }, + "optionalDependencies": { + "@wdio/globals": "^8.29.3", + "@wdio/logger": "^8.28.0", + "webdriverio": "^8.29.3" + } + }, + "node_modules/expect-webdriverio/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/expect-webdriverio/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "optional": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/expect-webdriverio/node_modules/@types/node": { + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/expect-webdriverio/node_modules/@types/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz", + "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/expect-webdriverio/node_modules/@wdio/config": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.2.tgz", + "integrity": "sha512-RED2vcdX5Zdd6r+K+aWcjK4douxjJY4LP/8YvvavgqM0TURd5PDI0Y7IEz7+BIJOT4Uh+3atZawIN9/3yWFeag==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/expect-webdriverio/node_modules/@wdio/config/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/expect-webdriverio/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "optional": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/expect-webdriverio/node_modules/@wdio/protocols": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.38.0.tgz", + "integrity": "sha512-7BPi7aXwUtnXZPeWJRmnCNFjyDvGrXlBmN9D4Pi58nILkyjVRQKEY9/qv/pcdyB0cvmIvw++Kl/1Lg+RxG++UA==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/expect-webdriverio/node_modules/@wdio/repl": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-8.40.3.tgz", + "integrity": "sha512-mWEiBbaC7CgxvSd2/ozpbZWebnRIc8KRu/J81Hlw/txUWio27S7IpXBlZGVvhEsNzq0+cuxB/8gDkkXvMPbesw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "^22.2.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/expect-webdriverio/node_modules/@wdio/repl/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dev": true, + "optional": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/expect-webdriverio/node_modules/@wdio/utils": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.2.tgz", + "integrity": "sha512-leYcCUSaAdLUCVKqRKNgMCASPOUo/VvOTKETiZ/qpdY2azCBt/KnLugtiycCzakeYg6Kp+VIjx5fkm0M7y4qhA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.39.0", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/expect-webdriverio/node_modules/@wdio/utils/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/expect-webdriverio/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/expect-webdriverio/node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "optional": true, + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/expect-webdriverio/node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "optional": true, + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/expect-webdriverio/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/expect-webdriverio/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/expect-webdriverio/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/expect-webdriverio/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/expect-webdriverio/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/expect-webdriverio/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/expect-webdriverio/node_modules/chrome-launcher": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/expect-webdriverio/node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dev": true, + "optional": true, + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/expect-webdriverio/node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, + "optional": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">=4.0" + "node": ">= 14" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/expect-webdriverio/node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dev": true, - "engines": { - "node": ">=4.0" + "optional": true, + "dependencies": { + "node-fetch": "^2.6.12" } }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "node_modules/expect-webdriverio/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/expect-webdriverio/node_modules/devtools": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-8.40.2.tgz", + "integrity": "sha512-DR/P5LEdxTJO5tVGW4UtjMKKpZbg3g8+VmLQWwq5Lz7pMP1I83G2PlQ3JrRJGDTx9ur52/1QLYHuDrhxYjCMCA==", "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "^20.1.0", + "@wdio/config": "8.40.2", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.38.0", + "@wdio/types": "8.39.0", + "@wdio/utils": "8.40.2", + "chrome-launcher": "^1.0.0", + "edge-paths": "^3.0.5", + "import-meta-resolve": "^4.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "ua-parser-js": "^1.0.37", + "uuid": "^10.0.0", + "which": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^16.13 || >=18" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/expect-webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1232444", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", + "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==", "dev": true, - "engines": { - "node": ">= 0.6" - } + "optional": true }, - "node_modules/event-pubsub": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-5.0.3.tgz", - "integrity": "sha512-2QiHxshejKgJrYMzSI9MEHrvhmzxBL+eLyiM5IiyjDBySkgwS2+tdtnO3gbx8pEisu/yOFCIhfCb63gCEu0yBQ==", + "node_modules/expect-webdriverio/node_modules/devtools/node_modules/@wdio/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-8.39.0.tgz", + "integrity": "sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { - "copyfiles": "^2.4.0", - "strong-type": "^0.1.3" + "@types/node": "^20.1.0" }, "engines": { - "node": ">=13.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/event-pubsub/node_modules/strong-type": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/strong-type/-/strong-type-0.1.6.tgz", - "integrity": "sha512-eJe5caH6Pi5oMMeQtIoBPpvNu/s4jiyb63u5tkHNnQXomK+puyQ5i+Z5iTLBr/xUz/pIcps0NSfzzFI34+gAXg==", + "node_modules/expect-webdriverio/node_modules/devtools/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, "engines": { - "node": ">=12.0.0" + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "node_modules/expect-webdriverio/node_modules/edge-paths": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz", + "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==", "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@types/which": "^2.0.1", + "which": "^2.0.2" + }, "engines": { - "node": ">=6" + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/shirshak55" } }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/expect-webdriverio/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "optional": true, + "peer": true, "engines": { - "node": ">=0.8.x" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "node_modules/expect-webdriverio/node_modules/get-port": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", + "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", "dev": true, - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "optional": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", + "node_modules/expect-webdriverio/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", "dev": true, "optional": true, - "peer": true - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sindresorhus/got?sponsor=1" } }, - "node_modules/execall": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz", - "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==", + "node_modules/expect-webdriverio/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", "dev": true, + "optional": true, "dependencies": { - "clone-regexp": "^2.1.0" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" }, "engines": { - "node": ">=8" + "node": ">=10.19.0" } }, - "node_modules/exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==", - "dev": true - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "node_modules/expect-webdriverio/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, + "optional": true, "engines": { - "node": ">= 0.8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", + "node_modules/expect-webdriverio/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "dependencies": { - "is-posix-bracket": "^0.1.0" - }, + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=16" } }, - "node_modules/expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "node_modules/expect-webdriverio/node_modules/ky": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.33.3.tgz", + "integrity": "sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==", "dev": true, - "dependencies": { - "fill-range": "^2.1.0" - }, + "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, - "node_modules/expand-range/node_modules/fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "node_modules/expect-webdriverio/node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" + "debug": "^2.6.9", + "marky": "^1.2.2" } }, - "node_modules/expand-range/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/expand-range/node_modules/is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "node_modules/expect-webdriverio/node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "ms": "2.0.0" } }, - "node_modules/expand-range/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/expand-range/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "node_modules/expect-webdriverio/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", "dev": true, - "dependencies": { - "isarray": "1.0.0" + "optional": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expect-webdriverio/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "optional": true, "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expand-range/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/expect-webdriverio/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "optional": true, "dependencies": { - "is-buffer": "^1.1.5" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "node_modules/expect-webdriverio/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, + "optional": true, + "peer": true + }, + "node_modules/expect-webdriverio/node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, + "optional": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect-webdriverio": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-3.6.0.tgz", - "integrity": "sha512-8HuVToXDVzkKgUKIUzW/v3bP4ZoMDEwCjX9QmlRlMIvjt3HOSzSIBnRMv8lpeVTUKoR9DZNr/lSuKH4Amx4BBg==", + "node_modules/expect-webdriverio/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", "dev": true, - "dependencies": { - "expect": "^28.1.0", - "jest-matcher-utils": "^28.1.0" + "optional": true, + "engines": { + "node": ">=12.20" } }, - "node_modules/expect-webdriverio/node_modules/@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "node_modules/expect-webdriverio/node_modules/puppeteer-core": { + "version": "21.11.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.11.0.tgz", + "integrity": "sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==", "dev": true, + "optional": true, "dependencies": { - "jest-get-type": "^28.0.2" + "@puppeteer/browsers": "1.9.1", + "chromium-bidi": "0.5.8", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1232444", + "ws": "8.16.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=16.13.2" } }, - "node_modules/expect-webdriverio/node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "node_modules/expect-webdriverio/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, + "optional": true, "dependencies": { - "@sinclair/typebox": "^0.24.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/expect-webdriverio/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "node_modules/expect-webdriverio/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", "dev": true, + "optional": true, "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "lowercase-keys": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect-webdriverio/node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "node_modules/expect-webdriverio/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/expect-webdriverio/node_modules/serialize-error": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", + "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", "dev": true, + "optional": true, "dependencies": { - "color-convert": "^2.0.1" + "type-fest": "^2.12.2" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect-webdriverio/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/expect-webdriverio/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "optional": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/expect-webdriverio/node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "node_modules/expect-webdriverio/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "optional": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, - "node_modules/expect-webdriverio/node_modules/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "node_modules/expect-webdriverio/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "dev": true, - "dependencies": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "optional": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/expect-webdriverio/node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "node_modules/expect-webdriverio/node_modules/webdriver": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.40.3.tgz", + "integrity": "sha512-mc/pxLpgAQphnIaWvix/QXzp9CJpEvIA3YeF9t5plPaTbvbEaCAYYWkTP6e3vYPYWvx57krjGaYkNUnDCBNolA==", "dev": true, + "optional": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "@types/node": "^22.2.0", + "@types/ws": "^8.5.3", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "deepmerge-ts": "^5.1.0", + "got": "^12.6.1", + "ky": "^0.33.0", + "ws": "^8.8.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "node_modules/expect-webdriverio/node_modules/webdriver/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "optional": true, + "dependencies": { + "undici-types": "~6.19.2" } }, - "node_modules/expect-webdriverio/node_modules/jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "node_modules/expect-webdriverio/node_modules/webdriver/node_modules/@wdio/config": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.3.tgz", + "integrity": "sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==", "dev": true, + "optional": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "node_modules/expect-webdriverio/node_modules/webdriver/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", + "dev": true, + "optional": true + }, + "node_modules/expect-webdriverio/node_modules/webdriver/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", "dev": true, + "optional": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "node_modules/expect-webdriverio/node_modules/webdriverio": { + "version": "8.40.5", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.40.5.tgz", + "integrity": "sha512-fKzaAF8lbgVFWIP8i0eGk22MpjactVVTWP8qtUXDob5Kdo8ffrg1lCKP8mcyrz6fiZM1OY1m6dvkbFelf23Nxw==", "dev": true, + "optional": true, "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "@types/node": "^22.2.0", + "@wdio/config": "8.40.3", + "@wdio/logger": "8.38.0", + "@wdio/protocols": "8.40.3", + "@wdio/repl": "8.40.3", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "archiver": "^7.0.0", + "aria-query": "^5.0.0", + "css-shorthand-properties": "^1.1.1", + "css-value": "^0.0.1", + "devtools-protocol": "^0.0.1342118", + "grapheme-splitter": "^1.0.2", + "import-meta-resolve": "^4.0.0", + "is-plain-obj": "^4.1.0", + "jszip": "^3.10.1", + "lodash.clonedeep": "^4.5.0", + "lodash.zip": "^4.2.0", + "minimatch": "^9.0.0", + "puppeteer-core": "^21.11.0", + "query-selector-shadow-dom": "^1.0.0", + "resq": "^1.9.1", + "rgb2hex": "0.2.5", + "serialize-error": "^11.0.1", + "webdriver": "8.40.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^16.13 || >=18" + }, + "peerDependencies": { + "devtools": "^8.14.0" + }, + "peerDependenciesMeta": { + "devtools": { + "optional": true + } } }, - "node_modules/expect-webdriverio/node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/@types/node": { + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", "dev": true, + "optional": true, "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "undici-types": "~6.19.2" + } + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/@wdio/config": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.40.3.tgz", + "integrity": "sha512-HIi+JnHEDAExhzGRQuZOXw1HWIpe/bsVFHwNISJhY6wS4Nijaigmegs2p14Rv16ydOF19hGrxdKsl8k5STIP2A==", + "dev": true, + "optional": true, + "dependencies": { + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "@wdio/utils": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.0.0", + "glob": "^10.2.2", + "import-meta-resolve": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/@wdio/protocols": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-8.40.3.tgz", + "integrity": "sha512-wK7+eyrB3TAei8RwbdkcyoNk2dPu+mduMBOdPJjp8jf/mavd15nIUXLID1zA+w5m1Qt1DsT1NbvaeO9+aJQ33A==", "dev": true, - "engines": { - "node": ">=10" + "optional": true + }, + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/@wdio/utils": { + "version": "8.40.3", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.40.3.tgz", + "integrity": "sha512-pv/848KGfPN3YXU4QRfTYGkAu4/lejIfoGzGpvGNDcACiVxgZhyRZkJ2xVaSnGaXzF0R7pMozrkU5/DnEhcxMg==", + "dev": true, + "optional": true, + "dependencies": { + "@puppeteer/browsers": "^1.6.0", + "@wdio/logger": "8.38.0", + "@wdio/types": "8.40.3", + "decamelize": "^6.0.0", + "deepmerge-ts": "^5.1.0", + "edgedriver": "^5.5.0", + "geckodriver": "^4.3.1", + "get-port": "^7.0.0", + "import-meta-resolve": "^4.0.0", + "locate-app": "^2.1.0", + "safaridriver": "^0.1.0", + "split2": "^4.2.0", + "wait-port": "^1.0.4" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": "^16.13 || >=18" } }, - "node_modules/expect-webdriverio/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/expect-webdriverio/node_modules/webdriverio/node_modules/devtools-protocol": { + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", + "dev": true, + "optional": true + }, + "node_modules/expect-webdriverio/node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, + "optional": true, "dependencies": { - "has-flag": "^4.0.0" + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">= 14" } }, "node_modules/exponential-backoff": { @@ -20950,27 +24870,6 @@ "node": ">=0.10.0" } }, - "node_modules/extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -21035,6 +24934,12 @@ "dev": true, "peer": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -21069,6 +24974,28 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-xml-parser": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -21136,6 +25063,29 @@ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", "dev": true }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fetch-retry": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.6.tgz", @@ -21252,15 +25202,6 @@ "node": ">=10" } }, - "node_modules/filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -21512,18 +25453,8 @@ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", - "dev": true, - "dependencies": { - "for-in": "^1.0.1" - }, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21659,6 +25590,15 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, "node_modules/format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", @@ -21668,6 +25608,18 @@ "node": ">=0.4.x" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -21757,6 +25709,56 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/glob": { + "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", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -21805,6 +25807,209 @@ "node": ">= 4.0.0" } }, + "node_modules/geckodriver": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-4.2.1.tgz", + "integrity": "sha512-4m/CRk0OI8MaANRuFIahvOxYTSjlNAO2p9JmE14zxueknq6cdtB5M9UGRQ8R9aMV0bLGNVHHDnDXmoXdOwJfWg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@wdio/logger": "^8.11.0", + "decamelize": "^6.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.1", + "tar-fs": "^3.0.4", + "unzipper": "^0.10.14", + "which": "^4.0.0" + }, + "bin": { + "geckodriver": "bin/geckodriver.js" + }, + "engines": { + "node": "^16.13 || >=18 || >=20" + } + }, + "node_modules/geckodriver/node_modules/@wdio/logger": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-8.38.0.tgz", + "integrity": "sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==", + "dev": true, + "dependencies": { + "chalk": "^5.1.2", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": "^16.13 || >=18" + } + }, + "node_modules/geckodriver/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/geckodriver/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/geckodriver/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/geckodriver/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/geckodriver/node_modules/decamelize": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/geckodriver/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/geckodriver/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==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/geckodriver/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/geckodriver/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/geckodriver/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/geckodriver/node_modules/tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/geckodriver/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/geckodriver/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -21823,16 +26028,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -21916,6 +26125,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -22010,49 +26248,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", - "dev": true, - "dependencies": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-base/node_modules/glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", - "dev": true, - "dependencies": { - "is-glob": "^2.0.0" - } - }, - "node_modules/glob-base/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-base/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -22258,6 +26453,7 @@ "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -22456,27 +26652,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -22496,12 +26671,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -23612,6 +27787,16 @@ "node": ">=8" } }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -23656,29 +27841,29 @@ "integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ==" }, "node_modules/inquirer": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "version": "9.2.12", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz", + "integrity": "sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==", "dev": true, "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", + "@ljharb/through": "^2.3.11", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^5.0.0", "lodash": "^4.17.21", - "mute-stream": "0.0.8", + "mute-stream": "1.0.0", "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.18.0" } }, "node_modules/inquirer/node_modules/ansi-styles": { @@ -23697,28 +27882,66 @@ } }, "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/inquirer/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=8" @@ -23794,6 +28017,25 @@ "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, "node_modules/ip-regex": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", @@ -24069,38 +28311,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-electron-renderer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz", "integrity": "sha512-pRlQnpaCFhDVPtkXkP+g9Ybv/CjbiQDjnKFQTEjpBfDKeV6dRDBczuFRDpM6DVfk2EjpMS8t5kwE5jPnqYl3zA==", "dev": true }, - "node_modules/is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==", - "dev": true, - "dependencies": { - "is-primitive": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -24298,30 +28521,12 @@ "node": ">=0.10.0" } }, - "node_modules/is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, - "node_modules/is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -24449,12 +28654,6 @@ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", "dev": true }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true - }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -26941,229 +31140,6 @@ "node": ">=8" } }, - "node_modules/jest-matchers": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", - "integrity": "sha512-aDlp50L8qPJ+Y+tifrlKewT0ZU1uC9OP7GJ5T0UKSw/wB73wf6jKEAZUqyA67BocW8BZD7qVVWHasm7u2D1CMQ==", - "dev": true, - "dependencies": { - "jest-diff": "^20.0.3", - "jest-matcher-utils": "^20.0.3", - "jest-message-util": "^20.0.3", - "jest-regex-util": "^20.0.3" - } - }, - "node_modules/jest-matchers/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==", - "dev": true, - "dependencies": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/chalk/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/jest-matchers/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/jest-matchers/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/jest-diff": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", - "integrity": "sha512-DITOXlTg0HDL9QKiVpf82vDu/nva60/V9xp056zjnAYpHVTZlJgfLMIHJmgPCoSu0+7n7QUAfxyFUHUGyHLFSw==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "diff": "^3.2.0", - "jest-matcher-utils": "^20.0.3", - "pretty-format": "^20.0.3" - } - }, - "node_modules/jest-matchers/node_modules/jest-matcher-utils": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", - "integrity": "sha512-eSNh2n3aXULZUbherq5+lZVdpUau8sniowi1tcc1ZueBk/97avAwwoDwBVvxI9JINVrPTsCI51SiQtrjBkVvPw==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "pretty-format": "^20.0.3" - } - }, - "node_modules/jest-matchers/node_modules/jest-message-util": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", - "integrity": "sha512-p4UQLFjZmXw9Optr6c0aAIDN622+tdVW9XjaCODww/Y8MRGo1S60CICl0Jb4XdJWmMkmD07osWc6aElLxo0mDg==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "micromatch": "^2.3.11", - "slash": "^1.0.0" - } - }, - "node_modules/jest-matchers/node_modules/jest-regex-util": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz", - "integrity": "sha512-WVFSnROOYgYA+AyTytpZA93EEv16DfPkkR8V8okVQjirXLfRs9n451BPgiiUJSHIyJv+OQ4El0+q16hyY1dEdA==", - "dev": true - }, - "node_modules/jest-matchers/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", - "dev": true, - "dependencies": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/pretty-format": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", - "integrity": "sha512-dSW/15bmtC3vuheyzWUveowskTAUAWKE08+x06rgYzvSoDzg6cVg/MPKgNvh87jRJvOQ/qaQZLLWml2jrukk6w==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.1.1", - "ansi-styles": "^3.0.0" - } - }, - "node_modules/jest-matchers/node_modules/slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-matchers/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/jest-message-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", @@ -28046,6 +32022,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/jschardet": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-3.1.2.tgz", @@ -28773,6 +32755,12 @@ "node": ">= 14" } }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, "node_modules/listr2": { "version": "6.6.1", "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", @@ -28915,55 +32903,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -28987,6 +32926,39 @@ "node": ">=8.9.0" } }, + "node_modules/locate-app": { + "version": "2.4.41", + "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.4.41.tgz", + "integrity": "sha512-viAOUsdA8QNM+p823ymlxPGXo+ePPZ8r9yhFoyFGUN6/ORE6uMZrKN8hPSKiPZMhFCeoZ5nfp4qEQvaMyPY46A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://buymeacoffee.com/hejny" + }, + { + "type": "github", + "url": "https://github.com/hejny/locate-app/blob/main/README.md#%EF%B8%8F-contributing" + } + ], + "dependencies": { + "@promptbook/utils": "0.70.0-1", + "type-fest": "2.13.0", + "userhome": "1.0.0" + } + }, + "node_modules/locate-app/node_modules/type-fest": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz", + "integrity": "sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -29377,7 +33349,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", - "dev": true, "engines": { "node": ">= 0.6.0" }, @@ -29389,8 +33360,7 @@ "node_modules/loglevel-plugin-prefix": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", - "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", - "dev": true + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==" }, "node_modules/longest-streak": { "version": "2.0.4", @@ -29473,15 +33443,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/make-dir": { @@ -29632,12 +33599,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true - }, "node_modules/mathml-tag-names": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", @@ -31508,6 +35469,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -31552,18 +35519,15 @@ } }, "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" + "dependencies": { + "minimist": "^1.2.6" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "bin": { + "mkdirp": "bin/cmd.js" } }, "node_modules/mkdirp-classic": { @@ -31790,10 +35754,13 @@ } }, "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/nanoid": { "version": "3.3.3", @@ -31874,6 +35841,15 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -31917,6 +35893,25 @@ "node": ">= 0.10.5" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -32740,7 +36735,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -32846,19 +36840,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==", - "dev": true, - "dependencies": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -33247,6 +37228,76 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "dev": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/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==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -33311,42 +37362,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", - "dev": true, - "dependencies": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-glob/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-glob/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "dev": true, - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -33501,9 +37516,9 @@ } }, "node_modules/pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true }, "node_modules/pbkdf2": { @@ -33578,27 +37593,6 @@ "node": ">=6" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", @@ -33751,18 +37745,6 @@ "ms": "^2.1.1" } }, - "node_modules/portfinder/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -34191,15 +38173,6 @@ "node": ">= 0.8.0" } }, - "node_modules/preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/prettier": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", @@ -34391,18 +38364,78 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/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==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -34562,18 +38595,6 @@ "node": ">= 6.0.0" } }, - "node_modules/puppeteer-core/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/puppeteer-core/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -34673,6 +38694,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -34734,29 +38761,6 @@ "url": "https://opencollective.com/ramda" } }, - "node_modules/randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "dev": true, - "dependencies": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/randomatic/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -36004,18 +40008,6 @@ "@babel/runtime": "^7.8.4" } }, - "node_modules/regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "dependencies": { - "is-equal-shallow": "^0.1.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -36295,7 +40287,9 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/renderkid": { "version": "3.0.0", @@ -36315,6 +40309,8 @@ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -36652,9 +40648,9 @@ } }, "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, "engines": { "node": ">=0.12.0" @@ -36698,6 +40694,12 @@ "tslib": "^2.1.0" } }, + "node_modules/safaridriver": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/safaridriver/-/safaridriver-0.1.2.tgz", + "integrity": "sha512-4R309+gWflJktzPXBQCobbWEHlzC4aK3a+Ov3tz2Ib2aBxiwd11phkdIBH1l0EO22x24CJMUQkpKFumRriCSRg==", + "dev": true + }, "node_modules/safe-array-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", @@ -37639,15 +41641,17 @@ "peer": true }, "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -38096,37 +42100,37 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" } }, "node_modules/socks-proxy-agent/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.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { "debug": "^4.3.4" @@ -38224,6 +42228,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/spacetrim": { + "version": "0.11.39", + "resolved": "https://registry.npmjs.org/spacetrim/-/spacetrim-0.11.39.tgz", + "integrity": "sha512-S/baW29azJ7py5ausQRE2S6uEDQnlxgMHOEEq4V770ooBDD1/9kZnxRcco/tjZYuDuqYXblCk/r3N13ZmvHZ2g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://buymeacoffee.com/hejny" + }, + { + "type": "github", + "url": "https://github.com/hejny/spacetrim/blob/main/README.md#%EF%B8%8F-contributing" + } + ] + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -38512,6 +42532,20 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "node_modules/streamx": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", + "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -38749,6 +42783,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "dev": true + }, "node_modules/strong-log-transformer": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", @@ -39095,15 +43135,6 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "dev": true }, - "node_modules/suffix": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", - "integrity": "sha512-j5uf6MJtMCfC4vBe5LFktSe4bGyNTBk7I2Kdri0jeLrcv5B9pWfxVa5JQpoxgtR8vaVB7bVxsWgnfQbX5wkhAA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/sugarss": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz", @@ -39848,6 +43879,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/text-decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", + "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -39969,6 +44009,15 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "dev": true }, + "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, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -40648,10 +44697,9 @@ "dev": true }, "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==", - "dev": true + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -41055,16 +45103,64 @@ "yaku": "^0.16.6" } }, - "node_modules/unzip-crx-3/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", "dev": true, "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "node_modules/unzipper/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" } }, "node_modules/update-browserslist-db": { @@ -41172,6 +45268,12 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true }, + "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 + }, "node_modules/usb": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz", @@ -41305,6 +45407,15 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/userhome": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/userhome/-/userhome-1.0.0.tgz", + "integrity": "sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", @@ -41517,6 +45628,75 @@ "node": ">=14" } }, + "node_modules/wait-port": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-1.1.0.tgz", + "integrity": "sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "commander": "^9.3.0", + "debug": "^4.3.4" + }, + "bin": { + "wait-port": "bin/wait-port.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wait-port/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wait-port/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/wait-port/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/wait-port/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -41665,25 +45845,21 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/wdio-json-reporter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/wdio-json-reporter/-/wdio-json-reporter-3.0.0.tgz", - "integrity": "sha512-j2/d1TJMa1ofUskg7OrcWkr9itW6IZdqnFL/px3xHWz7eaeqwkzc64yhcIz2CVej4ygJ9btOTiGCsCIVg4dcMw==", - "dev": true, - "dependencies": { - "@wdio/reporter": "^7.16.3", - "jest-matchers": "^20.0.3" - }, - "peerDependencies": { - "@wdio/cli": "^7.16.3" - } - }, "node_modules/wdio-wait-for": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/wdio-wait-for/-/wdio-wait-for-2.2.6.tgz", "integrity": "sha512-vXSe03frnMFHMDiEUZL3dyet1Wl+cOXPMSzWNFVjlr/W853Bw+Uu1Sos0SSXtsLwopEzsGzKtFvbOcqIlJ46sw==", "dev": true }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/webdriver": { "version": "7.33.0", "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-7.33.0.tgz", @@ -42731,9 +46907,9 @@ } }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -42917,117 +47093,6 @@ "node": ">=12" } }, - "node_modules/yarn-install": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", - "integrity": "sha512-VO1u181msinhPcGvQTVMnHVOae8zjX/NSksR17e6eXHRveDvHCF5mGjh9hkN8mzyfnCqcBe42LdTs7bScuTaeg==", - "dev": true, - "dependencies": { - "cac": "^3.0.3", - "chalk": "^1.1.3", - "cross-spawn": "^4.0.2" - }, - "bin": { - "yarn-install": "bin/yarn-install.js", - "yarn-remove": "bin/yarn-remove.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yarn-install/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yarn-install/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yarn-install/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yarn-install/node_modules/cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "node_modules/yarn-install/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/yarn-install/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yarn-install/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/yarn-install/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/yarn-install/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index 2680fc2e24..c768938d4b 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "@types/elasticlunr": "^0.9.5", "@types/electron-devtools-installer": "^2.2.2", "@types/electron-localshortcut": "^3.1.0", + "@types/fs-extra": "^11.0.4", "@types/history": "^4.7.9", "@types/jest": "^29.5.6", "@types/js-crc": "^0.2.3", @@ -137,12 +138,12 @@ "@types/webpack-env": "^1.17.0", "@typescript-eslint/eslint-plugin": "^ 6.7.4", "@typescript-eslint/parser": "^ 6.7.4", - "@wdio/cli": "^7.16.13", - "@wdio/local-runner": "^7.16.13", - "@wdio/mocha-framework": "^7.16.13", - "@wdio/reporter": "^7.16.14", - "@wdio/spec-reporter": "^7.16.14", - "@wdio/types": "^8.31.0", + "@wdio/cli": "^8.40.5", + "@wdio/local-runner": "^8.40.5", + "@wdio/mocha-framework": "^8.40.3", + "@wdio/reporter": "^8.40.3", + "@wdio/spec-reporter": "^8.40.3", + "@wdio/types": "^8.40.3", "archiver": "^5.3.1", "async-mutex": "^0.4.0", "axios": "^0.27.2", @@ -260,7 +261,6 @@ "uuid": "^9.0.1", "vcf": "^2.1.2", "wdio-chromedriver-service": "^8.1.1", - "wdio-json-reporter": "^3.0.0", "wdio-wait-for": "^2.2.1", "webpack": "^5.74.0", "webpack-cli": "^4.10.0", @@ -277,6 +277,7 @@ "@contentful/rich-text-plain-text-renderer": "^16.2.6", "@orama/orama": "^2.0.22", "@vscode/sudo-prompt": "^9.3.1", + "@wdio/json-reporter": "^8.40.3", "crypto-js": "^4.2.0", "js-crc": "^0.2.0", "jschardet": "^3.1.2", @@ -287,5 +288,8 @@ "serialport": "10.1.0", "tslib": "^2.3.0", "zod": "^3.22.4" + }, + "overrides": { + "geckodriver": "~4.2.0" } } From 9f6bb00f9dc8c295aeb6ccb24f01f6f180ce31ea Mon Sep 17 00:00:00 2001 From: MateuszMudita Date: Mon, 23 Sep 2024 12:28:45 +0200 Subject: [PATCH 11/64] [CP-3132] Added data testid to Cancel Backup Action --- libs/e2e-test-ids/src/e2e-test-ids.ts | 1 + .../ui/src/lib/predefined/backup/backup-features.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/e2e-test-ids/src/e2e-test-ids.ts b/libs/e2e-test-ids/src/e2e-test-ids.ts index b281207187..bb43215e3d 100644 --- a/libs/e2e-test-ids/src/e2e-test-ids.ts +++ b/libs/e2e-test-ids/src/e2e-test-ids.ts @@ -35,6 +35,7 @@ export enum BackupModalTestIds { FeatureElementActive = "backup-features-modal-element-active", FeatureElementInactive = "backup-features-modal-element-inactive", CreateBackupAction = "backup-features-modal-create-action", + CancelBackupAction = "backup-features-modal-cancel-action", } export enum ModalTestIds { diff --git a/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx b/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx index 3d2b09cf69..446a7b4ac9 100644 --- a/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx +++ b/libs/generic-view/ui/src/lib/predefined/backup/backup-features.tsx @@ -94,6 +94,7 @@ export const BackupFeatures: FunctionComponent = ({ text: intl.formatMessage(messages.cancelButtonLabel), action: closeAction, }} + data-testid={BackupModalTestIds.CancelBackupAction} /> Date: Mon, 23 Sep 2024 20:10:50 +0200 Subject: [PATCH 12/64] [CP-3075] Implemented entities store (#2049) Co-authored-by: Daniel Karski --- .env.example | 3 + .../__deprecated__/renderer/store/reducers.ts | 2 + .../constants/response-status.constant.ts | 1 + .../lib/api-entities/api-entities.service.ts | 297 +++++++++++++++++- .../create-entity-data.request.ts | 21 ++ .../delete-entities-data.request.ts | 21 ++ ...uest.ts => get-entities-config.request.ts} | 10 +- .../api-entities/get-entities-data.request.ts | 56 ++++ .../get-entities-metadata.request.ts | 16 + .../feature/src/lib/api-entities/index.ts | 7 +- .../update-entity-data.request.ts | 23 ++ libs/device/feature/src/lib/api-module.ts | 5 +- .../file-transfer/file-transfer.service.ts | 9 +- .../models/src/lib/api-request.model.ts | 8 +- .../entities-config.validator.test.ts | 150 +++++++++ ...idator.ts => entities-config.validator.ts} | 30 +- .../entities-data-get.validator.test.ts | 43 +++ .../entities/entities-data-get.validator.ts | 17 + .../lib/entities/entities-delete.validator.ts | 13 + .../entities-metadata.validator.test.ts | 28 ++ .../entities/entities-metadata.validator.ts | 12 + .../entities/entity-config.validator.test.ts | 76 ----- .../entity-data-get.validator.test.ts | 23 ++ .../lib/entities/entity-data-get.validator.ts | 12 + .../entities/entity-data-patch.validator.ts | 12 + .../entities/entity-data-post.validator.ts | 12 + .../src/lib/entities/entity-data.validator.ts | 9 + .../flatten-entity-configuration.test.ts | 18 +- libs/device/models/src/lib/entities/index.ts | 14 +- .../lib/feature/data-provider-config.test.ts | 71 +++++ .../src/lib/feature/data-provider-config.ts | 67 ++++ .../src/lib/feature/feature-config.test.ts | 14 +- .../models/src/lib/feature/feature-config.ts | 5 + libs/device/models/src/lib/feature/index.ts | 2 + .../src/lib/feature/layout-config.test.ts | 94 ++++++ .../models/src/lib/feature/layout-config.ts | 146 +++++++++ libs/device/models/src/lib/general-error.ts | 3 +- .../api-entities-service-events.ts | 9 +- .../feature/src/lib/generic-view.tsx | 4 + .../feature/src/lib/recursive-layout.tsx | 33 +- .../feature/src/lib/setup-component.tsx | 146 ++++++++- .../feature/src/lib/use-dev-console.ts | 97 ++++++ .../src/lib/use-dev-views/use-dev-views.tsx | 34 ++ .../lib/use-dev-views/views/contacts-view.ts | 238 ++++++++++++++ .../src/lib/use-dev-views/views/index.ts | 10 + libs/generic-view/models/src/index.ts | 12 + .../models/src/lib/common-validators.ts | 16 + .../models/src/lib/entities-loader.ts | 20 ++ .../models/src/lib/form-checkbox-input.ts | 2 +- .../src/lib/form-conditional-renderer.ts | 21 ++ .../generic-view/models/src/lib/table-cell.ts | 22 ++ libs/generic-view/models/src/lib/table.ts | 27 ++ libs/generic-view/store/src/index.ts | 10 + .../store/src/lib/action-names.ts | 13 + .../store/src/lib/entities/actions.ts | 38 +++ .../lib/entities/create-entity-data.action.ts | 58 ++++ .../entities/delete-entities-data.action.ts | 40 +++ .../entities/get-entities-config.action.ts | 48 +++ .../lib/entities/get-entities-data.action.ts | 69 ++++ .../entities/get-entities-metadata.action.ts | 31 ++ .../lib/entities/get-entity-data.action.ts | 88 ++++++ .../store/src/lib/entities/reducer.ts | 131 ++++++++ .../lib/entities/update-entity-data.action.ts | 64 ++++ .../features/get-generic-config.actions.ts | 1 + .../src/lib/file-transfer/get-file.action.ts | 5 +- .../store/src/lib/get-api-config.ts | 14 +- .../hooks/use-api-serial-port-listeners.ts | 2 + .../store/src/lib/selectors/component.ts | 5 + .../store/src/lib/selectors/entities.ts | 77 +++++ .../store/src/lib/selectors/index.ts | 1 + .../store/src/lib/views/actions.ts | 6 + .../store/src/lib/views/reducer.ts | 18 ++ libs/generic-view/ui/src/index.ts | 5 + .../buttons/button-base/use-button-action.ts | 18 ++ .../ui/src/lib/entities/entities-loader.tsx | 55 ++++ .../generic-view/ui/src/lib/entities/index.ts | 11 + .../ui/src/lib/interactive/form/form.tsx | 3 + .../helpers/form-conditional-renderer.tsx | 22 ++ .../interactive/form/input/checkbox-input.tsx | 15 +- .../ui/src/lib/interactive/interactive.ts | 2 + libs/generic-view/ui/src/lib/table/index.ts | 12 + .../ui/src/lib/table/table-cell.tsx | 43 +++ libs/generic-view/ui/src/lib/table/table.tsx | 199 ++++++++++++ libs/generic-view/utils/src/index.ts | 2 +- .../data-provider-filter.test.ts | 82 +++++ .../data-provider-filter.ts | 25 ++ .../data-provider-sort.test.ts | 151 +++++++++ .../data-provider-sort.ts | 62 ++++ .../src/lib/data-provider-helpers/index.ts | 7 + .../string-to-regex.test.ts | 30 ++ .../data-provider-helpers/string-to-regex.ts | 13 + .../lib/map-layout-sizes/map-layout-sizes.ts | 2 +- .../utils/src/lib/models/api-fc.types.ts | 8 +- .../utils/src/lib/models/api-views.types.ts | 4 +- .../utils/src/lib/models/button.types.ts | 20 +- .../utils/src/lib/models/layout.types.ts | 80 ----- 96 files changed, 3399 insertions(+), 232 deletions(-) create mode 100644 libs/device/feature/src/lib/api-entities/create-entity-data.request.ts create mode 100644 libs/device/feature/src/lib/api-entities/delete-entities-data.request.ts rename libs/device/feature/src/lib/api-entities/{get-api-entities-config.request.ts => get-entities-config.request.ts} (55%) create mode 100644 libs/device/feature/src/lib/api-entities/get-entities-data.request.ts create mode 100644 libs/device/feature/src/lib/api-entities/get-entities-metadata.request.ts create mode 100644 libs/device/feature/src/lib/api-entities/update-entity-data.request.ts create mode 100644 libs/device/models/src/lib/entities/entities-config.validator.test.ts rename libs/device/models/src/lib/entities/{entity-config.validator.ts => entities-config.validator.ts} (83%) create mode 100644 libs/device/models/src/lib/entities/entities-data-get.validator.test.ts create mode 100644 libs/device/models/src/lib/entities/entities-data-get.validator.ts create mode 100644 libs/device/models/src/lib/entities/entities-delete.validator.ts create mode 100644 libs/device/models/src/lib/entities/entities-metadata.validator.test.ts create mode 100644 libs/device/models/src/lib/entities/entities-metadata.validator.ts delete mode 100644 libs/device/models/src/lib/entities/entity-config.validator.test.ts create mode 100644 libs/device/models/src/lib/entities/entity-data-get.validator.test.ts create mode 100644 libs/device/models/src/lib/entities/entity-data-get.validator.ts create mode 100644 libs/device/models/src/lib/entities/entity-data-patch.validator.ts create mode 100644 libs/device/models/src/lib/entities/entity-data-post.validator.ts create mode 100644 libs/device/models/src/lib/entities/entity-data.validator.ts create mode 100644 libs/device/models/src/lib/feature/data-provider-config.test.ts create mode 100644 libs/device/models/src/lib/feature/data-provider-config.ts create mode 100644 libs/device/models/src/lib/feature/layout-config.test.ts create mode 100644 libs/device/models/src/lib/feature/layout-config.ts create mode 100644 libs/generic-view/feature/src/lib/use-dev-console.ts create mode 100644 libs/generic-view/feature/src/lib/use-dev-views/use-dev-views.tsx create mode 100644 libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts create mode 100644 libs/generic-view/feature/src/lib/use-dev-views/views/index.ts create mode 100644 libs/generic-view/models/src/lib/entities-loader.ts create mode 100644 libs/generic-view/models/src/lib/form-conditional-renderer.ts create mode 100644 libs/generic-view/models/src/lib/table-cell.ts create mode 100644 libs/generic-view/models/src/lib/table.ts create mode 100644 libs/generic-view/store/src/lib/entities/actions.ts create mode 100644 libs/generic-view/store/src/lib/entities/create-entity-data.action.ts create mode 100644 libs/generic-view/store/src/lib/entities/delete-entities-data.action.ts create mode 100644 libs/generic-view/store/src/lib/entities/get-entities-config.action.ts create mode 100644 libs/generic-view/store/src/lib/entities/get-entities-data.action.ts create mode 100644 libs/generic-view/store/src/lib/entities/get-entities-metadata.action.ts create mode 100644 libs/generic-view/store/src/lib/entities/get-entity-data.action.ts create mode 100644 libs/generic-view/store/src/lib/entities/reducer.ts create mode 100644 libs/generic-view/store/src/lib/entities/update-entity-data.action.ts create mode 100644 libs/generic-view/store/src/lib/selectors/entities.ts create mode 100644 libs/generic-view/ui/src/lib/entities/entities-loader.tsx create mode 100644 libs/generic-view/ui/src/lib/entities/index.ts create mode 100644 libs/generic-view/ui/src/lib/interactive/form/helpers/form-conditional-renderer.tsx create mode 100644 libs/generic-view/ui/src/lib/table/index.ts create mode 100644 libs/generic-view/ui/src/lib/table/table-cell.tsx create mode 100644 libs/generic-view/ui/src/lib/table/table.tsx create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.test.ts create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.ts create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.test.ts create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.ts create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/index.ts create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.test.ts create mode 100644 libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.ts delete mode 100644 libs/generic-view/utils/src/lib/models/layout.types.ts diff --git a/.env.example b/.env.example index afc4dc09a6..959c12302c 100644 --- a/.env.example +++ b/.env.example @@ -67,3 +67,6 @@ DEV_TOOLS_AUTO_OPEN_ENABLED= # [Optional] Allows to show unpublished content in Help. Disabled by default, set a secret token to enable DEV_HELP_PREVIEW_TOKEN= + +# [Optional] Enable DEV version of API configuration. Disabled by default, set "1" to enable +DEV_API_CONFIG= diff --git a/libs/core/__deprecated__/renderer/store/reducers.ts b/libs/core/__deprecated__/renderer/store/reducers.ts index eed1d29773..7420ce271f 100644 --- a/libs/core/__deprecated__/renderer/store/reducers.ts +++ b/libs/core/__deprecated__/renderer/store/reducers.ts @@ -32,6 +32,7 @@ import { genericViewsReducer, importsReducer, externalProvidersReducer, + genericEntitiesReducer, } from "generic-view/store" import { appStateReducer } from "shared/app-state" import { activeDeviceRegistryReducer } from "active-device-registry/feature" @@ -68,6 +69,7 @@ export const reducers = { dataMigration: dataMigrationReducer, genericDataTransfer: genericDataTransferReducer, helpV2: helpReducer, + genericEntities: genericEntitiesReducer, } export const combinedReducers = combineReducers(reducers) diff --git a/libs/core/device/constants/response-status.constant.ts b/libs/core/device/constants/response-status.constant.ts index c428a5c7f0..f6e62fdfee 100644 --- a/libs/core/device/constants/response-status.constant.ts +++ b/libs/core/device/constants/response-status.constant.ts @@ -8,6 +8,7 @@ export enum ResponseStatus { Accepted = 202, Redirect = 303, NoContent = 204, + MultiResponse = 207, BadRequest = 400, NotFound = 404, PhoneLocked = 403, diff --git a/libs/device/feature/src/lib/api-entities/api-entities.service.ts b/libs/device/feature/src/lib/api-entities/api-entities.service.ts index 714d9ac1d9..e4717731e8 100644 --- a/libs/device/feature/src/lib/api-entities/api-entities.service.ts +++ b/libs/device/feature/src/lib/api-entities/api-entities.service.ts @@ -8,17 +8,38 @@ import { DeviceId } from "Core/device/constants/device-id" import { Result, ResultObject } from "Core/core/builder" import { AppError, AppErrorType } from "Core/core/errors" import { - entityConfigValidator, + APIEntitiesServiceEvents, + EntitiesConfig, + entitiesConfigValidator, + entitiesDeletePartialSuccessValidator, + EntitiesDeleteResponse, EntitiesError, - EntityConfig, + EntitiesFileData, + entitiesFileDataValidator, + EntitiesJsonData, + entitiesJsonDataValidator, + EntitiesMetadata, + entitiesMetadataValidator, + EntityData, + EntityDataPatch, + entityDataPatchValidator, + EntityDataPost, + entityDataPostValidator, + EntityId, + EntityJsonData, + entityJsonDataValidator, GeneralError, - APIEntitiesServiceEvents, } from "device/models" -import { SafeParseSuccess } from "zod" +import { SafeParseReturnType, SafeParseSuccess } from "zod" import { IpcEvent } from "Core/core/decorators" +import { ServiceBridge } from "../service-bridge" +import logger from "Core/__deprecated__/main/utils/logger" export class APIEntitiesService { - constructor(private deviceProtocol: DeviceProtocol) {} + constructor( + private deviceProtocol: DeviceProtocol, + private serviceBridge: ServiceBridge + ) {} private getDevice = (deviceId?: DeviceId) => { return deviceId @@ -43,34 +64,284 @@ export class APIEntitiesService { return Result.success(response.data) } - @IpcEvent(APIEntitiesServiceEvents.EntityConfig) - public async getEntityConfiguration({ - entityType, + @IpcEvent(APIEntitiesServiceEvents.EntitiesConfig) + public async getEntitiesConfiguration({ + entitiesType, deviceId, }: { - entityType: string + entitiesType: string deviceId?: DeviceId - }): Promise> { + }): Promise> { const device = this.getDevice(deviceId) if (!device) { return Result.failed(new AppError(GeneralError.NoDevice, "")) } const response = await device.request({ - endpoint: "ENTITY_CONFIGURATION", + endpoint: "ENTITIES_CONFIGURATION", method: "GET", body: { - type: entityType, + entityType: entitiesType, }, }) if (!response.ok) { return this.handleError(response.error.type) } - const apiConfig = entityConfigValidator.safeParse(response.data.body) + const apiConfig = entitiesConfigValidator.safeParse(response.data.body) if (!apiConfig.success) { return this.handleError(response.data.status) } return this.handleSuccess(apiConfig) } + + @IpcEvent(APIEntitiesServiceEvents.EntitiesMetadata) + public async getEntitiesMetadata({ + entitiesType, + deviceId, + }: { + entitiesType: string + deviceId?: DeviceId + }): Promise> { + const device = this.getDevice(deviceId) + if (!device) { + return Result.failed(new AppError(GeneralError.NoDevice, "")) + } + + const response = await device.request({ + endpoint: "ENTITIES_METADATA", + method: "GET", + body: { + entityType: entitiesType, + }, + }) + if (!response.ok) { + return this.handleError(response.error.type) + } + + const metadata = entitiesMetadataValidator.safeParse(response.data.body) + if (!metadata.success) { + return this.handleError(response.data.status) + } + return this.handleSuccess(metadata) + } + + @IpcEvent(APIEntitiesServiceEvents.EntitiesDataGet) + public async getEntitiesData({ + entitiesType, + entityId, + responseType, + deviceId, + }: { + entitiesType: string + responseType: "json" | "file" + entityId?: EntityId + deviceId?: DeviceId + }): Promise< + ResultObject + > { + const device = this.getDevice(deviceId) + if (!device) { + return Result.failed(new AppError(GeneralError.NoDevice, "")) + } + + const response = await device.request({ + endpoint: "ENTITIES_DATA", + method: "GET", + body: { + entityType: entitiesType, + responseType, + ...(entityId && { entityId }), + }, + }) + if (!response.ok) { + return this.handleError(response.error.type) + } + + let data: SafeParseReturnType< + typeof response.data.body, + EntitiesJsonData | EntityJsonData | EntitiesFileData + > + + if (responseType === "file") { + if (response.data.status === 202) { + return this.getEntitiesData({ + entitiesType, + entityId, + responseType, + deviceId, + }) + } else if (response.data.status === 200) { + data = entitiesFileDataValidator.safeParse(response.data.body) + } + } + if (responseType === "json") { + if (entityId === undefined) { + data = entitiesJsonDataValidator.safeParse(response.data.body) + } else { + data = entityJsonDataValidator.safeParse(response.data.body) + } + } + + if (!data!.success) { + return this.handleError(response.data.status) + } + return this.handleSuccess(data!) + } + + @IpcEvent(APIEntitiesServiceEvents.EntitiesDataReadFromFile) + public async readEntitiesDataFromFile({ + transferId, + }: { + transferId: number + }): Promise> { + try { + const file = + this.serviceBridge.fileTransfer.getFileByTransferId(transferId) + const decodedFile = Buffer.from(file.chunks.join(""), "base64").toString() + const data = entitiesJsonDataValidator.safeParse(JSON.parse(decodedFile)) + this.serviceBridge.fileTransfer.transferClear({ transferId }) + if (!data.success) { + return this.handleError(EntitiesError.EntitiesDataFileCorrupted) + } + return this.handleSuccess(data) + } catch (error) { + logger.error(error) + return this.handleError(EntitiesError.EntitiesDataFileCorrupted) + } + } + + @IpcEvent(APIEntitiesServiceEvents.EntityDataReadFromFile) + public async readEntityDataFromFile({ + transferId, + }: { + transferId: number + }): Promise> { + try { + const file = + this.serviceBridge.fileTransfer.getFileByTransferId(transferId) + const decodedFile = Buffer.from(file.chunks.join(""), "base64").toString() + const data = entityJsonDataValidator.safeParse(JSON.parse(decodedFile)) + this.serviceBridge.fileTransfer.transferClear({ transferId }) + if (!data.success) { + return this.handleError(EntitiesError.EntitiesDataFileCorrupted) + } + return this.handleSuccess(data) + } catch (error) { + logger.error(error) + return this.handleError(EntitiesError.EntitiesDataFileCorrupted) + } + } + + @IpcEvent(APIEntitiesServiceEvents.EntitiesDataDelete) + public async deleteEntityData({ + entitiesType, + ids, + deviceId, + }: { + entitiesType: string + ids: EntityId[] + deviceId?: DeviceId + }): Promise> { + const device = this.getDevice(deviceId) + if (!device) { + return Result.failed(new AppError(GeneralError.NoDevice, "")) + } + + const response = await device.request({ + endpoint: "ENTITIES_DATA", + method: "DELETE", + body: { + entityType: entitiesType, + ids, + }, + }) + + if (!response.ok) { + return this.handleError(response.error.type) + } + + if (response.data.status === 207) { + const failedIdsValidator = + entitiesDeletePartialSuccessValidator.safeParse(response.data.body) + if (!failedIdsValidator.success) { + logger.error(failedIdsValidator.error) + return this.handleError(response.data.status) + } + return Result.success({ failedIds: failedIdsValidator.data.failedIds }) + } + + return Result.success(undefined) + } + + @IpcEvent(APIEntitiesServiceEvents.EntityDataCreate) + public async createEntityData({ + entitiesType, + data, + deviceId, + }: { + entitiesType: string + data: EntityData + deviceId?: DeviceId + }): Promise> { + const device = this.getDevice(deviceId) + if (!device) { + return Result.failed(new AppError(GeneralError.NoDevice, "")) + } + + const response = await device.request({ + endpoint: "ENTITIES_DATA", + method: "POST", + body: { + entityType: entitiesType, + data, + }, + }) + if (!response.ok) { + return this.handleError(response.error.type) + } + const dataValidator = entityDataPostValidator.safeParse(response.data.body) + if (!dataValidator.success) { + logger.error(dataValidator.error) + return this.handleError(response.data.status) + } + return Result.success(dataValidator.data) + } + + @IpcEvent(APIEntitiesServiceEvents.EntityDataUpdate) + public async updateEntityData({ + entitiesType, + entityId, + data, + deviceId, + }: { + entitiesType: string + entityId: EntityId + data: EntityData + deviceId?: DeviceId + }): Promise> { + const device = this.getDevice(deviceId) + if (!device) { + return Result.failed(new AppError(GeneralError.NoDevice, "")) + } + + const response = await device.request({ + endpoint: "ENTITIES_DATA", + method: "PATCH", + body: { + entityType: entitiesType, + entityId, + data, + }, + }) + if (!response.ok) { + return this.handleError(response.error.type) + } + const dataValidator = entityDataPatchValidator.safeParse(response.data.body) + if (!dataValidator.success) { + logger.error(dataValidator.error) + return this.handleError(response.data.status) + } + return Result.success(dataValidator.data) + } } diff --git a/libs/device/feature/src/lib/api-entities/create-entity-data.request.ts b/libs/device/feature/src/lib/api-entities/create-entity-data.request.ts new file mode 100644 index 0000000000..814e4eecfb --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/create-entity-data.request.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ipcRenderer } from "electron-better-ipc" +import { + APIEntitiesServiceEvents, + EntityData, + EntityDataPost, +} from "device/models" +import { ResultObject } from "Core/core/builder" +import { DeviceId } from "Core/device/constants/device-id" + +export const createEntityDataRequest = (data: { + entitiesType: string + data: EntityData + deviceId?: DeviceId +}): Promise> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntityDataCreate, data) +} diff --git a/libs/device/feature/src/lib/api-entities/delete-entities-data.request.ts b/libs/device/feature/src/lib/api-entities/delete-entities-data.request.ts new file mode 100644 index 0000000000..71abd5bd7f --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/delete-entities-data.request.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ipcRenderer } from "electron-better-ipc" +import { + APIEntitiesServiceEvents, + EntitiesDeleteResponse, + EntityId, +} from "device/models" +import { ResultObject } from "Core/core/builder" +import { DeviceId } from "Core/device/constants/device-id" + +export const deleteEntitiesDataRequest = (data: { + entitiesType: string + ids: EntityId[] + deviceId?: DeviceId +}): Promise> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntitiesDataDelete, data) +} diff --git a/libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts b/libs/device/feature/src/lib/api-entities/get-entities-config.request.ts similarity index 55% rename from libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts rename to libs/device/feature/src/lib/api-entities/get-entities-config.request.ts index 8c18dedf7f..44db1b1039 100644 --- a/libs/device/feature/src/lib/api-entities/get-api-entities-config.request.ts +++ b/libs/device/feature/src/lib/api-entities/get-entities-config.request.ts @@ -6,11 +6,11 @@ import { ipcRenderer } from "electron-better-ipc" import { ResultObject } from "Core/core/builder" import { DeviceId } from "Core/device/constants/device-id" -import { APIEntitiesServiceEvents, EntityConfig } from "device/models" +import { APIEntitiesServiceEvents, EntitiesConfig } from "device/models" -export const getAPIEntitiesConfigRequest = (data: { - entityType: string +export const getEntitiesConfigRequest = (data: { + entitiesType: string deviceId?: DeviceId -}): Promise> => { - return ipcRenderer.callMain(APIEntitiesServiceEvents.EntityConfig, data) +}): Promise> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntitiesConfig, data) } diff --git a/libs/device/feature/src/lib/api-entities/get-entities-data.request.ts b/libs/device/feature/src/lib/api-entities/get-entities-data.request.ts new file mode 100644 index 0000000000..6c65f353c5 --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/get-entities-data.request.ts @@ -0,0 +1,56 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ipcRenderer } from "electron-better-ipc" +import { ResultObject } from "Core/core/builder" +import { DeviceId } from "Core/device/constants/device-id" +import { + APIEntitiesServiceEvents, + EntitiesFileData, + EntitiesJsonData, + EntityId, + EntityJsonData, +} from "device/models" + +export type EntityDataResponseType = "json" | "file" + +type ReturnType< + R extends string = EntityDataResponseType, + E extends EntityId | undefined = undefined +> = R extends "json" + ? E extends undefined + ? EntitiesJsonData + : EntityJsonData + : EntitiesFileData + +export const getEntitiesDataRequest = < + R extends string = EntityDataResponseType, + E extends EntityId | undefined = undefined +>(data: { + entitiesType: string + entityId?: E + responseType: R + deviceId: DeviceId +}): Promise>> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntitiesDataGet, data) +} + +export const readEntitiesDataFromFileRequest = (data: { + transferId: number +}): Promise> => { + return ipcRenderer.callMain( + APIEntitiesServiceEvents.EntitiesDataReadFromFile, + data + ) +} + +export const readEntityDataFromFileRequest = (data: { + transferId: number +}): Promise> => { + return ipcRenderer.callMain( + APIEntitiesServiceEvents.EntityDataReadFromFile, + data + ) +} diff --git a/libs/device/feature/src/lib/api-entities/get-entities-metadata.request.ts b/libs/device/feature/src/lib/api-entities/get-entities-metadata.request.ts new file mode 100644 index 0000000000..14b8d5ef9d --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/get-entities-metadata.request.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ipcRenderer } from "electron-better-ipc" +import { ResultObject } from "Core/core/builder" +import { DeviceId } from "Core/device/constants/device-id" +import { APIEntitiesServiceEvents, EntitiesMetadata } from "device/models" + +export const getEntitiesMetadataRequest = (data: { + entitiesType: string + deviceId?: DeviceId +}): Promise> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntitiesMetadata, data) +} diff --git a/libs/device/feature/src/lib/api-entities/index.ts b/libs/device/feature/src/lib/api-entities/index.ts index 743f3ba553..71743d8a98 100644 --- a/libs/device/feature/src/lib/api-entities/index.ts +++ b/libs/device/feature/src/lib/api-entities/index.ts @@ -4,4 +4,9 @@ */ export * from "./api-entities.service" -export * from "./get-api-entities-config.request" +export * from "./delete-entities-data.request" +export * from "./create-entity-data.request" +export * from "./get-entities-config.request" +export * from "./get-entities-data.request" +export * from "./get-entities-metadata.request" +export * from "./update-entity-data.request" diff --git a/libs/device/feature/src/lib/api-entities/update-entity-data.request.ts b/libs/device/feature/src/lib/api-entities/update-entity-data.request.ts new file mode 100644 index 0000000000..b9840d7b0a --- /dev/null +++ b/libs/device/feature/src/lib/api-entities/update-entity-data.request.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ipcRenderer } from "electron-better-ipc" +import { + APIEntitiesServiceEvents, + EntityData, + EntityDataPatch, + EntityId, +} from "device/models" +import { ResultObject } from "Core/core/builder" +import { DeviceId } from "Core/device/constants/device-id" + +export const updateEntityDataRequest = (data: { + entitiesType: string + entityId: EntityId + data: EntityData + deviceId?: DeviceId +}): Promise> => { + return ipcRenderer.callMain(APIEntitiesServiceEvents.EntityDataUpdate, data) +} diff --git a/libs/device/feature/src/lib/api-module.ts b/libs/device/feature/src/lib/api-module.ts index 1bb94ca5ec..5b19a03cde 100644 --- a/libs/device/feature/src/lib/api-module.ts +++ b/libs/device/feature/src/lib/api-module.ts @@ -45,7 +45,10 @@ export class APIModule { this.apiFeaturesService = new APIFeaturesService(deviceProtocol) this.apiOutboxService = new APIOutboxService(deviceProtocol) this.apiMenuService = new APIMenuService(deviceProtocol) - this.apiEntitiesService = new APIEntitiesService(deviceProtocol) + this.apiEntitiesService = new APIEntitiesService( + deviceProtocol, + this.serviceBridge + ) this.serverService = new ServerService() this.backupService = new APIBackupService(deviceProtocol) this.apiDataTransferService = new APIDataTransferService(deviceProtocol) diff --git a/libs/device/feature/src/lib/file-transfer/file-transfer.service.ts b/libs/device/feature/src/lib/file-transfer/file-transfer.service.ts index d9a7c29103..d3398e7da0 100644 --- a/libs/device/feature/src/lib/file-transfer/file-transfer.service.ts +++ b/libs/device/feature/src/lib/file-transfer/file-transfer.service.ts @@ -26,6 +26,7 @@ import { APIDevice } from "../api-device" import { ServiceBridge } from "../service-bridge" import AES from "crypto-js/aes" import encUtf8 from "crypto-js/enc-utf8" +import logger from "Core/__deprecated__/main/utils/logger" interface Transfer { crc32: string @@ -244,7 +245,13 @@ export class APIFileTransferService { const transfer = this.transfers[transferId] const data = transfer.chunks.join("") const crc32 = crc.crc32(data) - return crc32.toLowerCase() === transfer.crc32.toLowerCase() + const validChecksum = crc32.toLowerCase() === transfer.crc32.toLowerCase() + if (!validChecksum) { + logger.error( + `File checksum mismatch for ${transfer.filePath}. Expected: ${transfer.crc32} (${transfer.fileSize} bytes), calculated: ${crc32} (${data.length} bytes).` + ) + } + return validChecksum } @IpcEvent(ApiFileTransferServiceEvents.PreGet) diff --git a/libs/device/models/src/lib/api-request.model.ts b/libs/device/models/src/lib/api-request.model.ts index b7e7826c5f..37f8586304 100644 --- a/libs/device/models/src/lib/api-request.model.ts +++ b/libs/device/models/src/lib/api-request.model.ts @@ -19,7 +19,9 @@ export const APIEndpoints = [ "SYSTEM", "PRE_DATA_TRANSFER", "DATA_TRANSFER", - "ENTITY_CONFIGURATION", + "ENTITIES_CONFIGURATION", + "ENTITIES_DATA", + "ENTITIES_METADATA", ] as const export type APIEndpointType = (typeof APIEndpoints)[number] @@ -44,7 +46,9 @@ const APIRequests = { SYSTEM: ["POST"], PRE_DATA_TRANSFER: ["POST"], DATA_TRANSFER: ["POST", "GET", "DELETE"], - ENTITY_CONFIGURATION: ["GET"], + ENTITIES_CONFIGURATION: ["GET"], + ENTITIES_DATA: ["GET", "DELETE", "POST", "PATCH"], + ENTITIES_METADATA: ["GET"], } as const interface APIRequestConfig< diff --git a/libs/device/models/src/lib/entities/entities-config.validator.test.ts b/libs/device/models/src/lib/entities/entities-config.validator.test.ts new file mode 100644 index 0000000000..cd51947390 --- /dev/null +++ b/libs/device/models/src/lib/entities/entities-config.validator.test.ts @@ -0,0 +1,150 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { + EntitiesConfig, + entitiesConfigValidator, +} from "./entities-config.validator" +import { ZodError } from "zod" + +describe("entitiesConfigValidator", () => { + it("validates a correct entity configuration", () => { + const validConfig: EntitiesConfig = { + globalValidators: { + requiredFieldsCombinations: [ + { + fields: ["field2", "field3", "field4.field4a", "5[]"], + countLogic: "gt", + fieldsCount: 1, + }, + ], + }, + fields: { + field1: { type: "string", defaultValue: "default" }, + field2: { type: "id" }, + field3: { type: "string", validators: [{ pattern: "/abc/" }] }, + field4: { type: "object", fields: { field4a: { type: "string" } } }, + 5: { type: "array", items: { type: "string" } }, + }, + } + expect(() => entitiesConfigValidator.parse(validConfig)).not.toThrow() + }) + + it("throws an error when there is no field of 'id' type on the top level", () => { + const invalidConfig: EntitiesConfig = { + fields: { + field1: { type: "string" }, + }, + } + const result = () => entitiesConfigValidator.parse(invalidConfig) + expect(result).toThrow() + + try { + result() + } catch (error) { + expect((error as ZodError).errors).toEqual([ + { + code: "custom", + message: + "There must be exactly one field of 'id' type on the top level of the 'fields' object", + path: ["fields"], + }, + ]) + } + }) + + it("throws an error when there is more than one field of 'id' type on the top level", () => { + const invalidConfig: EntitiesConfig = { + fields: { + field1: { type: "id" }, + field2: { type: "id" }, + }, + } + const result = () => entitiesConfigValidator.parse(invalidConfig) + expect(result).toThrow() + + try { + result() + } catch (error) { + expect((error as ZodError).errors).toEqual([ + { + code: "custom", + message: + "There must be exactly one field of 'id' type on the top level of the 'fields' object", + path: ["fields"], + }, + ]) + } + }) + + it("throws an error when `defaultValue` is assigned to 'id' type field", () => { + const invalidConfig: EntitiesConfig = { + fields: { + field1: { type: "id", defaultValue: "default" }, + }, + } as EntitiesConfig + const result = () => entitiesConfigValidator.parse(invalidConfig) + expect(result).toThrow() + + try { + result() + } catch (error) { + expect((error as ZodError).errors).toEqual([ + { + code: "unrecognized_keys", + keys: ["defaultValue"], + message: "Unrecognized key(s) in object: 'defaultValue'", + path: ["fields", "field1"], + }, + ]) + } + }) + + it("throws an error when 'requiredFieldsCombinations' uses wrong fields", () => { + const invalidConfig: EntitiesConfig = { + globalValidators: { + requiredFieldsCombinations: [ + { + fields: ["field1", "field2.field3a", "field3"], + countLogic: "gt", + fieldsCount: 1, + }, + ], + }, + fields: { + field1: { type: "id" }, + field2: { + type: "array", + items: { + type: "object", + fields: { + field3a: { type: "string" }, + }, + }, + }, + }, + } + const result = () => entitiesConfigValidator.parse(invalidConfig) + expect(result).toThrow() + + try { + result() + } catch (error) { + expect((error as ZodError).errors).toEqual([ + { + code: "custom", + message: + "global validators are mentioning fields not defined in the 'fields' object", + path: [ + "globalValidators", + "requiredFieldsCombinations[0]", + "fields", + "[field2.field3a, field3]", + ], + }, + ]) + } + }) +}) diff --git a/libs/device/models/src/lib/entities/entity-config.validator.ts b/libs/device/models/src/lib/entities/entities-config.validator.ts similarity index 83% rename from libs/device/models/src/lib/entities/entity-config.validator.ts rename to libs/device/models/src/lib/entities/entities-config.validator.ts index 90a78b6aae..c9de56fd53 100644 --- a/libs/device/models/src/lib/entities/entity-config.validator.ts +++ b/libs/device/models/src/lib/entities/entities-config.validator.ts @@ -41,13 +41,16 @@ const fieldValidatorsSchema = z ) .optional() +const defaultValueSchema = z.any().optional() + const idFieldSchema = z.object({ type: z.literal("id"), -}) +}).strict() const primitiveFieldSchema = z.object({ type: z.enum(["string", "number", "boolean"]), validators: fieldValidatorsSchema, + defaultValue: defaultValueSchema, }) const basicFieldSchema = z.discriminatedUnion("type", [ @@ -57,18 +60,21 @@ const basicFieldSchema = z.discriminatedUnion("type", [ const nestedArrayFieldSchema = z.object({ type: z.literal("array"), + defaultValue: defaultValueSchema, items: basicFieldSchema, validators: fieldValidatorsSchema, }) const nestedObjectFieldSchema = z.object({ type: z.literal("object"), + defaultValue: defaultValueSchema, fields: z.record(z.string(), basicFieldSchema), validators: fieldValidatorsSchema, }) const arrayFieldSchema = z.object({ type: z.literal("array"), + defaultValue: defaultValueSchema, items: z.union([ basicFieldSchema, nestedArrayFieldSchema, @@ -79,6 +85,7 @@ const arrayFieldSchema = z.object({ const objectFieldSchema = z.object({ type: z.literal("object"), + defaultValue: defaultValueSchema, fields: z.record( z.string(), z.union([basicFieldSchema, nestedArrayFieldSchema, nestedObjectFieldSchema]) @@ -110,11 +117,10 @@ const globalValidatorSchema = z }) .optional() -export const entityConfigValidator = z +export const entitiesConfigValidator = z .object({ - fields: z.record(z.string(), fieldSchema), + fields: z.record(z.union([z.string(), z.number()]), fieldSchema), globalValidators: globalValidatorSchema, - metadata: z.unknown().optional(), }) .refine( (data) => { @@ -160,5 +166,19 @@ export const entityConfigValidator = z } } ) + .refine( + (data) => { + const fields = data.fields + const idFieldsCount = Object.values(fields).filter( + (field) => field.type === "id" + ).length + return idFieldsCount === 1 + }, + { + message: + "There must be exactly one field of 'id' type on the top level of the 'fields' object", + path: ["fields"], + } + ) -export type EntityConfig = z.infer +export type EntitiesConfig = z.infer diff --git a/libs/device/models/src/lib/entities/entities-data-get.validator.test.ts b/libs/device/models/src/lib/entities/entities-data-get.validator.test.ts new file mode 100644 index 0000000000..3e72ab2828 --- /dev/null +++ b/libs/device/models/src/lib/entities/entities-data-get.validator.test.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { + entitiesJsonDataValidator, + entitiesFileDataValidator, +} from "./entities-data-get.validator" + +describe("entitiesJsonDataValidator", () => { + it("validates a correct JSON data structure", () => { + const validJsonData = { data: [{ id: "1", name: "Entity1", 3: "value" }] } + expect(() => entitiesJsonDataValidator.parse(validJsonData)).not.toThrow() + }) + + it("validates a correct JSON data with empty data array", () => { + const validJsonData = { data: [] } + expect(() => entitiesJsonDataValidator.parse(validJsonData)).not.toThrow() + }) + + it("fails validation for JSON data with non-array data field", () => { + const invalidJsonData = { data: { id: "1", name: "Entity1" } } + expect(() => entitiesJsonDataValidator.parse(invalidJsonData)).toThrow() + }) +}) + +describe("entitiesFileDataValidator", () => { + it("validates a correct file data structure", () => { + const validFileData = { filePath: "/path/to/file" } + expect(() => entitiesFileDataValidator.parse(validFileData)).not.toThrow() + }) + + it("fails validation for file data with empty filePath", () => { + const invalidFileData = { filePath: "" } + expect(() => entitiesFileDataValidator.parse(invalidFileData)).toThrow() + }) + + it("fails validation for file data with non-string filePath", () => { + const invalidFileData = { filePath: 123 } + expect(() => entitiesFileDataValidator.parse(invalidFileData)).toThrow() + }) +}) diff --git a/libs/device/models/src/lib/entities/entities-data-get.validator.ts b/libs/device/models/src/lib/entities/entities-data-get.validator.ts new file mode 100644 index 0000000000..98e4e357b7 --- /dev/null +++ b/libs/device/models/src/lib/entities/entities-data-get.validator.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" +import { entityDataSchema } from "./entity-data.validator" + +export const entitiesFileDataValidator = z.object({ + filePath: z.string().min(1), +}) +export type EntitiesFileData = z.infer + +export const entitiesJsonDataValidator = z.object({ + data: z.array(entityDataSchema), +}) +export type EntitiesJsonData = z.infer diff --git a/libs/device/models/src/lib/entities/entities-delete.validator.ts b/libs/device/models/src/lib/entities/entities-delete.validator.ts new file mode 100644 index 0000000000..816beb04af --- /dev/null +++ b/libs/device/models/src/lib/entities/entities-delete.validator.ts @@ -0,0 +1,13 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +export const entitiesDeletePartialSuccessValidator = z.object({ + failedIds: z.array(z.string()), +}) +export type EntitiesDeletePartialSuccess = z.infer< + typeof entitiesDeletePartialSuccessValidator +> diff --git a/libs/device/models/src/lib/entities/entities-metadata.validator.test.ts b/libs/device/models/src/lib/entities/entities-metadata.validator.test.ts new file mode 100644 index 0000000000..7d5c9dd10d --- /dev/null +++ b/libs/device/models/src/lib/entities/entities-metadata.validator.test.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { entitiesMetadataValidator } from "./entities-metadata.validator" + +describe("entitiesMetadataValidator", () => { + it("validates metadata with a nonnegative totalEntities", () => { + const validMetadata = { totalEntities: 10 } + expect(() => entitiesMetadataValidator.parse(validMetadata)).not.toThrow() + }) + + it("fails validation for negative totalEntities", () => { + const invalidMetadata = { totalEntities: -1 } + expect(() => entitiesMetadataValidator.parse(invalidMetadata)).toThrow() + }) + + it("fails validation for missing totalEntities", () => { + const invalidMetadata = {} + expect(() => entitiesMetadataValidator.parse(invalidMetadata)).toThrow() + }) + + it("fails validation for non-numeric totalEntities", () => { + const invalidMetadata = { totalEntities: "ten" } + expect(() => entitiesMetadataValidator.parse(invalidMetadata)).toThrow() + }) +}) diff --git a/libs/device/models/src/lib/entities/entities-metadata.validator.ts b/libs/device/models/src/lib/entities/entities-metadata.validator.ts new file mode 100644 index 0000000000..826bbe4ba7 --- /dev/null +++ b/libs/device/models/src/lib/entities/entities-metadata.validator.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +export const entitiesMetadataValidator = z.object({ + totalEntities: z.number().nonnegative(), +}) + +export type EntitiesMetadata = z.infer diff --git a/libs/device/models/src/lib/entities/entity-config.validator.test.ts b/libs/device/models/src/lib/entities/entity-config.validator.test.ts deleted file mode 100644 index 654094c580..0000000000 --- a/libs/device/models/src/lib/entities/entity-config.validator.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import { EntityConfig, entityConfigValidator } from "./entity-config.validator" -import { ZodError } from "zod" - -describe("entityConfigValidator", () => { - it("validates a correct entity configuration", () => { - const validConfig: EntityConfig = { - globalValidators: { - requiredFieldsCombinations: [ - { - fields: ["field1", "field2", "field3.field3a", "field4[]"], - countLogic: "gt", - fieldsCount: 1, - }, - ], - }, - fields: { - field1: { type: "id" }, - field2: { type: "string", validators: [{ pattern: "/abc/" }] }, - field3: { type: "object", fields: { field3a: { type: "string" } } }, - field4: { type: "array", items: { type: "string" } }, - }, - } - expect(() => entityConfigValidator.parse(validConfig)).not.toThrow() - }) - - it("throws an error when 'requiredFieldsCombinations' uses wrong fields", () => { - const invalidConfig: EntityConfig = { - globalValidators: { - requiredFieldsCombinations: [ - { - fields: ["field1", "field2.field3a", "field3"], - countLogic: "gt", - fieldsCount: 1, - }, - ], - }, - fields: { - field1: { type: "id" }, - field2: { - type: "array", - items: { - type: "object", - fields: { - field3a: { type: "string" }, - }, - }, - }, - }, - } - const result = () => entityConfigValidator.parse(invalidConfig) - expect(result).toThrow() - - try { - result() - } catch (error) { - expect((error as ZodError).errors).toEqual([ - { - code: "custom", - message: - "global validators are mentioning fields not defined in the 'fields' object", - path: [ - "globalValidators", - "requiredFieldsCombinations[0]", - "fields", - "[field2.field3a, field3]", - ], - }, - ]) - } - }) -}) diff --git a/libs/device/models/src/lib/entities/entity-data-get.validator.test.ts b/libs/device/models/src/lib/entities/entity-data-get.validator.test.ts new file mode 100644 index 0000000000..9a36d75ad4 --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-data-get.validator.test.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { entityJsonDataValidator } from "./entity-data-get.validator" + +describe("entityJsonDataValidator", () => { + it("validates a correct JSON data structure", () => { + const validJsonData = { data: { key1: "value1", key2: 123, 3: "value2" } } + expect(() => entityJsonDataValidator.parse(validJsonData)).not.toThrow() + }) + + it("fails validation for JSON data with non-object data field", () => { + const invalidJsonData = { data: "invalid data" } + expect(() => entityJsonDataValidator.parse(invalidJsonData)).toThrow() + }) + + it("fails validation for JSON data with array data field", () => { + const invalidJsonData = { data: [] } + expect(() => entityJsonDataValidator.parse(invalidJsonData)).toThrow() + }) +}) diff --git a/libs/device/models/src/lib/entities/entity-data-get.validator.ts b/libs/device/models/src/lib/entities/entity-data-get.validator.ts new file mode 100644 index 0000000000..38c80707c4 --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-data-get.validator.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" +import { entityDataSchema } from "./entity-data.validator" + +export const entityJsonDataValidator = z.object({ + data: entityDataSchema, +}) +export type EntityJsonData = z.infer diff --git a/libs/device/models/src/lib/entities/entity-data-patch.validator.ts b/libs/device/models/src/lib/entities/entity-data-patch.validator.ts new file mode 100644 index 0000000000..4292ae1b2a --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-data-patch.validator.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" +import { entityDataSchema } from "./entity-data.validator" + +export const entityDataPatchValidator = z.object({ + data: entityDataSchema, +}) +export type EntityDataPatch = z.infer diff --git a/libs/device/models/src/lib/entities/entity-data-post.validator.ts b/libs/device/models/src/lib/entities/entity-data-post.validator.ts new file mode 100644 index 0000000000..d5fd2a0d20 --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-data-post.validator.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" +import { entityDataSchema } from "./entity-data.validator" + +export const entityDataPostValidator = z.object({ + data: entityDataSchema, +}) +export type EntityDataPost = z.infer diff --git a/libs/device/models/src/lib/entities/entity-data.validator.ts b/libs/device/models/src/lib/entities/entity-data.validator.ts new file mode 100644 index 0000000000..6d9623facb --- /dev/null +++ b/libs/device/models/src/lib/entities/entity-data.validator.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +export const entityDataSchema = z.record(z.string(), z.unknown()) +export type EntityData = z.infer diff --git a/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts b/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts index 6a3853dfc9..f59f723c74 100644 --- a/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts +++ b/libs/device/models/src/lib/entities/helpers/flatten-entity-configuration.test.ts @@ -4,11 +4,11 @@ */ import { flattenEntityConfiguration } from "./flatten-entity-configuration" -import { EntityConfig } from "device/models" +import { EntitiesConfig } from "device/models" describe("flattenEntityConfiguration", () => { it("handles objects with non-object values correctly", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "id", }, @@ -31,7 +31,7 @@ describe("flattenEntityConfiguration", () => { }) it("converts a simple nested object to dot notation correctly", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "object", fields: { @@ -54,7 +54,7 @@ describe("flattenEntityConfiguration", () => { }) it("handles objects with nested arrays correctly", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "object", fields: { @@ -75,7 +75,7 @@ describe("flattenEntityConfiguration", () => { }) it("handles arrays with nested arrays correctly", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "array", items: { @@ -94,7 +94,7 @@ describe("flattenEntityConfiguration", () => { }) it("handles arrays with nested objects correctly", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "array", items: { @@ -115,7 +115,7 @@ describe("flattenEntityConfiguration", () => { }) it("excludes 'validators' key", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "string", validators: [], @@ -139,12 +139,12 @@ describe("flattenEntityConfiguration", () => { }) it("handles empty objects correctly", () => { - const input: EntityConfig["fields"] = {} + const input: EntitiesConfig["fields"] = {} expect(flattenEntityConfiguration(input)).toEqual({}) }) it("handles nested objects with mixed types", () => { - const input: EntityConfig["fields"] = { + const input: EntitiesConfig["fields"] = { a: { type: "object", fields: { diff --git a/libs/device/models/src/lib/entities/index.ts b/libs/device/models/src/lib/entities/index.ts index 22b0994766..6b791e7218 100644 --- a/libs/device/models/src/lib/entities/index.ts +++ b/libs/device/models/src/lib/entities/index.ts @@ -3,4 +3,16 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -export * from "./entity-config.validator" +import { EntitiesDeletePartialSuccess } from "./entities-delete.validator" + +export * from "./entities-config.validator" +export * from "./entity-data-get.validator" +export * from "./entities-metadata.validator" +export * from "./entities-data-get.validator" +export * from "./entities-delete.validator" +export * from "./entity-data.validator" +export * from "./entity-data-post.validator" +export * from "./entity-data-patch.validator" + +export type EntityId = string +export type EntitiesDeleteResponse = EntitiesDeletePartialSuccess | undefined diff --git a/libs/device/models/src/lib/feature/data-provider-config.test.ts b/libs/device/models/src/lib/feature/data-provider-config.test.ts new file mode 100644 index 0000000000..825f5bde9f --- /dev/null +++ b/libs/device/models/src/lib/feature/data-provider-config.test.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { dataProviderSchema } from "./data-provider-config" + +describe("dataProviderSchema", () => { + it("validates entities-array with sort and filters", () => { + const validData = { + source: "entities-array", + entitiesType: "someType", + sort: { + someField: { + priority: 1, + direction: "asc", + orderingPatterns: ["/pattern/"], + }, + }, + filters: { + someField: ["/pattern/"], + }, + } + expect(dataProviderSchema.safeParse(validData).success).toBe(true) + }) + + it("fails validation for entities-array with invalid sort direction", () => { + const invalidData = { + source: "entities-array", + sort: { + someField: { + priority: 1, + direction: "invalid", + }, + }, + } + expect(dataProviderSchema.safeParse(invalidData).success).toBe(false) + }) + + it("fails validation for entities-array with invalid regex in filters", () => { + const invalidData = { + source: "entities-array", + filters: { + someField: ["invalid-regex"], + }, + } + expect(dataProviderSchema.safeParse(invalidData).success).toBe(false) + }) + + it("validates entities-field", () => { + const validData = { + source: "entities-field", + entitiesType: "someType", + fields: { + dataItemId: "value1", + "data.someField": "value2", + }, + } + expect(dataProviderSchema.safeParse(validData).success).toBe(true) + }) + + it("fails validation for form-fields with invalid field key", () => { + const invalidData = { + source: "form-fields", + fields: { + invalidField: "value", + }, + } + expect(dataProviderSchema.safeParse(invalidData).success).toBe(false) + }) +}) diff --git a/libs/device/models/src/lib/feature/data-provider-config.ts b/libs/device/models/src/lib/feature/data-provider-config.ts new file mode 100644 index 0000000000..a3be0d3b43 --- /dev/null +++ b/libs/device/models/src/lib/feature/data-provider-config.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +const entitiesTypeSchema = z.string().min(1) + +const regexSchema = z + .string() + .regex( + /^\/.+\/[gmiyuvsd]*$/m, + "Regex must be in format /regex/ or /regex/flags" + ) + +const fieldsSchema = z.record( + z.union([ + z.literal("dataItemId"), + z.string().startsWith("data."), + z.string().startsWith("config."), + ]), + z.string() +) + +const sortSchema = z + .record( + z.string(), + z.object({ + priority: z.number().nonnegative(), + direction: z.union([z.literal("asc"), z.literal("desc")]), + orderingPatterns: z.array(regexSchema).optional(), + }) + ) + .optional() + +export type DataProviderSortConfig = z.infer + +const filtersSchema = z.record(z.string(), z.array(regexSchema)).optional() + +export type DataProviderFilterConfig = z.infer + +const entitiesArraySchema = z.object({ + source: z.literal("entities-array"), + entitiesType: entitiesTypeSchema, + sort: sortSchema, + filters: filtersSchema, +}) + +const entitiesFieldSchema = z.object({ + source: z.literal("entities-field"), + entitiesType: entitiesTypeSchema, + fields: fieldsSchema, +}) + +const formFieldsSchema = z.object({ + source: z.literal("form-fields"), + fields: fieldsSchema, +}) + +export const dataProviderSchema = z.union([ + entitiesArraySchema, + entitiesFieldSchema, + formFieldsSchema, +]) + +export type DataProviderConfig = z.infer diff --git a/libs/device/models/src/lib/feature/feature-config.test.ts b/libs/device/models/src/lib/feature/feature-config.test.ts index 16e21dd7e9..99049fc8a6 100644 --- a/libs/device/models/src/lib/feature/feature-config.test.ts +++ b/libs/device/models/src/lib/feature/feature-config.test.ts @@ -25,6 +25,13 @@ const featureConfig: FeatureConfig = { callback: jest.fn, }, }, + dataProvider: { + source: "entities-field", + entitiesType: "dummy", + fields: { + dataItemId: "dummy", + }, + }, }, } @@ -37,7 +44,12 @@ describe("FeatureConfigValidator", () => { it("should return fail when correct config is incorrect", () => { const feature = { ...featureConfig, - ...{ incorrect: { component: "incorrect" } }, + "dummy-1": { + ...featureConfig["dummy-1"], + config: { + wrongProp: "dummy", + }, + }, } const result = featureConfigValidator.safeParse(feature) expect(result.success).toBeFalsy() diff --git a/libs/device/models/src/lib/feature/feature-config.ts b/libs/device/models/src/lib/feature/feature-config.ts index 7200709e8e..93588589d8 100644 --- a/libs/device/models/src/lib/feature/feature-config.ts +++ b/libs/device/models/src/lib/feature/feature-config.ts @@ -6,6 +6,8 @@ import { z } from "zod" import componentValidators from "generic-view/models" import { ComponentPropsByName } from "generic-view/utils" +import { layoutSchema } from "./layout-config" +import { dataProviderSchema } from "./data-provider-config" const validators = Object.values(componentValidators).map( ({ key, configValidator }) => { @@ -13,6 +15,9 @@ const validators = Object.values(componentValidators).map( .object({ component: z.literal(key), config: configValidator, + layout: layoutSchema.optional(), + dataProvider: dataProviderSchema.optional(), + childrenKeys: z.array(z.string()).optional(), }) .passthrough() } diff --git a/libs/device/models/src/lib/feature/index.ts b/libs/device/models/src/lib/feature/index.ts index b29e8ce2d5..d0f19b70cd 100644 --- a/libs/device/models/src/lib/feature/index.ts +++ b/libs/device/models/src/lib/feature/index.ts @@ -4,3 +4,5 @@ */ export * from "./feature-config" +export * from "./layout-config" +export * from "./data-provider-config" diff --git a/libs/device/models/src/lib/feature/layout-config.test.ts b/libs/device/models/src/lib/feature/layout-config.test.ts new file mode 100644 index 0000000000..c72d82a4f6 --- /dev/null +++ b/libs/device/models/src/lib/feature/layout-config.test.ts @@ -0,0 +1,94 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { layoutSchema } from "./layout-config" + +describe("layoutSchema", () => { + it("validates layout with margin and padding", () => { + const validData = { + margin: "10px 5px", + padding: "5px 10px", + } + expect(layoutSchema.safeParse(validData).success).toBe(true) + }) + + it("validates grid layout with all optional fields", () => { + const validData = { + gridLayout: { + rows: ["1fr", "2fr"], + columns: ["1fr", "2fr"], + justifyContent: "center", + justifyItems: "stretch", + alignItems: "baseline", + rowGap: "10px", + columnGap: "10px", + }, + } + expect(layoutSchema.safeParse(validData).success).toBe(true) + }) + + it("validates flex layout with all optional fields", () => { + const validData = { + flexLayout: { + direction: "row", + justifyContent: "space-between", + alignItems: "center", + alignContent: "stretch", + wrap: "wrap", + rowGap: "10px", + columnGap: "10px", + }, + } + expect(layoutSchema.safeParse(validData).success).toBe(true) + }) + + it("validates layout with grid and flex placement", () => { + const validData = { + gridPlacement: { + row: 1, + column: 2, + width: 3, + height: 4, + }, + flexPlacement: { + grow: 1, + shrink: 0, + basis: "auto", + order: 1, + alignSelf: "center", + }, + } + expect(layoutSchema.safeParse(validData).success).toBe(true) + }) + + it("fails validation for invalid grid layout justifyContent value", () => { + const invalidData = { + gridLayout: { + rows: ["1fr", "2fr"], + columns: ["1fr", "2fr"], + justifyContent: "invalid", + }, + } + expect(layoutSchema.safeParse(invalidData).success).toBe(false) + }) + + it("fails validation for invalid flex layout direction value", () => { + const invalidData = { + flexLayout: { + direction: "invalid", + }, + } + expect(layoutSchema.safeParse(invalidData).success).toBe(false) + }) + + it("fails validation for missing required gridPlacement fields", () => { + const invalidData = { + gridPlacement: { + row: 1, + }, + } + expect(layoutSchema.safeParse(invalidData).success).toBe(false) + }) +}) diff --git a/libs/device/models/src/lib/feature/layout-config.ts b/libs/device/models/src/lib/feature/layout-config.ts new file mode 100644 index 0000000000..85640bd018 --- /dev/null +++ b/libs/device/models/src/lib/feature/layout-config.ts @@ -0,0 +1,146 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +const primitiveValueSchema = z.union([z.string(), z.number()]) + +export type PrimitiveValue = z.infer + +const gapSchema = z.object({ + rowGap: z.string().optional(), + columnGap: z.string().optional(), +}) + +const gridLayoutSchema = z.intersection( + gapSchema, + z.object({ + rows: z.array(primitiveValueSchema), + columns: z.array(primitiveValueSchema), + justifyContent: z + .union([ + z.literal("start"), + z.literal("end"), + z.literal("center"), + z.literal("stretch"), + z.literal("space-around"), + z.literal("space-between"), + z.literal("space-evenly"), + ]) + .optional(), + justifyItems: z + .union([ + z.literal("start"), + z.literal("end"), + z.literal("center"), + z.literal("stretch"), + ]) + .optional(), + alignItems: z + .union([ + z.literal("start"), + z.literal("end"), + z.literal("center"), + z.literal("stretch"), + z.literal("baseline"), + ]) + .optional(), + }) +) + +const gridLayoutBaseSchema = z.object({ + gridLayout: gridLayoutSchema.optional(), +}) + +const flexLayoutSchema = z.intersection( + gapSchema, + z.object({ + direction: z.union([ + z.literal("row"), + z.literal("column"), + z.literal("row-reverse"), + z.literal("column-reverse"), + ]), + justifyContent: z + .union([ + z.literal("flex-start"), + z.literal("flex-end"), + z.literal("center"), + z.literal("space-between"), + z.literal("space-around"), + z.literal("space-evenly"), + ]) + .optional(), + alignItems: z + .union([ + z.literal("flex-start"), + z.literal("flex-end"), + z.literal("center"), + z.literal("stretch"), + z.literal("baseline"), + ]) + .optional(), + alignContent: z + .union([ + z.literal("flex-start"), + z.literal("flex-end"), + z.literal("center"), + z.literal("stretch"), + z.literal("space-between"), + z.literal("space-around"), + ]) + .optional(), + wrap: z + .union([ + z.literal("wrap"), + z.literal("nowrap"), + z.literal("wrap-reverse"), + ]) + .optional(), + }) +) + +const flexLayoutBaseSchema = z.object({ + flexLayout: flexLayoutSchema.optional(), +}) + +const layoutBaseSchema = z.intersection( + gridLayoutBaseSchema, + flexLayoutBaseSchema +) + +const gridPlacementSchema = z.object({ + row: z.number(), + column: z.number(), + width: z.number(), + height: z.number(), +}) + +const flexPlacementSchema = z.object({ + grow: primitiveValueSchema.optional(), + shrink: primitiveValueSchema.optional(), + basis: primitiveValueSchema.optional(), + order: primitiveValueSchema.optional(), + alignSelf: z + .union([ + z.literal("flex-start"), + z.literal("flex-end"), + z.literal("center"), + z.literal("stretch"), + ]) + .optional(), +}) + +export const layoutSchema = z.intersection( + layoutBaseSchema, + z.object({ + gridPlacement: gridPlacementSchema.optional(), + flexPlacement: flexPlacementSchema.optional(), + margin: z.string().optional(), + padding: z.string().optional(), + }) +) + +export type Layout = z.infer diff --git a/libs/device/models/src/lib/general-error.ts b/libs/device/models/src/lib/general-error.ts index 0c8ea12b6c..1dddb2796d 100644 --- a/libs/device/models/src/lib/general-error.ts +++ b/libs/device/models/src/lib/general-error.ts @@ -24,5 +24,6 @@ export enum ApiFileTransferError { } export enum EntitiesError { - EntityTypeNotSupported = 406 + EntityTypeNotSupported = 406, + EntitiesDataFileCorrupted = 422, } diff --git a/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts b/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts index e513bdc23e..69fa75bed6 100644 --- a/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts +++ b/libs/device/models/src/lib/renderer-to-main-events/api-entities-service-events.ts @@ -4,5 +4,12 @@ */ export enum APIEntitiesServiceEvents { - EntityConfig = "apiservice_entity-config", + EntitiesConfig = "apiservice_entities-config", + EntitiesMetadata = "apiservice_entities-metadata", + EntitiesDataGet = "apiservice_entities-data-get", + EntitiesDataReadFromFile = "apiservice_entities-data-read-from-file", + EntityDataReadFromFile = "apiservice_entity-data-read-from-file", + EntitiesDataDelete = "apiservice_entity-data-delete", + EntityDataCreate = "apiservice_entity-data-create", + EntityDataUpdate = "apiservice_entity-data-update", } diff --git a/libs/generic-view/feature/src/lib/generic-view.tsx b/libs/generic-view/feature/src/lib/generic-view.tsx index 2d58ac385d..ee0c1f1878 100644 --- a/libs/generic-view/feature/src/lib/generic-view.tsx +++ b/libs/generic-view/feature/src/lib/generic-view.tsx @@ -8,13 +8,17 @@ import { useParams } from "react-router" import { GenericThemeProvider } from "generic-view/theme" import RecursiveLayout from "./recursive-layout" import GenericModals from "./generic-modals" +import { useDevConsole } from "./use-dev-console" +import { useDevViews } from "./use-dev-views/use-dev-views" export const GenericView: FunctionComponent = () => { + useDevConsole() const { viewKey, subviewKey } = useParams<{ viewKey: string subviewKey?: string }>() const currentViewKey = subviewKey || viewKey + useDevViews(currentViewKey) return ( diff --git a/libs/generic-view/feature/src/lib/recursive-layout.tsx b/libs/generic-view/feature/src/lib/recursive-layout.tsx index 90ebaf43c7..641fada5e7 100644 --- a/libs/generic-view/feature/src/lib/recursive-layout.tsx +++ b/libs/generic-view/feature/src/lib/recursive-layout.tsx @@ -3,8 +3,9 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import React, { FunctionComponent, useMemo } from "react" +import React, { useMemo } from "react" import { useSelector } from "react-redux" +import { FunctionComponent } from "Core/core/types/function-component.interface" import { ReduxRootState } from "Core/__deprecated__/renderer/store" import apiComponents from "generic-view/ui" import { APIFC } from "generic-view/utils" @@ -18,6 +19,7 @@ import logger from "Core/__deprecated__/main/utils/logger" interface Properties { viewKey: string componentKey: string + dataItemId?: string } export const RecursiveLayout: FunctionComponent = ( @@ -31,35 +33,44 @@ export const RecursiveLayout: FunctionComponent = ( return selectComponentChildrenKeys(state, { viewKey, componentKey }) }) as string[] | undefined const childrenKeysDependency = JSON.stringify(childrenKeys) + const recursiveComponentMetadataDependency = JSON.stringify( + recursiveComponentMetadata + ) return useMemo(() => { - if (!componentName || !(componentName in apiComponents)) { + if (!componentName) { + return null + } + if (!(componentName in apiComponents)) { logger.error( `Tried to render unknown component "${componentName}" in view "${viewKey}"` ) - // TODO: implement error handling return null } - const ApiComponent = setupComponent( apiComponents[componentName as keyof typeof apiComponents] as APIFC ) - return ( - + {childrenKeys?.map((key) => { return ( - + ) })} ) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ - childrenKeysDependency, - componentName, - componentKey, - recursiveComponentMetadata, viewKey, + componentName, + childrenKeysDependency, + recursiveComponentMetadataDependency, ]) } diff --git a/libs/generic-view/feature/src/lib/setup-component.tsx b/libs/generic-view/feature/src/lib/setup-component.tsx index cb83bf8e25..8da69b2a42 100644 --- a/libs/generic-view/feature/src/lib/setup-component.tsx +++ b/libs/generic-view/feature/src/lib/setup-component.tsx @@ -3,39 +3,163 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import React, { ComponentType } from "react" +import React, { ComponentType, ReactElement, useMemo } from "react" import { ReduxRootState } from "Core/__deprecated__/renderer/store" import styled, { css } from "styled-components" import { useSelector } from "react-redux" import { + selectActiveApiDeviceId, selectComponentConfig, selectComponentData, + selectComponentDataProvider, selectComponentLayout, + selectEntitiesData, + selectEntitiesIdFieldKey, + selectEntityData, } from "generic-view/store" -import { Layout, mapLayoutSizes, RecursiveComponent } from "generic-view/utils" +import { + dataProviderFilter, + dataProviderSort, + mapLayoutSizes, + RecursiveComponent, +} from "generic-view/utils" +import { EntityData, Layout } from "device/models" +import { set } from "lodash" +import { useFormContext } from "react-hook-form" export const setupComponent =

    ( Component: ComponentType

    ): RecursiveComponent => { - return (props) => { - const { viewKey, componentKey } = props + return ({ children, ...props }) => { + const { + viewKey, + componentKey, + style, + className, + componentName, + ...dataProps + } = props + const deviceId = useSelector(selectActiveApiDeviceId)! + const formContext = useFormContext() + let dataItemId = props.dataItemId const layout = useSelector((state: ReduxRootState) => { return selectComponentLayout(state, { viewKey, componentKey }) }) const config = useSelector((state: ReduxRootState) => { return selectComponentConfig(state, { viewKey, componentKey }) }) - const data = useSelector((state: ReduxRootState) => { + const dataProvider = useSelector((state: ReduxRootState) => { + return selectComponentDataProvider(state, { viewKey, componentKey }) + }) + const componentData = useSelector((state: ReduxRootState) => { + if (dataProvider) return return selectComponentData(state, { viewKey, componentKey }) }) - if (layout) { - return ( - - - + const entitiesData = + useSelector((state: ReduxRootState) => { + if (dataProvider?.source !== "entities-array") return + return selectEntitiesData(state, { + entitiesType: dataProvider.entitiesType, + deviceId, + }) as EntityData[] + }) || [] + const idFieldKey = useSelector((state: ReduxRootState) => { + if (dataProvider?.source !== "entities-array") return + return selectEntitiesIdFieldKey(state, { + deviceId, + entitiesType: dataProvider.entitiesType!, + }) + }) + const entityData = useSelector((state: ReduxRootState) => { + if (dataProvider?.source !== "entities-field") return + return selectEntityData(state, { + entitiesType: dataProvider.entitiesType, + entityId: dataItemId!, + deviceId, + }) as EntityData + }) + + const editableProps = { + ...dataProps, + config: { + ...config, + }, + data: undefined as unknown, + } + + if (!dataProvider) { + editableProps.data = componentData + } else if (dataProvider?.source === "entities-array") { + const filteredData = dataProviderFilter( + [...entitiesData], + dataProvider.filters ) + const sortedData = dataProviderSort([...filteredData], dataProvider.sort) + editableProps.data = sortedData?.map((item) => item[idFieldKey!]) + } else if (dataProvider?.source === "entities-field") { + if (entityData) { + for (const [key, field] of Object.entries(dataProvider.fields)) { + const value = entityData[field] + if (value === undefined) continue + set(editableProps || {}, key, value) + } + } + } else if (dataProvider?.source === "form-fields") { + for (const [key, field] of Object.entries(dataProvider.fields)) { + const value = formContext.getValues(field) + if (value === undefined) continue + if (key === "dataItemId") { + dataItemId = value + continue + } + set(editableProps, key, value) + } } - return + const editablePropsDependency = JSON.stringify(editableProps) + const layoutDependency = JSON.stringify(layout) + const dataProviderDependency = JSON.stringify(dataProvider) + + return useMemo(() => { + const ComponentWithProps = () => ( + + {React.Children.map(children, (child) => { + if (!React.isValidElement(child)) return null + return React.cloneElement(child as ReactElement, { + dataItemId, + }) + })} + + ) + + if (layout) { + return ( + + + + ) + } + return + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + children, + style, + className, + componentKey, + viewKey, + componentName, + dataItemId, + layoutDependency, + editablePropsDependency, + dataProviderDependency, + ]) } } diff --git a/libs/generic-view/feature/src/lib/use-dev-console.ts b/libs/generic-view/feature/src/lib/use-dev-console.ts new file mode 100644 index 0000000000..d6b47c6286 --- /dev/null +++ b/libs/generic-view/feature/src/lib/use-dev-console.ts @@ -0,0 +1,97 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { useEffect } from "react" +import { + getEntitiesDataAction, + getEntitiesMetadataAction, + getEntityDataAction, + selectActiveApiDeviceId, + createEntityDataAction, + updateEntityDataAction, + deleteEntitiesDataAction, +} from "generic-view/store" +import { useDispatch, useSelector } from "react-redux" +import { Dispatch } from "Core/__deprecated__/renderer/store" +import { EntityData, EntityId } from "device/models" + +export const useDevConsole = () => { + const dispatch = useDispatch() + const activeDeviceId = useSelector(selectActiveApiDeviceId) + + // Functions for internal testing + useEffect(() => { + if (process.env.NODE_ENV === "development" && activeDeviceId) { + if (typeof global !== "undefined") { + Object.assign(global, { + _getEntitiesData: ( + entitiesType: string, + responseType: "json" | "file" = "json", + deviceId = activeDeviceId + ) => { + return dispatch( + getEntitiesDataAction({ + entitiesType, + deviceId, + responseType, + }) + ) + }, + _getEntityData: ( + entitiesType: string, + entityId: string, + responseType: "json" | "file" = "json", + deviceId = activeDeviceId + ) => { + return dispatch( + getEntityDataAction({ + entitiesType, + entityId, + deviceId, + responseType, + }) + ) + }, + _getEntitiesMetadata: ( + entitiesType: string, + deviceId = activeDeviceId + ) => { + return dispatch( + getEntitiesMetadataAction({ entitiesType, deviceId }) + ) + }, + _deleteEntitiesDataAction: ( + entitiesType: string, + ids: EntityId[], + deviceId = activeDeviceId + ) => { + return dispatch( + deleteEntitiesDataAction({ entitiesType, ids, deviceId }) + ) + }, + _createEntityDataAction: ( + entitiesType: string, + data: EntityData, + deviceId = activeDeviceId + ) => { + return dispatch( + createEntityDataAction({ entitiesType, data, deviceId }) + ) + }, + _updateEntityDataAction: ( + entitiesType: string, + entityId: EntityId, + data: EntityData, + deviceId = activeDeviceId + ) => { + return dispatch( + updateEntityDataAction({ entitiesType, entityId, data, deviceId }) + ) + }, + }) + } + } + }, [activeDeviceId, dispatch]) +} diff --git a/libs/generic-view/feature/src/lib/use-dev-views/use-dev-views.tsx b/libs/generic-view/feature/src/lib/use-dev-views/use-dev-views.tsx new file mode 100644 index 0000000000..a4f8ad892d --- /dev/null +++ b/libs/generic-view/feature/src/lib/use-dev-views/use-dev-views.tsx @@ -0,0 +1,34 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { useEffect } from "react" +import { selectActiveApiDeviceId, setGenericConfig } from "generic-view/store" +import customViews from "./views" +import { useDispatch, useSelector } from "react-redux" +import { Dispatch } from "Core/__deprecated__/renderer/store" + +export const useDevViews = (viewKey: string) => { + const dispatch = useDispatch() + const activeDeviceId = useSelector(selectActiveApiDeviceId) + + // @ts-ignore + // eslint-disable-next-line react-hooks/exhaustive-deps + const newConfig = + viewKey in customViews + ? customViews[viewKey as keyof typeof customViews] + : undefined + + useEffect(() => { + if (newConfig && process.env.DEV_API_CONFIG === "1") { + dispatch( + setGenericConfig({ + feature: viewKey, + deviceId: activeDeviceId!, + config: newConfig, + }) + ) + } + }, [activeDeviceId, dispatch, newConfig, viewKey]) +} diff --git a/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts b/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts new file mode 100644 index 0000000000..77409b3796 --- /dev/null +++ b/libs/generic-view/feature/src/lib/use-dev-views/views/contacts-view.ts @@ -0,0 +1,238 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { View } from "generic-view/utils" + +const view: View = { + main: { + // @ts-ignore + screenTitle: "Contacts", + component: "block-plain", + layout: { + gridLayout: { + rows: ["auto", "1fr"], + columns: ["1fr"], + }, + }, + childrenKeys: ["importContactsButton", "contactsLoader"], + }, + contactsLoader: { + component: "entities-loader", + config: { + entitiesTypes: ["contacts"], + }, + childrenKeys: ["contactsForm"], + }, + contactsForm: { + component: "form", + config: { + formOptions: { + defaultValues: { + activeContactId: undefined, + selectedContacts: [], + totalContacts: 0, + }, + }, + }, + childrenKeys: ["contactsFormWrapper"], + }, + contactsFormWrapper: { + component: "block-box", + layout: { + flexLayout: { + direction: "row", + }, + }, + childrenKeys: ["contactsListTable", "detailsWrapper"], + }, + contactsListTable: { + component: "table", + dataProvider: { + source: "entities-array", + entitiesType: "contacts", + sort: { + firstName: { + priority: 2, + direction: "asc", + }, + lastName: { + priority: 1, + direction: "asc", + orderingPatterns: ["/^\\p{L}/miu", "/^\\d/m", "/^\\#/m"], + }, + }, + filters: { + firstName: ["/.+/"], + }, + }, + config: { + formOptions: { + activeIdFieldName: "activeContactId", + selectedIdsFieldName: "selectedContacts", + totalItemsFieldName: "totalContacts", + }, + }, + childrenKeys: ["columnCheckbox", "columnName", "columnOptional"], + }, + columnCheckbox: { + component: "table.cell", + config: { + width: 40, + }, + childrenKeys: ["contactCheckbox"], + }, + contactCheckbox: { + component: "form.checkboxInput", + config: { + name: "selectedContacts", + }, + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "config.value": "contactId", + }, + }, + }, + columnName: { + component: "table.cell", + config: { + width: 300, + }, + childrenKeys: ["contactJoinedNames"], + }, + contactJoinedNames: { + component: "block-plain", + layout: { + flexLayout: { + direction: "row", + columnGap: "0.5rem", + }, + }, + childrenKeys: ["contactFirstName", "contactLastName"], + }, + contactFirstName: { + component: "block-plain", + layout: { + flexLayout: { + direction: "row", + columnGap: "0.5rem", + }, + }, + childrenKeys: ["contactFirstNamePrefix", "contactFirstNameValue"], + }, + contactFirstNamePrefix: { + component: "text-plain", + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "data.text": "namePrefix", + }, + }, + }, + contactFirstNameValue: { + component: "text-plain", + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "data.text": "firstName", + }, + }, + }, + contactLastName: { + component: "text-plain", + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "data.text": "lastName", + }, + }, + }, + columnOptional: { + component: "form.conditionalRenderer", + config: { + formFieldName: "activeContactId", + renderIfFalse: true, + }, + childrenKeys: ["columnCompany"], + }, + columnCompany: { + component: "table.cell", + config: { + width: 200, + }, + childrenKeys: ["contactCompany"], + }, + contactCompany: { + component: "text-plain", + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "data.text": "company", + }, + }, + }, + detailsWrapper: { + component: "form.conditionalRenderer", + config: { + formFieldName: "activeContactId", + }, + childrenKeys: ["details"], + }, + details: { + component: "block-box", + config: { + title: "Contact", + }, + dataProvider: { + source: "form-fields", + fields: { + dataItemId: "activeContactId", + }, + }, + childrenKeys: ["contactDetails", "disableButton"], + }, + contactDetails: { + component: "block-plain", + childrenKeys: ["contactDetailsEmail", "contactDetailsName"], + }, + contactDetailsEmail: { + component: "text-plain", + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "data.text": "email", + }, + }, + }, + contactDetailsName: { + component: "text-plain", + dataProvider: { + source: "entities-field", + entitiesType: "contacts", + fields: { + "data.text": "firstName", + }, + }, + }, + disableButton: { + component: "button-primary", + config: { + text: "Hide details", + action: { + type: "form-set-field", + key: "activeContactId", + value: undefined, + }, + }, + }, +} + +export default view diff --git a/libs/generic-view/feature/src/lib/use-dev-views/views/index.ts b/libs/generic-view/feature/src/lib/use-dev-views/views/index.ts new file mode 100644 index 0000000000..05d4a0ec54 --- /dev/null +++ b/libs/generic-view/feature/src/lib/use-dev-views/views/index.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import contactsView from "./contacts-view" + +export default { + contacts: contactsView, +} diff --git a/libs/generic-view/models/src/index.ts b/libs/generic-view/models/src/index.ts index 1b6998e940..a220caac7b 100644 --- a/libs/generic-view/models/src/index.ts +++ b/libs/generic-view/models/src/index.ts @@ -47,6 +47,10 @@ import { backupRestoreAvailable } from "./lib/backup-restore-available" import { mcImportContactsButton } from "./lib/mc-import-contacts-button" import { mcDataMigration } from "./lib/mc-data-migration" import { incomingFeatureInfo } from "./lib/incoming-feature-info" +import { table } from "./lib/table" +import { formConditionalRenderer } from "./lib/form-conditional-renderer" +import { tableCell } from "./lib/table-cell" +import { entitiesLoader } from "./lib/entities-loader" export * from "./lib/block-box" export * from "./lib/block-plain" @@ -93,6 +97,10 @@ export * from "./lib/mc-import-contacts-button" export * from "./lib/modal-visibility-controller" export * from "./lib/mc-data-migration" export * from "./lib/incoming-feature-info" +export * from "./lib/table" +export * from "./lib/table-cell" +export * from "./lib/form-conditional-renderer" +export * from "./lib/entities-loader" export default { [blockBox.key]: blockBox, @@ -123,6 +131,7 @@ export default { [formRadioInput.key]: formRadioInput, [formSearchInput.key]: formSearchInput, [formCheckboxInput.key]: formCheckboxInput, + [formConditionalRenderer.key]: formConditionalRenderer, [progressBar.key]: progressBar, [tooltip.key]: tooltip, [tooltipAnchor.key]: tooltipAnchor, @@ -143,4 +152,7 @@ export default { [mcImportContactsButton.key]: mcImportContactsButton, [mcDataMigration.key]: mcDataMigration, [incomingFeatureInfo.key]: incomingFeatureInfo, + [table.key]: table, + [tableCell.key]: tableCell, + [entitiesLoader.key]: entitiesLoader, } as const diff --git a/libs/generic-view/models/src/lib/common-validators.ts b/libs/generic-view/models/src/lib/common-validators.ts index 6b62209d38..cb495ff6a2 100644 --- a/libs/generic-view/models/src/lib/common-validators.ts +++ b/libs/generic-view/models/src/lib/common-validators.ts @@ -50,10 +50,26 @@ export const customActionValidator = z.object({ export type CustomAction = z.infer +export const formActionValidator = z.union([ + z.object({ + type: z.literal("form-set-field"), + key: z.string(), + value: z.union([z.string(), z.number(), z.boolean()]).optional(), + }), + z.object({ + type: z.literal("form-toggle-field"), + key: z.string(), + }), + z.object({ + type: z.literal("form-reset"), + }), +]) + export const buttonActionValidator = z.union([ modalActionValidator, navigateActionValidator, customActionValidator, + formActionValidator, ]) export type ButtonAction = z.infer diff --git a/libs/generic-view/models/src/lib/entities-loader.ts b/libs/generic-view/models/src/lib/entities-loader.ts new file mode 100644 index 0000000000..d5f630c6d8 --- /dev/null +++ b/libs/generic-view/models/src/lib/entities-loader.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +const dataValidator = z.undefined() + +const configValidator = z.object({ + entitiesTypes: z.array(z.string()), +}) + +export type EntitiesLoaderConfig = z.infer + +export const entitiesLoader = { + key: "entities-loader", + dataValidator, + configValidator, +} as const diff --git a/libs/generic-view/models/src/lib/form-checkbox-input.ts b/libs/generic-view/models/src/lib/form-checkbox-input.ts index ff540b92a0..dadb98bfc7 100644 --- a/libs/generic-view/models/src/lib/form-checkbox-input.ts +++ b/libs/generic-view/models/src/lib/form-checkbox-input.ts @@ -14,7 +14,7 @@ const inputValidation: z.ZodType> = z.object({ const configValidator = z.object({ name: z.string(), - value: z.string(), + value: z.string().optional(), checked: z.boolean().optional(), label: z.string().optional(), validation: inputValidation.optional(), diff --git a/libs/generic-view/models/src/lib/form-conditional-renderer.ts b/libs/generic-view/models/src/lib/form-conditional-renderer.ts new file mode 100644 index 0000000000..f78095648d --- /dev/null +++ b/libs/generic-view/models/src/lib/form-conditional-renderer.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +const dataValidator = z.undefined() + +const configValidator = z.object({ + formFieldName: z.string(), + renderIfFalse: z.boolean().optional(), +}) + +export type FormConditionalRendererConfig = z.infer + +export const formConditionalRenderer = { + key: "form.conditionalRenderer", + dataValidator, + configValidator, +} as const diff --git a/libs/generic-view/models/src/lib/table-cell.ts b/libs/generic-view/models/src/lib/table-cell.ts new file mode 100644 index 0000000000..b72f39ead0 --- /dev/null +++ b/libs/generic-view/models/src/lib/table-cell.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +const dataValidator = z.undefined() + +const configValidator = z.object({ + width: z.number(), + colSpan: z.number().optional(), + rowSpan: z.number().optional(), +}) + +export type TableCellConfig = z.infer + +export const tableCell = { + key: "table.cell", + dataValidator, + configValidator, +} as const diff --git a/libs/generic-view/models/src/lib/table.ts b/libs/generic-view/models/src/lib/table.ts new file mode 100644 index 0000000000..3090092699 --- /dev/null +++ b/libs/generic-view/models/src/lib/table.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { z } from "zod" + +const dataValidator = z.array(z.string()).optional() + +export type TableData = z.infer + +const configValidator = z.object({ + formOptions: z.object({ + activeIdFieldName: z.string().optional(), + selectedIdsFieldName: z.string().optional(), + totalItemsFieldName: z.string().optional(), + }), + columnsNames: z.array(z.string()).optional(), +}) + +export type TableConfig = z.infer + +export const table = { + key: "table", + dataValidator, + configValidator, +} as const diff --git a/libs/generic-view/store/src/index.ts b/libs/generic-view/store/src/index.ts index 71e0c8ecb5..30cbb153da 100644 --- a/libs/generic-view/store/src/index.ts +++ b/libs/generic-view/store/src/index.ts @@ -42,6 +42,16 @@ export * from "./lib/external-providers/outlook/outlook.constants" export * from "./lib/external-providers/outlook/token-requester" export * from "./lib/external-providers/external-providers.interface" +export * from "./lib/entities/reducer" +export * from "./lib/entities/actions" +export * from "./lib/entities/get-entities-config.action" +export * from "./lib/entities/get-entities-data.action" +export * from "./lib/entities/get-entity-data.action" +export * from "./lib/entities/get-entities-metadata.action" +export * from "./lib/entities/delete-entities-data.action" +export * from "./lib/entities/create-entity-data.action" +export * from "./lib/entities/update-entity-data.action" + export * from "./lib/data-migration/reducer" export * from "./lib/data-migration/actions" export * from "./lib/data-migration/start-data.migration" diff --git a/libs/generic-view/store/src/lib/action-names.ts b/libs/generic-view/store/src/lib/action-names.ts index b71a7f01b6..538ebaa1af 100644 --- a/libs/generic-view/store/src/lib/action-names.ts +++ b/libs/generic-view/store/src/lib/action-names.ts @@ -16,6 +16,7 @@ export enum ActionName { AddDevice = "generic-views/add-device", RemoveDevice = "generic-views/remove-device", SetDeviceState = "generic-views/set-device-state", + SetGenericConfig = "generic-views/set-generic-config", OpenModal = "generic-modals/open-modal", CloseModal = "generic-modals/close-modal", @@ -83,4 +84,16 @@ export enum ActionName { HelpSetData = "help/set-data", HelpRateArticle = "help/rate-article", + + GetEntitiesConfig = "entities/get-entities-config", + SetEntitiesConfig = "entities/set-entities-config", + SetEntitiesData = "entities/set-entities-data", + SetEntityData = "entities/set-entity-data", + GetEntitiesData = "entities/get-entities-data", + GetEntityData = "entities/get-entity-data", + SetEntitiesMetadata = "entities/set-entities-metadata", + ClearEntitiesData = "entities/clear-entities-data", + DeleteEntityData = "entities/delete-entity-data", + CreateEntityData = "entities/create-entity-data", + UpdateEntityData = "entities/update-entity-data", } diff --git a/libs/generic-view/store/src/lib/entities/actions.ts b/libs/generic-view/store/src/lib/entities/actions.ts new file mode 100644 index 0000000000..b65095e88e --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/actions.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAction } from "@reduxjs/toolkit" +import { ActionName } from "../action-names" +import { + EntityData, + EntitiesMetadata, + EntitiesConfig, + EntityId, +} from "device/models" +import { DeviceId } from "Core/device/constants/device-id" + +export const setEntitiesConfig = createAction<{ + entitiesType: string + config: EntitiesConfig + idFieldKey: string + deviceId: DeviceId +}>(ActionName.SetEntitiesConfig) + +export const setEntitiesMetadata = createAction<{ + entitiesType: string + metadata: EntitiesMetadata + deviceId: DeviceId +}>(ActionName.SetEntitiesMetadata) + +export const setEntityData = createAction<{ + entitiesType: string + entityId: EntityId + data: EntityData + deviceId: DeviceId +}>(ActionName.SetEntityData) + +export const clearEntities = createAction<{ deviceId: DeviceId }>( + ActionName.ClearEntitiesData +) diff --git a/libs/generic-view/store/src/lib/entities/create-entity-data.action.ts b/libs/generic-view/store/src/lib/entities/create-entity-data.action.ts new file mode 100644 index 0000000000..22cb49a7da --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/create-entity-data.action.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { createEntityDataRequest } from "device/feature" +import { EntityData } from "device/models" +import { DeviceId } from "Core/device/constants/device-id" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import { ActionName } from "../action-names" +import logger from "Core/__deprecated__/main/utils/logger" + +export const createEntityDataAction = createAsyncThunk< + EntityData, + { + entitiesType: string + data: EntityData + deviceId: DeviceId + }, + { state: ReduxRootState } +>( + ActionName.CreateEntityData, + async ({ entitiesType, data, deviceId }, { rejectWithValue, getState }) => { + const response = await createEntityDataRequest({ + entitiesType, + data, + deviceId, + }) + if (!response.ok) { + return rejectWithValue(response.error) + } + + const { genericEntities } = getState() + const entities = genericEntities[deviceId][entitiesType] + const idFieldKey = entities?.idFieldKey + if (!entities || !idFieldKey) { + logger.error( + `Entities of type ${entitiesType} for device ${deviceId} not found` + ) + return rejectWithValue(undefined) + } + if ( + entities.data?.find( + (entity) => entity[idFieldKey] === response.data.data[idFieldKey] + ) + ) { + logger.error( + `Entity of type ${entitiesType} with id ${ + response.data.data[idFieldKey] as string + } already exists` + ) + return rejectWithValue(undefined) + } + + return response.data.data + } +) diff --git a/libs/generic-view/store/src/lib/entities/delete-entities-data.action.ts b/libs/generic-view/store/src/lib/entities/delete-entities-data.action.ts new file mode 100644 index 0000000000..c18afe2d3c --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/delete-entities-data.action.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { deleteEntitiesDataRequest } from "device/feature" +import { DeviceId } from "Core/device/constants/device-id" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import { ActionName } from "../action-names" +import { EntityId } from "device/models" +import { difference } from "lodash" + +export const deleteEntitiesDataAction = createAsyncThunk< + EntityId[], + { + entitiesType: string + ids: EntityId[] + deviceId: DeviceId + }, + { state: ReduxRootState } +>( + ActionName.DeleteEntityData, + async ({ entitiesType, ids, deviceId }, { rejectWithValue }) => { + const response = await deleteEntitiesDataRequest({ + entitiesType, + ids, + deviceId, + }) + + if (!response.ok) { + return rejectWithValue(response.error) + } + if (response.data?.failedIds) { + // TODO: Handle partial deletion of entities + return difference(ids, response.data.failedIds) + } + return ids + } +) diff --git a/libs/generic-view/store/src/lib/entities/get-entities-config.action.ts b/libs/generic-view/store/src/lib/entities/get-entities-config.action.ts new file mode 100644 index 0000000000..6201c2a93f --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/get-entities-config.action.ts @@ -0,0 +1,48 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { ActionName } from "../action-names" +import { getEntitiesConfigRequest } from "device/feature" +import { DeviceId } from "Core/device/constants/device-id" +import { setEntitiesConfig } from "./actions" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import { getEntitiesMetadataAction } from "./get-entities-metadata.action" +import { getEntitiesDataAction } from "./get-entities-data.action" + +export const getEntitiesConfigAction = createAsyncThunk< + undefined, + { deviceId: DeviceId; entitiesTypes?: string[] }, + { state: ReduxRootState } +>( + ActionName.GetEntitiesConfig, + async ({ deviceId, entitiesTypes = [] }, { rejectWithValue, dispatch }) => { + for (const entitiesType of entitiesTypes) { + const response = await getEntitiesConfigRequest({ + deviceId, + entitiesType, + }) + if (!response.ok) { + return rejectWithValue(response.error) + } + const config = response.data + const idFieldKey = Object.entries(config.fields).find( + ([, field]) => field.type === "id" + )![0] + + dispatch( + setEntitiesConfig({ + entitiesType, + config, + idFieldKey, + deviceId, + }) + ) + await dispatch(getEntitiesMetadataAction({ entitiesType, deviceId })) + dispatch(getEntitiesDataAction({ entitiesType, deviceId })) + } + return + } +) diff --git a/libs/generic-view/store/src/lib/entities/get-entities-data.action.ts b/libs/generic-view/store/src/lib/entities/get-entities-data.action.ts new file mode 100644 index 0000000000..387a3601e1 --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/get-entities-data.action.ts @@ -0,0 +1,69 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { ActionName } from "../action-names" +import { + EntityDataResponseType, + getEntitiesDataRequest, + readEntitiesDataFromFileRequest, +} from "device/feature" +import { DeviceId } from "Core/device/constants/device-id" +import { EntitiesFileData, EntitiesJsonData, EntityData } from "device/models" +import { getFile } from "../file-transfer/get-file.action" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import { AppError } from "Core/core/errors" + +export const getEntitiesDataAction = createAsyncThunk< + EntityData[], + { + entitiesType: string + deviceId: DeviceId + responseType?: EntityDataResponseType + }, + { state: ReduxRootState; rejectValue?: AppError } +>( + ActionName.GetEntitiesData, + async ( + { responseType = "file", entitiesType, deviceId }, + { rejectWithValue, dispatch } + ) => { + const response = await getEntitiesDataRequest({ + entitiesType, + deviceId, + responseType, + }) + if (!response.ok) { + return rejectWithValue(response.error) + } + + if (responseType === "file") { + const { filePath } = response.data as EntitiesFileData + const getFileResponse = await dispatch( + getFile({ + deviceId, + filePath, + }) + ) + if ( + !getFileResponse.payload || + !("transferId" in getFileResponse.payload) + ) { + return rejectWithValue(getFileResponse.payload) + } + + const readFileResponse = await readEntitiesDataFromFileRequest({ + transferId: getFileResponse.payload.transferId, + }) + if (!readFileResponse.ok) { + return rejectWithValue(readFileResponse.error) + } + return readFileResponse.data.data + } else { + const { data } = response.data as EntitiesJsonData + return data + } + } +) diff --git a/libs/generic-view/store/src/lib/entities/get-entities-metadata.action.ts b/libs/generic-view/store/src/lib/entities/get-entities-metadata.action.ts new file mode 100644 index 0000000000..529955d562 --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/get-entities-metadata.action.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { ActionName } from "../action-names" +import { getEntitiesMetadataRequest } from "device/feature" +import { setEntitiesMetadata } from "./actions" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" + +export const getEntitiesMetadataAction = createAsyncThunk< + undefined, + Required[0]>, + { state: ReduxRootState } +>(ActionName.GetEntitiesData, async (data, { rejectWithValue, dispatch }) => { + const response = await getEntitiesMetadataRequest(data) + + if (!response.ok) { + return rejectWithValue(response.error) + } + + dispatch( + setEntitiesMetadata({ + entitiesType: data.entitiesType, + metadata: response.data, + deviceId: data.deviceId, + }) + ) + return +}) diff --git a/libs/generic-view/store/src/lib/entities/get-entity-data.action.ts b/libs/generic-view/store/src/lib/entities/get-entity-data.action.ts new file mode 100644 index 0000000000..f5d07b03b2 --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/get-entity-data.action.ts @@ -0,0 +1,88 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { ActionName } from "../action-names" +import { + EntityDataResponseType, + getEntitiesDataRequest, + readEntityDataFromFileRequest, +} from "device/feature" +import { setEntityData } from "./actions" +import { DeviceId } from "Core/device/constants/device-id" +import { EntitiesFileData, EntityId, EntityJsonData } from "device/models" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import { getFile } from "../file-transfer/get-file.action" + +export const getEntityDataAction = createAsyncThunk< + undefined, + { + entitiesType: string + entityId: EntityId + deviceId: DeviceId + responseType?: EntityDataResponseType + }, + { state: ReduxRootState } +>( + ActionName.GetEntityData, + async ( + { responseType = "file", entityId, entitiesType, deviceId }, + { rejectWithValue, dispatch } + ) => { + const response = await getEntitiesDataRequest({ + entitiesType: entitiesType, + deviceId, + responseType, + entityId, + }) + + if (!response.ok) { + return rejectWithValue(response.error) + } + + if (responseType === "file") { + const { filePath } = response.data as EntitiesFileData + const getFileResponse = await dispatch( + getFile({ + deviceId, + filePath, + }) + ) + if ( + !getFileResponse.payload || + !("transferId" in getFileResponse.payload) + ) { + return rejectWithValue(getFileResponse.payload) + } + + const readFileResponse = await readEntityDataFromFileRequest({ + transferId: getFileResponse.payload.transferId, + }) + if (!readFileResponse.ok) { + return rejectWithValue(readFileResponse.error) + } + dispatch( + setEntityData({ + entitiesType, + entityId, + data: readFileResponse.data.data, + deviceId, + }) + ) + return + } else { + const { data } = response.data as EntityJsonData + dispatch( + setEntityData({ + entitiesType, + entityId, + data, + deviceId, + }) + ) + return + } + } +) diff --git a/libs/generic-view/store/src/lib/entities/reducer.ts b/libs/generic-view/store/src/lib/entities/reducer.ts new file mode 100644 index 0000000000..3a6beed822 --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/reducer.ts @@ -0,0 +1,131 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createReducer } from "@reduxjs/toolkit" +import { EntitiesConfig, EntitiesMetadata, EntityData } from "device/models" +import { + clearEntities, + setEntitiesConfig, + setEntitiesMetadata, + setEntityData, +} from "./actions" +import { getEntitiesDataAction } from "./get-entities-data.action" +import { DeviceId } from "Core/device/constants/device-id" +import { deleteEntitiesDataAction } from "./delete-entities-data.action" +import { createEntityDataAction } from "./create-entity-data.action" +import { updateEntityDataAction } from "./update-entity-data.action" + +type EntitiesType = string + +interface Entities { + idFieldKey: string + config: EntitiesConfig + data?: EntityData[] + metadata?: EntitiesMetadata + loading?: boolean + error?: boolean +} + +interface EntitiesState { + [key: DeviceId]: { + [key: EntitiesType]: Entities | undefined + } +} + +const initialState: EntitiesState = {} + +export const genericEntitiesReducer = createReducer(initialState, (builder) => { + builder.addCase(setEntitiesConfig, (state, action) => { + const { deviceId, entitiesType } = action.payload + + if (!state[deviceId]) { + state[deviceId] = { + [entitiesType]: { + config: action.payload.config, + idFieldKey: action.payload.idFieldKey, + }, + } + } else if (!state[deviceId][entitiesType]) { + state[deviceId][entitiesType] = { + config: action.payload.config, + idFieldKey: action.payload.idFieldKey, + } + } + }) + builder.addCase(getEntitiesDataAction.pending, (state, action) => { + const { deviceId, entitiesType } = action.meta.arg + state[deviceId][entitiesType]!.loading = true + }) + builder.addCase(getEntitiesDataAction.fulfilled, (state, action) => { + const { deviceId, entitiesType } = action.meta.arg + + state[deviceId][entitiesType]!.data = action.payload + state[deviceId][entitiesType]!.loading = false + }) + builder.addCase(getEntitiesDataAction.rejected, (state, action) => { + const { deviceId, entitiesType } = action.meta.arg + + state[deviceId][entitiesType]!.loading = false + state[deviceId][entitiesType]!.error = true + }) + + builder.addCase(setEntityData, (state, action) => { + const { deviceId, entitiesType, entityId, data } = action.payload + const idFieldKey = state[deviceId][entitiesType]?.idFieldKey + if (!idFieldKey) { + return + } + const entityIndex = state[deviceId][entitiesType]!.data?.findIndex( + (entity) => entity[idFieldKey] === entityId + ) + if (entityIndex !== -1 && state[deviceId][entitiesType]?.data) { + state[deviceId][entitiesType]!.data![entityIndex!] = data + } + }) + builder.addCase(setEntitiesMetadata, (state, action) => { + const { deviceId, entitiesType, metadata } = action.payload + state[deviceId][entitiesType]!.metadata = metadata + }) + builder.addCase(clearEntities, (state, action) => { + state[action.payload.deviceId] = {} + }) + builder.addCase(deleteEntitiesDataAction.fulfilled, (state, action) => { + const entitiesIds = action.payload + const { entitiesType, deviceId } = action.meta.arg + const entities = state[deviceId][entitiesType] + + if (entities && entities.data && entities.idFieldKey) { + entities.data = entities.data.filter( + (entity) => + !entitiesIds.includes(entity[entities.idFieldKey!] as string) + ) + } + }) + builder.addCase(createEntityDataAction.fulfilled, (state, action) => { + const { entitiesType, deviceId } = action.meta.arg + const newEntity = action.payload + const entities = state[deviceId][entitiesType] + + if (!entities) return + if (!entities.data) { + entities.data = [newEntity] + } else { + entities.data.push(newEntity) + } + }) + builder.addCase(updateEntityDataAction.fulfilled, (state, action) => { + const { entitiesType, deviceId } = action.meta.arg + const updatedEntity = action.payload + const entities = state[deviceId][entitiesType] + const idFieldKey = entities?.idFieldKey + + if (!entities || !entities.data || !idFieldKey) return + const entityIndex = entities.data.findIndex( + (entity) => entity[idFieldKey] === updatedEntity[idFieldKey!] + ) + if (entityIndex === -1) return + entities.data[entityIndex] = updatedEntity + }) +}) diff --git a/libs/generic-view/store/src/lib/entities/update-entity-data.action.ts b/libs/generic-view/store/src/lib/entities/update-entity-data.action.ts new file mode 100644 index 0000000000..5cce2f738b --- /dev/null +++ b/libs/generic-view/store/src/lib/entities/update-entity-data.action.ts @@ -0,0 +1,64 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createAsyncThunk } from "@reduxjs/toolkit" +import { updateEntityDataRequest } from "device/feature" +import { EntityData, EntityId } from "device/models" +import { DeviceId } from "Core/device/constants/device-id" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" +import { ActionName } from "../action-names" +import logger from "Core/__deprecated__/main/utils/logger" + +export const updateEntityDataAction = createAsyncThunk< + EntityData, + { + entitiesType: string + entityId: EntityId + data: EntityData + deviceId: DeviceId + }, + { state: ReduxRootState } +>( + ActionName.UpdateEntityData, + async ( + { entitiesType, entityId, data, deviceId }, + { rejectWithValue, getState } + ) => { + const response = await updateEntityDataRequest({ + entitiesType, + entityId, + data, + deviceId, + }) + + if (!response.ok) { + return rejectWithValue(response.error) + } + + const { genericEntities } = getState() + const entities = genericEntities[deviceId][entitiesType] + const idFieldKey = entities?.idFieldKey + if (!entities || !idFieldKey) { + logger.error( + `Entities of type ${entitiesType} for device ${deviceId} not found` + ) + return rejectWithValue(undefined) + } + if ( + !entities.data?.find( + (entity) => entity[idFieldKey] === response.data.data[idFieldKey] + ) + ) { + logger.error( + `Entity of type ${entitiesType} with id ${ + response.data.data[idFieldKey] as string + } not found` + ) + return rejectWithValue(undefined) + } + + return response.data.data + } +) diff --git a/libs/generic-view/store/src/lib/features/get-generic-config.actions.ts b/libs/generic-view/store/src/lib/features/get-generic-config.actions.ts index a8325b0344..e6458bd14a 100644 --- a/libs/generic-view/store/src/lib/features/get-generic-config.actions.ts +++ b/libs/generic-view/store/src/lib/features/get-generic-config.actions.ts @@ -26,6 +26,7 @@ export const getGenericConfig = createAsyncThunk< if (response.ok) { const fullView = transformGenericComponents(response.data) + return { deviceId, feature, view: fullView } } diff --git a/libs/generic-view/store/src/lib/file-transfer/get-file.action.ts b/libs/generic-view/store/src/lib/file-transfer/get-file.action.ts index c5dd38ea7b..497acd6c04 100644 --- a/libs/generic-view/store/src/lib/file-transfer/get-file.action.ts +++ b/libs/generic-view/store/src/lib/file-transfer/get-file.action.ts @@ -33,7 +33,7 @@ export const getFile = createAsyncThunk< { deviceId: DeviceId filePath: string - targetPath: string + targetPath?: string preTransfer?: PreTransferGet }, { state: ReduxRootState; rejectValue: GetFileError | undefined } @@ -80,7 +80,8 @@ export const getFile = createAsyncThunk< if (aborted) { return rejectWithValue(undefined) } - const { ok, error } = await getFileRequest(transferId, chunkNumber) + const fileResp = await getFileRequest(transferId, chunkNumber, deviceId) + const { ok, error } = fileResp if (!ok) { await sendClearRequest(transferId) return rejectWithValue({ diff --git a/libs/generic-view/store/src/lib/get-api-config.ts b/libs/generic-view/store/src/lib/get-api-config.ts index 722be9276c..3af59038a1 100644 --- a/libs/generic-view/store/src/lib/get-api-config.ts +++ b/libs/generic-view/store/src/lib/get-api-config.ts @@ -12,6 +12,7 @@ import { ActionName } from "./action-names" import { getAllFeatures } from "./features/get-all-features" import { getMenuConfig } from "./get-menu-config" import { ResultObject } from "Core/core/builder" +import { getEntitiesConfigAction } from "./entities/get-entities-config.action" export const getAPIConfig = createAsyncThunk< { deviceId: string; apiConfig: ApiConfig }, @@ -28,8 +29,17 @@ export const getAPIConfig = createAsyncThunk< } while (retry && retires++ < retryLimit && !response.ok) if (response.ok) { - dispatch(getMenuConfig({ deviceId })) - dispatch(getAllFeatures({ deviceId, features: response.data.features })) + await dispatch(getMenuConfig({ deviceId })) + await dispatch( + getAllFeatures({ deviceId, features: response.data.features }) + ) + dispatch( + getEntitiesConfigAction({ + deviceId, + entitiesTypes: response.data.entityTypes, + }) + ) + return { deviceId, apiConfig: response.data } } return rejectWithValue(response.error) diff --git a/libs/generic-view/store/src/lib/hooks/use-api-serial-port-listeners.ts b/libs/generic-view/store/src/lib/hooks/use-api-serial-port-listeners.ts index 42fe4fdf19..d6cddc56bd 100644 --- a/libs/generic-view/store/src/lib/hooks/use-api-serial-port-listeners.ts +++ b/libs/generic-view/store/src/lib/hooks/use-api-serial-port-listeners.ts @@ -21,6 +21,7 @@ import { selectDataMigrationSourceDevice, selectDataMigrationTargetDevice, } from "../selectors/data-migration-devices" +import { clearEntities } from "../entities/actions" export const useAPISerialPortListeners = () => { const dispatch = useDispatch() @@ -93,6 +94,7 @@ const useHandleDevicesDetached = () => { for (const event of apiEvents) { dispatch(removeDevice(event)) + dispatch(clearEntities({ deviceId: event.id })) } dispatch(closeAllModals()) diff --git a/libs/generic-view/store/src/lib/selectors/component.ts b/libs/generic-view/store/src/lib/selectors/component.ts index 7bb102d625..926b74f6bd 100644 --- a/libs/generic-view/store/src/lib/selectors/component.ts +++ b/libs/generic-view/store/src/lib/selectors/component.ts @@ -26,6 +26,11 @@ export const selectComponentConfig = createSelector( (config) => config?.config ) +export const selectComponentDataProvider = createSelector( + selectComponent, + (config) => config?.dataProvider +) + export const selectComponentLayout = createSelector( selectComponent, (config) => config?.layout diff --git a/libs/generic-view/store/src/lib/selectors/entities.ts b/libs/generic-view/store/src/lib/selectors/entities.ts new file mode 100644 index 0000000000..afb6c943f7 --- /dev/null +++ b/libs/generic-view/store/src/lib/selectors/entities.ts @@ -0,0 +1,77 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createSelector } from "reselect" +import { ReduxRootState } from "Core/__deprecated__/renderer/store" + +const selectEntitiesOfDevice = createSelector( + (state: ReduxRootState) => state.genericEntities, + (state: ReduxRootState, { deviceId }: { deviceId: string }) => deviceId, + (entities, deviceId) => { + return entities[deviceId] + } +) + +export const selectEntitiesIdFieldKey = createSelector( + selectEntitiesOfDevice, + (state: ReduxRootState, { entitiesType }: { entitiesType?: string }) => { + return entitiesType + }, + (entities, entitiesType) => { + if (!entitiesType) return undefined + return entities[entitiesType]?.idFieldKey + } +) + +const selectEntities = createSelector( + selectEntitiesOfDevice, + (state: ReduxRootState, { entitiesType }: { entitiesType: string }) => + entitiesType, + (entities, entityType) => { + return entities[entityType] + } +) + +export const selectEntitiesData = createSelector( + selectEntities, + (entities) => entities?.data +) + +export const selectEntityData = createSelector( + selectEntities, + (state: ReduxRootState, { entityId }: { entityId: string }) => entityId, + (entities, entityId) => { + if (!entities || !entities.data || !entities.idFieldKey) { + return undefined + } + return entities.data.find( + (entity) => entity[entities.idFieldKey!] === entityId + ) + } +) + +export const selectEntitiesLoadingState = createSelector( + selectEntitiesOfDevice, + (entities) => { + return Object.entries(entities).reduce( + ( + acc: Record, + [entitiesType, entity] + ) => { + if (entity?.error) { + acc[entitiesType] = "error" + } else if (entity?.metadata?.totalEntities === 0 || entity?.data) { + acc[entitiesType] = "loaded" + } else if (entity?.loading) { + acc[entitiesType] = "loading" + } else { + acc[entitiesType] = "idle" + } + return acc + }, + {} + ) + } +) diff --git a/libs/generic-view/store/src/lib/selectors/index.ts b/libs/generic-view/store/src/lib/selectors/index.ts index 2aff2bd537..94836956dc 100644 --- a/libs/generic-view/store/src/lib/selectors/index.ts +++ b/libs/generic-view/store/src/lib/selectors/index.ts @@ -31,3 +31,4 @@ export * from "./select-generic-view-state" export * from "./data-migration-pure-db-indexing" export * from "./device-error-modal-opened" export * from "./data-transfer-error-type" +export * from "./entities" diff --git a/libs/generic-view/store/src/lib/views/actions.ts b/libs/generic-view/store/src/lib/views/actions.ts index a39b4104a5..fa0221358b 100644 --- a/libs/generic-view/store/src/lib/views/actions.ts +++ b/libs/generic-view/store/src/lib/views/actions.ts @@ -34,3 +34,9 @@ export const setLastRefresh = createAction(ActionName.SetLastRefresh) export const setDeviceState = createAction<{ id: string; state: DeviceState }>( ActionName.SetDeviceState ) + +export const setGenericConfig = createAction<{ + config: View + feature: string + deviceId: string +}>(ActionName.SetGenericConfig) diff --git a/libs/generic-view/store/src/lib/views/reducer.ts b/libs/generic-view/store/src/lib/views/reducer.ts index 536ebaec03..9f33dc3b0a 100644 --- a/libs/generic-view/store/src/lib/views/reducer.ts +++ b/libs/generic-view/store/src/lib/views/reducer.ts @@ -21,11 +21,13 @@ import { addDevice, removeDevice, setDeviceState, + setGenericConfig, setLastRefresh, setMenu, setViewData, setViewLayout, } from "./actions" +import { transformGenericComponents } from "../features/transform-generic-components" export interface GenericState { menu: MenuElement[] | undefined @@ -195,4 +197,20 @@ export const genericViewsReducer = createReducer(initialState, (builder) => { } } }) + // Helper action for setting custom generic config without a need of reloading the app + builder.addCase(setGenericConfig, (state, action) => { + const { deviceId, feature, config } = action.payload + if (state.devices[deviceId] !== undefined) { + state.devices[deviceId].features = { + ...state.devices[deviceId].features, + [feature]: { + config: transformGenericComponents({ + ...state.devices[deviceId].features?.[feature].config, + ...config, + }), + data: state.devices[deviceId].features?.[feature]?.data, + }, + } + } + }) }) diff --git a/libs/generic-view/ui/src/index.ts b/libs/generic-view/ui/src/index.ts index 575a88447c..f7e3459752 100644 --- a/libs/generic-view/ui/src/index.ts +++ b/libs/generic-view/ui/src/index.ts @@ -11,6 +11,8 @@ import { interactive } from "./lib/interactive/interactive" import { buttons } from "./lib/buttons/buttons" import { texts } from "./lib/texts" import { Icon } from "./lib/icon/icon" +import { table } from "./lib/table" +import { entities } from "./lib/entities" export * from "./lib/icon/icon" export * from "./lib/api-connection-demo" @@ -29,6 +31,7 @@ export * from "./lib/buttons/button-text" export * from "./lib/buttons/button-primary" export * from "./lib/texts/paragraphs" export * from "./lib/texts/headers" +export * from "./lib/entities" const apiComponents = { ...predefinedComponents, @@ -38,6 +41,8 @@ const apiComponents = { ...interactive, ...buttons, ...texts, + ...table, + ...entities, icon: Icon, } diff --git a/libs/generic-view/ui/src/lib/buttons/button-base/use-button-action.ts b/libs/generic-view/ui/src/lib/buttons/button-base/use-button-action.ts index aa63cba9f1..690356d801 100644 --- a/libs/generic-view/ui/src/lib/buttons/button-base/use-button-action.ts +++ b/libs/generic-view/ui/src/lib/buttons/button-base/use-button-action.ts @@ -15,11 +15,14 @@ import { ButtonAction } from "generic-view/utils" import { useDispatch } from "react-redux" import { useHistory } from "react-router" import { Dispatch } from "Core/__deprecated__/renderer/store" +import { useFormContext } from "react-hook-form" +import logger from "Core/__deprecated__/main/utils/logger" export const useButtonAction = (viewKey: string) => { const dispatch = useDispatch() const navigate = useHistory() const currentViewName = useScreenTitle(viewKey) + const formContext = useFormContext() return (action?: ButtonAction) => { if (!action) return @@ -59,6 +62,21 @@ export const useButtonAction = (viewKey: string) => { }, }) break + case "form-set-field": + formContext.setValue(action.key, action.value) + break + case "form-toggle-field": + if (typeof formContext.getValues(action.key) === "boolean") { + formContext.setValue(action.key, !formContext.getValues(action.key)) + } else if (typeof formContext.getValues(action.key) === "undefined") { + logger.error(`Tried to toggle not existing field: ${action.key}`) + } else { + logger.error(`Tried to toggle non-boolean field: ${action.key}`) + } + break + case "form-reset": + formContext.reset() + break case "custom": action.callback() break diff --git a/libs/generic-view/ui/src/lib/entities/entities-loader.tsx b/libs/generic-view/ui/src/lib/entities/entities-loader.tsx new file mode 100644 index 0000000000..872d345c41 --- /dev/null +++ b/libs/generic-view/ui/src/lib/entities/entities-loader.tsx @@ -0,0 +1,55 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import React, { useEffect } from "react" +import { APIFC } from "generic-view/utils" +import { EntitiesLoaderConfig } from "generic-view/models" +import { + getEntitiesDataAction, + selectActiveApiDeviceId, + selectEntitiesLoadingState, +} from "generic-view/store" +import { useDispatch, useSelector } from "react-redux" +import { Dispatch, ReduxRootState } from "Core/__deprecated__/renderer/store" +import { SpinnerLoader } from "../shared/spinner-loader" +import styled from "styled-components" + +export const EntitiesLoader: APIFC = ({ + config, + children, +}) => { + const dispatch = useDispatch() + const deviceId = useSelector(selectActiveApiDeviceId)! + const entitiesLoadingStates = useSelector((state: ReduxRootState) => + selectEntitiesLoadingState(state, { deviceId }) + ) + const allLoaded = config.entitiesTypes.every( + (entitiesType) => entitiesLoadingStates[entitiesType] === "loaded" + ) + + useEffect(() => { + for (const entitiesType of config.entitiesTypes) { + if (entitiesLoadingStates[entitiesType] === "idle") { + dispatch(getEntitiesDataAction({ entitiesType, deviceId })) + } + } + }, [config.entitiesTypes, deviceId, dispatch, entitiesLoadingStates]) + + if (allLoaded) { + return children + } + return ( + + + + ) +} + +const Wrapper = styled.div` + & > * { + width: 5rem; + height: 5rem; + } +` diff --git a/libs/generic-view/ui/src/lib/entities/index.ts b/libs/generic-view/ui/src/lib/entities/index.ts new file mode 100644 index 0000000000..07dae8db43 --- /dev/null +++ b/libs/generic-view/ui/src/lib/entities/index.ts @@ -0,0 +1,11 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { EntitiesLoader } from "./entities-loader" +import { entitiesLoader } from "generic-view/models" + +export const entities = { + [entitiesLoader.key]: EntitiesLoader, +} diff --git a/libs/generic-view/ui/src/lib/interactive/form/form.tsx b/libs/generic-view/ui/src/lib/interactive/form/form.tsx index 4baaefab11..20b96a3a4c 100644 --- a/libs/generic-view/ui/src/lib/interactive/form/form.tsx +++ b/libs/generic-view/ui/src/lib/interactive/form/form.tsx @@ -11,12 +11,14 @@ import { RadioInput } from "./input/radio-input" import { CheckboxInput } from "./input/checkbox-input" import { SearchInput } from "./input/search-input" import { FormConfig } from "generic-view/models" +import { FormConditionalRenderer } from "./helpers/form-conditional-renderer" export const Form: APIFC & { TextInput: typeof TextInput RadioInput: typeof RadioInput CheckboxInput: typeof CheckboxInput SearchInput: typeof SearchInput + ConditionalRenderer: typeof FormConditionalRenderer } = ({ config, children }) => { const methods = useForm({ mode: "onTouched", @@ -28,5 +30,6 @@ Form.TextInput = TextInput Form.RadioInput = RadioInput Form.CheckboxInput = CheckboxInput Form.SearchInput = SearchInput +Form.ConditionalRenderer = FormConditionalRenderer export default Form diff --git a/libs/generic-view/ui/src/lib/interactive/form/helpers/form-conditional-renderer.tsx b/libs/generic-view/ui/src/lib/interactive/form/helpers/form-conditional-renderer.tsx new file mode 100644 index 0000000000..914252a48c --- /dev/null +++ b/libs/generic-view/ui/src/lib/interactive/form/helpers/form-conditional-renderer.tsx @@ -0,0 +1,22 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { APIFC } from "generic-view/utils" +import { FormConditionalRendererConfig } from "generic-view/models" +import { useFormContext } from "react-hook-form" + +export const FormConditionalRenderer: APIFC< + undefined, + FormConditionalRendererConfig +> = ({ children, config }) => { + const formContext = useFormContext() + const value = Boolean(formContext.watch(config.formFieldName)) + const shouldRender = config.renderIfFalse ? !value : value + + if (shouldRender) { + return children + } + return null +} diff --git a/libs/generic-view/ui/src/lib/interactive/form/input/checkbox-input.tsx b/libs/generic-view/ui/src/lib/interactive/form/input/checkbox-input.tsx index 7ba1dd99d9..98ddf01c49 100644 --- a/libs/generic-view/ui/src/lib/interactive/form/input/checkbox-input.tsx +++ b/libs/generic-view/ui/src/lib/interactive/form/input/checkbox-input.tsx @@ -27,7 +27,12 @@ export const CheckboxInput: APIFC = ({ }) return ( - + { + e.stopPropagation() + }} + > = ({ - {children || config.label} + {children || (config.label ? {config.label} : null)} ) @@ -87,11 +92,15 @@ const InputBox = styled.div` align-self: baseline; border-radius: ${({ theme }) => theme.radius.xs}; border: 0.1rem solid ${({ theme }) => theme.color.grey4}; - margin: 0 1.4rem 0 0; + margin: 0; transition: background-color 0.2s ease-in-out; overflow: hidden; box-sizing: border-box; + & + * { + margin-left: 1.4rem; + } + ${CheckIcon} { opacity: 0; visibility: hidden; diff --git a/libs/generic-view/ui/src/lib/interactive/interactive.ts b/libs/generic-view/ui/src/lib/interactive/interactive.ts index eb4a479520..0cb6c30873 100644 --- a/libs/generic-view/ui/src/lib/interactive/interactive.ts +++ b/libs/generic-view/ui/src/lib/interactive/interactive.ts @@ -11,6 +11,7 @@ import Tooltip from "./tooltip/tooltip" import { form, formCheckboxInput, + formConditionalRenderer, formRadioInput, formSearchInput, formTextInput, @@ -44,6 +45,7 @@ export const interactive = { [formSearchInput.key]: Form.SearchInput, [formRadioInput.key]: Form.RadioInput, [formCheckboxInput.key]: Form.CheckboxInput, + [formConditionalRenderer.key]: Form.ConditionalRenderer, [progressBar.key]: ProgressBar, [tooltip.key]: Tooltip, [tooltipAnchor.key]: Tooltip.Anchor, diff --git a/libs/generic-view/ui/src/lib/table/index.ts b/libs/generic-view/ui/src/lib/table/index.ts new file mode 100644 index 0000000000..e17c62956e --- /dev/null +++ b/libs/generic-view/ui/src/lib/table/index.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { table as tableWrapper, tableCell } from "generic-view/models" +import { Table } from "./table" + +export const table = { + [tableWrapper.key]: Table, + [tableCell.key]: Table.Cell, +} diff --git a/libs/generic-view/ui/src/lib/table/table-cell.tsx b/libs/generic-view/ui/src/lib/table/table-cell.tsx new file mode 100644 index 0000000000..d21d31f05f --- /dev/null +++ b/libs/generic-view/ui/src/lib/table/table-cell.tsx @@ -0,0 +1,43 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import React, { useMemo } from "react" +import { APIFC } from "generic-view/utils" +import { TableCellConfig } from "generic-view/models" +import styled from "styled-components" + +export const TableCell: APIFC = ({ + children, + config, + data, + ...props +}) => { + const propsDependencies = JSON.stringify(props) + const configDependencies = JSON.stringify(config) + return useMemo( + () => { + return ( + + {children} + + ) + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [children, configDependencies, propsDependencies] + ) +} + +export const Cell = styled.td<{ + $width: number +}>` + min-width: ${({ $width }) => $width}px; + max-width: ${({ $width }) => $width}px; + overflow: hidden; +` diff --git a/libs/generic-view/ui/src/lib/table/table.tsx b/libs/generic-view/ui/src/lib/table/table.tsx new file mode 100644 index 0000000000..1ec7dd1cdb --- /dev/null +++ b/libs/generic-view/ui/src/lib/table/table.tsx @@ -0,0 +1,199 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import React, { + Children, + ReactElement, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react" +import styled, { css } from "styled-components" +import { APIFC } from "generic-view/utils" +import { TableConfig, TableData } from "generic-view/models" +import { TableCell } from "./table-cell" +import { useFormContext } from "react-hook-form" +import { P1 } from "../texts/paragraphs" + +const rowHeight = 64 + +export const Table: APIFC & { + Cell: typeof TableCell +} = ({ data = [], config, children, ...props }) => { + const formContext = useFormContext() + const scrollWrapperRef = useRef(null) + const [visibleRowsBounds, setVisibleRowsBounds] = useState<[number, number]>([ + -1, -1, + ]) + + const { formOptions, columnsNames } = config + const { activeIdFieldName } = formOptions + + const activeRowId = activeIdFieldName + ? formContext.watch(activeIdFieldName) + : undefined + + const onRowClick = useCallback( + (id: string) => { + if (!activeIdFieldName) return + formContext.setValue(activeIdFieldName!, id) + }, + [activeIdFieldName, formContext] + ) + + const handleScroll = useCallback(() => { + if (!scrollWrapperRef.current) return + const { scrollTop, clientHeight } = scrollWrapperRef.current + const rowsPerPage = Math.ceil(clientHeight / rowHeight) || 0 + const currentRowIndex = Math.floor(scrollTop / rowHeight) + const firstVisibleRowIndex = currentRowIndex - rowsPerPage + const lastVisibleRowIndex = currentRowIndex + rowsPerPage * 2 + setVisibleRowsBounds([firstVisibleRowIndex, lastVisibleRowIndex]) + }, []) + + useEffect(() => { + if (formOptions.totalItemsFieldName) { + formContext.setValue(formOptions.totalItemsFieldName, data?.length) + } + }, [formOptions.totalItemsFieldName, data?.length, formContext]) + + useEffect(() => { + const scrollWrapper = scrollWrapperRef.current + if (!scrollWrapper) return + + handleScroll() + scrollWrapper.addEventListener("scroll", handleScroll) + return () => { + scrollWrapper.removeEventListener("scroll", handleScroll) + } + }, [data.length, handleScroll]) + + const placeholder = useMemo(() => { + return ( + + +

    + + + ) + }, [children]) + + const renderChildren = useCallback( + (id: string) => { + return Children.map(children, (child) => { + if (!React.isValidElement(child)) return null + return React.cloneElement(child as ReactElement, { + dataItemId: id, + }) + }) + }, + [children] + ) + + const renderRow = useCallback( + (id: string, index: number) => { + if (index < visibleRowsBounds[0] || index > visibleRowsBounds[1]) { + return placeholder + } + const onClick = () => onRowClick(id) + const isActive = activeRowId === id + + return ( + + {renderChildren(id)} + + ) + }, + [activeRowId, onRowClick, placeholder, renderChildren, visibleRowsBounds] + ) + + return useMemo( + () => ( + + + {columnsNames && columnsNames?.length > 0 && ( + + + {columnsNames.map((columnName) => ( + + {columnName} + + ))} + + + )} + + {data?.map((id, index) => renderRow(id, index))} + + + + ), + [columnsNames, data, props, renderRow] + ) +} + +Table.Cell = TableCell + +const ScrollableWrapper = styled.div` + height: 100%; + width: 100%; + overflow: auto; + position: relative; +` + +const TableWrapper = styled.table` + position: absolute; + top: 0; + left: 0; + width: min-content; + max-height: 100%; + border-collapse: collapse; + border-spacing: 0; +` + +const TableHeader = styled.thead` + background: #fff; + height: ${rowHeight / 10}rem; + position: sticky; + z-index: 2; + top: 0; + + th { + text-align: left; + white-space: nowrap; + } +` + +const TableBody = styled.tbody` + tr { + height: ${rowHeight / 10}rem; + } + td { + text-align: left; + } +` + +// TODO: Add proper styles for the table row +const Row = styled.tr<{ $active?: boolean }>` + ${({ $active }) => + $active && + css` + border-left: 0.2rem solid #000; + `} + height: ${rowHeight / 10}rem; +` + +const RowPlaceholder = styled.tr` + height: ${rowHeight / 10}rem; + + div { + display: block; + height: 2.4rem; + border-radius: ${({ theme }) => theme.radius.md}; + background: ${({ theme }) => theme.color.grey6}; + } +` diff --git a/libs/generic-view/utils/src/index.ts b/libs/generic-view/utils/src/index.ts index ac7fe08d3c..c9d9f25a0f 100644 --- a/libs/generic-view/utils/src/index.ts +++ b/libs/generic-view/utils/src/index.ts @@ -8,7 +8,7 @@ export * from "./lib/models/api-fc.types" export * from "./lib/models/api-views.types" export * from "./lib/models/icons.types" export * from "./lib/models/button.types" -export * from "./lib/models/layout.types" export * from "./lib/view-generators/generate-view-config" export * from "./lib/map-layout-sizes/map-layout-sizes" export * from "./lib/models/modal.types" +export * from "./lib/data-provider-helpers" diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.test.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.test.ts new file mode 100644 index 0000000000..bfc8e351c1 --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.test.ts @@ -0,0 +1,82 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { dataProviderFilter } from "./data-provider-filter" + +describe("dataProviderFilter", () => { + it("returns all data when no filters are provided", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const result = dataProviderFilter(data) + expect(result).toEqual(data) + }) + + it("filters data based on single field with single pattern", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const filters = { name: ["/Alice/"] } + const result = dataProviderFilter(data, filters) + expect(result).toEqual([{ name: "Alice" }]) + }) + + it("filters data based on nested field with single pattern", () => { + const data = [{ user: { name: "Alice" } }, { user: { name: "Bob" } }] + const filters = { "user.name": ["/Alice/"] } + const result = dataProviderFilter(data, filters) + expect(result).toEqual([{ user: { name: "Alice" } }]) + }) + + it("filters data based on single field with multiple patterns", () => { + const data = [{ name: "Alice" }, { name: "Anastasia" }, { name: "Charlie" }] + const filters = { name: ["/^A/m", "/.+e$/m"] } + const result = dataProviderFilter(data, filters) + expect(result).toEqual([{ name: "Alice" }]) + }) + + it("filters data based on multiple fields", () => { + const data = [ + { name: "Alice", age: "25" }, + { name: "Anastasia", age: "29" }, + { name: "Agnes", age: "30" }, + ] + const filters = { name: ["/^A/m"], age: ["/2[\\d]/"] } + const result = dataProviderFilter(data, filters) + expect(result).toEqual([ + { name: "Alice", age: "25" }, + { name: "Anastasia", age: "29" }, + ]) + }) + + it("returns empty array when no data matches the filters", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const filters = { name: ["/Charlie/"] } + const result = dataProviderFilter(data, filters) + expect(result).toEqual([]) + }) + + it("handles empty data array", () => { + const data: Record[] = [] + const filters = { name: ["/Alice/"] } + const result = dataProviderFilter(data, filters) + expect(result).toEqual([]) + }) + + it("handles undefined data", () => { + const filters = { name: ["/Alice/"] } + const result = dataProviderFilter(undefined, filters) + expect(result).toEqual([]) + }) + + it("handles undefined filters", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const result = dataProviderFilter(data, undefined) + expect(result).toEqual(data) + }) + + it("handles empty filters", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const filters = {} + const result = dataProviderFilter(data, filters) + expect(result).toEqual(data) + }) +}) diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.ts new file mode 100644 index 0000000000..33022cb6c8 --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-filter.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { DataProviderFilterConfig } from "device/models" +import { stringToRegex } from "./string-to-regex" +import { get } from "lodash" + +export const dataProviderFilter = ( + data: Record[] = [], + filters?: DataProviderFilterConfig +) => { + if (!filters || !data) return data + + return data.filter((item) => { + return Object.entries(filters).every(([key, patterns]) => { + const field = get(item, key) as string + return patterns.every((pattern) => { + const regex = stringToRegex(pattern) + return regex.test(field || "") + }) + }) + }) +} diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.test.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.test.ts new file mode 100644 index 0000000000..26663baf19 --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.test.ts @@ -0,0 +1,151 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { dataProviderSort } from "./data-provider-sort" +import { DataProviderSortConfig } from "device/models" + +describe("dataProviderSort", () => { + it("returns all data when no sort configuration is provided", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const result = dataProviderSort(data) + expect(result).toEqual(data) + }) + + it("sorts data based on single field in ascending order", () => { + const data = [{ name: "Charlie" }, { name: "Alice" }, { name: "Bob" }] + const sort = { + name: { direction: "asc", priority: 1 }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([ + { name: "Alice" }, + { name: "Bob" }, + { name: "Charlie" }, + ]) + }) + + it("sorts data based on nested field in ascending order", () => { + const data = [ + { user: { name: "Charlie" } }, + { user: { name: "Alice" } }, + { user: { name: "Bob" } }, + ] + const sort = { + "user.name": { direction: "asc", priority: 1 }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([ + { user: { name: "Alice" } }, + { user: { name: "Bob" } }, + { user: { name: "Charlie" } }, + ]) + }) + + it("sorts data based on single field in descending order", () => { + const data = [{ name: "Charlie" }, { name: "Alice" }, { name: "Bob" }] + const sort = { + name: { direction: "desc", priority: 1 }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([ + { name: "Charlie" }, + { name: "Bob" }, + { name: "Alice" }, + ]) + }) + + it("sorts data based on multiple fields with different priorities", () => { + const data = [ + { name: "Alice", age: "30" }, + { name: "Alice", age: "25" }, + { name: "Bob", age: "20" }, + ] + const sort = { + name: { direction: "asc", priority: 1 }, + age: { direction: "asc", priority: 2 }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([ + { name: "Alice", age: "25" }, + { name: "Alice", age: "30" }, + { name: "Bob", age: "20" }, + ]) + }) + + it("sorts incomplete data based on multiple fields with different priorities", () => { + const data = [ + { name: "Bob", surname: "Smith" }, + { name: "Alice" }, + { name: "Alice", surname: "Smith" }, + ] + const sort = { + name: { direction: "asc", priority: 2 }, + surname: { direction: "asc", priority: 1 }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([ + { + name: "Alice", + }, + { + name: "Alice", + surname: "Smith", + }, + { + name: "Bob", + surname: "Smith", + }, + ]) + }) + + it("sorts data based on ordering patterns ", () => { + const data = [ + { name: "Charlie" }, + { name: "Bob" }, + { name: "Alice" }, + { name: "Beatrice" }, + ] + const sort = { + name: { direction: "asc", priority: 1, orderingPatterns: ["/^B/m"] }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([ + { name: "Beatrice" }, + { name: "Bob" }, + { name: "Alice" }, + { name: "Charlie" }, + ]) + }) + + it("returns empty array when data is empty", () => { + const data: Record[] = [] + const sort = { + name: { direction: "asc", priority: 1 }, + } as DataProviderSortConfig + const result = dataProviderSort(data, sort) + expect(result).toEqual([]) + }) + + it("handles undefined data", () => { + const sort = { + name: { direction: "asc", priority: 1 }, + } as DataProviderSortConfig + const result = dataProviderSort(undefined, sort) + expect(result).toEqual([]) + }) + + it("handles undefined sort configuration", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const result = dataProviderSort(data, undefined) + expect(result).toEqual(data) + }) + + it("handles empty sort configuration", () => { + const data = [{ name: "Alice" }, { name: "Bob" }] + const sort = {} + const result = dataProviderSort(data, sort) + expect(result).toEqual(data) + }) +}) diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.ts new file mode 100644 index 0000000000..156e57e29c --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/data-provider-sort.ts @@ -0,0 +1,62 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { DataProviderSortConfig } from "device/models" +import { stringToRegex } from "./string-to-regex" +import { get } from "lodash" + +export const dataProviderSort = ( + data: Record[] = [], + sort?: DataProviderSortConfig +) => { + if (!sort || !data) return data + const fieldsSortedByPriority = Object.entries(sort) + .sort((a, b) => a[1].priority - b[1].priority) + .map(([key, { direction, orderingPatterns }]) => ({ + key, + direction, + orderingPatterns, + })) + + return data.sort((a, b) => { + let score = 0 + for (const { + key, + direction, + orderingPatterns = [], + } of fieldsSortedByPriority) { + const fieldA = get(a, key) as string + const fieldB = get(b, key) as string + if (!fieldA || !fieldB) { + continue + } + + for (let i = 0; i < orderingPatterns.length; i++) { + const regex = stringToRegex(orderingPatterns[i]) + const matchA = regex.test(fieldA) + const matchB = regex.test(fieldB) + + if (matchA && !matchB) { + score = -1 + break + } + if (!matchA && matchB) { + score = 1 + break + } + } + if (score === 0) { + score = + direction === "asc" + ? fieldA.localeCompare(fieldB) + : fieldB.localeCompare(fieldA) + if (score !== 0) { + break + } + } + } + return score + }) +} diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/index.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/index.ts new file mode 100644 index 0000000000..167c355b9f --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/index.ts @@ -0,0 +1,7 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +export * from "./data-provider-sort" +export * from "./data-provider-filter" diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.test.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.test.ts new file mode 100644 index 0000000000..ac47356170 --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.test.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { stringToRegex } from "./string-to-regex" + +describe("stringToRegex", () => { + it("converts valid regex string with options", () => { + const regex = stringToRegex("/abc/i") + expect(regex).toEqual(new RegExp("abc", "i")) + }) + + it("converts valid regex string without options", () => { + const regex = stringToRegex("/abc/") + expect(regex).toEqual(new RegExp("abc")) + }) + + it("throws error for invalid regex string", () => { + expect(() => stringToRegex("abc")).toThrow("Invalid regex") + }) + + it("throws error for empty string", () => { + expect(() => stringToRegex("")).toThrow("Invalid regex") + }) + + it("throws error for undefined input", () => { + expect(() => stringToRegex(undefined)).toThrow("Invalid regex") + }) +}) diff --git a/libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.ts b/libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.ts new file mode 100644 index 0000000000..d6938c248f --- /dev/null +++ b/libs/generic-view/utils/src/lib/data-provider-helpers/string-to-regex.ts @@ -0,0 +1,13 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +export const stringToRegex = (value?: string) => { + const main = value?.match(/\/(.+)\/.*/)?.[1] + const options = value?.match(/\/.+\/(.*)/)?.[1] + if (!main) { + throw new Error("Invalid regex") + } + return new RegExp(main, options) +} diff --git a/libs/generic-view/utils/src/lib/map-layout-sizes/map-layout-sizes.ts b/libs/generic-view/utils/src/lib/map-layout-sizes/map-layout-sizes.ts index 3749464af8..702b605090 100644 --- a/libs/generic-view/utils/src/lib/map-layout-sizes/map-layout-sizes.ts +++ b/libs/generic-view/utils/src/lib/map-layout-sizes/map-layout-sizes.ts @@ -3,7 +3,7 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ -import { PrimitiveValue } from "../models/layout.types" +import { PrimitiveValue } from "device/models" export const mapLayoutSizes = (sizes: PrimitiveValue[]) => { return sizes diff --git a/libs/generic-view/utils/src/lib/models/api-fc.types.ts b/libs/generic-view/utils/src/lib/models/api-fc.types.ts index f0b6401f0d..a1757ba559 100644 --- a/libs/generic-view/utils/src/lib/models/api-fc.types.ts +++ b/libs/generic-view/utils/src/lib/models/api-fc.types.ts @@ -28,7 +28,11 @@ export type BaseGenericComponent< export type APIFC = BaseGenericComponent< Data, Config, - { viewKey?: string; componentKey?: string } + { + viewKey?: string + componentKey?: string + dataItemId?: string + } > export type RecursiveComponent = BaseGenericComponent< @@ -37,5 +41,7 @@ export type RecursiveComponent = BaseGenericComponent< { viewKey: string componentKey: string + dataItemId?: string + componentName?: string } > diff --git a/libs/generic-view/utils/src/lib/models/api-views.types.ts b/libs/generic-view/utils/src/lib/models/api-views.types.ts index b10e5f26e9..61912ea586 100644 --- a/libs/generic-view/utils/src/lib/models/api-views.types.ts +++ b/libs/generic-view/utils/src/lib/models/api-views.types.ts @@ -4,8 +4,8 @@ */ import { z } from "zod" -import { Layout } from "./layout.types" import componentsValidators from "generic-view/models" +import { DataProviderConfig, Layout } from "device/models" type ComponentConfigProp = T extends undefined ? { config?: T } @@ -14,11 +14,13 @@ type ComponentConfigProp = T extends undefined type ComponentProps = T extends { key: string configValidator: z.ZodSchema + dataValidator: z.ZodSchema } ? { component: T["key"] layout?: Layout childrenKeys?: string[] + dataProvider?: DataProviderConfig } & ComponentConfigProp> : never diff --git a/libs/generic-view/utils/src/lib/models/button.types.ts b/libs/generic-view/utils/src/lib/models/button.types.ts index 1a9c203e3b..5b1a15355f 100644 --- a/libs/generic-view/utils/src/lib/models/button.types.ts +++ b/libs/generic-view/utils/src/lib/models/button.types.ts @@ -28,9 +28,27 @@ export interface NavigateAction { viewKey: string } +export type FormAction = + | { + type: "form-set-field" + key: string + value?: string | number | boolean + } + | { + type: "form-toggle-field" + key: string + } + | { + type: "form-reset" + } + export interface CustomAction { type: "custom" callback: VoidFunction } -export type ButtonAction = ModalAction | NavigateAction | CustomAction +export type ButtonAction = + | ModalAction + | NavigateAction + | FormAction + | CustomAction diff --git a/libs/generic-view/utils/src/lib/models/layout.types.ts b/libs/generic-view/utils/src/lib/models/layout.types.ts deleted file mode 100644 index b3ae28309c..0000000000 --- a/libs/generic-view/utils/src/lib/models/layout.types.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -export type PrimitiveValue = string | number - -interface Gap { - rowGap?: string - columnGap?: string -} - -export interface GridLayout extends Gap { - rows: PrimitiveValue[] - columns: PrimitiveValue[] - justifyContent?: - | "start" - | "end" - | "center" - | "stretch" - | "space-around" - | "space-between" - | "space-evenly" - justifyItems?: "start" | "end" | "center" | "stretch" - alignItems?: "start" | "end" | "center" | "stretch" | "baseline" -} - -export interface GridPlacement { - row: number - column: number - width: number - height: number -} - -export interface FlexLayout extends Gap { - direction?: "row" | "column" | "row-reverse" | "column-reverse" - justifyContent?: - | "flex-start" - | "flex-end" - | "center" - | "space-between" - | "space-around" - | "space-evenly" - alignItems?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline" - alignContent?: - | "flex-start" - | "flex-end" - | "center" - | "stretch" - | "space-between" - | "space-around" - wrap?: "wrap" | "nowrap" | "wrap-reverse" -} - -export interface FlexPlacement { - grow?: PrimitiveValue - shrink?: PrimitiveValue - basis?: PrimitiveValue - order?: PrimitiveValue - alignSelf?: "flex-start" | "flex-end" | "center" | "stretch" -} - -interface GridLayoutBase { - gridLayout?: GridLayout - flexLayout?: undefined -} - -interface FlexLayoutBase { - flexLayout?: FlexLayout - gridLayout?: undefined -} - -type LayoutBase = GridLayoutBase | FlexLayoutBase - -export type Layout = { - gridPlacement?: GridPlacement - flexPlacement?: FlexPlacement - margin?: string - padding?: string -} & LayoutBase From 4c95d6b617aa06e409ec3a8078246a631c27c5d1 Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Tue, 24 Sep 2024 10:40:35 +0200 Subject: [PATCH 13/64] [CP-3134] Random values are throwing errors in code that compiles and works fine on mudita-center-e2e project (#2075) --- apps/mudita-center-e2e/tsconfig.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/mudita-center-e2e/tsconfig.json b/apps/mudita-center-e2e/tsconfig.json index 865837d96d..eb7f7b6494 100644 --- a/apps/mudita-center-e2e/tsconfig.json +++ b/apps/mudita-center-e2e/tsconfig.json @@ -10,9 +10,8 @@ "resolveJsonModule": true, "esModuleInterop": true, "target": "es5", - "outDir": "./dist", - "typeRoots": ["./node_modules/@types", "./typings"] + "outDir": "./dist" }, - "include": ["src/**/*", "./wdio.conf.ts"], + "include": ["src/**/*"], "exclude": ["node_modules"] } From ef865401ef6b42a5e02012b2e95677e62cfe2e1c Mon Sep 17 00:00:00 2001 From: Maciej Kupiec <115480562+MaciejMDDV@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:08:24 +0200 Subject: [PATCH 14/64] Cp e2e - Windows/Linux fix for self-hosted (#2083) --- .github/workflows/e2e-feature-branch.yml | 64 +++++++++++++++++++++--- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/.github/workflows/e2e-feature-branch.yml b/.github/workflows/e2e-feature-branch.yml index 3961132b44..94462b2f18 100644 --- a/.github/workflows/e2e-feature-branch.yml +++ b/.github/workflows/e2e-feature-branch.yml @@ -1,4 +1,4 @@ -name: e2e on Linux for feature branch +name: e2e on Linux / Windows self-hosted for feature branch on: push: @@ -7,7 +7,10 @@ on: jobs: e2e: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ Windows, Linux ] environment: development steps: - name: Checkout code @@ -16,7 +19,8 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18.16.1 - - name: Setup environment variables + - name: Setup environment variables for Linux + if: matrix.os == 'Linux' env: E2ECI: "true" TEST_GITHUB_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} @@ -46,14 +50,60 @@ jobs: MOCK_SERVICE_ENABLED: ${{ secrets.MOCK_SERVICE_ENABLED }} run: | printenv > .env + - name: Setup environment variables for Windows + if: matrix.os == 'Windows' + env: + E2ECI: "true" + TEST_GITHUB_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} + TEST_BINARY_PATH: 'C:\actions-runner\_work\mudita-center\mudita-center\apps\mudita-center\release\win-unpacked\Mudita Center.exe' + PHRASE_API_KEY: ${{ secrets.PHRASE_API_KEY }} + PHRASE_API_URL: ${{ secrets.PHRASE_API_URL }} + PHRASE_API_KEY_DEV: ${{ secrets.PHRASE_API_KEY_DEV }} + MUDITA_CENTER_SERVER_URL: ${{ secrets.MUDITA_CENTER_SERVER_URL }} + MUDITA_CENTER_SERVER_V2_URL: ${{ secrets.MUDITA_CENTER_SERVER_V2_URL }} + ROLLBAR_TOKEN: ${{ secrets.ROLLBAR_TOKEN }} + RELEASES_REPOSITORY_NAME: ${{ secrets.RELEASES_REPOSITORY_NAME }} + PRERELEASES_ENABLED: ${{ secrets.PRERELEASES_ENABLED }} + GITHUB_ACCESS_TOKEN: ${{ secrets.MC_GITHUB_ACCESS_TOKEN }} + LOGIN_MICROSOFT_ONLINE_CLIENT_ID: ${{ secrets.LOGIN_MICROSOFT_ONLINE_CLIENT_ID }} + FONTS_DIRECTORY_URL: ${{ secrets.FONTS_DIRECTORY_URL }} + FRESHDESK_API_URL: ${{ secrets.FRESHDESK_API_URL }} + FRESHDESK_API_TOKEN: ${{ secrets.FRESHDESK_API_TOKEN }} + ANALYTICS_ENABLED: ${{ secrets.ANALYTICS_ENABLED }} + ANALYTICS_API_URL: ${{ secrets.ANALYTICS_API_URL }} + ANALYTICS_API_SITE_ID: ${{ secrets.ANALYTICS_API_SITE_ID }} + FEATURE_TOGGLE_ENVIRONMENT: ${{ secrets.FEATURE_TOGGLE_ENVIRONMENT }} + STATIC_CONFIGURATION_FILE_PATH: ${{ secrets.STATIC_CONFIGURATION_FILE_PATH }} + DEV_REDUX_LOGGER_ENABLED: ${{ secrets.DEV_REDUX_LOGGER_ENABLED }} + DEV_DEVICE_LOGGER_ENABLED: ${{ secrets.DEV_DEVICE_LOGGER_ENABLED }} + FEATURE_TOGGLE_RELEASE_ENVIRONMENT: ${{ secrets.FEATURE_TOGGLE_RELEASE_ENVIRONMENT }} + MUDITA_CENTER_PRERELEASE_ENABLED: ${{ secrets.MUDITA_CENTER_PRERELEASE_ENABLED }} + MOCK_SERVICE_ENABLED: ${{ secrets.MOCK_SERVICE_ENABLED }} + NEW_HELP_ENABLED: ${{ secrets.NEW_HELP_ENABLED }} + shell: cmd + run: | + SET > .env - name: Setup dependencies run: npm run setup - - name: Build App + - name: Build App for Linux + if: matrix.os == 'Linux' run: | export NODE_OPTIONS="--max-old-space-size=4096" npm run app:dist - - name: Run E2E tests headless with Xvfb + - name: Build App for Windows + if: matrix.os == 'Windows' + run: | + $env:NODE_OPTIONS="--max-old-space-size=4096" + $env:LOCALAPPDATA="" + npm run app:dist + - name: Run E2E tests headless with Xvfb on Linux + if: matrix.os == 'Linux' run: | - sudo apt-get update - sudo apt-get install -y xvfb npm run e2e:test:cicd:standalone + - name: Run E2E tests headless on Windows + env: + TEST_BINARY_PATH: 'C:\actions-runner\_work\mudita-center\mudita-center\apps\mudita-center\release\win-unpacked\Mudita Center.exe' + if: matrix.os == 'Windows' + run: | + cd apps/mudita-center-e2e + npm run e2e:test:cicd:standalone \ No newline at end of file From f235e33313897b98fa88be4d87942ded8ca70171 Mon Sep 17 00:00:00 2001 From: robertmudi Date: Thu, 26 Sep 2024 11:16:19 +0200 Subject: [PATCH 15/64] CP-3150 fixed typo contacts to contact --- libs/e2e-mock/responses/src/lib/default-responses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/e2e-mock/responses/src/lib/default-responses.ts b/libs/e2e-mock/responses/src/lib/default-responses.ts index 692283a7f2..743b979c64 100644 --- a/libs/e2e-mock/responses/src/lib/default-responses.ts +++ b/libs/e2e-mock/responses/src/lib/default-responses.ts @@ -166,7 +166,7 @@ export const DEFAULT_RESPONSES: MockResponsesMap = { type: "mc-overview-backup", title: "Backup", backupFeatures: [ - { label: "Contacts list", key: "CONTACTS_LIST" }, + { label: "Contact list", key: "CONTACT_LIST" }, { label: "Call log", key: "CALL_LOG" }, { label: "Messages", key: "MESSAGES" }, { label: "Notes", key: "NOTES" }, From 34ad1bb62ad8416bb72f10712481c530017c397b Mon Sep 17 00:00:00 2001 From: robertmudi Date: Mon, 30 Sep 2024 11:05:00 +0200 Subject: [PATCH 16/64] CP-2726 first part of the test --- .../src/page-objects/help-modal.page.ts | 47 ++++++++++++ .../src/page-objects/help.page.ts | 4 + .../help/contact-support-unhappy-path.ts | 73 +++++++++++++++++++ .../consts/test-filenames.const.ts | 1 + apps/mudita-center-e2e/wdio.conf.ts | 17 ++++- 5 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts diff --git a/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts b/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts index 9dcfb00b17..2e0f784a5f 100644 --- a/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts @@ -27,6 +27,10 @@ class HelpModalPage extends Page { return $('[data-testid="submit-button"]') } + public get sendButtonLabel() { + return $("p*=Send") + } + /** returns an Array containing list of attached files */ async attachmentsList() { return $('[data-testid="file-list"]').$$('[data-testid="file-list-file"]') @@ -46,6 +50,49 @@ class HelpModalPage extends Page { public get invalidEmailTextElement() { return $('//input[@data-testid="email-input"]/following-sibling::*[1]') } + + public get iconSupport() { + return $('[data-testid="icon-Support"]') + } + + public get iconAttachment() { + return $('[data-testid="icon-Attachment"]') + } + + public get modalTitle() { + return $("h1*=Mudita Center Support") + } + + public get modalSubtitle() { + return $( + "p*=Contact Mudita support team and we will do our best to help you resolve your issues." + ) + } + + public get currentDateZipFile() { + const currentDate = new Date().toISOString().split("T")[0] // Get current date in YYYY-MM-DD format + return $(`p*=${currentDate}.zip`) + } + + public get attachedFilesText() { + return $("p*=Attached files") + } + + public get attachedFilesSubText() { + return $("p*=The attached files will help us resolve your problem") + } + + public get emailLabel() { + return $("p*=Email") + } + + public get messageLabel() { + return $("p*=Message (optional)") + } + + public get wholeModal() { + return $('[data-testid="contact-support-modal"]') + } } export default new HelpModalPage() diff --git a/apps/mudita-center-e2e/src/page-objects/help.page.ts b/apps/mudita-center-e2e/src/page-objects/help.page.ts index 59106add62..da8a0af04f 100644 --- a/apps/mudita-center-e2e/src/page-objects/help.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help.page.ts @@ -41,6 +41,10 @@ class HelpPage extends Page { public get contactSupportButtonTooltip() { return $('[data-testid="icon-button-with-tooltip-description"]') } + + public get helpMainFooterContactSupportButton() { + return $('[data-testid="help-main-footer-contact-support-button"]') + } } export default new HelpPage() diff --git a/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts b/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts new file mode 100644 index 0000000000..b5fb4d1f1d --- /dev/null +++ b/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts @@ -0,0 +1,73 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import NavigationTabs from "../../page-objects/tabs.page" +import HelpPage from "../../page-objects/help.page" +import HomePage from "../../page-objects/home.page" +import HelpModalPage from "../../page-objects/help-modal.page" + +describe("Contact Support - Unhappy Path", () => { + before(async () => { + const notNowButton = await HomePage.notNowButton + await notNowButton.waitForDisplayed() + await notNowButton.click() + }) + + it("Open Mudita Help Center and open Contact Support Modal", async () => { + const helpTab = NavigationTabs.helpTab + await helpTab.click() + + const helpMainFooterContactSupportButton = + HelpPage.helpMainFooterContactSupportButton + await helpMainFooterContactSupportButton.click() + }) + + it("Check contents of Contact Form", async () => { + const wholeModal = HelpModalPage.wholeModal + await expect(wholeModal).toBeDisplayed() + + const closeModalButton = HelpModalPage.closeModalButton + await expect(closeModalButton).toBeDisplayed() + + const modalHeader = HelpModalPage.modalHeader + await expect(modalHeader).toBeDisplayed() + + const iconSupport = HelpModalPage.iconSupport + await expect(iconSupport).toBeDisplayed() + + const modalTitle = HelpModalPage.modalTitle + await expect(modalTitle).toBeDisplayed() + await expect(modalTitle).toHaveText("Mudita Center Support") + + const modalSubtitle = HelpModalPage.modalSubtitle + await expect(modalSubtitle).toBeDisplayed() + await expect(modalSubtitle).toHaveText( + "Contact Mudita support team and we will do our best to help you resolve your issues." + ) + + const emailLabel = HelpModalPage.emailLabel + await expect(emailLabel).toHaveText("Email") + const emailInput = HelpModalPage.emailInput + await expect(emailInput).toBeDisplayed() + + const messageLabel = HelpModalPage.messageLabel + await expect(messageLabel).toHaveText("Message (optional)") + const descriptionInput = HelpModalPage.descriptionInput + await expect(descriptionInput).toBeDisplayed() + + const attachedFilesText = HelpModalPage.attachedFilesText + const attachedFilesSubText = HelpModalPage.attachedFilesSubText + const singleAttachment = HelpModalPage.singleAttachment + const iconAttachment = HelpModalPage.iconAttachment + const currentDateZipFile = HelpModalPage.currentDateZipFile + await expect(singleAttachment).toBeDisplayed() + await expect(iconAttachment).toBeDisplayed() + await expect(currentDateZipFile).toBeDisplayed() //checks if zipfile has current date (date of sending the logs is the same as zip file name) + await expect(attachedFilesText).toHaveText("Attached files") + await expect(attachedFilesSubText).toHaveText( + "The attached files will help us resolve your problem" + ) + }) +}) diff --git a/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts b/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts index 0ab7dc591e..ffb04d240c 100644 --- a/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts +++ b/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts @@ -27,5 +27,6 @@ export enum TestFilesPaths { kompaktAbout = "src/specs/overview/kompakt-about.ts", kompaktConnectedDevicesModalStressTest = "src/specs/stress-tests/connected-devices-stress-test.ts", kompaktDrawerStressTest = "src/specs/stress-tests/device-drawer-stress-test.ts", + contactSupportUnhappyPath = "src/specs/help/contact-support-unhappy-path.ts", } export const toRelativePath = (path: string) => `./${path}` diff --git a/apps/mudita-center-e2e/wdio.conf.ts b/apps/mudita-center-e2e/wdio.conf.ts index 2c8ab5a6c3..4b951b5a15 100644 --- a/apps/mudita-center-e2e/wdio.conf.ts +++ b/apps/mudita-center-e2e/wdio.conf.ts @@ -76,6 +76,7 @@ export const config: Options.Testrunner = { toRelativePath(TestFilesPaths.kompaktAbout), toRelativePath(TestFilesPaths.kompaktConnectedDevicesModalStressTest), toRelativePath(TestFilesPaths.kompaktDrawerStressTest), + toRelativePath(TestFilesPaths.contactSupportUnhappyPath), ], suites: { standalone: [ @@ -86,6 +87,7 @@ export const config: Options.Testrunner = { toRelativePath(TestFilesPaths.backupLocationTest), toRelativePath(TestFilesPaths.privacyPolicyTest), toRelativePath(TestFilesPaths.licenseTest), + toRelativePath(TestFilesPaths.contactSupportUnhappyPath), ], mock: [ toRelativePath(TestFilesPaths.mcCheckForUpdatesTest), @@ -118,6 +120,7 @@ export const config: Options.Testrunner = { //toRelativePath(TestFilesPaths.homePageTestDeviceNotConnectedTest), toRelativePath(TestFilesPaths.newsPageOnlineTest), toRelativePath(TestFilesPaths.termsOfServiceTest), + toRelativePath(TestFilesPaths.contactSupportUnhappyPath), ], cicdMock: [ toRelativePath(TestFilesPaths.mcCheckForUpdatesTest), @@ -174,9 +177,17 @@ export const config: Options.Testrunner = { binary: process.env.TEST_BINARY_PATH, args: [], }, - 'wdio:chromedriverOptions': { - binary: path.resolve(__dirname, '..', '..', 'node_modules', 'chromedriver', 'bin', 'chromedriver') - } + "wdio:chromedriverOptions": { + binary: path.resolve( + __dirname, + "..", + "..", + "node_modules", + "chromedriver", + "bin", + "chromedriver" + ), + }, // If outputDir is provided WebdriverIO can capture driver session logs // it is possible to configure which logTypes to include/exclude. // excludeDriverLogs: ['*'], // pass '*' to exclude all driver session logs From 7b339612eeca5885a22334620abbea767a76449d Mon Sep 17 00:00:00 2001 From: Tomasz Malecki <135224481+tomaszmaleckimudita@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:00:36 +0200 Subject: [PATCH 17/64] CP-3071 [E2E][Help] Q4 2024 Change - Verify Help Contents, Search and Contact button (#2052) --- .../src/page-objects/help-article.page.ts | 69 +++++++ .../src/page-objects/help.page.ts | 71 ++++--- .../src/specs/help/help-section-check.e2e.ts | 180 ++++++++++++++++++ .../src/specs/help/help-window-check.e2e.ts | 107 ----------- .../consts/test-filenames.const.ts | 2 +- apps/mudita-center-e2e/wdio.conf.ts | 6 +- 6 files changed, 298 insertions(+), 137 deletions(-) create mode 100644 apps/mudita-center-e2e/src/page-objects/help-article.page.ts create mode 100644 apps/mudita-center-e2e/src/specs/help/help-section-check.e2e.ts delete mode 100644 apps/mudita-center-e2e/src/specs/help/help-window-check.e2e.ts diff --git a/apps/mudita-center-e2e/src/page-objects/help-article.page.ts b/apps/mudita-center-e2e/src/page-objects/help-article.page.ts new file mode 100644 index 0000000000..2276653183 --- /dev/null +++ b/apps/mudita-center-e2e/src/page-objects/help-article.page.ts @@ -0,0 +1,69 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { ChainablePromiseElement } from "webdriverio" +import Page from "./page" + +class HelpArticlePage extends Page { + public get helpTabTitle() { + return $('[data-testid="location"]') + } + public get helpArticleBackButton() { + return $('[data-testid="help-article-back-button"]') + } + public get helpArticleTitle() { + return $('[data-testid="help-article-title"]') + } + public get helpArticleWarningIcon() { + return $('[data-testid="help-article-warning-icon"]') + } + public get helpArticleWarning() { + return $('[data-testid="help-article-warning"]') + } + public get helpArticleContent() { + return $('[data-testid="help-article-content"]') + } + public get helpArticleContentBlocks() { + return $$('[data-testid="help-article-content-block"]') + } + getHelpArticleContentBlock(index: number) { + return $$('[data-testid="help-article-content-block"]')[index] + } + getHelpArticleContentBlockTitle(index: number) { + return $$('[data-testid="help-article-content-block-title"]')[index] + } + public get helpArticleContentBlockText() { + return $$('[data-testid="help-article-content-block-text"]') + } + getHelpArticleContentBlockText(index: number) { + return $$('[data-testid="help-article-content-block"]')[index].$('[data-testid="help-article-content-block-text"]') + } + public get helpArticleFeedback() { + return $('[data-testid="help-article-feedback"]') + } + public get helpArticleFeedbackTitle() { + return $('[data-testid="help-article-feedback-title"]') + } + public get helpArticleFeedbackYesButton() { + return $('[data-testid="help-article-feedback-yes-button"]') + } + public get helpArticleFeedbackNoButton() { + return $('[data-testid="help-article-feedback-no-button"]') + } + public get helpArticleFooter() { + return $('[data-testid="help-article-footer"]') + } + public get helpArticleFooterTitle() { + return $('[data-testid="help-article-footer-title"]') + } + public get helpArticleFooterButton() { + return $('[data-testid="help-article-footer-button"]') + } + public get helpArticleFooterVisitSupportButton() { + return $('[data-testid="help-article-footer-button"]') + } +} + +export default new HelpArticlePage() diff --git a/apps/mudita-center-e2e/src/page-objects/help.page.ts b/apps/mudita-center-e2e/src/page-objects/help.page.ts index da8a0af04f..d3f3ca5796 100644 --- a/apps/mudita-center-e2e/src/page-objects/help.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help.page.ts @@ -6,40 +6,59 @@ import Page from "./page" class HelpPage extends Page { - public get listElement() { - return $('[data-testid="help-component-question"]') + public get helpTabTitle() { + return $('[data-testid="location"]') } - - public get listElements() { - return $$('[data-testid="help-component-question"]') + public get helpMainHeader() { + return $('[data-testid="help-main-header"]') } - - public get windowTitle() { - return $('[data-testid="help-component-title"]') + public get helpMainSubHeader() { + return $('[data-testid="help-main-subheader"]') } - - public get searchIcon() { - return $('[data-testid="icon-Magnifier"]') + public get iconSearch() { + return $('[data-testid="icon-search"]') } - - public get searchPlaceholder() { - return $('[type="search"]') + public get helpSearchInput() { + return $('[data-testid="help-search-input"]') } - - public get topicContent() { - return $('[data-testid="content"]') + public get helpSearchResults() { + return $('[data-testid="help-search-results"]') } - - public get articleBackLink() { - return $('[data-testid="back-link"]') + public get helpSearchResultsParagraph() { + return $('[data-testid="help-search-results"] p') } - - public get contactSupportButton() { - return $('[data-testid="help-support-button"]') + public get helpSearchResultsList() { + return $('[data-testid="help-search-results"] ul') } - - public get contactSupportButtonTooltip() { - return $('[data-testid="icon-button-with-tooltip-description"]') + public get helpSearchResultsItems() { + return $$('[data-testid="help-search-result-item"]') + } + public get helpCategoriesTitle() { + return $('[data-testid="help-categories-title"]') + } + public get helpCategoriesList() { + return $('[data-testid="help-categories-list"]') + } + public get helpCategoriesListItems() { + return $$('[data-testid="help-categories-list-item"]') + } + public get helpSubCategoriesList() { + return $('[data-testid="help-subcategories-list"]') + } + public get helpSubCategoriesListItems() { + return $$('[data-testid="help-subcategories-list-item"]') + } + public get helpSubCategoriesListItemsLeftColumn() { + return $$('[data-testid="help-subcategories-list"]>div')[0].$$('[data-testid="help-subcategories-list-item"]') + } + public get helpSubCategoriesListItemsRightColumn() { + return $$('[data-testid="help-subcategories-list"]>div')[1].$$('[data-testid="help-subcategories-list-item"]') + } + public get helpMainFooterDescription() { + return $('[data-testid="help-main-footer-description"]') + } + public get helpMainFooterContactSupportButton() { + return $('[data-testid="help-main-footer-contact-support-button"]') } public get helpMainFooterContactSupportButton() { diff --git a/apps/mudita-center-e2e/src/specs/help/help-section-check.e2e.ts b/apps/mudita-center-e2e/src/specs/help/help-section-check.e2e.ts new file mode 100644 index 0000000000..7b66bbdaef --- /dev/null +++ b/apps/mudita-center-e2e/src/specs/help/help-section-check.e2e.ts @@ -0,0 +1,180 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import NavigationTabs from "../../page-objects/tabs.page" +import HelpPage from "../../page-objects/help.page" +import HelpArticlePage from "../../page-objects/help-article.page" +import HomePage from "../../page-objects/home.page" + +describe("Check Help window", () => { + before(async () => { + const notNowButton = await HomePage.notNowButton + await notNowButton.waitForDisplayed() + await notNowButton.click() + }) + + it("Open Help window", async () => { + const helpTab = await NavigationTabs.helpTab + await helpTab.waitForDisplayed({ timeout: 15000 }) + await helpTab.click() + + //Check window title + const helpTabTitle = await HelpPage.helpTabTitle + await helpTabTitle.waitForDisplayed({ timeout: 15000 }) + await expect(helpTabTitle).toHaveText("Mudita Help Center") + + //Verify welcome message + const helpMainHeader = await HelpPage.helpMainHeader + await expect(helpMainHeader).toHaveText("Welcome! How can we help you?") + + //Verify welcome paragraph + const helpMainSubHeader = await HelpPage.helpMainSubHeader + await expect(helpMainSubHeader).toHaveText("Browse our selection of how-to and troubleshooting guides") + + //Verify search bar + const iconSearch = await HelpPage.iconSearch + await expect(iconSearch).toBeDisplayed() + + //Verify search bar icon + const helpSearchInput = await HelpPage.helpSearchInput + await expect(helpSearchInput).toBeDisplayed() + + //Verify placeholder + await expect(helpSearchInput).toHaveAttrContaining("placeholder", "Search topics") + + //Verify main section title + const helpCategoriesTitle = await HelpPage.helpCategoriesTitle + await expect(helpCategoriesTitle).toHaveText("Which device are you using with Mudita Center?") + + //Section tabs + const helpCategoriesList = await HelpPage.helpCategoriesList + await expect(helpCategoriesList).toBeDisplayed() + const helpCategoriesListItems = await HelpPage.helpCategoriesListItems + await expect(helpCategoriesListItems).toBeElementsArrayOfSize({ gte: 1 }) + await expect(helpCategoriesListItems).toBeDisplayed() + + //Active section tab + expect(helpCategoriesListItems[0]).toHaveElementClassContaining("active") + const activeTabColor = await helpCategoriesListItems[0].getCSSProperty("color") + await expect(activeTabColor.value).toBe("rgba(0,0,0,1)") + const activeTabBackground = await helpCategoriesListItems[0].getCSSProperty( + "background-color" + ) + await expect(activeTabBackground.value).toBe( + "rgba(237,237,237,1)" + ) + + //Hover on section tabs + await helpCategoriesListItems[1].moveTo() + const hoverTabColor = await helpCategoriesListItems[0].getCSSProperty("color") + await expect(hoverTabColor.value).toBe("rgba(0,0,0,1)") + const hoverTabBackground = await helpCategoriesListItems[0].getCSSProperty( + "background-color" + ) + await expect(hoverTabBackground.value).toBe( + "rgba(237,237,237,1)" + ) + }) + + it("Verify Harmony Section titles", async () => { + + //Verify all items + const helpSubCategoriesListItems = await HelpPage.helpSubCategoriesListItems + await expect(helpSubCategoriesListItems).toBeElementsArrayOfSize({ gte: 1 }) + + //Verify left column + const helpSubCategoriesListItemsLeftColumn = await HelpPage.helpSubCategoriesListItemsLeftColumn + await expect(helpSubCategoriesListItemsLeftColumn).toBeElementsArrayOfSize({ gte: 1 }) + + //Verify right column + const helpSubCategoriesListItemsRightColumn = await HelpPage.helpSubCategoriesListItemsRightColumn + await expect(helpSubCategoriesListItemsRightColumn).toBeElementsArrayOfSize({ gte: 1 }) + + //Every sub category should not be empty + const helpSubCategoryArticlesListItemTitles = await helpSubCategoriesListItems.map((element) => { + return element.$('[data-testid="help-subcategories-list-item-title"]').getText() + }) + await expect(helpSubCategoryArticlesListItemTitles.length).toBeGreaterThanOrEqual(1) + + //List of articles should not be empty in any of the categories + let helpSubCategoriesListItem + for await (helpSubCategoriesListItem of helpSubCategoriesListItems) { + await expect(helpSubCategoriesListItem.$$('[data-testid="help-subcategory-articles-list-item"]')).toBeElementsArrayOfSize({ gte: 1 }) + } + }) + it("Search for questions and verify results", async () => { + const helpSearchInput = await HelpPage.helpSearchInput + await helpSearchInput.setValue("How to do factory reset on Pure") + + //Verify quick search results + const helpSearchResults = await HelpPage.helpSearchResults + await expect(helpSearchResults).toBeDisplayed() + const helpSearchResultsParagraph = await HelpPage.helpSearchResultsParagraph + await expect(helpSearchResultsParagraph).toBeDisplayed() + await expect(helpSearchResultsParagraph).toHaveText("Quick Links") + //List should not be empty, bigger than 1 + const helpSearchResultsItems = await HelpPage.helpSearchResultsItems + await expect(helpSearchResultsItems).toBeElementsArrayOfSize({ gte: 1 }) + //Click first article + helpSearchResultsItems[0].click() + }) + it("Check first article", async () => { + //Check window title + const helpTabTitle = await HelpPage.helpTabTitle + await helpTabTitle.waitForDisplayed({ timeout: 15000 }) + await expect(helpTabTitle).toHaveText("Mudita Help Center") + + //Check back button + const helpArticleBackButton = await HelpArticlePage.helpArticleBackButton + await expect(helpArticleBackButton).toBeClickable() + + //Check article title + const helpArticleTitle = await HelpArticlePage.helpArticleTitle + await expect(helpArticleTitle).toHaveText("How to do factory reset on Pure") + + //Check article warning + const helpArticleWarningIcon = await HelpArticlePage.helpArticleWarningIcon + await expect(helpArticleWarningIcon).toBeDisplayed() + + const helpArticleWarning = await HelpArticlePage.helpArticleWarning + await expect(helpArticleWarning).toHaveTextContaining("This will delete everything on your phone!") + + //Check article content + const helpArticleContent = await HelpArticlePage.helpArticleContent + await expect(helpArticleContent).toBeDisplayed() + const helpArticleContentBlocks = await HelpArticlePage.helpArticleContentBlocks + await expect(helpArticleContentBlocks).toBeElementsArrayOfSize({ gte: 2 }) + await expect(HelpArticlePage.getHelpArticleContentBlockTitle(0)).toHaveTextContaining("If your Pure is locked:") + await expect(HelpArticlePage.getHelpArticleContentBlockText(0)).toHaveTextContaining("Turn off your Pure, hold down the right selection key > select Yes") + + //Check article helpful section + const helpArticleFeedbackYesButton = await HelpArticlePage.helpArticleFeedbackYesButton + await expect(helpArticleFeedbackYesButton).toBeDisplayed() + await expect(helpArticleFeedbackYesButton).toBeClickable() + + const helpArticleFeedbackNoButton = await HelpArticlePage.helpArticleFeedbackNoButton + await expect(helpArticleFeedbackNoButton).toBeDisplayed() + await expect(helpArticleFeedbackNoButton).toBeClickable() + + const helpArticleFooter = await HelpArticlePage.helpArticleFooter + await helpArticleFooter.scrollIntoView() + + const helpArticleFooterTitle = await HelpArticlePage.helpArticleFooterTitle + await expect(helpArticleFooterTitle).toHaveText("Need more help?\nVisit our Support Website") + + const helpArticleFooterVisitSupportButton = await HelpArticlePage.helpArticleFooterVisitSupportButton + await expect(helpArticleFooterVisitSupportButton).toHaveText("VISIT SUPPORT WEBSITE") + + helpArticleBackButton.click() + }) + it("Verify you are back in active first category", async () => { + const helpCategoriesListItems = await HelpPage.helpCategoriesListItems + await expect(helpCategoriesListItems).toBeElementsArrayOfSize({ gte: 1 }) + await expect(helpCategoriesListItems).toBeDisplayed() + + //Active section tab + expect(helpCategoriesListItems[0]).toHaveElementClassContaining("active") + }) +}) diff --git a/apps/mudita-center-e2e/src/specs/help/help-window-check.e2e.ts b/apps/mudita-center-e2e/src/specs/help/help-window-check.e2e.ts deleted file mode 100644 index a05bd5a71e..0000000000 --- a/apps/mudita-center-e2e/src/specs/help/help-window-check.e2e.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) Mudita sp. z o.o. All rights reserved. - * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md - */ - -import NavigationTabs from "../../page-objects/tabs.page" -import HelpPage from "../../page-objects/help.page" -import HomePage from "../../page-objects/home.page" -import HelpModalPage from "../../page-objects/help-modal.page" -import NewsPage from "../../page-objects/news.page" - -describe("Check Help window", () => { - before(async () => { - const notNowButton = await HomePage.notNowButton - await notNowButton.waitForDisplayed() - await notNowButton.click() - }) - - it("Open Help window", async () => { - const helpTab = await NavigationTabs.helpTab - await helpTab.waitForDisplayed({ timeout: 15000 }) - await helpTab.click() - - await browser.switchWindow("#/help") - - // Check window title - const helpTitle = await HelpPage.windowTitle - await helpTitle.waitForDisplayed({ timeout: 15000 }) - await expect(helpTitle).toHaveText("Mudita Center Help") - }) - - it("Check contents of Mudita Help", async () => { - // Check presence of the search engine - const searchIcon = await HelpPage.searchIcon - await expect(searchIcon).toBeDisplayed() - - const searchPlaceholder = await HelpPage.searchPlaceholder - await expect(searchPlaceholder).toHaveAttributeContaining( - "placeholder", - "Search" - ) - - // Check presence of Contact support button - const contactSupportButton = await HelpPage.contactSupportButton - await expect(contactSupportButton).toBeDisplayed() - await expect(contactSupportButton).toBeClickable() - - const contactSupportButtonTooltip = - await HelpPage.contactSupportButtonTooltip - contactSupportButton.moveTo() - await expect(contactSupportButtonTooltip).toBeDisplayed() - await expect(contactSupportButtonTooltip).toHaveText("Contact support") - - // Check accordion - const helpTopic = await HelpPage.listElement - - await expect(helpTopic).toBeDisplayed() - const noOfArticles = await HelpPage.listElements - await expect(noOfArticles).toBeElementsArrayOfSize({ gte: 25 }) - }) - - it("Check content of first article", async () => { - const helpTopic = await HelpPage.listElement - await expect(helpTopic).toHaveText( - "How to import my iCloud contacts into Mudita Pure by using .vcf file?" - ) - await helpTopic.click() - const helpTopicContent = await HelpPage.topicContent - await expect(helpTopicContent).toBeDisplayed() - await expect(helpTopicContent).toHaveTextContaining( - "Click on the “Import” button." - ) - const backLink = await HelpPage.articleBackLink - await backLink.click() - const helpTitle = await HelpPage.windowTitle - await expect(helpTitle).toHaveText("Mudita Center Help") - }) - - it("Search for questions & check search results", async () => { - const searchPlaceholder = await HelpPage.searchPlaceholder - searchPlaceholder.setValue("fail") - browser.keys("\uE007") - const helpTopic = await HelpPage.listElement - await expect(helpTopic).toHaveText("OS update failed") - searchPlaceholder.setValue("harMony") - await helpTopic.waitForDisplayed({ timeout: 15000 }) - await expect(helpTopic).toHaveText( - "How to connect my Mudita Harmony to Center?" - ) - const noOfArticles = await HelpPage.listElements - await expect(noOfArticles).toBeElementsArrayOfSize({ gte: 4 }) - }) - - it("Check Contact support modal", async () => { - const contactSupportButton = await HelpPage.contactSupportButton - await contactSupportButton.click() - const modalHeader = await HelpModalPage.modalHeader - await expect(modalHeader).toBeDisplayed - const closeButton = await HelpModalPage.closeModalButton - await closeButton.click() - - await browser.switchWindow("#/news") - const newsHeader = await NewsPage.newsHeader - await expect(newsHeader).toBeDisplayed - await expect(newsHeader).toHaveText("Mudita News") - }) -}) diff --git a/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts b/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts index ffb04d240c..1d40ca54ca 100644 --- a/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts +++ b/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts @@ -6,7 +6,7 @@ // the format should stay as it is - it should contain `./` at the beginning export enum TestFilesPaths { messagesInAppNavigationTest = "src/specs/messages/messages-in-app-navigation.e2e.ts", - helpWindowCheckTest = "src/specs/help/help-window-check.e2e.ts", + helpSectionCheckTest = "src/specs/help/help-section-check.e2e.ts", homePageTestDeviceNotConnectedTest = "src/specs/overview/home-page-device-not-connecting.e2e.ts", e2eMockSample = "src/specs/overview/e2e-mock-sample.e2e.ts", mcCheckForUpdatesTest = "src/specs/settings/mc-version-check-for-updates.e2e.ts", diff --git a/apps/mudita-center-e2e/wdio.conf.ts b/apps/mudita-center-e2e/wdio.conf.ts index 4b951b5a15..9942f6ca00 100644 --- a/apps/mudita-center-e2e/wdio.conf.ts +++ b/apps/mudita-center-e2e/wdio.conf.ts @@ -56,7 +56,7 @@ export const config: Options.Testrunner = { // specs: [ toRelativePath(TestFilesPaths.messagesInAppNavigationTest), - toRelativePath(TestFilesPaths.helpWindowCheckTest), + toRelativePath(TestFilesPaths.helpSectionCheckTest), toRelativePath(TestFilesPaths.mcCheckForUpdatesTest), toRelativePath(TestFilesPaths.homePageTestDeviceNotConnectedTest), toRelativePath(TestFilesPaths.newsPageOnlineTest), @@ -80,7 +80,7 @@ export const config: Options.Testrunner = { ], suites: { standalone: [ - //toRelativePath(TestFilesPaths.helpWindowCheckTest), + //toRelativePath(TestFilesPaths.helpSectionCheckTest), //toRelativePath(TestFilesPaths.homePageTestDeviceNotConnectedTest), toRelativePath(TestFilesPaths.newsPageOnlineTest), toRelativePath(TestFilesPaths.termsOfServiceTest), @@ -116,7 +116,7 @@ export const config: Options.Testrunner = { kompakt: [], deviceUpdate: [], cicdStandalone: [ - //toRelativePath(TestFilesPaths.helpWindowCheckTest), + //toRelativePath(TestFilesPaths.helpSectionCheckTest), //toRelativePath(TestFilesPaths.homePageTestDeviceNotConnectedTest), toRelativePath(TestFilesPaths.newsPageOnlineTest), toRelativePath(TestFilesPaths.termsOfServiceTest), From 20350d34b54b4e96534f17cedba77576181b1b6a Mon Sep 17 00:00:00 2001 From: robertmudi <158469469+robertmudi@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:35:58 +0200 Subject: [PATCH 18/64] CP-2930 [API Device][Kompakt] Backup - Getting Initial Information (Overview Config Check) (#2069) --- .../page-objects/modal-backup-kompakt.page.ts | 94 +++++++++ .../kompakt-backup-getting-initial-info.ts | 192 ++++++++++++++++++ .../consts/test-filenames.const.ts | 1 + apps/mudita-center-e2e/wdio.conf.ts | 3 + .../responses/src/lib/default-responses.ts | 6 +- .../responses/src/lib/overview-responses.ts | 90 ++++++++ 6 files changed, 383 insertions(+), 3 deletions(-) create mode 100644 apps/mudita-center-e2e/src/page-objects/modal-backup-kompakt.page.ts create mode 100644 apps/mudita-center-e2e/src/specs/overview/kompakt-backup-getting-initial-info.ts diff --git a/apps/mudita-center-e2e/src/page-objects/modal-backup-kompakt.page.ts b/apps/mudita-center-e2e/src/page-objects/modal-backup-kompakt.page.ts new file mode 100644 index 0000000000..de4baace23 --- /dev/null +++ b/apps/mudita-center-e2e/src/page-objects/modal-backup-kompakt.page.ts @@ -0,0 +1,94 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { OverviewPage } from "./overview.page" + +class ModalBackupKompaktPage extends OverviewPage { + public get backupInfo() { + return $('//div[@data-testid="block-box-backup"]//p') + } + public get createBackupButton() { + return $('//button[@type="button" and .//span[text()="Create backup"]]') + } + public get createBackupProceedNext() { + return $('[data-testid="backup-features-modal-create-action"]') + } + + public get contactList() { + return $$('[data-testid="backup-features-modal-element-active"]')[0] + } + public get callLog() { + return $$('[data-testid="backup-features-modal-element-active"]')[1] + } + public get backupModalTitle() { + return $('[data-testid="backup-features-modal-title"]') + } + public get backupModalDescription() { + return $('[data-testid="backup-features-modal-description"]') + } + public get backupModalCancel() { + return $('[data-testid="backup-features-modal-cancel-action"]') + } + + public get backupModalClose() { + return $('[data-testid="modal-close-button-icon-button"]') + } + + public get createBackupPasswordModalTitle() { + return $('[data-testid="predefined-backup-password-title"]') + } + + public get createBackupPasswordOptionalText() { + return $('[data-testid="predefined-backup-password-title"] span') + } + public get createBackupPasswordModalDescription() { + return $('[data-testid="predefined-backup-password-description"]') + } + + public get createBackupPasswordModalDescriptionMore() { + return $('[data-testid="predefined-backup-password-description"] span') + } + + public get createBackupPasswordPlaceholder() { + return $('[data-testid="predefined-backup-password-placeholder"]') + } + + public get createBackupPasswordRepeatPlaceholder() { + return $('[data-testid="predefined-backup-password-repeat-placeholder"]') + } + + public get createBackupPasswordConfirm() { + return $('[data-testid="predefined-backup-password-confirm-button"]') + } + + public get createBackupPasswordSkip() { + return $('[data-testid="predefined-backup-password-skip-button"]') + } + + public get createBackupPasswordClose() { + return $('[data-testid="modal-close-button-icon-button"]') + } + + public get inputPassword() { + return $$('[data-testid="interactive-text-input-input"]')[0] + } + + public get repeatInputPassword() { + return $$('[data-testid="interactive-text-input-input"]')[1] + } + + public get unhidePasswordIcon() { + return $('[data-testid="icon-password-hide"]') + } + + public get hidePasswordIcon() { + return $('[data-testid="icon-password-show"]') + } + + public get passwordsDoNotMatch() { + return $('[data-testid="interactive-text-input-error-text"]') + } +} +export default new ModalBackupKompaktPage() diff --git a/apps/mudita-center-e2e/src/specs/overview/kompakt-backup-getting-initial-info.ts b/apps/mudita-center-e2e/src/specs/overview/kompakt-backup-getting-initial-info.ts new file mode 100644 index 0000000000..f4ce089902 --- /dev/null +++ b/apps/mudita-center-e2e/src/specs/overview/kompakt-backup-getting-initial-info.ts @@ -0,0 +1,192 @@ +import { E2EMockClient } from "../../../../../libs/e2e-mock/client/src" +import { + overviewConfigForBackup, + overviewDataWithOneSimCard, +} from "../../../../../libs/e2e-mock/responses/src" +import ModalBackupKompaktPage from "../../page-objects/modal-backup-kompakt.page" + +describe("E2E mock sample - overview view", () => { + before(async () => { + E2EMockClient.connect() + //wait for a connection to be established + await browser.waitUntil(() => { + return E2EMockClient.checkConnection() + }) + }) + + after(() => { + E2EMockClient.stopServer() + E2EMockClient.disconnect() + }) + + it("Connect device", async () => { + E2EMockClient.mockResponse({ + path: "path-1", + body: overviewConfigForBackup, + endpoint: "FEATURE_CONFIGURATION", + method: "GET", + status: 200, + }) + E2EMockClient.mockResponse({ + path: "path-1", + body: overviewDataWithOneSimCard, + endpoint: "FEATURE_DATA", + method: "GET", + status: 200, + }) + E2EMockClient.addDevice({ + path: "path-1", + serialNumber: "first-serial-number", + }) + + await browser.pause(6000) + const menuItem = await $(`//a[@href="#/generic/mc-overview"]`) + + await menuItem.waitForDisplayed({ timeout: 10000 }) + await expect(menuItem).toBeDisplayed() + }) + + it("Wait for Overview Page and click Create Backup", async () => { + const createBackupButton = await ModalBackupKompaktPage.createBackupButton + await expect(createBackupButton).toBeDisplayed() + await expect(createBackupButton).toBeClickable() + await createBackupButton.click() + }) + + it("Verify modal in scope of available backup options, verify text and buttons", async () => { + const contactList = await ModalBackupKompaktPage.contactList + await expect(contactList).toBeDisplayed() + const contactListText = await contactList?.getProperty("textContent") + expect(contactListText).toContain("Contact list") + expect(contactListText).not.toContain("Coming soon!") + + const callLog = await ModalBackupKompaktPage.callLog + await expect(callLog).toBeDisplayed() + const callLogText = await callLog?.getProperty("textContent") + expect(callLogText).toContain("Call log") + expect(callLogText).not.toContain("Coming soon!") + + const backupModalTitle = ModalBackupKompaktPage.backupModalTitle + await expect(backupModalTitle).toBeDisplayed() + await expect(backupModalTitle).toHaveText("Create backup") + + const backupModalDescription = ModalBackupKompaktPage.backupModalDescription + await expect(backupModalDescription).toBeDisplayed() + await expect(backupModalDescription).toHaveText( + "All backup data stays on your computer." + ) + + const backupModalCancel = ModalBackupKompaktPage.backupModalCancel + await expect(backupModalCancel).toBeClickable() + + const backupModalClose = ModalBackupKompaktPage.backupModalClose + await expect(backupModalClose).toBeClickable() + }) + + it("Click Create backup - verify modal about create password for backup", async () => { + const createBackupProceedNext = + await ModalBackupKompaktPage.createBackupProceedNext + await expect(createBackupProceedNext).toBeClickable() + await createBackupProceedNext.click() + + const createBackupPasswordModalTitle = + ModalBackupKompaktPage.createBackupPasswordModalTitle + await expect(createBackupPasswordModalTitle).toHaveTextContaining( + "Create password for backup" + ) + + const createBackupPasswordOptionalText = + ModalBackupKompaktPage.createBackupPasswordOptionalText + await expect(createBackupPasswordOptionalText).toHaveText("(optional)") + + const createBackupPasswordModalDescription = + ModalBackupKompaktPage.createBackupPasswordModalDescription + await expect(createBackupPasswordModalDescription).toHaveTextContaining( + "You can protect backup with a new password." + ) + + const createBackupPasswordModalDescriptionMore = + ModalBackupKompaktPage.createBackupPasswordModalDescriptionMore + await expect(createBackupPasswordModalDescriptionMore).toHaveText( + "* You can't change/recover the password later." + ) + + const createBackupPasswordPlaceholder = + ModalBackupKompaktPage.createBackupPasswordPlaceholder + await expect(createBackupPasswordPlaceholder).toBeClickable() + + const createBackupPasswordRepeatPlaceholder = + ModalBackupKompaktPage.createBackupPasswordRepeatPlaceholder + await expect(createBackupPasswordRepeatPlaceholder).toBeClickable() + + const createBackupPasswordConfirm = + ModalBackupKompaktPage.createBackupPasswordConfirm + await expect(createBackupPasswordConfirm).not.toBeClickable() + + const createBackupPasswordSkip = + ModalBackupKompaktPage.createBackupPasswordSkip + await expect(createBackupPasswordSkip).toBeClickable() + + const createBackupPasswordClose = + ModalBackupKompaktPage.createBackupPasswordClose + await expect(createBackupPasswordClose).toBeClickable() + }) + + it("Fill password for a backup, unhide it and verify value and design", async () => { + const inputPassword = ModalBackupKompaktPage.inputPassword + await inputPassword.click() + const randomPassword = Math.random().toString(36).substring(2, 10) + await inputPassword.setValue(randomPassword) + + const checkPassword = await inputPassword.getAttribute("type") + await expect(checkPassword).toBe("password") + + const unhidePasswordIcon = ModalBackupKompaktPage.unhidePasswordIcon + await unhidePasswordIcon.click() + + //Verify design, and it's value to check if user can hide password if it was displayed + const hidePasswordIcon = ModalBackupKompaktPage.hidePasswordIcon + await expect(hidePasswordIcon).toBeClickable() + }) + + it("Fill repeat password for a backup, unhide it and verify value and design, verify (passwords do not match)", async () => { + const repeatInputPassword = ModalBackupKompaktPage.repeatInputPassword + await repeatInputPassword.click() + const randomPassword2 = Math.random().toString(36).substring(2, 10) + await repeatInputPassword.setValue(randomPassword2) + + const checkPassword = await repeatInputPassword.getAttribute("type") + await expect(checkPassword).toBe("password") + + const unhidePasswordIcon = ModalBackupKompaktPage.unhidePasswordIcon + await unhidePasswordIcon.click() + + //Verify design and it's value to check if user can hide password if it was displayed + const hidePasswordIcon = ModalBackupKompaktPage.hidePasswordIcon + await expect(hidePasswordIcon).toBeClickable() + + const passwordsDoNotMatch = ModalBackupKompaktPage.passwordsDoNotMatch + await expect(passwordsDoNotMatch).toHaveText("Passwords do not match") + }) + + it("Fill repeat password with first filed password and verify if passwords do not match is gone", async () => { + const inputPassword = ModalBackupKompaktPage.inputPassword + const repeatInputPassword = ModalBackupKompaktPage.repeatInputPassword + const randomPassword = Math.random().toString(36).substring(2, 10) + await inputPassword.click() + await inputPassword.clearValue() + await inputPassword.setValue(randomPassword) + + await repeatInputPassword.click() + await repeatInputPassword.clearValue() + await repeatInputPassword.setValue(randomPassword) + + const passwordsDoNotMatch = ModalBackupKompaktPage.passwordsDoNotMatch + await expect(passwordsDoNotMatch).not.toBeDisplayed() + + const createBackupPasswordConfirm = + ModalBackupKompaktPage.createBackupPasswordConfirm + await expect(createBackupPasswordConfirm).toBeClickable() + await createBackupPasswordConfirm.click() + }) +}) diff --git a/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts b/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts index 1d40ca54ca..c93795b1ee 100644 --- a/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts +++ b/apps/mudita-center-e2e/src/test-filenames/consts/test-filenames.const.ts @@ -28,5 +28,6 @@ export enum TestFilesPaths { kompaktConnectedDevicesModalStressTest = "src/specs/stress-tests/connected-devices-stress-test.ts", kompaktDrawerStressTest = "src/specs/stress-tests/device-drawer-stress-test.ts", contactSupportUnhappyPath = "src/specs/help/contact-support-unhappy-path.ts", + kompaktBackupModalGettingInitialInfo = "src/specs/overview/kompakt-backup-getting-initial-info.ts", } export const toRelativePath = (path: string) => `./${path}` diff --git a/apps/mudita-center-e2e/wdio.conf.ts b/apps/mudita-center-e2e/wdio.conf.ts index 9942f6ca00..738ccc734e 100644 --- a/apps/mudita-center-e2e/wdio.conf.ts +++ b/apps/mudita-center-e2e/wdio.conf.ts @@ -77,6 +77,7 @@ export const config: Options.Testrunner = { toRelativePath(TestFilesPaths.kompaktConnectedDevicesModalStressTest), toRelativePath(TestFilesPaths.kompaktDrawerStressTest), toRelativePath(TestFilesPaths.contactSupportUnhappyPath), + toRelativePath(TestFilesPaths.kompaktBackupModalGettingInitialInfo), ], suites: { standalone: [ @@ -103,6 +104,7 @@ export const config: Options.Testrunner = { toRelativePath(TestFilesPaths.kompaktAbout), toRelativePath(TestFilesPaths.kompaktConnectedDevicesModalStressTest), toRelativePath(TestFilesPaths.kompaktDrawerStressTest), + toRelativePath(TestFilesPaths.kompaktBackupModalGettingInitialInfo), ], multidevicePureHarmony: [], multideviceSingleHarmony: [], @@ -136,6 +138,7 @@ export const config: Options.Testrunner = { toRelativePath(TestFilesPaths.kompaktAbout), toRelativePath(TestFilesPaths.kompaktConnectedDevicesModalStressTest), toRelativePath(TestFilesPaths.kompaktDrawerStressTest), + toRelativePath(TestFilesPaths.kompaktBackupModalGettingInitialInfo), ], }, // Patterns to exclude. diff --git a/libs/e2e-mock/responses/src/lib/default-responses.ts b/libs/e2e-mock/responses/src/lib/default-responses.ts index 743b979c64..e9b4fe9db8 100644 --- a/libs/e2e-mock/responses/src/lib/default-responses.ts +++ b/libs/e2e-mock/responses/src/lib/default-responses.ts @@ -179,9 +179,9 @@ export const DEFAULT_RESPONSES: MockResponsesMap = { ], restoreFeatures: [ { - label: "Contacts list", - feature: "CONTACTS_LIST", - keys: ["CONTACTS_LIST"], + label: "Contact list", + feature: "CONTACT_LIST", + keys: ["CONTACT_LIST"], }, { label: "Call log", feature: "CALL_LOG", keys: ["CALL_LOG"] }, { label: "Messages", feature: "MESSAGES", keys: ["MESSAGES"] }, diff --git a/libs/e2e-mock/responses/src/lib/overview-responses.ts b/libs/e2e-mock/responses/src/lib/overview-responses.ts index f9fb72dd07..a7edba2edc 100644 --- a/libs/e2e-mock/responses/src/lib/overview-responses.ts +++ b/libs/e2e-mock/responses/src/lib/overview-responses.ts @@ -172,3 +172,93 @@ export const overviewDataWithOneSimCard6th = { }, }, } +export const overviewConfigForBackup = { + title: "Overview", + summary: { + show: true, + showImg: true, + imgVariant: "black", + showSerialNumber: true, + serialNumberLabel: "Serial number", + showAbout: true, + aboutTitle: "About your device", + aboutIcon: "device", + aboutSubtitle: "Device details", + aboutFields: [ + { + dataKey: "serialNumber", + type: "detail-list-text", + title: "Serial number", + }, + { + dataKey: "imei1", + type: "detail-list-text", + title: "IMEI (sim slot 1)", + }, + { + dataKey: "imei2", + type: "detail-list-text", + title: "IMEI (sim slot 2)", + }, + { + dataKey: "sar", + type: "detail-list-modal", + title: "SAR", + buttonText: "Check SAR information", + }, + ], + }, + sections: [ + { + title: "Status", + type: "tile-list", + dataKey: "status", + fields: [ + { dataKey: "battery", type: "icon-text" }, + { dataKey: "airplane-mode", type: "icon-text" }, + ], + }, + { + dataKey: "update", + type: "mc-overview-update", + title: "Android OS", + currentVersionKey: "version", + showBadge: false, + versionLabel: "Current version:", + }, + { + dataKey: "backup", + type: "mc-overview-backup", + title: "Backup", + backupFeatures: [ + { label: "Contact list", key: "CONTACT_LIST" }, + { label: "Call log", key: "CALL_LOG" }, + ], + restoreFeatures: [ + { + label: "Contact list", + feature: "CONTACT_LIST", + keys: ["CONTACT_LIST"], + }, + { label: "Call log", feature: "CALL_LOG", keys: ["CALL_LOG"] }, + { label: "Messages", feature: "MESSAGES", keys: ["MESSAGES"] }, + { label: "Notes", feature: "NOTES", keys: ["NOTES"] }, + { + label: "Calendar events", + feature: "CALENDAR_EVENTS", + keys: ["CALENDAR_EVENTS"], + }, + { + label: "OS version & OS settings", + feature: "OS_VERSION_AND_SETTINGS", + keys: ["OS_VERSION_AND_SETTINGS"], + }, + { + label: "App settings: Phone, Messages", + feature: "APP_SETTINGS", + keys: ["APP_SETTINGS"], + }, + ], + }, + ], +} From 0c1578856583a8a1ed924d732e5be99e742f8ada Mon Sep 17 00:00:00 2001 From: robertmudi Date: Mon, 30 Sep 2024 12:46:43 +0200 Subject: [PATCH 19/64] CP-2726 updated help-modal.page.ts --- .../src/page-objects/help-modal.page.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts b/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts index 2e0f784a5f..22fb98910a 100644 --- a/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help-modal.page.ts @@ -26,11 +26,10 @@ class HelpModalPage extends Page { public get sendButton() { return $('[data-testid="submit-button"]') } - + /**[Selector] Send button label */ public get sendButtonLabel() { return $("p*=Send") } - /** returns an Array containing list of attached files */ async attachmentsList() { return $('[data-testid="file-list"]').$$('[data-testid="file-list-file"]') @@ -47,49 +46,51 @@ class HelpModalPage extends Page { public get closeBottomButton() { return $('[data-testid="close-bottom-button"]') } + /**[Selector] Invalid email text */ public get invalidEmailTextElement() { return $('//input[@data-testid="email-input"]/following-sibling::*[1]') } + /**[Selector] Support icon */ public get iconSupport() { return $('[data-testid="icon-Support"]') } - + /**[Selector] Attachment icon */ public get iconAttachment() { return $('[data-testid="icon-Attachment"]') } - + /**[Selector] Modal title with specific text */ public get modalTitle() { return $("h1*=Mudita Center Support") } - + /**[Selector] Modal subtitle */ public get modalSubtitle() { return $( "p*=Contact Mudita support team and we will do our best to help you resolve your issues." ) } - + /**[Selector] Current date zip file */ public get currentDateZipFile() { const currentDate = new Date().toISOString().split("T")[0] // Get current date in YYYY-MM-DD format return $(`p*=${currentDate}.zip`) } - + /**[Selector] Attached files text */ public get attachedFilesText() { return $("p*=Attached files") } - + /**[Selector] Attached files subtext */ public get attachedFilesSubText() { return $("p*=The attached files will help us resolve your problem") } - + /**[Selector] Email label */ public get emailLabel() { return $("p*=Email") } - + /**[Selector] Message label */ public get messageLabel() { return $("p*=Message (optional)") } - + /**[Selector] Whole modal */ public get wholeModal() { return $('[data-testid="contact-support-modal"]') } From d74d0275a5d9dd1a4657a960d1ee5ba4019de7a4 Mon Sep 17 00:00:00 2001 From: robertmudi Date: Mon, 30 Sep 2024 12:48:25 +0200 Subject: [PATCH 20/64] CP-2726 removed duplicated selector --- .../src/page-objects/help.page.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/mudita-center-e2e/src/page-objects/help.page.ts b/apps/mudita-center-e2e/src/page-objects/help.page.ts index d3f3ca5796..97ae9e1d94 100644 --- a/apps/mudita-center-e2e/src/page-objects/help.page.ts +++ b/apps/mudita-center-e2e/src/page-objects/help.page.ts @@ -6,13 +6,13 @@ import Page from "./page" class HelpPage extends Page { - public get helpTabTitle() { + public get helpTabTitle() { return $('[data-testid="location"]') } public get helpMainHeader() { return $('[data-testid="help-main-header"]') } - public get helpMainSubHeader() { + public get helpMainSubHeader() { return $('[data-testid="help-main-subheader"]') } public get iconSearch() { @@ -27,7 +27,7 @@ class HelpPage extends Page { public get helpSearchResultsParagraph() { return $('[data-testid="help-search-results"] p') } - public get helpSearchResultsList() { + public get helpSearchResultsList() { return $('[data-testid="help-search-results"] ul') } public get helpSearchResultsItems() { @@ -49,18 +49,18 @@ class HelpPage extends Page { return $$('[data-testid="help-subcategories-list-item"]') } public get helpSubCategoriesListItemsLeftColumn() { - return $$('[data-testid="help-subcategories-list"]>div')[0].$$('[data-testid="help-subcategories-list-item"]') + return $$('[data-testid="help-subcategories-list"]>div')[0].$$( + '[data-testid="help-subcategories-list-item"]' + ) } public get helpSubCategoriesListItemsRightColumn() { - return $$('[data-testid="help-subcategories-list"]>div')[1].$$('[data-testid="help-subcategories-list-item"]') + return $$('[data-testid="help-subcategories-list"]>div')[1].$$( + '[data-testid="help-subcategories-list-item"]' + ) } public get helpMainFooterDescription() { - return $('[data-testid="help-main-footer-description"]') + return $('[data-testid="help-main-footer-description"]') } - public get helpMainFooterContactSupportButton() { - return $('[data-testid="help-main-footer-contact-support-button"]') - } - public get helpMainFooterContactSupportButton() { return $('[data-testid="help-main-footer-contact-support-button"]') } From 7b2616295489fabf4d237cea25da365d755eb8ba Mon Sep 17 00:00:00 2001 From: robertmudi Date: Mon, 30 Sep 2024 13:58:18 +0200 Subject: [PATCH 21/64] CP-2726 added 6 more tests to finish --- .../help/contact-support-unhappy-path.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts b/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts index b5fb4d1f1d..85e6daf69b 100644 --- a/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts +++ b/apps/mudita-center-e2e/src/specs/help/contact-support-unhappy-path.ts @@ -70,4 +70,58 @@ describe("Contact Support - Unhappy Path", () => { "The attached files will help us resolve your problem" ) }) + + it("Check if SEND button is present, has proper name and is disabled", async () => { + const sendButton = HelpModalPage.sendButton + const sendButtonLabel = HelpModalPage.sendButtonLabel + await expect(sendButton).toBeDisplayed() + await expect(sendButtonLabel).toHaveText("SEND") + await expect(sendButton).toBeDisabled() + }) + + it("Try to Send form without any input", async () => { + const sendButton = HelpModalPage.sendButton + + const isDisabled = await sendButton.getAttribute("disabled") + + // Verify if the button is disabled before attempting to click + if (isDisabled !== null) { + console.log("The button is disabled and cannot be clicked.") + } else { + // Attempt to click only if the button is not disabled + await sendButton.click() + console.log("The button was clicked successfully.") + } + }) + + it("Verify e-mail without @ character", async () => { + const emailInput = HelpModalPage.emailInput + await emailInput.setValue("emailtest.com") + const emailWarning = "Email is invalid" + const invalidEmailTextElement = HelpModalPage.invalidEmailTextElement + await expect(invalidEmailTextElement).toHaveText(emailWarning) + }) + + it("Check e-mail with @@ characters", async () => { + const emailInput = HelpModalPage.emailInput + await emailInput.setValue("email@@test.com") + const emailWarning = "Email is invalid" + const invalidEmailTextElement = HelpModalPage.invalidEmailTextElement + await expect(invalidEmailTextElement).toHaveText(emailWarning) + }) + + it("Enter correct e-mail to check if error message dissappears", async () => { + const emailInput = HelpModalPage.emailInput + await emailInput.setValue("email@test.com") + const invalidEmailTextElement = HelpModalPage.invalidEmailTextElement + await expect(invalidEmailTextElement).not.toBeDisplayed() + }) + + it("Check e-mail with , character", async () => { + const emailInput = HelpModalPage.emailInput + await emailInput.setValue("email@test,com") + const emailWarning = "Email is invalid" + const invalidEmailTextElement = HelpModalPage.invalidEmailTextElement + await expect(invalidEmailTextElement).toHaveText(emailWarning) + }) }) From 4259ba26d5b541ed84a5d56543971be6da7d888d Mon Sep 17 00:00:00 2001 From: MateuszMudita Date: Tue, 1 Oct 2024 14:37:59 +0200 Subject: [PATCH 22/64] [CP-3153] Added test ids to start backup action and contact support modal --- apps/mudita-center-e2e/src/helpers/index.ts | 1 + .../src/helpers/testid.helper.ts | 10 +++++++ .../contact-support-modal.component.tsx | 30 ++++++++++++++----- libs/e2e-test-ids/src/e2e-test-ids.ts | 13 ++++++++ .../ui/src/lib/buttons/button-primary.tsx | 8 ++++- 5 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 apps/mudita-center-e2e/src/helpers/testid.helper.ts diff --git a/apps/mudita-center-e2e/src/helpers/index.ts b/apps/mudita-center-e2e/src/helpers/index.ts index 844f85e401..62a4e2bea6 100644 --- a/apps/mudita-center-e2e/src/helpers/index.ts +++ b/apps/mudita-center-e2e/src/helpers/index.ts @@ -4,3 +4,4 @@ */ export * from "./sleep.helper" +export * from "./testid.helper" diff --git a/apps/mudita-center-e2e/src/helpers/testid.helper.ts b/apps/mudita-center-e2e/src/helpers/testid.helper.ts new file mode 100644 index 0000000000..be1037dee1 --- /dev/null +++ b/apps/mudita-center-e2e/src/helpers/testid.helper.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +const PRIMARY_BUTTON_TEST_ID = "primary-button" + +export const getPrimaryButtonTestId = (componentId: string) => { + return `${PRIMARY_BUTTON_TEST_ID}-${componentId}` +} diff --git a/libs/core/contact-support/components/contact-support-modal.component.tsx b/libs/core/contact-support/components/contact-support-modal.component.tsx index 96e25a9ee7..f60a60b667 100644 --- a/libs/core/contact-support/components/contact-support-modal.component.tsx +++ b/libs/core/contact-support/components/contact-support-modal.component.tsx @@ -36,6 +36,7 @@ import { HelpActions } from "Core/__deprecated__/common/enums/help-actions.enum" import { ModalTestIds } from "Core/__deprecated__/renderer/components/core/modal/modal-test-ids.enum" import { Close } from "Core/__deprecated__/renderer/components/core/modal/modal.styled.elements" import { SpinnerLoader } from "../../../generic-view/ui/src/lib/shared/spinner-loader" +import { NewContactSupportModalTestIds } from "e2e-test-ids" const messages = defineMessages({ actionButton: { @@ -95,8 +96,12 @@ interface FormInputLabelProps { export const FormInputLabelComponent: FunctionComponent< FormInputLabelProps -> = ({ className, label, optional }) => ( - +> = ({ className, label, optional, ...rest }) => ( + {optional && ( = ({ -

    +

    -

    +

    - + = ({ label={intl.formatMessage(messages.emailPlaceholder)} {...register(FieldKeys.Email, emailValidator)} /> - + = ({ data-testid={ContactSupportModalTestIds.DescriptionInput} {...register(FieldKeys.Description)} /> - + = ({ data, @@ -17,7 +18,12 @@ export const ButtonPrimary: APIFC = ({ ...props }) => { return ( -