diff --git a/.eslintrc.json b/.eslintrc.json index 2a40c6cc29..525072dc6c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -34,7 +34,6 @@ }, { "files": ["**/*.ts"], - "excludedFiles": ["qa-core/**"], "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint"], "extends": ["eslint:recommended"], @@ -49,7 +48,6 @@ }, { "files": ["**/*.spec.ts"], - "excludedFiles": ["qa-core/**"], "parser": "@typescript-eslint/parser", "plugins": ["jest", "@typescript-eslint"], "extends": ["eslint:recommended", "plugin:jest/recommended"], diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 030ad6578e..42d73ba8bb 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -91,6 +91,9 @@ jobs: test-libraries: runs-on: ubuntu-latest + env: + DEBUG: testcontainers,testcontainers:exec,testcontainers:build,testcontainers:pull + REUSE_CONTAINERS: true steps: - name: Checkout repo uses: actions/checkout@v4 @@ -104,6 +107,14 @@ jobs: with: node-version: 20.x cache: yarn + - name: Pull testcontainers images + run: | + docker pull testcontainers/ryuk:0.5.1 & + docker pull budibase/couchdb & + docker pull redis & + + wait $(jobs -p) + - run: yarn --frozen-lockfile - name: Test run: | @@ -138,9 +149,10 @@ jobs: fi test-server: - runs-on: ubuntu-latest + runs-on: budi-tubby-tornado-quad-core-150gb env: DEBUG: testcontainers,testcontainers:exec,testcontainers:build,testcontainers:pull + REUSE_CONTAINERS: true steps: - name: Checkout repo uses: actions/checkout@v4 @@ -157,13 +169,16 @@ jobs: - name: Pull testcontainers images run: | - docker pull mcr.microsoft.com/mssql/server:2022-latest - docker pull mysql:8.3 - docker pull postgres:16.1-bullseye - docker pull mongo:7.0-jammy - docker pull mariadb:lts - docker pull testcontainers/ryuk:0.5.1 - docker pull budibase/couchdb + docker pull mcr.microsoft.com/mssql/server:2022-latest & + docker pull mysql:8.3 & + docker pull postgres:16.1-bullseye & + docker pull mongo:7.0-jammy & + docker pull mariadb:lts & + docker pull testcontainers/ryuk:0.5.1 & + docker pull budibase/couchdb & + docker pull redis & + + wait $(jobs -p) - run: yarn --frozen-lockfile @@ -175,35 +190,6 @@ jobs: yarn test --scope=@budibase/server fi - integration-test: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: ${{ env.IS_OSS_CONTRIBUTOR == 'false' }} - token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }} - - - name: Use Node.js 20.x - uses: actions/setup-node@v4 - with: - node-version: 20.x - cache: yarn - - run: yarn --frozen-lockfile - - name: Build packages - run: yarn build --scope @budibase/server --scope @budibase/worker - - name: Build backend-core for OSS contributor (required for pro) - if: ${{ env.IS_OSS_CONTRIBUTOR == 'true' }} - run: yarn build --scope @budibase/backend-core - - name: Run tests - run: | - cd qa-core - yarn setup - yarn serve:test:self:ci - env: - BB_ADMIN_USER_EMAIL: admin - BB_ADMIN_USER_PASSWORD: admin - check-pro-submodule: runs-on: ubuntu-latest if: inputs.run_as_oss != true && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase') diff --git a/.gitignore b/.gitignore index 661c60e95e..b68ddd975f 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,6 @@ typings/ # dotenv environment variables file .env -!qa-core/.env !hosting/.env # parcel-bundler cache (https://parceljs.org/) diff --git a/globalSetup.ts b/globalSetup.ts index 4cb542a3c3..7bf5e2152c 100644 --- a/globalSetup.ts +++ b/globalSetup.ts @@ -1,25 +1,47 @@ import { GenericContainer, Wait } from "testcontainers" +import path from "path" +import lockfile from "proper-lockfile" export default async function setup() { - await new GenericContainer("budibase/couchdb") - .withExposedPorts(5984) - .withEnvironment({ - COUCHDB_PASSWORD: "budibase", - COUCHDB_USER: "budibase", - }) - .withCopyContentToContainer([ - { - content: ` + const lockPath = path.resolve(__dirname, "globalSetup.ts") + if (process.env.REUSE_CONTAINERS) { + // If you run multiple tests at the same time, it's possible for the CouchDB + // shared container to get started multiple times despite having an + // identical reuse hash. To avoid that, we do a filesystem-based lock so + // that only one globalSetup.ts is running at a time. + lockfile.lockSync(lockPath) + } + + try { + let couchdb = new GenericContainer("budibase/couchdb") + .withExposedPorts(5984) + .withEnvironment({ + COUCHDB_PASSWORD: "budibase", + COUCHDB_USER: "budibase", + }) + .withCopyContentToContainer([ + { + content: ` [log] level = warn `, - target: "/opt/couchdb/etc/local.d/test-couchdb.ini", - }, - ]) - .withWaitStrategy( - Wait.forSuccessfulCommand( - "curl http://budibase:budibase@localhost:5984/_up" - ).withStartupTimeout(20000) - ) - .start() + target: "/opt/couchdb/etc/local.d/test-couchdb.ini", + }, + ]) + .withWaitStrategy( + Wait.forSuccessfulCommand( + "curl http://budibase:budibase@localhost:5984/_up" + ).withStartupTimeout(20000) + ) + + if (process.env.REUSE_CONTAINERS) { + couchdb = couchdb.withReuse() + } + + await couchdb.start() + } finally { + if (process.env.REUSE_CONTAINERS) { + lockfile.unlockSync(lockPath) + } + } } diff --git a/lerna.json b/lerna.json index 906e9fba50..7186c0ca17 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.22.14", + "version": "2.22.16", "npmClient": "yarn", "packages": [ "packages/*", diff --git a/package.json b/package.json index 32693a0b6f..4b6716f7e7 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@babel/preset-env": "^7.22.5", "@esbuild-plugins/tsconfig-paths": "^0.1.2", "@types/node": "20.10.0", + "@types/proper-lockfile": "^4.1.4", "@typescript-eslint/parser": "6.9.0", "esbuild": "^0.18.17", "esbuild-node-externals": "^1.8.0", @@ -23,6 +24,7 @@ "nx-cloud": "16.0.5", "prettier": "2.8.8", "prettier-plugin-svelte": "^2.3.0", + "proper-lockfile": "^4.1.2", "svelte": "^4.2.10", "svelte-eslint-parser": "^0.33.1", "typescript": "5.2.2", @@ -58,11 +60,11 @@ "dev:built": "yarn run kill-all && cd packages/server && yarn dev:stack:up && cd ../../ && lerna run --stream dev:built", "dev:docker": "yarn build --scope @budibase/server --scope @budibase/worker && docker-compose -f hosting/docker-compose.build.yaml -f hosting/docker-compose.dev.yaml --env-file hosting/.env up --build --scale proxy-service=0", "test": "lerna run --stream test --stream", - "lint:eslint": "eslint packages qa-core --max-warnings=0", - "lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --check \"qa-core/**/*.{js,ts,svelte}\"", + "lint:eslint": "eslint packages --max-warnings=0", + "lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\"", "lint": "yarn run lint:eslint && yarn run lint:prettier", - "lint:fix:eslint": "eslint --fix --max-warnings=0 packages qa-core", - "lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --write \"qa-core/**/*.{js,ts,svelte}\"", + "lint:fix:eslint": "eslint --fix --max-warnings=0 packages", + "lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\"", "lint:fix": "yarn run lint:fix:eslint && yarn run lint:fix:prettier", "build:specs": "lerna run --stream specs", "build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild", diff --git a/packages/account-portal b/packages/account-portal index 360ad2dc29..532c4db35c 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit 360ad2dc29c3f1fd5a1182ae258c45666b7f5eb1 +Subproject commit 532c4db35cecd346b5c24f0b89ab7b397a122a36 diff --git a/packages/backend-core/tests/core/utilities/testContainerUtils.ts b/packages/backend-core/tests/core/utilities/testContainerUtils.ts index 5d4f5a3c11..951a6f0517 100644 --- a/packages/backend-core/tests/core/utilities/testContainerUtils.ts +++ b/packages/backend-core/tests/core/utilities/testContainerUtils.ts @@ -1,6 +1,7 @@ -import { DatabaseImpl } from "../../../src/db" import { execSync } from "child_process" +const IPV4_PORT_REGEX = new RegExp(`0\\.0\\.0\\.0:(\\d+)->(\\d+)/tcp`, "g") + interface ContainerInfo { Command: string CreatedAt: string @@ -19,7 +20,10 @@ interface ContainerInfo { } function getTestcontainers(): ContainerInfo[] { - return execSync("docker ps --format json") + // We use --format json to make sure the output is nice and machine-readable, + // and we use --no-trunc so that the command returns full container IDs so we + // can filter on them correctly. + return execSync("docker ps --format json --no-trunc") .toString() .split("\n") .filter(x => x.length > 0) @@ -27,32 +31,55 @@ function getTestcontainers(): ContainerInfo[] { .filter(x => x.Labels.includes("org.testcontainers=true")) } -function getContainerByImage(image: string) { - return getTestcontainers().find(x => x.Image.startsWith(image)) +export function getContainerByImage(image: string) { + const containers = getTestcontainers().filter(x => x.Image.startsWith(image)) + if (containers.length > 1) { + let errorMessage = `Multiple containers found starting with image: "${image}"\n\n` + for (const container of containers) { + errorMessage += JSON.stringify(container, null, 2) + } + throw new Error(errorMessage) + } + return containers[0] } -function getExposedPort(container: ContainerInfo, port: number) { - const match = container.Ports.match(new RegExp(`0.0.0.0:(\\d+)->${port}/tcp`)) - if (!match) { - return undefined +export function getContainerById(id: string) { + return getTestcontainers().find(x => x.ID === id) +} + +export interface Port { + host: number + container: number +} + +export function getExposedV4Ports(container: ContainerInfo): Port[] { + let ports: Port[] = [] + for (const match of container.Ports.matchAll(IPV4_PORT_REGEX)) { + ports.push({ host: parseInt(match[1]), container: parseInt(match[2]) }) } - return parseInt(match[1]) + return ports +} + +export function getExposedV4Port(container: ContainerInfo, port: number) { + return getExposedV4Ports(container).find(x => x.container === port)?.host } export function setupEnv(...envs: any[]) { + // We start couchdb in globalSetup.ts, in the root of the monorepo, so it + // should be relatively safe to look for it by its image name. const couch = getContainerByImage("budibase/couchdb") if (!couch) { throw new Error("CouchDB container not found") } - const couchPort = getExposedPort(couch, 5984) + const couchPort = getExposedV4Port(couch, 5984) if (!couchPort) { throw new Error("CouchDB port not found") } const configs = [ { key: "COUCH_DB_PORT", value: `${couchPort}` }, - { key: "COUCH_DB_URL", value: `http://localhost:${couchPort}` }, + { key: "COUCH_DB_URL", value: `http://127.0.0.1:${couchPort}` }, ] for (const config of configs.filter(x => !!x.value)) { @@ -60,7 +87,4 @@ export function setupEnv(...envs: any[]) { env._set(config.key, config.value) } } - - // @ts-expect-error - DatabaseImpl.nano = undefined } diff --git a/packages/builder/package.json b/packages/builder/package.json index f61ac4fe26..253f5a0c14 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -72,7 +72,7 @@ "fast-json-patch": "^3.1.1", "json-format-highlight": "^1.0.4", "lodash": "4.17.21", - "posthog-js": "^1.36.0", + "posthog-js": "^1.116.6", "remixicon": "2.5.0", "sanitize-html": "^2.7.0", "shortid": "2.2.15", diff --git a/packages/builder/src/components/backend/DataTable/formula.js b/packages/builder/src/components/backend/DataTable/formula.js index ac1da8f4ed..ee108d066b 100644 --- a/packages/builder/src/components/backend/DataTable/formula.js +++ b/packages/builder/src/components/backend/DataTable/formula.js @@ -1,3 +1,4 @@ +import { FieldType } from "@budibase/types" import { FIELDS } from "constants/backend" import { tables } from "stores/builder" import { get as svelteGet } from "svelte/store" @@ -5,15 +6,13 @@ import { get as svelteGet } from "svelte/store" // currently supported level of relationship depth (server side) const MAX_DEPTH = 1 -//https://github.com/Budibase/budibase/issues/3030 -const internalType = "internal" - const TYPES_TO_SKIP = [ - FIELDS.FORMULA.type, - FIELDS.LONGFORM.type, - FIELDS.ATTACHMENT.type, - FIELDS.SIGNATURE.type, - internalType, + FieldType.FORMULA, + FieldType.LONGFORM, + FieldType.ATTACHMENT, + FieldType.SIGNATURE, + //https://github.com/Budibase/budibase/issues/3030 + FieldType.INTERNAL, ] export function getBindings({ @@ -27,7 +26,7 @@ export function getBindings({ return bindings } for (let [column, schema] of Object.entries(table.schema)) { - const isRelationship = schema.type === FIELDS.LINK.type + const isRelationship = schema.type === FieldType.LINK // skip relationships after a certain depth and types which // can't bind to if ( diff --git a/packages/builder/src/components/backend/Datasources/relationshipErrors.js b/packages/builder/src/components/backend/Datasources/relationshipErrors.js index 259484e9a9..610ff9f1fe 100644 --- a/packages/builder/src/components/backend/Datasources/relationshipErrors.js +++ b/packages/builder/src/components/backend/Datasources/relationshipErrors.js @@ -1,4 +1,4 @@ -import { RelationshipType } from "constants/backend" +import { RelationshipType } from "@budibase/types" const typeMismatch = "Column type of the foreign key must match the primary key" const columnBeingUsed = "Column name cannot be an existing column" diff --git a/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte b/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte index eb1e7bc7ff..efbfd26565 100644 --- a/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte +++ b/packages/builder/src/components/backend/TableNavigator/ExistingTableDataImport.svelte @@ -49,7 +49,10 @@ label: "Long Form Text", value: FIELDS.LONGFORM.type, }, - + { + label: "Attachment", + value: FIELDS.ATTACHMENT.type, + }, { label: "User", value: `${FIELDS.USER.type}${FIELDS.USER.subtype}`, diff --git a/packages/builder/src/components/backend/TableNavigator/utils.js b/packages/builder/src/components/backend/TableNavigator/utils.js index b7e46042be..ae7aaa0f0a 100644 --- a/packages/builder/src/components/backend/TableNavigator/utils.js +++ b/packages/builder/src/components/backend/TableNavigator/utils.js @@ -12,7 +12,7 @@ const getDefaultSchema = rows => { newSchema[column] = { name: column, type: "string", - constraints: FIELDS["STRING"].constraints, + constraints: FIELDS.STRING.constraints, } }) }) diff --git a/packages/builder/src/components/design/settings/controls/FieldConfiguration/utils.js b/packages/builder/src/components/design/settings/controls/FieldConfiguration/utils.js index 420d542028..66da034518 100644 --- a/packages/builder/src/components/design/settings/controls/FieldConfiguration/utils.js +++ b/packages/builder/src/components/design/settings/controls/FieldConfiguration/utils.js @@ -1,3 +1,5 @@ +import { FieldType } from "@budibase/types" + export const convertOldFieldFormat = fields => { if (!fields) { return [] @@ -31,18 +33,18 @@ export const getComponentForField = (field, schema) => { } export const FieldTypeToComponentMap = { - string: "stringfield", - number: "numberfield", - bigint: "bigintfield", - options: "optionsfield", - array: "multifieldselect", - boolean: "booleanfield", - longform: "longformfield", - datetime: "datetimefield", - attachment: "attachmentfield", - link: "relationshipfield", - json: "jsonfield", - barcodeqr: "codescanner", - signature: "signaturefield", - bb_reference: "bbreferencefield", + [FieldType.STRING]: "stringfield", + [FieldType.NUMBER]: "numberfield", + [FieldType.BIGINT]: "bigintfield", + [FieldType.OPTIONS]: "optionsfield", + [FieldType.ARRAY]: "multifieldselect", + [FieldType.BOOLEAN]: "booleanfield", + [FieldType.LONGFORM]: "longformfield", + [FieldType.DATETIME]: "datetimefield", + [FieldType.ATTACHMENT]: "attachmentfield", + [FieldType.SIGNATURE]: "signaturefield", + [FieldType.LINK]: "relationshipfield", + [FieldType.JSON]: "jsonfield", + [FieldType.BARCODEQR]: "codescanner", + [FieldType.BB_REFERENCE]: "bbreferencefield", } diff --git a/packages/builder/src/constants/backend/index.js b/packages/builder/src/constants/backend/index.js index f66bf1cec6..c058d6168c 100644 --- a/packages/builder/src/constants/backend/index.js +++ b/packages/builder/src/constants/backend/index.js @@ -1,12 +1,14 @@ -import { FieldType, FieldSubtype } from "@budibase/types" +import { + FieldType, + FieldSubtype, + INTERNAL_TABLE_SOURCE_ID, + AutoFieldSubType, + Hosting, +} from "@budibase/types" -export const AUTO_COLUMN_SUB_TYPES = { - AUTO_ID: "autoID", - CREATED_BY: "createdBy", - CREATED_AT: "createdAt", - UPDATED_BY: "updatedBy", - UPDATED_AT: "updatedAt", -} +export { RelationshipType } from "@budibase/types" + +export const AUTO_COLUMN_SUB_TYPES = AutoFieldSubType export const AUTO_COLUMN_DISPLAY_NAMES = { AUTO_ID: "Auto ID", @@ -176,10 +178,7 @@ export const FILE_TYPES = { DOCUMENT: ["odf", "docx", "doc", "pdf", "csv"], } -export const HostingTypes = { - CLOUD: "cloud", - SELF: "self", -} +export const HostingTypes = Hosting export const Roles = { ADMIN: "ADMIN", @@ -196,12 +195,6 @@ export function isAutoColumnUserRelationship(subtype) { ) } -export const RelationshipType = { - MANY_TO_MANY: "many-to-many", - ONE_TO_MANY: "one-to-many", - MANY_TO_ONE: "many-to-one", -} - export const PrettyRelationshipDefinitions = { MANY: "Many rows", ONE: "One row", @@ -227,7 +220,7 @@ export const SWITCHABLE_TYPES = [ ...ALLOWABLE_NUMBER_TYPES, ] -export const BUDIBASE_INTERNAL_DB_ID = "bb_internal" +export const BUDIBASE_INTERNAL_DB_ID = INTERNAL_TABLE_SOURCE_ID export const DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default" export const BUDIBASE_DATASOURCE_TYPE = "budibase" export const DB_TYPE_INTERNAL = "internal" @@ -274,10 +267,10 @@ export const IntegrationNames = { } export const SchemaTypeOptions = [ - { label: "Text", value: "string" }, - { label: "Number", value: "number" }, - { label: "Boolean", value: "boolean" }, - { label: "Datetime", value: "datetime" }, + { label: "Text", value: FieldType.STRING }, + { label: "Number", value: FieldType.NUMBER }, + { label: "Boolean", value: FieldType.BOOLEAN }, + { label: "Datetime", value: FieldType.DATETIME }, ] export const SchemaTypeOptionsExpanded = SchemaTypeOptions.map(el => ({ @@ -314,10 +307,10 @@ export const PaginationLocations = [ ] export const BannedSearchTypes = [ - "link", - "attachment", - "formula", - "json", + FieldType.LINK, + FieldType.ATTACHMENT, + FieldType.FORMULA, + FieldType.JSON, "jsonarray", "queryarray", ] diff --git a/packages/builder/src/helpers/schemaGenerator.js b/packages/builder/src/helpers/schemaGenerator.js index 33115fc997..eb044496f6 100644 --- a/packages/builder/src/helpers/schemaGenerator.js +++ b/packages/builder/src/helpers/schemaGenerator.js @@ -1,17 +1,17 @@ -import { FIELDS } from "constants/backend" +import { FieldType } from "@budibase/types" function baseConversion(type) { if (type === "string") { return { - type: FIELDS.STRING.type, + type: FieldType.STRING, } } else if (type === "boolean") { return { - type: FIELDS.BOOLEAN.type, + type: FieldType.BOOLEAN, } } else if (type === "number") { return { - type: FIELDS.NUMBER.type, + type: FieldType.NUMBER, } } } @@ -31,7 +31,7 @@ function recurse(schemaLevel = {}, objectLevel) { const schema = recurse(schemaLevel[key], value[0]) if (schema) { schemaLevel[key] = { - type: FIELDS.ARRAY.type, + type: FieldType.ARRAY, schema, } } @@ -45,7 +45,7 @@ function recurse(schemaLevel = {}, objectLevel) { } } if (!schemaLevel.type) { - return { type: FIELDS.JSON.type, schema: schemaLevel } + return { type: FieldType.JSON, schema: schemaLevel } } else { return schemaLevel } diff --git a/packages/builder/src/helpers/utils.js b/packages/builder/src/helpers/utils.js index 6bb333f3c4..a1f9b34e3d 100644 --- a/packages/builder/src/helpers/utils.js +++ b/packages/builder/src/helpers/utils.js @@ -1,3 +1,4 @@ +import { FieldType } from "@budibase/types" import { ActionStepID } from "constants/backend/automations" import { TableNames } from "constants" import { @@ -20,20 +21,20 @@ export function buildAutoColumn(tableName, name, subtype) { switch (subtype) { case AUTO_COLUMN_SUB_TYPES.UPDATED_BY: case AUTO_COLUMN_SUB_TYPES.CREATED_BY: - type = FIELDS.LINK.type + type = FieldType.LINK constraints = FIELDS.LINK.constraints break case AUTO_COLUMN_SUB_TYPES.AUTO_ID: - type = FIELDS.NUMBER.type + type = FieldType.NUMBER constraints = FIELDS.NUMBER.constraints break case AUTO_COLUMN_SUB_TYPES.UPDATED_AT: case AUTO_COLUMN_SUB_TYPES.CREATED_AT: - type = FIELDS.DATETIME.type + type = FieldType.DATETIME constraints = FIELDS.DATETIME.constraints break default: - type = FIELDS.STRING.type + type = FieldType.STRING constraints = FIELDS.STRING.constraints break } diff --git a/packages/builder/src/stores/builder/tables.js b/packages/builder/src/stores/builder/tables.js index f86b37ab85..0163281480 100644 --- a/packages/builder/src/stores/builder/tables.js +++ b/packages/builder/src/stores/builder/tables.js @@ -1,7 +1,8 @@ +import { FieldType } from "@budibase/types" import { get, writable, derived } from "svelte/store" import { cloneDeep } from "lodash/fp" import { API } from "api" -import { SWITCHABLE_TYPES, FIELDS } from "constants/backend" +import { SWITCHABLE_TYPES } from "constants/backend" export function createTablesStore() { const store = writable({ @@ -83,14 +84,14 @@ export function createTablesStore() { // make sure tables up to date (related) let newTableIds = [] for (let column of Object.values(updatedTable?.schema || {})) { - if (column.type === FIELDS.LINK.type) { + if (column.type === FieldType.LINK) { newTableIds.push(column.tableId) } } let oldTableIds = [] for (let column of Object.values(oldTable?.schema || {})) { - if (column.type === FIELDS.LINK.type) { + if (column.type === FieldType.LINK) { oldTableIds.push(column.tableId) } } diff --git a/packages/builder/src/templates/commonComponents.js b/packages/builder/src/templates/commonComponents.js index 63a0c93f66..884419ae6c 100644 --- a/packages/builder/src/templates/commonComponents.js +++ b/packages/builder/src/templates/commonComponents.js @@ -1,22 +1,7 @@ +import { FieldTypeToComponentMap } from "components/design/settings/controls/FieldConfiguration/utils" import { Component } from "./Component" import { getSchemaForDatasource } from "dataBinding" -const fieldTypeToComponentMap = { - string: "stringfield", - number: "numberfield", - bigint: "bigintfield", - options: "optionsfield", - array: "multifieldselect", - boolean: "booleanfield", - longform: "longformfield", - datetime: "datetimefield", - attachment: "attachmentfield", - link: "relationshipfield", - json: "jsonfield", - signature: "signaturefield", - barcodeqr: "codescanner", -} - export function makeDatasourceFormComponents(datasource) { const { schema } = getSchemaForDatasource(null, datasource, { formSchema: true, @@ -31,7 +16,7 @@ export function makeDatasourceFormComponents(datasource) { } const fieldType = typeof fieldSchema === "object" ? fieldSchema.type : fieldSchema - const componentType = fieldTypeToComponentMap[fieldType] + const componentType = FieldTypeToComponentMap[fieldType] const fullComponentType = `@budibase/standard-components/${componentType}` if (componentType) { const component = new Component(fullComponentType) diff --git a/packages/client/src/components/app/blocks/FormBlockComponent.svelte b/packages/client/src/components/app/blocks/FormBlockComponent.svelte index dff49fb43e..bce25d8623 100644 --- a/packages/client/src/components/app/blocks/FormBlockComponent.svelte +++ b/packages/client/src/components/app/blocks/FormBlockComponent.svelte @@ -7,20 +7,20 @@ export let order const FieldTypeToComponentMap = { - string: "stringfield", - number: "numberfield", - bigint: "bigintfield", - options: "optionsfield", - array: "multifieldselect", - boolean: "booleanfield", - longform: "longformfield", - datetime: "datetimefield", - attachment: "attachmentfield", - link: "relationshipfield", - json: "jsonfield", - barcodeqr: "codescanner", - signature: "signaturefield", - bb_reference: "bbreferencefield", + [FieldType.STRING]: "stringfield", + [FieldType.NUMBER]: "numberfield", + [FieldType.BIGINT]: "bigintfield", + [FieldType.OPTIONS]: "optionsfield", + [FieldType.ARRAY]: "multifieldselect", + [FieldType.BOOLEAN]: "booleanfield", + [FieldType.LONGFORM]: "longformfield", + [FieldType.DATETIME]: "datetimefield", + [FieldType.ATTACHMENT]: "attachmentfield", + [FieldType.SIGNATURE]: "signaturefield", + [FieldType.LINK]: "relationshipfield", + [FieldType.JSON]: "jsonfield", + [FieldType.BARCODEQR]: "codescanner", + [FieldType.BB_REFERENCE]: "bbreferencefield", } const getFieldSchema = field => { diff --git a/packages/client/src/components/devtools/DevToolsStatsTab.svelte b/packages/client/src/components/devtools/DevToolsStatsTab.svelte index 24f587332c..bc0b1a562b 100644 --- a/packages/client/src/components/devtools/DevToolsStatsTab.svelte +++ b/packages/client/src/components/devtools/DevToolsStatsTab.svelte @@ -23,6 +23,6 @@ label="Components" value={$componentStore.mountedComponentCount} /> - - + + diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index fd37af63dc..4ca88de8f2 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -8,6 +8,7 @@ "dependencies": { "@budibase/bbui": "0.0.0", "@budibase/shared-core": "0.0.0", + "@budibase/types": "0.0.0", "dayjs": "^1.10.8", "lodash": "4.17.21", "socket.io-client": "^4.6.1" diff --git a/packages/frontend-core/src/components/grid/lib/renderers.js b/packages/frontend-core/src/components/grid/lib/renderers.js index 3c10e47b44..b3be40a211 100644 --- a/packages/frontend-core/src/components/grid/lib/renderers.js +++ b/packages/frontend-core/src/components/grid/lib/renderers.js @@ -1,3 +1,5 @@ +import { FieldType } from "@budibase/types" + import OptionsCell from "../cells/OptionsCell.svelte" import DateCell from "../cells/DateCell.svelte" import MultiSelectCell from "../cells/MultiSelectCell.svelte" @@ -13,20 +15,20 @@ import BBReferenceCell from "../cells/BBReferenceCell.svelte" import SignatureCell from "../cells/SignatureCell.svelte" const TypeComponentMap = { - text: TextCell, - options: OptionsCell, - datetime: DateCell, - barcodeqr: TextCell, - signature: SignatureCell, - longform: LongFormCell, - array: MultiSelectCell, - number: NumberCell, - boolean: BooleanCell, - attachment: AttachmentCell, - link: RelationshipCell, - formula: FormulaCell, - json: JSONCell, - bb_reference: BBReferenceCell, + [FieldType.STRING]: TextCell, + [FieldType.OPTIONS]: OptionsCell, + [FieldType.DATETIME]: DateCell, + [FieldType.BARCODEQR]: TextCell, + [FieldType.SIGNATURE]: SignatureCell, + [FieldType.LONGFORM]: LongFormCell, + [FieldType.ARRAY]: MultiSelectCell, + [FieldType.NUMBER]: NumberCell, + [FieldType.BOOLEAN]: BooleanCell, + [FieldType.ATTACHMENT]: AttachmentCell, + [FieldType.LINK]: RelationshipCell, + [FieldType.FORMULA]: FormulaCell, + [FieldType.JSON]: JSONCell, + [FieldType.BB_REFERENCE]: BBReferenceCell, } export const getCellRenderer = column => { return TypeComponentMap[column?.schema?.type] || TextCell diff --git a/packages/frontend-core/src/components/grid/lib/utils.js b/packages/frontend-core/src/components/grid/lib/utils.js index 5a87ae1ed1..cd8272f72f 100644 --- a/packages/frontend-core/src/components/grid/lib/utils.js +++ b/packages/frontend-core/src/components/grid/lib/utils.js @@ -1,3 +1,5 @@ +import { FieldType, FieldTypeSubtypes } from "@budibase/types" + export const getColor = (idx, opacity = 0.3) => { if (idx == null || idx === -1) { idx = 0 @@ -6,23 +8,23 @@ export const getColor = (idx, opacity = 0.3) => { } const TypeIconMap = { - text: "Text", - options: "Dropdown", - datetime: "Date", - barcodeqr: "Camera", - signature: "AnnotatePen", - longform: "TextAlignLeft", - array: "Dropdown", - number: "123", - boolean: "Boolean", - attachment: "AppleFiles", - link: "DataCorrelated", - formula: "Calculator", - json: "Brackets", - bigint: "TagBold", - bb_reference: { - user: "User", - users: "UserGroup", + [FieldType.STRING]: "Text", + [FieldType.OPTIONS]: "Dropdown", + [FieldType.DATETIME]: "Date", + [FieldType.BARCODEQR]: "Camera", + [FieldType.SIGNATURE]: "AnnotatePen", + [FieldType.LONGFORM]: "TextAlignLeft", + [FieldType.ARRAY]: "Dropdown", + [FieldType.NUMBER]: "123", + [FieldType.BOOLEAN]: "Boolean", + [FieldType.ATTACHMENT]: "AppleFiles", + [FieldType.LINK]: "DataCorrelated", + [FieldType.FORMULA]: "Calculator", + [FieldType.JSON]: "Brackets", + [FieldType.BIGINT]: "TagBold", + [FieldType.BB_REFERENCE]: { + [FieldTypeSubtypes.BB_REFERENCE.USER]: "User", + [FieldTypeSubtypes.BB_REFERENCE.USERS]: "UserGroup", }, } diff --git a/packages/pro b/packages/pro index 6b62505be0..f8e8f87bd5 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 6b62505be0c0b50a57b4f4980d86541ebdc86428 +Subproject commit f8e8f87bd52081e1303a5ae92c432ea5b38f3bb4 diff --git a/packages/server/__mocks__/pg.ts b/packages/server/__mocks__/pg.ts deleted file mode 100644 index 50a7c7349e..0000000000 --- a/packages/server/__mocks__/pg.ts +++ /dev/null @@ -1,25 +0,0 @@ -const query = jest.fn(() => ({ - rows: [ - { - a: "string", - b: 1, - }, - ], -})) - -class Client { - query = query - end = jest.fn(cb => { - if (cb) cb() - }) - connect = jest.fn() - release = jest.fn() -} - -const on = jest.fn() - -module.exports = { - Client, - queryMock: query, - on, -} diff --git a/packages/server/jest.config.ts b/packages/server/jest.config.ts index 85c75f9039..6341c8e5bd 100644 --- a/packages/server/jest.config.ts +++ b/packages/server/jest.config.ts @@ -42,12 +42,6 @@ if (fs.existsSync("../pro/src")) { const config: Config.InitialOptions = { projects: [ - { - ...baseConfig, - displayName: "sequential test", - testMatch: ["/**/*.seq.spec.[jt]s"], - runner: "jest-serial-runner", - }, { ...baseConfig, testMatch: ["/**/!(*.seq).spec.[jt]s"], @@ -60,6 +54,9 @@ const config: Config.InitialOptions = { "!src/db/views/staticViews.*", "!src/**/*.spec.{js,ts}", "!src/tests/**/*.{js,ts}", + // The use of coverage in the JS runner breaks tests by inserting + // coverage functions into code that will run inside of the isolate. + "!src/jsRunner/**/*.{js,ts}", ], coverageReporters: ["lcov", "json", "clover"], } diff --git a/packages/server/package.json b/packages/server/package.json index da99ff6dea..4d1df4d734 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -143,7 +143,7 @@ "jest": "29.7.0", "jest-openapi": "0.14.2", "jest-runner": "29.7.0", - "jest-serial-runner": "1.2.1", + "nock": "13.5.4", "nodemon": "2.0.15", "openapi-typescript": "5.2.0", "path-to-regexp": "6.2.0", diff --git a/packages/server/scripts/test.sh b/packages/server/scripts/test.sh index 3ecf8bb794..4b456e4731 100644 --- a/packages/server/scripts/test.sh +++ b/packages/server/scripts/test.sh @@ -4,11 +4,9 @@ set -e if [[ -n $CI ]] then export NODE_OPTIONS="--max-old-space-size=4096 --no-node-snapshot $NODE_OPTIONS" - echo "jest --coverage --maxWorkers=2 --forceExit --workerIdleMemoryLimit=2000MB --bail $@" - jest --coverage --maxWorkers=2 --forceExit --workerIdleMemoryLimit=2000MB --bail $@ + jest --coverage --maxWorkers=4 --forceExit --workerIdleMemoryLimit=2000MB --bail $@ else # --maxWorkers performs better in development export NODE_OPTIONS="--no-node-snapshot $NODE_OPTIONS" - echo "jest --coverage --maxWorkers=2 --forceExit $@" jest --coverage --maxWorkers=2 --forceExit $@ fi \ No newline at end of file diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index 0f17c5a2f5..243d0a17a0 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -1,6 +1,6 @@ import { getQueryParams, getTableParams } from "../../db/utils" import { getIntegration } from "../../integrations" -import { invalidateDynamicVariables } from "../../threads/utils" +import { invalidateCachedVariable } from "../../threads/utils" import { context, db as dbCore, events } from "@budibase/backend-core" import { BuildSchemaFromSourceRequest, @@ -121,7 +121,7 @@ async function invalidateVariables( } }) } - await invalidateDynamicVariables(toInvalidate) + await invalidateCachedVariable(toInvalidate) } export async function update( diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index 055f3bd888..b52cea553f 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -2,7 +2,7 @@ import { generateQueryID } from "../../../db/utils" import { Thread, ThreadType } from "../../../threads" import { save as saveDatasource } from "../datasource" import { RestImporter } from "./import" -import { invalidateDynamicVariables } from "../../../threads/utils" +import { invalidateCachedVariable } from "../../../threads/utils" import env from "../../../environment" import { events, context, utils, constants } from "@budibase/backend-core" import sdk from "../../../sdk" @@ -281,49 +281,52 @@ export async function preview( return { previewSchema, nestedSchemaFields } } + const inputs: QueryEvent = { + appId: ctx.appId, + queryVerb: query.queryVerb, + fields: query.fields, + parameters: enrichParameters(query), + transformer: query.transformer, + schema: query.schema, + nullDefaultSupport: query.nullDefaultSupport, + queryId, + datasource, + // have to pass down to the thread runner - can't put into context now + environmentVariables: envVars, + ctx: { + user: ctx.user, + auth: { ...authConfigCtx }, + }, + } + + let queryResponse: QueryResponse try { - const inputs: QueryEvent = { - appId: ctx.appId, - queryVerb: query.queryVerb, - fields: query.fields, - parameters: enrichParameters(query), - transformer: query.transformer, - schema: query.schema, - nullDefaultSupport: query.nullDefaultSupport, - queryId, - datasource, - // have to pass down to the thread runner - can't put into context now - environmentVariables: envVars, - ctx: { - user: ctx.user, - auth: { ...authConfigCtx }, - }, - } - - const { rows, keys, info, extra } = await Runner.run(inputs) - const { previewSchema, nestedSchemaFields } = getSchemaFields(rows, keys) - - // if existing schema, update to include any previous schema keys - if (existingSchema) { - for (let key of Object.keys(previewSchema)) { - if (existingSchema[key]) { - previewSchema[key] = existingSchema[key] - } - } - } - // remove configuration before sending event - delete datasource.config - await events.query.previewed(datasource, ctx.request.body) - ctx.body = { - rows, - nestedSchemaFields, - schema: previewSchema, - info, - extra, - } + queryResponse = await Runner.run(inputs) } catch (err: any) { ctx.throw(400, err) } + + const { rows, keys, info, extra } = queryResponse + const { previewSchema, nestedSchemaFields } = getSchemaFields(rows, keys) + + // if existing schema, update to include any previous schema keys + if (existingSchema) { + for (let key of Object.keys(previewSchema)) { + if (existingSchema[key]) { + previewSchema[key] = existingSchema[key] + } + } + } + // remove configuration before sending event + delete datasource.config + await events.query.previewed(datasource, ctx.request.body) + ctx.body = { + rows, + nestedSchemaFields, + schema: previewSchema, + info, + extra, + } } async function execute( @@ -416,7 +419,7 @@ const removeDynamicVariables = async (queryId: string) => { const variablesToDelete = dynamicVariables!.filter( (dv: any) => dv.queryId === queryId ) - await invalidateDynamicVariables(variablesToDelete) + await invalidateCachedVariable(variablesToDelete) } } diff --git a/packages/server/src/api/routes/public/tests/metrics.spec.js b/packages/server/src/api/routes/public/tests/metrics.spec.js index 8231596d59..2fb5e91000 100644 --- a/packages/server/src/api/routes/public/tests/metrics.spec.js +++ b/packages/server/src/api/routes/public/tests/metrics.spec.js @@ -1,7 +1,5 @@ const setup = require("../../tests/utilities") -jest.setTimeout(30000) - describe("/metrics", () => { let request = setup.getRequest() let config = setup.getConfig() diff --git a/packages/server/src/api/routes/tests/appImport.spec.ts b/packages/server/src/api/routes/tests/appImport.spec.ts index 75e9f91d63..bc211024d4 100644 --- a/packages/server/src/api/routes/tests/appImport.spec.ts +++ b/packages/server/src/api/routes/tests/appImport.spec.ts @@ -1,7 +1,6 @@ import * as setup from "./utilities" import path from "path" -jest.setTimeout(15000) const PASSWORD = "testtest" describe("/applications/:appId/import", () => { diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index 322694df75..7885e97fbf 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -23,8 +23,6 @@ let { collectAutomation, } = setup.structures -jest.setTimeout(30000) - describe("/automations", () => { let request = setup.getRequest() let config = setup.getConfig() diff --git a/packages/server/src/api/routes/tests/datasource.spec.ts b/packages/server/src/api/routes/tests/datasource.spec.ts index cbd830aee5..0066be2a64 100644 --- a/packages/server/src/api/routes/tests/datasource.spec.ts +++ b/packages/server/src/api/routes/tests/datasource.spec.ts @@ -1,18 +1,16 @@ -jest.mock("pg") import * as setup from "./utilities" import { checkBuilderEndpoint } from "./utilities/TestFunctions" -import { checkCacheForDynamicVariable } from "../../../threads/utils" +import { getCachedVariable } from "../../../threads/utils" import { context, events } from "@budibase/backend-core" import sdk from "../../../sdk" import tk from "timekeeper" import { mocks } from "@budibase/backend-core/tests" -import { QueryPreview } from "@budibase/types" +import { QueryPreview, SourceName } from "@budibase/types" tk.freeze(mocks.date.MOCK_DATE) let { basicDatasource } = setup.structures -const pg = require("pg") describe("/datasources", () => { let request = setup.getRequest() @@ -42,6 +40,23 @@ describe("/datasources", () => { expect(res.body.errors).toEqual({}) expect(events.datasource.created).toHaveBeenCalledTimes(1) }) + + it("should fail if the datasource is invalid", async () => { + await config.api.datasource.create( + { + name: "Test", + type: "test", + source: "invalid" as SourceName, + config: {}, + }, + { + status: 500, + body: { + message: "No datasource implementation found.", + }, + } + ) + }) }) describe("update", () => { @@ -74,7 +89,7 @@ describe("/datasources", () => { schema: {}, readable: true, } - return config.api.query.previewQuery(queryPreview) + return config.api.query.preview(queryPreview) } it("should invalidate changed or removed variables", async () => { @@ -85,10 +100,7 @@ describe("/datasources", () => { queryString: "test={{ variable3 }}", }) // check variables in cache - let contents = await checkCacheForDynamicVariable( - query._id!, - "variable3" - ) + let contents = await getCachedVariable(query._id!, "variable3") expect(contents.rows.length).toEqual(1) // update the datasource to remove the variables @@ -102,7 +114,7 @@ describe("/datasources", () => { expect(res.body.errors).toBeUndefined() // check variables no longer in cache - contents = await checkCacheForDynamicVariable(query._id!, "variable3") + contents = await getCachedVariable(query._id!, "variable3") expect(contents).toBe(null) }) }) @@ -149,35 +161,6 @@ describe("/datasources", () => { }) }) - describe("query", () => { - it("should be able to query a pg datasource", async () => { - const res = await request - .post(`/api/datasources/query`) - .send({ - endpoint: { - datasourceId: datasource._id, - operation: "READ", - // table name below - entityId: "users", - }, - resource: { - fields: ["users.name", "users.age"], - }, - filters: { - string: { - name: "John", - }, - }, - }) - .set(config.defaultHeaders()) - .expect(200) - // this is mock data, can't test it - expect(res.body).toBeDefined() - const expSql = `select "users"."name" as "users.name", "users"."age" as "users.age" from (select * from "users" where "users"."name" ilike $1 limit $2) as "users"` - expect(pg.queryMock).toHaveBeenCalledWith(expSql, ["John%", 5000]) - }) - }) - describe("destroy", () => { beforeAll(setupTest) diff --git a/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts b/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts index f9a3ac6e03..7790f909e7 100644 --- a/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts +++ b/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts @@ -1,11 +1,18 @@ -import { Datasource, Query, SourceName } from "@budibase/types" +import { + Datasource, + Operation, + Query, + QueryPreview, + SourceName, +} from "@budibase/types" import * as setup from "../utilities" -import { databaseTestProviders } from "../../../../integrations/tests/utils" -import pg from "pg" -import mysql from "mysql2/promise" -import mssql from "mssql" - -jest.unmock("pg") +import { + DatabaseName, + getDatasource, + rawQuery, +} from "../../../../integrations/tests/utils" +import { Expectations } from "src/tests/utilities/api/base" +import { events } from "@budibase/backend-core" const createTableSQL: Record = { [SourceName.POSTGRES]: ` @@ -34,16 +41,22 @@ const createTableSQL: Record = { const insertSQL = `INSERT INTO test_table (name) VALUES ('one'), ('two'), ('three'), ('four'), ('five')` const dropTableSQL = `DROP TABLE test_table;` -describe.each([ - ["postgres", databaseTestProviders.postgres], - ["mysql", databaseTestProviders.mysql], - ["mssql", databaseTestProviders.mssql], - ["mariadb", databaseTestProviders.mariadb], -])("queries (%s)", (dbName, dsProvider) => { +describe.each( + [ + DatabaseName.POSTGRES, + DatabaseName.MYSQL, + DatabaseName.SQL_SERVER, + DatabaseName.MARIADB, + ].map(name => [name, getDatasource(name)]) +)("queries (%s)", (dbName, dsProvider) => { const config = setup.getConfig() + let rawDatasource: Datasource let datasource: Datasource - async function createQuery(query: Partial): Promise { + async function createQuery( + query: Partial, + expectations?: Expectations + ): Promise { const defaultQuery: Query = { datasourceId: datasource._id!, name: "New Query", @@ -54,140 +67,350 @@ describe.each([ transformer: "return data", readable: true, } - return await config.api.query.save({ ...defaultQuery, ...query }) - } - - async function rawQuery(sql: string): Promise { - // We re-fetch the datasource here because the one returned by - // config.api.datasource.create has the password field blanked out, and we - // need the password to connect to the database. - const ds = await dsProvider.datasource() - switch (ds.source) { - case SourceName.POSTGRES: { - const client = new pg.Client(ds.config!) - await client.connect() - try { - const { rows } = await client.query(sql) - return rows - } finally { - await client.end() - } - } - case SourceName.MYSQL: { - const con = await mysql.createConnection(ds.config!) - try { - const [rows] = await con.query(sql) - return rows - } finally { - con.end() - } - } - case SourceName.SQL_SERVER: { - const pool = new mssql.ConnectionPool(ds.config! as mssql.config) - const client = await pool.connect() - try { - const { recordset } = await client.query(sql) - return recordset - } finally { - await pool.close() - } - } - } + return await config.api.query.save( + { ...defaultQuery, ...query }, + expectations + ) } beforeAll(async () => { await config.init() - datasource = await config.api.datasource.create( - await dsProvider.datasource() - ) }) beforeEach(async () => { - await rawQuery(createTableSQL[datasource.source]) - await rawQuery(insertSQL) + rawDatasource = await dsProvider + datasource = await config.api.datasource.create(rawDatasource) + + // The Datasource API does not return the password, but we need + // it later to connect to the underlying database, so we fill it + // back in here. + datasource.config!.password = rawDatasource.config!.password + + await rawQuery(datasource, createTableSQL[datasource.source]) + await rawQuery(datasource, insertSQL) + + jest.clearAllMocks() }) afterEach(async () => { - await rawQuery(dropTableSQL) + const ds = await config.api.datasource.get(datasource._id!) + config.api.datasource.delete(ds) + await rawQuery(datasource, dropTableSQL) }) afterAll(async () => { - await dsProvider.stop() setup.afterAll() }) - describe("create", () => { - it("should be able to insert with bindings", async () => { - const query = await createQuery({ - fields: { - sql: "INSERT INTO test_table (name) VALUES ({{ foo }})", - }, - parameters: [ - { - name: "foo", - default: "bar", + describe("query admin", () => { + describe("create", () => { + it("should be able to create a query", async () => { + const query = await createQuery({ + name: "New Query", + fields: { + sql: "SELECT * FROM test_table", }, - ], - queryVerb: "create", + }) + + expect(query).toMatchObject({ + datasourceId: datasource._id!, + name: "New Query", + parameters: [], + fields: { + sql: "SELECT * FROM test_table", + }, + schema: {}, + queryVerb: "read", + transformer: "return data", + readable: true, + createdAt: expect.any(String), + updatedAt: expect.any(String), + }) + + expect(events.query.created).toHaveBeenCalledTimes(1) + expect(events.query.updated).not.toHaveBeenCalled() }) - - const result = await config.api.query.execute(query._id!, { - parameters: { - foo: "baz", - }, - }) - - expect(result.data).toEqual([ - { - created: true, - }, - ]) - - const rows = await rawQuery("SELECT * FROM test_table WHERE name = 'baz'") - expect(rows).toHaveLength(1) }) - it.each(["2021-02-05T12:01:00.000Z", "2021-02-05"])( - "should coerce %s into a date", - async datetimeStr => { - const date = new Date(datetimeStr) + describe("update", () => { + it("should be able to update a query", async () => { const query = await createQuery({ fields: { - sql: `INSERT INTO test_table (name, birthday) VALUES ('foo', {{ birthday }})`, + sql: "SELECT * FROM test_table", }, - parameters: [ + }) + + jest.clearAllMocks() + + const updatedQuery = await config.api.query.save({ + ...query, + name: "Updated Query", + fields: { + sql: "SELECT * FROM test_table WHERE id = 1", + }, + }) + + expect(updatedQuery).toMatchObject({ + datasourceId: datasource._id!, + name: "Updated Query", + parameters: [], + fields: { + sql: "SELECT * FROM test_table WHERE id = 1", + }, + schema: {}, + queryVerb: "read", + transformer: "return data", + readable: true, + }) + + expect(events.query.created).not.toHaveBeenCalled() + expect(events.query.updated).toHaveBeenCalledTimes(1) + }) + }) + + describe("delete", () => { + it("should be able to delete a query", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table", + }, + }) + + await config.api.query.delete(query) + await config.api.query.get(query._id!, { status: 404 }) + + const queries = await config.api.query.fetch() + expect(queries).not.toContainEqual(query) + + expect(events.query.deleted).toHaveBeenCalledTimes(1) + expect(events.query.deleted).toHaveBeenCalledWith(datasource, query) + }) + }) + + describe("read", () => { + it("should be able to list queries", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table", + }, + }) + + const queries = await config.api.query.fetch() + expect(queries).toContainEqual(query) + }) + + it("should strip sensitive fields for prod apps", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table", + }, + }) + + await config.publish() + const prodQuery = await config.api.query.getProd(query._id!) + + expect(prodQuery._id).toEqual(query._id) + expect(prodQuery.fields).toBeUndefined() + expect(prodQuery.parameters).toBeUndefined() + expect(prodQuery.schema).toBeDefined() + }) + }) + }) + + describe("preview", () => { + it("should be able to preview a query", async () => { + const request: QueryPreview = { + datasourceId: datasource._id!, + queryVerb: "read", + fields: { + sql: `SELECT * FROM test_table WHERE id = 1`, + }, + parameters: [], + transformer: "return data", + name: datasource.name!, + schema: {}, + readable: true, + } + const response = await config.api.query.preview(request) + expect(response.schema).toEqual({ + birthday: { + name: "birthday", + type: "string", + }, + id: { + name: "id", + type: "number", + }, + name: { + name: "name", + type: "string", + }, + number: { + name: "number", + type: "string", + }, + }) + expect(response.rows).toEqual([ + { + birthday: null, + id: 1, + name: "one", + number: null, + }, + ]) + expect(events.query.previewed).toHaveBeenCalledTimes(1) + }) + + it("should work with static variables", async () => { + await config.api.datasource.update({ + ...datasource, + config: { + ...datasource.config, + staticVariables: { + foo: "bar", + }, + }, + }) + + const request: QueryPreview = { + datasourceId: datasource._id!, + queryVerb: "read", + fields: { + sql: `SELECT '{{ foo }}' as foo`, + }, + parameters: [], + transformer: "return data", + name: datasource.name!, + schema: {}, + readable: true, + } + + const response = await config.api.query.preview(request) + + expect(response.schema).toEqual({ + foo: { + name: "foo", + type: "string", + }, + }) + + expect(response.rows).toEqual([ + { + foo: "bar", + }, + ]) + }) + + it("should work with dynamic variables", async () => { + const basedOnQuery = await createQuery({ + fields: { + sql: "SELECT name FROM test_table WHERE id = 1", + }, + }) + + await config.api.datasource.update({ + ...datasource, + config: { + ...datasource.config, + dynamicVariables: [ { - name: "birthday", - default: "", + queryId: basedOnQuery._id!, + name: "foo", + value: "{{ data[0].name }}", }, ], - queryVerb: "create", - }) + }, + }) - const result = await config.api.query.execute(query._id!, { - parameters: { birthday: datetimeStr }, - }) + const preview = await config.api.query.preview({ + datasourceId: datasource._id!, + queryVerb: "read", + fields: { + sql: `SELECT '{{ foo }}' as foo`, + }, + parameters: [], + transformer: "return data", + name: datasource.name!, + schema: {}, + readable: true, + }) - expect(result.data).toEqual([{ created: true }]) + expect(preview.schema).toEqual({ + foo: { + name: "foo", + type: "string", + }, + }) - const rows = await rawQuery( - `SELECT * FROM test_table WHERE birthday = '${date.toISOString()}'` - ) - expect(rows).toHaveLength(1) - } - ) + expect(preview.rows).toEqual([ + { + foo: "one", + }, + ]) + }) - it.each(["2021,02,05", "202205-1500"])( - "should not coerce %s as a date", - async notDateStr => { + it("should handle the dynamic base query being deleted", async () => { + const basedOnQuery = await createQuery({ + fields: { + sql: "SELECT name FROM test_table WHERE id = 1", + }, + }) + + await config.api.datasource.update({ + ...datasource, + config: { + ...datasource.config, + dynamicVariables: [ + { + queryId: basedOnQuery._id!, + name: "foo", + value: "{{ data[0].name }}", + }, + ], + }, + }) + + await config.api.query.delete(basedOnQuery) + + const preview = await config.api.query.preview({ + datasourceId: datasource._id!, + queryVerb: "read", + fields: { + sql: `SELECT '{{ foo }}' as foo`, + }, + parameters: [], + transformer: "return data", + name: datasource.name!, + schema: {}, + readable: true, + }) + + expect(preview.schema).toEqual({ + foo: { + name: "foo", + type: "string", + }, + }) + + expect(preview.rows).toEqual([ + { + foo: datasource.source === SourceName.SQL_SERVER ? "" : null, + }, + ]) + }) + }) + + describe("query verbs", () => { + describe("create", () => { + it("should be able to insert with bindings", async () => { const query = await createQuery({ fields: { - sql: "INSERT INTO test_table (name) VALUES ({{ name }})", + sql: "INSERT INTO test_table (name) VALUES ({{ foo }})", }, parameters: [ { - name: "name", - default: "", + name: "foo", + default: "bar", }, ], queryVerb: "create", @@ -195,153 +418,349 @@ describe.each([ const result = await config.api.query.execute(query._id!, { parameters: { - name: notDateStr, + foo: "baz", }, }) - expect(result.data).toEqual([{ created: true }]) + expect(result.data).toEqual([ + { + created: true, + }, + ]) const rows = await rawQuery( - `SELECT * FROM test_table WHERE name = '${notDateStr}'` + datasource, + "SELECT * FROM test_table WHERE name = 'baz'" ) expect(rows).toHaveLength(1) - } - ) - }) - - describe("read", () => { - it("should execute a query", async () => { - const query = await createQuery({ - fields: { - sql: "SELECT * FROM test_table ORDER BY id", - }, }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - id: 1, - name: "one", - birthday: null, - number: null, - }, - { - id: 2, - name: "two", - birthday: null, - number: null, - }, - { - id: 3, - name: "three", - birthday: null, - number: null, - }, - { - id: 4, - name: "four", - birthday: null, - number: null, - }, - { - id: 5, - name: "five", - birthday: null, - number: null, - }, - ]) - }) - - it("should be able to transform a query", async () => { - const query = await createQuery({ - fields: { - sql: "SELECT * FROM test_table WHERE id = 1", - }, - transformer: ` - data[0].id = data[0].id + 1; - return data; - `, - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - id: 2, - name: "one", - birthday: null, - number: null, - }, - ]) - }) - - it("should coerce numeric bindings", async () => { - const query = await createQuery({ - fields: { - sql: "SELECT * FROM test_table WHERE id = {{ id }}", - }, - parameters: [ - { - name: "id", - default: "", + it("should not allow handlebars as parameters", async () => { + const query = await createQuery({ + fields: { + sql: "INSERT INTO test_table (name) VALUES ({{ foo }})", }, - ], + parameters: [ + { + name: "foo", + default: "bar", + }, + ], + queryVerb: "create", + }) + + await config.api.query.execute( + query._id!, + { + parameters: { + foo: "{{ 'test' }}", + }, + }, + { + status: 400, + body: { + message: + "Parameter 'foo' input contains a handlebars binding - this is not allowed.", + }, + } + ) }) - const result = await config.api.query.execute(query._id!, { - parameters: { - id: "1", - }, + it.each(["2021-02-05T12:01:00.000Z", "2021-02-05"])( + "should coerce %s into a date", + async datetimeStr => { + const date = new Date(datetimeStr) + const query = await createQuery({ + fields: { + sql: `INSERT INTO test_table (name, birthday) VALUES ('foo', {{ birthday }})`, + }, + parameters: [ + { + name: "birthday", + default: "", + }, + ], + queryVerb: "create", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { birthday: datetimeStr }, + }) + + expect(result.data).toEqual([{ created: true }]) + + const rows = await rawQuery( + datasource, + `SELECT * FROM test_table WHERE birthday = '${date.toISOString()}'` + ) + expect(rows).toHaveLength(1) + } + ) + + it.each(["2021,02,05", "202205-1500"])( + "should not coerce %s as a date", + async notDateStr => { + const query = await createQuery({ + fields: { + sql: "INSERT INTO test_table (name) VALUES ({{ name }})", + }, + parameters: [ + { + name: "name", + default: "", + }, + ], + queryVerb: "create", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + name: notDateStr, + }, + }) + + expect(result.data).toEqual([{ created: true }]) + + const rows = await rawQuery( + datasource, + `SELECT * FROM test_table WHERE name = '${notDateStr}'` + ) + expect(rows).toHaveLength(1) + } + ) + }) + + describe("read", () => { + it("should execute a query", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table ORDER BY id", + }, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + id: 1, + name: "one", + birthday: null, + number: null, + }, + { + id: 2, + name: "two", + birthday: null, + number: null, + }, + { + id: 3, + name: "three", + birthday: null, + number: null, + }, + { + id: 4, + name: "four", + birthday: null, + number: null, + }, + { + id: 5, + name: "five", + birthday: null, + number: null, + }, + ]) }) - expect(result.data).toEqual([ - { - id: 1, - name: "one", - birthday: null, - number: null, - }, - ]) + it("should be able to transform a query", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table WHERE id = 1", + }, + transformer: ` + data[0].id = data[0].id + 1; + return data; + `, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + id: 2, + name: "one", + birthday: null, + number: null, + }, + ]) + }) + + it("should coerce numeric bindings", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table WHERE id = {{ id }}", + }, + parameters: [ + { + name: "id", + default: "", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + id: "1", + }, + }) + + expect(result.data).toEqual([ + { + id: 1, + name: "one", + birthday: null, + number: null, + }, + ]) + }) + }) + + describe("update", () => { + it("should be able to update rows", async () => { + const query = await createQuery({ + fields: { + sql: "UPDATE test_table SET name = {{ name }} WHERE id = {{ id }}", + }, + parameters: [ + { + name: "id", + default: "", + }, + { + name: "name", + default: "updated", + }, + ], + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + id: "1", + name: "foo", + }, + }) + + expect(result.data).toEqual([ + { + updated: true, + }, + ]) + + const rows = await rawQuery( + datasource, + "SELECT * FROM test_table WHERE id = 1" + ) + expect(rows).toEqual([ + { id: 1, name: "foo", birthday: null, number: null }, + ]) + }) + + it("should be able to execute an update that updates no rows", async () => { + const query = await createQuery({ + fields: { + sql: "UPDATE test_table SET name = 'updated' WHERE id = 100", + }, + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + updated: true, + }, + ]) + }) + + it("should be able to execute a delete that deletes no rows", async () => { + const query = await createQuery({ + fields: { + sql: "DELETE FROM test_table WHERE id = 100", + }, + queryVerb: "delete", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + deleted: true, + }, + ]) + }) + }) + + describe("delete", () => { + it("should be able to delete rows", async () => { + const query = await createQuery({ + fields: { + sql: "DELETE FROM test_table WHERE id = {{ id }}", + }, + parameters: [ + { + name: "id", + default: "", + }, + ], + queryVerb: "delete", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + id: "1", + }, + }) + + expect(result.data).toEqual([ + { + deleted: true, + }, + ]) + + const rows = await rawQuery( + datasource, + "SELECT * FROM test_table WHERE id = 1" + ) + expect(rows).toHaveLength(0) + }) }) }) - describe("update", () => { - it("should be able to update rows", async () => { - const query = await createQuery({ - fields: { - sql: "UPDATE test_table SET name = {{ name }} WHERE id = {{ id }}", + describe("query through datasource", () => { + it("should be able to query a pg datasource", async () => { + const res = await config.api.datasource.query({ + endpoint: { + datasourceId: datasource._id!, + operation: Operation.READ, + entityId: "test_table", }, - parameters: [ - { - name: "id", - default: "", + resource: { + fields: ["id", "name"], + }, + filters: { + string: { + name: "two", }, - { - name: "name", - default: "updated", - }, - ], - queryVerb: "update", - }) - - const result = await config.api.query.execute(query._id!, { - parameters: { - id: "1", - name: "foo", }, }) - - expect(result.data).toEqual([ - { - updated: true, - }, - ]) - - const rows = await rawQuery("SELECT * FROM test_table WHERE id = 1") - expect(rows).toEqual([ - { id: 1, name: "foo", birthday: null, number: null }, - ]) + expect(res).toHaveLength(1) + expect(res[0]).toEqual({ + id: 2, + name: "two", + }) }) it("should be able to execute an update that updates no rows", async () => { @@ -352,7 +771,7 @@ describe.each([ queryVerb: "update", }) - const result = await config.api.query.execute(query._id!) + const result = await config.api.query.execute(query._id!, {}) expect(result.data).toEqual([ { @@ -360,55 +779,6 @@ describe.each([ }, ]) }) - - it("should be able to execute a delete that deletes no rows", async () => { - const query = await createQuery({ - fields: { - sql: "DELETE FROM test_table WHERE id = 100", - }, - queryVerb: "delete", - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - deleted: true, - }, - ]) - }) - }) - - describe("delete", () => { - it("should be able to delete rows", async () => { - const query = await createQuery({ - fields: { - sql: "DELETE FROM test_table WHERE id = {{ id }}", - }, - parameters: [ - { - name: "id", - default: "", - }, - ], - queryVerb: "delete", - }) - - const result = await config.api.query.execute(query._id!, { - parameters: { - id: "1", - }, - }) - - expect(result.data).toEqual([ - { - deleted: true, - }, - ]) - - const rows = await rawQuery("SELECT * FROM test_table WHERE id = 1") - expect(rows).toHaveLength(0) - }) }) // this parameter really only impacts SQL queries diff --git a/packages/server/src/api/routes/tests/queries/mongodb.spec.ts b/packages/server/src/api/routes/tests/queries/mongodb.spec.ts index 492f24abf9..c79ae68a36 100644 --- a/packages/server/src/api/routes/tests/queries/mongodb.spec.ts +++ b/packages/server/src/api/routes/tests/queries/mongodb.spec.ts @@ -1,14 +1,17 @@ import { Datasource, Query } from "@budibase/types" import * as setup from "../utilities" -import { databaseTestProviders } from "../../../../integrations/tests/utils" -import { MongoClient, type Collection, BSON } from "mongodb" - -const collection = "test_collection" +import { + DatabaseName, + getDatasource, +} from "../../../../integrations/tests/utils" +import { MongoClient, type Collection, BSON, Db } from "mongodb" +import { generator } from "@budibase/backend-core/tests" const expectValidId = expect.stringMatching(/^\w{24}$/) const expectValidBsonObjectId = expect.any(BSON.ObjectId) describe("/queries", () => { + let collection: string let config = setup.getConfig() let datasource: Datasource @@ -37,8 +40,7 @@ describe("/queries", () => { async function withClient( callback: (client: MongoClient) => Promise ): Promise { - const ds = await databaseTestProviders.mongodb.datasource() - const client = new MongoClient(ds.config!.connectionString) + const client = new MongoClient(datasource.config!.connectionString) await client.connect() try { return await callback(client) @@ -47,30 +49,33 @@ describe("/queries", () => { } } + async function withDb(callback: (db: Db) => Promise): Promise { + return await withClient(async client => { + return await callback(client.db(datasource.config!.db)) + }) + } + async function withCollection( callback: (collection: Collection) => Promise ): Promise { - return await withClient(async client => { - const db = client.db( - (await databaseTestProviders.mongodb.datasource()).config!.db - ) + return await withDb(async db => { return await callback(db.collection(collection)) }) } afterAll(async () => { - await databaseTestProviders.mongodb.stop() setup.afterAll() }) beforeAll(async () => { await config.init() datasource = await config.api.datasource.create( - await databaseTestProviders.mongodb.datasource() + await getDatasource(DatabaseName.MONGODB) ) }) beforeEach(async () => { + collection = generator.guid() await withCollection(async collection => { await collection.insertMany([ { name: "one" }, @@ -83,345 +88,491 @@ describe("/queries", () => { }) afterEach(async () => { - await withCollection(async collection => { - await collection.drop() - }) + await withCollection(collection => collection.drop()) }) - it("should execute a count query", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "count", + describe("preview", () => { + it("should generate a nested schema with an empty array", async () => { + const name = generator.guid() + await withCollection( + async collection => await collection.insertOne({ name, nested: [] }) + ) + + const preview = await config.api.query.preview({ + name: "New Query", + datasourceId: datasource._id!, + fields: { + json: { + name: { $eq: name }, + }, + extra: { + collection, + actionType: "findOne", + }, }, - }, + schema: {}, + queryVerb: "read", + parameters: [], + transformer: "return data", + readable: true, + }) + + expect(preview).toEqual({ + nestedSchemaFields: {}, + rows: [{ _id: expect.any(String), name, nested: [] }], + schema: { + _id: { + type: "string", + name: "_id", + }, + name: { + type: "string", + name: "name", + }, + nested: { + type: "array", + name: "nested", + }, + }, + }) }) - const result = await config.api.query.execute(query._id!) + it("should generate a nested schema based on all of the nested items", async () => { + const name = generator.guid() + const item = { + name, + contacts: [ + { + address: "123 Lane", + }, + { + address: "456 Drive", + }, + { + postcode: "BT1 12N", + lat: 54.59, + long: -5.92, + }, + { + city: "Belfast", + }, + { + address: "789 Avenue", + phoneNumber: "0800-999-5555", + }, + { + name: "Name", + isActive: false, + }, + ], + } - expect(result.data).toEqual([{ value: 5 }]) - }) + await withCollection(collection => collection.insertOne(item)) - it("should execute a count query with a transformer", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "count", + const preview = await config.api.query.preview({ + name: "New Query", + datasourceId: datasource._id!, + fields: { + json: { + name: { $eq: name }, + }, + extra: { + collection, + actionType: "findOne", + }, }, - }, - transformer: "return data + 1", - }) + schema: {}, + queryVerb: "read", + parameters: [], + transformer: "return data", + readable: true, + }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([{ value: 6 }]) - }) - - it("should execute a find query", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "find", + expect(preview).toEqual({ + nestedSchemaFields: { + contacts: { + address: { + type: "string", + name: "address", + }, + postcode: { + type: "string", + name: "postcode", + }, + lat: { + type: "number", + name: "lat", + }, + long: { + type: "number", + name: "long", + }, + city: { + type: "string", + name: "city", + }, + phoneNumber: { + type: "string", + name: "phoneNumber", + }, + name: { + type: "string", + name: "name", + }, + isActive: { + type: "boolean", + name: "isActive", + }, + }, }, - }, - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { _id: expectValidId, name: "one" }, - { _id: expectValidId, name: "two" }, - { _id: expectValidId, name: "three" }, - { _id: expectValidId, name: "four" }, - { _id: expectValidId, name: "five" }, - ]) - }) - - it("should execute a findOne query", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "findOne", + rows: [{ ...item, _id: expect.any(String) }], + schema: { + _id: { type: "string", name: "_id" }, + name: { type: "string", name: "name" }, + contacts: { type: "json", name: "contacts", subtype: "array" }, }, - }, - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([{ _id: expectValidId, name: "one" }]) - }) - - it("should execute a findOneAndUpdate query", async () => { - const query = await createQuery({ - fields: { - json: { - filter: { name: { $eq: "one" } }, - update: { $set: { name: "newName" } }, - }, - extra: { - actionType: "findOneAndUpdate", - }, - }, - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - lastErrorObject: { n: 1, updatedExisting: true }, - ok: 1, - value: { _id: expectValidId, name: "one" }, - }, - ]) - - await withCollection(async collection => { - expect(await collection.countDocuments()).toBe(5) - - const doc = await collection.findOne({ name: { $eq: "newName" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - name: "newName", }) }) }) - it("should execute a distinct query", async () => { - const query = await createQuery({ - fields: { - json: "name", - extra: { - actionType: "distinct", + describe("execute", () => { + it("a count query", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "count", + }, }, - }, - }) - - const result = await config.api.query.execute(query._id!) - const values = result.data.map(o => o.value).sort() - expect(values).toEqual(["five", "four", "one", "three", "two"]) - }) - - it("should execute a create query with parameters", async () => { - const query = await createQuery({ - fields: { - json: { foo: "{{ foo }}" }, - extra: { - actionType: "insertOne", - }, - }, - queryVerb: "create", - parameters: [ - { - name: "foo", - default: "default", - }, - ], - }) - - const result = await config.api.query.execute(query._id!, { - parameters: { foo: "bar" }, - }) - - expect(result.data).toEqual([ - { - acknowledged: true, - insertedId: expectValidId, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ foo: { $eq: "bar" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - foo: "bar", }) - }) - }) - it("should execute a delete query with parameters", async () => { - const query = await createQuery({ - fields: { - json: { name: { $eq: "{{ name }}" } }, - extra: { - actionType: "deleteOne", + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([{ value: 5 }]) + }) + + it("should be able to updateOne by ObjectId", async () => { + const insertResult = await withCollection(c => + c.insertOne({ name: "one" }) + ) + const query = await createQuery({ + fields: { + json: { + filter: { _id: { $eq: `ObjectId("${insertResult.insertedId}")` } }, + update: { $set: { name: "newName" } }, + }, + extra: { + actionType: "updateOne", + }, }, - }, - queryVerb: "delete", - parameters: [ + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ { - name: "name", - default: "", + acknowledged: true, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0, + upsertedId: null, }, - ], - }) + ]) - const result = await config.api.query.execute(query._id!, { - parameters: { name: "one" }, - }) - - expect(result.data).toEqual([ - { - acknowledged: true, - deletedCount: 1, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ name: { $eq: "one" } }) - expect(doc).toBeNull() - }) - }) - - it("should execute an update query with parameters", async () => { - const query = await createQuery({ - fields: { - json: { - filter: { name: { $eq: "{{ name }}" } }, - update: { $set: { name: "{{ newName }}" } }, - }, - extra: { - actionType: "updateOne", - }, - }, - queryVerb: "update", - parameters: [ - { - name: "name", - default: "", - }, - { + await withCollection(async collection => { + const doc = await collection.findOne({ name: { $eq: "newName" } }) + expect(doc).toEqual({ + _id: insertResult.insertedId, name: "newName", - default: "", - }, - ], - }) - - const result = await config.api.query.execute(query._id!, { - parameters: { name: "one", newName: "newOne" }, - }) - - expect(result.data).toEqual([ - { - acknowledged: true, - matchedCount: 1, - modifiedCount: 1, - upsertedCount: 0, - upsertedId: null, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ name: { $eq: "newOne" } }) - expect(doc).toEqual({ - _id: expectValidBsonObjectId, - name: "newOne", - }) - - const oldDoc = await collection.findOne({ name: { $eq: "one" } }) - expect(oldDoc).toBeNull() - }) - }) - - it("should be able to updateOne by ObjectId", async () => { - const insertResult = await withCollection(c => c.insertOne({ name: "one" })) - const query = await createQuery({ - fields: { - json: { - filter: { _id: { $eq: `ObjectId("${insertResult.insertedId}")` } }, - update: { $set: { name: "newName" } }, - }, - extra: { - actionType: "updateOne", - }, - }, - queryVerb: "update", - }) - - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - acknowledged: true, - matchedCount: 1, - modifiedCount: 1, - upsertedCount: 0, - upsertedId: null, - }, - ]) - - await withCollection(async collection => { - const doc = await collection.findOne({ name: { $eq: "newName" } }) - expect(doc).toEqual({ - _id: insertResult.insertedId, - name: "newName", + }) }) }) - }) - it("should be able to delete all records", async () => { - const query = await createQuery({ - fields: { - json: {}, - extra: { - actionType: "deleteMany", + it("a count query with a transformer", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "count", + }, }, - }, - queryVerb: "delete", + transformer: "return data + 1", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([{ value: 6 }]) }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - acknowledged: true, - deletedCount: 5, - }, - ]) - - await withCollection(async collection => { - const docs = await collection.find().toArray() - expect(docs).toHaveLength(0) - }) - }) - - it("should be able to update all documents", async () => { - const query = await createQuery({ - fields: { - json: { - filter: {}, - update: { $set: { name: "newName" } }, + it("a find query", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "find", + }, }, - extra: { - actionType: "updateMany", - }, - }, - queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { _id: expectValidId, name: "one" }, + { _id: expectValidId, name: "two" }, + { _id: expectValidId, name: "three" }, + { _id: expectValidId, name: "four" }, + { _id: expectValidId, name: "five" }, + ]) }) - const result = await config.api.query.execute(query._id!) + it("a findOne query", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "findOne", + }, + }, + }) - expect(result.data).toEqual([ - { - acknowledged: true, - matchedCount: 5, - modifiedCount: 5, - upsertedCount: 0, - upsertedId: null, - }, - ]) + const result = await config.api.query.execute(query._id!) - await withCollection(async collection => { - const docs = await collection.find().toArray() - expect(docs).toHaveLength(5) - for (const doc of docs) { + expect(result.data).toEqual([{ _id: expectValidId, name: "one" }]) + }) + + it("a findOneAndUpdate query", async () => { + const query = await createQuery({ + fields: { + json: { + filter: { name: { $eq: "one" } }, + update: { $set: { name: "newName" } }, + }, + extra: { + actionType: "findOneAndUpdate", + }, + }, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + lastErrorObject: { n: 1, updatedExisting: true }, + ok: 1, + value: { _id: expectValidId, name: "one" }, + }, + ]) + + await withCollection(async collection => { + expect(await collection.countDocuments()).toBe(5) + + const doc = await collection.findOne({ name: { $eq: "newName" } }) expect(doc).toEqual({ _id: expectValidBsonObjectId, name: "newName", }) - } + }) + }) + + it("a distinct query", async () => { + const query = await createQuery({ + fields: { + json: "name", + extra: { + actionType: "distinct", + }, + }, + }) + + const result = await config.api.query.execute(query._id!) + const values = result.data.map(o => o.value).sort() + expect(values).toEqual(["five", "four", "one", "three", "two"]) + }) + + it("a create query with parameters", async () => { + const query = await createQuery({ + fields: { + json: { foo: "{{ foo }}" }, + extra: { + actionType: "insertOne", + }, + }, + queryVerb: "create", + parameters: [ + { + name: "foo", + default: "default", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { foo: "bar" }, + }) + + expect(result.data).toEqual([ + { + acknowledged: true, + insertedId: expectValidId, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ foo: { $eq: "bar" } }) + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + foo: "bar", + }) + }) + }) + + it("a delete query with parameters", async () => { + const query = await createQuery({ + fields: { + json: { name: { $eq: "{{ name }}" } }, + extra: { + actionType: "deleteOne", + }, + }, + queryVerb: "delete", + parameters: [ + { + name: "name", + default: "", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { name: "one" }, + }) + + expect(result.data).toEqual([ + { + acknowledged: true, + deletedCount: 1, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ name: { $eq: "one" } }) + expect(doc).toBeNull() + }) + }) + + it("an update query with parameters", async () => { + const query = await createQuery({ + fields: { + json: { + filter: { name: { $eq: "{{ name }}" } }, + update: { $set: { name: "{{ newName }}" } }, + }, + extra: { + actionType: "updateOne", + }, + }, + queryVerb: "update", + parameters: [ + { + name: "name", + default: "", + }, + { + name: "newName", + default: "", + }, + ], + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { name: "one", newName: "newOne" }, + }) + + expect(result.data).toEqual([ + { + acknowledged: true, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0, + upsertedId: null, + }, + ]) + + await withCollection(async collection => { + const doc = await collection.findOne({ name: { $eq: "newOne" } }) + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + name: "newOne", + }) + + const oldDoc = await collection.findOne({ name: { $eq: "one" } }) + expect(oldDoc).toBeNull() + }) + }) + + it("should be able to delete all records", async () => { + const query = await createQuery({ + fields: { + json: {}, + extra: { + actionType: "deleteMany", + }, + }, + queryVerb: "delete", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + acknowledged: true, + deletedCount: 5, + }, + ]) + + await withCollection(async collection => { + const docs = await collection.find().toArray() + expect(docs).toHaveLength(0) + }) + }) + + it("should be able to update all documents", async () => { + const query = await createQuery({ + fields: { + json: { + filter: {}, + update: { $set: { name: "newName" } }, + }, + extra: { + actionType: "updateMany", + }, + }, + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + acknowledged: true, + matchedCount: 5, + modifiedCount: 5, + upsertedCount: 0, + upsertedId: null, + }, + ]) + + await withCollection(async collection => { + const docs = await collection.find().toArray() + expect(docs).toHaveLength(5) + for (const doc of docs) { + expect(doc).toEqual({ + _id: expectValidBsonObjectId, + name: "newName", + }) + } + }) }) }) diff --git a/packages/server/src/api/routes/tests/queries/permissions.spec.ts b/packages/server/src/api/routes/tests/queries/permissions.spec.ts new file mode 100644 index 0000000000..a0b342e64d --- /dev/null +++ b/packages/server/src/api/routes/tests/queries/permissions.spec.ts @@ -0,0 +1,47 @@ +import * as setup from "../utilities" +import { checkBuilderEndpoint } from "../utilities/TestFunctions" +import TestConfiguration from "../../../../tests/utilities/TestConfiguration" +import { Datasource, Query, SourceName } from "@budibase/types" + +describe("query permissions", () => { + let config: TestConfiguration + let datasource: Datasource + let query: Query + + beforeAll(async () => { + config = setup.getConfig() + await config.init() + datasource = await config.api.datasource.create({ + name: "test datasource", + type: "test", + source: SourceName.REST, + config: {}, + }) + query = await config.api.query.save({ + name: "test query", + datasourceId: datasource._id!, + parameters: [], + fields: {}, + transformer: "", + schema: {}, + readable: true, + queryVerb: "read", + }) + }) + + it("delete should require builder", async () => { + await checkBuilderEndpoint({ + config, + method: "DELETE", + url: `/api/queries/${query._id}/${query._rev}`, + }) + }) + + it("preview should require builder", async () => { + await checkBuilderEndpoint({ + config, + method: "POST", + url: `/api/queries/preview`, + }) + }) +}) diff --git a/packages/server/src/api/routes/tests/queries/query.seq.spec.ts b/packages/server/src/api/routes/tests/queries/query.seq.spec.ts deleted file mode 100644 index 4c25a762b8..0000000000 --- a/packages/server/src/api/routes/tests/queries/query.seq.spec.ts +++ /dev/null @@ -1,774 +0,0 @@ -import tk from "timekeeper" - -const pg = require("pg") - -// Mock out postgres for this -jest.mock("pg") -jest.mock("node-fetch") - -// Mock isProdAppID to we can later mock the implementation and pretend we are -// using prod app IDs -jest.mock("@budibase/backend-core", () => { - const core = jest.requireActual("@budibase/backend-core") - return { - ...core, - db: { - ...core.db, - isProdAppID: jest.fn(), - }, - } -}) -import * as setup from "../utilities" -import { checkBuilderEndpoint } from "../utilities/TestFunctions" -import { checkCacheForDynamicVariable } from "../../../../threads/utils" - -const { basicQuery, basicDatasource } = setup.structures -import { events, db as dbCore } from "@budibase/backend-core" -import { - Datasource, - Query, - SourceName, - QueryPreview, - QueryParameter, -} from "@budibase/types" - -tk.freeze(Date.now()) - -const mockIsProdAppID = dbCore.isProdAppID as jest.MockedFunction< - typeof dbCore.isProdAppID -> - -describe("/queries", () => { - let request = setup.getRequest() - let config = setup.getConfig() - let datasource: Datasource & Required>, query: Query - - afterAll(setup.afterAll) - - const setupTest = async () => { - await config.init() - datasource = await config.createDatasource() - query = await config.createQuery() - } - - beforeAll(async () => { - await setupTest() - }) - - const createQuery = async (query: Query) => { - return request - .post(`/api/queries`) - .send(query) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - } - - describe("create", () => { - it("should create a new query", async () => { - const { _id } = await config.createDatasource() - const query = basicQuery(_id) - jest.clearAllMocks() - const res = await createQuery(query) - - expect((res as any).res.statusMessage).toEqual( - `Query ${query.name} saved successfully.` - ) - expect(res.body).toEqual({ - _rev: res.body._rev, - _id: res.body._id, - ...query, - nullDefaultSupport: true, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }) - expect(events.query.created).toHaveBeenCalledTimes(1) - expect(events.query.updated).not.toHaveBeenCalled() - }) - }) - - describe("update", () => { - it("should update query", async () => { - const { _id } = await config.createDatasource() - const query = basicQuery(_id) - const res = await createQuery(query) - jest.clearAllMocks() - query._id = res.body._id - query._rev = res.body._rev - await createQuery(query) - - expect((res as any).res.statusMessage).toEqual( - `Query ${query.name} saved successfully.` - ) - expect(res.body).toEqual({ - _rev: res.body._rev, - _id: res.body._id, - ...query, - nullDefaultSupport: true, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }) - expect(events.query.created).not.toHaveBeenCalled() - expect(events.query.updated).toHaveBeenCalledTimes(1) - }) - }) - - describe("fetch", () => { - beforeEach(async () => { - await setupTest() - }) - - it("returns all the queries from the server", async () => { - const res = await request - .get(`/api/queries`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - - const queries = res.body - expect(queries).toEqual([ - { - _rev: query._rev, - _id: query._id, - createdAt: new Date().toISOString(), - ...basicQuery(datasource._id), - nullDefaultSupport: true, - updatedAt: new Date().toISOString(), - readable: true, - }, - ]) - }) - - it("should apply authorization to endpoint", async () => { - await checkBuilderEndpoint({ - config, - method: "GET", - url: `/api/datasources`, - }) - }) - }) - - describe("find", () => { - it("should find a query in builder", async () => { - const query = await config.createQuery() - const res = await request - .get(`/api/queries/${query._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toEqual(query._id) - }) - - it("should find a query in cloud", async () => { - await config.withEnv({ SELF_HOSTED: "true" }, async () => { - const query = await config.createQuery() - const res = await request - .get(`/api/queries/${query._id}`) - .set(await config.defaultHeaders()) - .expect(200) - .expect("Content-Type", /json/) - expect(res.body.fields).toBeDefined() - expect(res.body.parameters).toBeDefined() - expect(res.body.schema).toBeDefined() - }) - }) - - it("should remove sensitive info for prod apps", async () => { - // Mock isProdAppID to pretend we are using a prod app - mockIsProdAppID.mockClear() - mockIsProdAppID.mockImplementation(() => true) - - const query = await config.createQuery() - const res = await request - .get(`/api/queries/${query._id}`) - .set(await config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body._id).toEqual(query._id) - expect(res.body.fields).toBeUndefined() - expect(res.body.parameters).toBeUndefined() - expect(res.body.schema).toBeDefined() - - // Reset isProdAppID mock - expect(dbCore.isProdAppID).toHaveBeenCalledTimes(1) - mockIsProdAppID.mockImplementation(() => false) - }) - }) - - describe("destroy", () => { - beforeEach(async () => { - await setupTest() - }) - - it("deletes a query and returns a success message", async () => { - await request - .delete(`/api/queries/${query._id}/${query._rev}`) - .set(config.defaultHeaders()) - .expect(200) - - const res = await request - .get(`/api/queries`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - - expect(res.body).toEqual([]) - expect(events.query.deleted).toHaveBeenCalledTimes(1) - expect(events.query.deleted).toHaveBeenCalledWith(datasource, query) - }) - - it("should apply authorization to endpoint", async () => { - const query = await config.createQuery() - await checkBuilderEndpoint({ - config, - method: "DELETE", - url: `/api/queries/${query._id}/${query._rev}`, - }) - }) - }) - - describe("preview", () => { - it("should be able to preview the query", async () => { - const queryPreview: QueryPreview = { - datasourceId: datasource._id, - queryVerb: "read", - fields: {}, - parameters: [], - transformer: "return data", - name: datasource.name!, - schema: {}, - readable: true, - } - const responseBody = await config.api.query.previewQuery(queryPreview) - // these responses come from the mock - expect(responseBody.schema).toEqual({ - a: { type: "string", name: "a" }, - b: { type: "number", name: "b" }, - }) - expect(responseBody.rows.length).toEqual(1) - expect(events.query.previewed).toHaveBeenCalledTimes(1) - delete datasource.config - expect(events.query.previewed).toHaveBeenCalledWith(datasource, { - ...queryPreview, - nullDefaultSupport: true, - }) - }) - - it("should apply authorization to endpoint", async () => { - await checkBuilderEndpoint({ - config, - method: "POST", - url: `/api/queries/preview`, - }) - }) - - it("should not error when trying to generate a nested schema for an empty array", async () => { - const queryPreview: QueryPreview = { - datasourceId: datasource._id, - parameters: [], - fields: {}, - queryVerb: "read", - name: datasource.name!, - transformer: "return data", - schema: {}, - readable: true, - } - const rows = [ - { - contacts: [], - }, - ] - pg.queryMock.mockImplementation(() => ({ - rows, - })) - - const responseBody = await config.api.query.previewQuery(queryPreview) - expect(responseBody).toEqual({ - nestedSchemaFields: {}, - rows, - schema: { - contacts: { type: "array", name: "contacts" }, - }, - }) - expect(responseBody.rows.length).toEqual(1) - delete datasource.config - }) - - it("should generate a nested schema based on all the nested items", async () => { - const queryPreview: QueryPreview = { - datasourceId: datasource._id, - parameters: [], - fields: {}, - queryVerb: "read", - name: datasource.name!, - transformer: "return data", - schema: {}, - readable: true, - } - const rows = [ - { - contacts: [ - { - address: "123 Lane", - }, - { - address: "456 Drive", - }, - { - postcode: "BT1 12N", - lat: 54.59, - long: -5.92, - }, - { - city: "Belfast", - }, - { - address: "789 Avenue", - phoneNumber: "0800-999-5555", - }, - { - name: "Name", - isActive: false, - }, - ], - }, - ] - - pg.queryMock.mockImplementation(() => ({ - rows, - })) - - const responseBody = await config.api.query.previewQuery(queryPreview) - expect(responseBody).toEqual({ - nestedSchemaFields: { - contacts: { - address: { - type: "string", - name: "address", - }, - postcode: { - type: "string", - name: "postcode", - }, - lat: { - type: "number", - name: "lat", - }, - long: { - type: "number", - name: "long", - }, - city: { - type: "string", - name: "city", - }, - phoneNumber: { - type: "string", - name: "phoneNumber", - }, - name: { - type: "string", - name: "name", - }, - isActive: { - type: "boolean", - name: "isActive", - }, - }, - }, - rows, - schema: { - contacts: { type: "json", name: "contacts", subtype: "array" }, - }, - }) - expect(responseBody.rows.length).toEqual(1) - delete datasource.config - }) - }) - - describe("execute", () => { - beforeEach(async () => { - await setupTest() - }) - - it("should be able to execute the query", async () => { - const res = await request - .post(`/api/queries/${query._id}`) - .send({ - parameters: {}, - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body.length).toEqual(1) - }) - - it("should fail with invalid integration type", async () => { - const datasource: Datasource = { - ...basicDatasource().datasource, - source: "INVALID_INTEGRATION" as SourceName, - } - await config.api.datasource.create(datasource, { - status: 500, - body: { - message: "No datasource implementation found.", - }, - }) - }) - - it("shouldn't allow handlebars to be passed as parameters", async () => { - const res = await request - .post(`/api/queries/${query._id}`) - .send({ - parameters: { - a: "{{ 'test' }}", - }, - }) - .set(config.defaultHeaders()) - .expect(400) - expect(res.body.message).toEqual( - "Parameter 'a' input contains a handlebars binding - this is not allowed." - ) - }) - }) - - describe("variables", () => { - async function preview(datasource: Datasource, fields: any) { - const queryPreview: QueryPreview = { - datasourceId: datasource._id!, - parameters: [], - fields, - queryVerb: "read", - name: datasource.name!, - transformer: "return data", - schema: {}, - readable: true, - } - return await config.api.query.previewQuery(queryPreview) - } - - it("should work with static variables", async () => { - const datasource = await config.restDatasource({ - staticVariables: { - variable: "google", - variable2: "1", - }, - }) - const responseBody = await preview(datasource, { - path: "www.{{ variable }}.com", - queryString: "test={{ variable2 }}", - }) - // these responses come from the mock - expect(responseBody.schema).toEqual({ - opts: { type: "json", name: "opts" }, - url: { type: "string", name: "url" }, - value: { type: "string", name: "value" }, - }) - expect(responseBody.rows[0].url).toEqual("http://www.google.com?test=1") - }) - - it("should work with dynamic variables", async () => { - const { datasource } = await config.dynamicVariableDatasource() - const responseBody = await preview(datasource, { - path: "www.google.com", - queryString: "test={{ variable3 }}", - }) - expect(responseBody.schema).toEqual({ - opts: { type: "json", name: "opts" }, - url: { type: "string", name: "url" }, - value: { type: "string", name: "value" }, - }) - expect(responseBody.rows[0].url).toContain("doctype%20html") - }) - - it("check that it automatically retries on fail with cached dynamics", async () => { - const { datasource, query: base } = - await config.dynamicVariableDatasource() - // preview once to cache - await preview(datasource, { - path: "www.google.com", - queryString: "test={{ variable3 }}", - }) - // check its in cache - const contents = await checkCacheForDynamicVariable( - base._id!, - "variable3" - ) - expect(contents.rows.length).toEqual(1) - const responseBody = await preview(datasource, { - path: "www.failonce.com", - queryString: "test={{ variable3 }}", - }) - expect(responseBody.schema).toEqual({ - fails: { type: "number", name: "fails" }, - opts: { type: "json", name: "opts" }, - url: { type: "string", name: "url" }, - }) - expect(responseBody.rows[0].fails).toEqual(1) - }) - - it("deletes variables when linked query is deleted", async () => { - const { datasource, query: base } = - await config.dynamicVariableDatasource() - // preview once to cache - await preview(datasource, { - path: "www.google.com", - queryString: "test={{ variable3 }}", - }) - // check its in cache - let contents = await checkCacheForDynamicVariable(base._id!, "variable3") - expect(contents.rows.length).toEqual(1) - - // delete the query - await request - .delete(`/api/queries/${base._id}/${base._rev}`) - .set(config.defaultHeaders()) - .expect(200) - - // check variables no longer in cache - contents = await checkCacheForDynamicVariable(base._id!, "variable3") - expect(contents).toBe(null) - }) - }) - - describe("Current User Request Mapping", () => { - async function previewGet( - datasource: Datasource, - fields: any, - params: QueryParameter[] - ) { - const queryPreview: QueryPreview = { - datasourceId: datasource._id!, - parameters: params, - fields, - queryVerb: "read", - name: datasource.name!, - transformer: "return data", - schema: {}, - readable: true, - } - return await config.api.query.previewQuery(queryPreview) - } - - async function previewPost( - datasource: Datasource, - fields: any, - params: QueryParameter[] - ) { - const queryPreview: QueryPreview = { - datasourceId: datasource._id!, - parameters: params, - fields, - queryVerb: "create", - name: datasource.name!, - transformer: null, - schema: {}, - readable: false, - } - return await config.api.query.previewQuery(queryPreview) - } - - it("should parse global and query level header mappings", async () => { - const userDetails = config.getUserDetails() - - const datasource = await config.restDatasource({ - defaultHeaders: { - test: "headerVal", - emailHdr: "{{[user].[email]}}", - }, - }) - const responseBody = await previewGet( - datasource, - { - path: "www.google.com", - queryString: "email={{[user].[email]}}", - headers: { - queryHdr: "{{[user].[firstName]}}", - secondHdr: "1234", - }, - }, - [] - ) - - const parsedRequest = JSON.parse(responseBody.extra.raw) - expect(parsedRequest.opts.headers).toEqual({ - test: "headerVal", - emailHdr: userDetails.email, - queryHdr: userDetails.firstName, - secondHdr: "1234", - }) - expect(responseBody.rows[0].url).toEqual( - "http://www.google.com?email=" + userDetails.email.replace("@", "%40") - ) - }) - - it("should bind the current user to query parameters", async () => { - const userDetails = config.getUserDetails() - - const datasource = await config.restDatasource() - - const responseBody = await previewGet( - datasource, - { - path: "www.google.com", - queryString: - "test={{myEmail}}&testName={{myName}}&testParam={{testParam}}", - }, - [ - { name: "myEmail", default: "{{[user].[email]}}" }, - { name: "myName", default: "{{[user].[firstName]}}" }, - { name: "testParam", default: "1234" }, - ] - ) - - expect(responseBody.rows[0].url).toEqual( - "http://www.google.com?test=" + - userDetails.email.replace("@", "%40") + - "&testName=" + - userDetails.firstName + - "&testParam=1234" - ) - }) - - it("should bind the current user the request body - plain text", async () => { - const userDetails = config.getUserDetails() - const datasource = await config.restDatasource() - - const responseBody = await previewPost( - datasource, - { - path: "www.google.com", - queryString: "testParam={{testParam}}", - requestBody: - "This is plain text and this is my email: {{[user].[email]}}. This is a test param: {{testParam}}", - bodyType: "text", - }, - [{ name: "testParam", default: "1234" }] - ) - - const parsedRequest = JSON.parse(responseBody.extra.raw) - expect(parsedRequest.opts.body).toEqual( - `This is plain text and this is my email: ${userDetails.email}. This is a test param: 1234` - ) - expect(responseBody.rows[0].url).toEqual( - "http://www.google.com?testParam=1234" - ) - }) - - it("should bind the current user the request body - json", async () => { - const userDetails = config.getUserDetails() - const datasource = await config.restDatasource() - - const responseBody = await previewPost( - datasource, - { - path: "www.google.com", - queryString: "testParam={{testParam}}", - requestBody: - '{"email":"{{[user].[email]}}","queryCode":{{testParam}},"userRef":"{{userRef}}"}', - bodyType: "json", - }, - [ - { name: "testParam", default: "1234" }, - { name: "userRef", default: "{{[user].[firstName]}}" }, - ] - ) - - const parsedRequest = JSON.parse(responseBody.extra.raw) - const test = `{"email":"${userDetails.email}","queryCode":1234,"userRef":"${userDetails.firstName}"}` - expect(parsedRequest.opts.body).toEqual(test) - expect(responseBody.rows[0].url).toEqual( - "http://www.google.com?testParam=1234" - ) - }) - - it("should bind the current user the request body - xml", async () => { - const userDetails = config.getUserDetails() - const datasource = await config.restDatasource() - - const responseBody = await previewPost( - datasource, - { - path: "www.google.com", - queryString: "testParam={{testParam}}", - requestBody: - " {{[user].[email]}} {{testParam}} " + - "{{userId}} testing ", - bodyType: "xml", - }, - [ - { name: "testParam", default: "1234" }, - { name: "userId", default: "{{[user].[firstName]}}" }, - ] - ) - - const parsedRequest = JSON.parse(responseBody.extra.raw) - const test = ` ${userDetails.email} 1234 ${userDetails.firstName} testing ` - - expect(parsedRequest.opts.body).toEqual(test) - expect(responseBody.rows[0].url).toEqual( - "http://www.google.com?testParam=1234" - ) - }) - - it("should bind the current user the request body - form-data", async () => { - const userDetails = config.getUserDetails() - const datasource = await config.restDatasource() - - const responseBody = await previewPost( - datasource, - { - path: "www.google.com", - queryString: "testParam={{testParam}}", - requestBody: - '{"email":"{{[user].[email]}}","queryCode":{{testParam}},"userRef":"{{userRef}}"}', - bodyType: "form", - }, - [ - { name: "testParam", default: "1234" }, - { name: "userRef", default: "{{[user].[firstName]}}" }, - ] - ) - - const parsedRequest = JSON.parse(responseBody.extra.raw) - - const emailData = parsedRequest.opts.body._streams[1] - expect(emailData).toEqual(userDetails.email) - - const queryCodeData = parsedRequest.opts.body._streams[4] - expect(queryCodeData).toEqual("1234") - - const userRef = parsedRequest.opts.body._streams[7] - expect(userRef).toEqual(userDetails.firstName) - - expect(responseBody.rows[0].url).toEqual( - "http://www.google.com?testParam=1234" - ) - }) - - it("should bind the current user the request body - encoded", async () => { - const userDetails = config.getUserDetails() - const datasource = await config.restDatasource() - - const responseBody = await previewPost( - datasource, - { - path: "www.google.com", - queryString: "testParam={{testParam}}", - requestBody: - '{"email":"{{[user].[email]}}","queryCode":{{testParam}},"userRef":"{{userRef}}"}', - bodyType: "encoded", - }, - [ - { name: "testParam", default: "1234" }, - { name: "userRef", default: "{{[user].[firstName]}}" }, - ] - ) - const parsedRequest = JSON.parse(responseBody.extra.raw) - - expect(parsedRequest.opts.body.email).toEqual(userDetails.email) - expect(parsedRequest.opts.body.queryCode).toEqual("1234") - expect(parsedRequest.opts.body.userRef).toEqual(userDetails.firstName) - }) - }) -}) diff --git a/packages/server/src/api/routes/tests/queries/rest.spec.ts b/packages/server/src/api/routes/tests/queries/rest.spec.ts new file mode 100644 index 0000000000..5c41583244 --- /dev/null +++ b/packages/server/src/api/routes/tests/queries/rest.spec.ts @@ -0,0 +1,406 @@ +import * as setup from "../utilities" +import TestConfiguration from "../../../../tests/utilities/TestConfiguration" +import { Datasource, SourceName } from "@budibase/types" +import { getCachedVariable } from "../../../../threads/utils" +import nock from "nock" +import { generator } from "@budibase/backend-core/tests" + +jest.unmock("node-fetch") + +describe("rest", () => { + let config: TestConfiguration + let datasource: Datasource + + async function createQuery(fields: any) { + return await config.api.query.save({ + name: "test query", + datasourceId: datasource._id!, + parameters: [], + fields, + transformer: "", + schema: {}, + readable: true, + queryVerb: "read", + }) + } + + beforeAll(async () => { + config = setup.getConfig() + await config.init() + datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: {}, + }) + }) + + afterEach(() => { + nock.cleanAll() + }) + + it("should automatically retry on fail with cached dynamics", async () => { + const basedOnQuery = await createQuery({ + path: "one.example.com", + }) + + let cached = await getCachedVariable(basedOnQuery._id!, "foo") + expect(cached).toBeNull() + + await config.api.datasource.update({ + ...datasource, + config: { + ...datasource.config, + dynamicVariables: [ + { + queryId: basedOnQuery._id!, + name: "foo", + value: "{{ data[0].name }}", + }, + ], + }, + }) + + cached = await getCachedVariable(basedOnQuery._id!, "foo") + expect(cached).toBeNull() + + nock("http://one.example.com") + .get("/") + .reply(200, [{ name: "one" }]) + nock("http://two.example.com").get("/?test=one").reply(500) + nock("http://two.example.com") + .get("/?test=one") + .reply(200, [{ name: "two" }]) + + const res = await config.api.query.preview({ + datasourceId: datasource._id!, + name: "test query", + parameters: [], + queryVerb: "read", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "two.example.com", + queryString: "test={{ foo }}", + }, + }) + expect(res.schema).toEqual({ + name: { type: "string", name: "name" }, + }) + + cached = await getCachedVariable(basedOnQuery._id!, "foo") + expect(cached.rows.length).toEqual(1) + expect(cached.rows[0].name).toEqual("one") + }) + + it("should parse global and query level header mappings", async () => { + const datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: { + defaultHeaders: { + test: "headerVal", + emailHdr: "{{[user].[email]}}", + }, + }, + }) + + const user = config.getUserDetails() + const mock = nock("http://www.example.com", { + reqheaders: { + test: "headerVal", + emailhdr: user.email, + queryhdr: user.firstName!, + secondhdr: "1234", + }, + }) + .get("/?email=" + user.email.replace("@", "%40")) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [], + queryVerb: "read", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + queryString: "email={{[user].[email]}}", + headers: { + queryHdr: "{{[user].[firstName]}}", + secondHdr: "1234", + }, + }, + }) + + expect(mock.isDone()).toEqual(true) + }) + + it("should bind the current user to query params", async () => { + const user = config.getUserDetails() + const mock = nock("http://www.example.com") + .get( + "/?test=" + + user.email.replace("@", "%40") + + "&testName=" + + user.firstName + + "&testParam=1234" + ) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [ + { name: "myEmail", default: "{{[user].[email]}}" }, + { name: "myName", default: "{{[user].[firstName]}}" }, + { name: "testParam", default: "1234" }, + ], + queryVerb: "read", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + queryString: + "test={{myEmail}}&testName={{myName}}&testParam={{testParam}}", + }, + }) + + expect(mock.isDone()).toEqual(true) + }) + + it("should bind the current user to the request body - plain text", async () => { + const datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: { + method: "POST", + defaultHeaders: { + test: "headerVal", + emailHdr: "{{[user].[email]}}", + }, + }, + }) + + const user = config.getUserDetails() + const mock = nock("http://www.example.com") + .post( + "/?testParam=1234", + "This is plain text and this is my email: " + + user.email + + ". This is a test param: 1234" + ) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [{ name: "testParam", default: "1234" }], + queryVerb: "create", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + bodyType: "text", + queryString: "&testParam={{testParam}}", + requestBody: + "This is plain text and this is my email: {{[user].[email]}}. This is a test param: {{testParam}}", + }, + }) + + expect(mock.isDone()).toEqual(true) + }) + + it("should bind the current user to the request body - json", async () => { + const datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: { + method: "POST", + defaultHeaders: { + test: "headerVal", + emailHdr: "{{[user].[email]}}", + }, + }, + }) + + const user = config.getUserDetails() + const mock = nock("http://www.example.com") + .post("/?testParam=1234", { + email: user.email, + queryCode: 1234, + userRef: user.firstName, + }) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [ + { name: "testParam", default: "1234" }, + { name: "userRef", default: "{{[user].[firstName]}}" }, + ], + queryVerb: "create", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + bodyType: "json", + queryString: "&testParam={{testParam}}", + requestBody: + '{"email":"{{[user].[email]}}","queryCode":{{testParam}},"userRef":"{{userRef}}"}', + }, + }) + + expect(mock.isDone()).toEqual(true) + }) + + it("should bind the current user to the request body - xml", async () => { + const datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: { + method: "POST", + defaultHeaders: { + test: "headerVal", + emailHdr: "{{[user].[email]}}", + }, + }, + }) + + const user = config.getUserDetails() + const mock = nock("http://www.example.com") + .post( + "/?testParam=1234", + ` ${user.email} 1234 ${user.firstName} testing ` + ) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [ + { name: "testParam", default: "1234" }, + { name: "userId", default: "{{[user].[firstName]}}" }, + ], + queryVerb: "create", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + bodyType: "xml", + queryString: "&testParam={{testParam}}", + requestBody: + " {{[user].[email]}} {{testParam}} " + + "{{userId}} testing ", + }, + }) + + expect(mock.isDone()).toEqual(true) + }) + + it("should bind the current user to the request body - form-data", async () => { + const datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: { + method: "POST", + defaultHeaders: { + test: "headerVal", + emailHdr: "{{[user].[email]}}", + }, + }, + }) + + const user = config.getUserDetails() + const mock = nock("http://www.example.com") + .post("/?testParam=1234", body => { + return ( + body.includes('name="email"\r\n\r\n' + user.email + "\r\n") && + body.includes('name="queryCode"\r\n\r\n1234\r\n') && + body.includes('name="userRef"\r\n\r\n' + user.firstName + "\r\n") + ) + }) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [ + { name: "testParam", default: "1234" }, + { name: "userRef", default: "{{[user].[firstName]}}" }, + ], + queryVerb: "create", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + bodyType: "form", + queryString: "&testParam={{testParam}}", + requestBody: + '{"email":"{{[user].[email]}}","queryCode":{{testParam}},"userRef":"{{userRef}}"}', + }, + }) + + expect(mock.isDone()).toEqual(true) + }) + + it("should bind the current user to the request body - encoded", async () => { + const datasource = await config.api.datasource.create({ + name: generator.guid(), + type: "test", + source: SourceName.REST, + config: { + method: "POST", + defaultHeaders: { + test: "headerVal", + emailHdr: "{{[user].[email]}}", + }, + }, + }) + + const user = config.getUserDetails() + const mock = nock("http://www.example.com") + .post("/?testParam=1234", { + email: user.email, + queryCode: 1234, + userRef: user.firstName, + }) + .reply(200, {}) + + await config.api.query.preview({ + datasourceId: datasource._id!, + name: generator.guid(), + parameters: [ + { name: "testParam", default: "1234" }, + { name: "userRef", default: "{{[user].[firstName]}}" }, + ], + queryVerb: "create", + transformer: "", + schema: {}, + readable: true, + fields: { + path: "www.example.com", + bodyType: "encoded", + queryString: "&testParam={{testParam}}", + requestBody: + '{"email":"{{[user].[email]}}","queryCode":{{testParam}},"userRef":"{{userRef}}"}', + }, + }) + + expect(mock.isDone()).toEqual(true) + }) +}) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index f638f2c4bf..f9e05c5bd8 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1,4 +1,4 @@ -import { databaseTestProviders } from "../../../integrations/tests/utils" +import { DatabaseName, getDatasource } from "../../../integrations/tests/utils" import tk from "timekeeper" import { outputProcessing } from "../../../utilities/rowProcessor" @@ -30,14 +30,13 @@ const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) jest.unmock("mssql") -jest.unmock("pg") describe.each([ ["internal", undefined], - ["postgres", databaseTestProviders.postgres], - ["mysql", databaseTestProviders.mysql], - ["mssql", databaseTestProviders.mssql], - ["mariadb", databaseTestProviders.mariadb], + [DatabaseName.POSTGRES, getDatasource(DatabaseName.POSTGRES)], + [DatabaseName.MYSQL, getDatasource(DatabaseName.MYSQL)], + [DatabaseName.SQL_SERVER, getDatasource(DatabaseName.SQL_SERVER)], + [DatabaseName.MARIADB, getDatasource(DatabaseName.MARIADB)], ])("/rows (%s)", (__, dsProvider) => { const isInternal = dsProvider === undefined const config = setup.getConfig() @@ -49,23 +48,23 @@ describe.each([ await config.init() if (dsProvider) { datasource = await config.createDatasource({ - datasource: await dsProvider.datasource(), + datasource: await dsProvider, }) } }) afterAll(async () => { - if (dsProvider) { - await dsProvider.stop() - } setup.afterAll() }) function saveTableRequest( - ...overrides: Partial[] + // We omit the name field here because it's generated in the function with a + // high likelihood to be unique. Tests should not have any reason to control + // the table name they're writing to. + ...overrides: Partial>[] ): SaveTableRequest { const req: SaveTableRequest = { - name: uuid.v4().substring(0, 16), + name: uuid.v4().substring(0, 10), type: "table", sourceType: datasource ? TableSourceType.EXTERNAL @@ -87,7 +86,10 @@ describe.each([ } function defaultTable( - ...overrides: Partial[] + // We omit the name field here because it's generated in the function with a + // high likelihood to be unique. Tests should not have any reason to control + // the table name they're writing to. + ...overrides: Partial>[] ): SaveTableRequest { return saveTableRequest( { @@ -194,7 +196,6 @@ describe.each([ const newTable = await config.api.table.save( saveTableRequest({ - name: "TestTableAuto", schema: { "Row ID": { name: "Row ID", @@ -383,11 +384,9 @@ describe.each([ isInternal && it("doesn't allow creating in user table", async () => { - const userTableId = InternalTable.USER_METADATA const response = await config.api.row.save( - userTableId, + InternalTable.USER_METADATA, { - tableId: userTableId, firstName: "Joe", lastName: "Joe", email: "joe@joe.com", @@ -462,7 +461,6 @@ describe.each([ table = await config.api.table.save(defaultTable()) otherTable = await config.api.table.save( defaultTable({ - name: "a", schema: { relationship: { name: "relationship", @@ -898,8 +896,8 @@ describe.each([ let o2mTable: Table let m2mTable: Table beforeAll(async () => { - o2mTable = await config.api.table.save(defaultTable({ name: "o2m" })) - m2mTable = await config.api.table.save(defaultTable({ name: "m2m" })) + o2mTable = await config.api.table.save(defaultTable()) + m2mTable = await config.api.table.save(defaultTable()) }) describe.each([ @@ -1256,7 +1254,6 @@ describe.each([ otherTable = await config.api.table.save(defaultTable()) table = await config.api.table.save( saveTableRequest({ - name: "b", schema: { links: { name: "links", @@ -1298,7 +1295,7 @@ describe.each([ describe("Formula JS protection", () => { it("should time out JS execution if a single cell takes too long", async () => { - await config.withEnv({ JS_PER_INVOCATION_TIMEOUT_MS: 20 }, async () => { + await config.withEnv({ JS_PER_INVOCATION_TIMEOUT_MS: 40 }, async () => { const js = Buffer.from( ` let i = 0; @@ -1338,8 +1335,8 @@ describe.each([ it("should time out JS execution if a multiple cells take too long", async () => { await config.withEnv( { - JS_PER_INVOCATION_TIMEOUT_MS: 20, - JS_PER_REQUEST_TIMEOUT_MS: 40, + JS_PER_INVOCATION_TIMEOUT_MS: 40, + JS_PER_REQUEST_TIMEOUT_MS: 80, }, async () => { const js = Buffer.from( @@ -1354,7 +1351,6 @@ describe.each([ const table = await config.api.table.save( saveTableRequest({ - name: "table", schema: { text: { name: "text", diff --git a/packages/server/src/api/routes/tests/user.spec.ts b/packages/server/src/api/routes/tests/user.spec.ts index ff8c0d54b3..a46de8f3b3 100644 --- a/packages/server/src/api/routes/tests/user.spec.ts +++ b/packages/server/src/api/routes/tests/user.spec.ts @@ -3,8 +3,6 @@ import { checkPermissionsEndpoint } from "./utilities/TestFunctions" import * as setup from "./utilities" import { UserMetadata } from "@budibase/types" -jest.setTimeout(30000) - jest.mock("../../../utilities/workerRequests", () => ({ getGlobalUsers: jest.fn(() => { return {} diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index f9d213a26b..1ed6b45a08 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -19,21 +19,19 @@ import { ViewV2, } from "@budibase/types" import { generator, mocks } from "@budibase/backend-core/tests" -import * as uuid from "uuid" -import { databaseTestProviders } from "../../../integrations/tests/utils" +import { DatabaseName, getDatasource } from "../../../integrations/tests/utils" import merge from "lodash/merge" import { quotas } from "@budibase/pro" import { roles } from "@budibase/backend-core" jest.unmock("mssql") -jest.unmock("pg") describe.each([ ["internal", undefined], - ["postgres", databaseTestProviders.postgres], - ["mysql", databaseTestProviders.mysql], - ["mssql", databaseTestProviders.mssql], - ["mariadb", databaseTestProviders.mariadb], + [DatabaseName.POSTGRES, getDatasource(DatabaseName.POSTGRES)], + [DatabaseName.MYSQL, getDatasource(DatabaseName.MYSQL)], + [DatabaseName.SQL_SERVER, getDatasource(DatabaseName.SQL_SERVER)], + [DatabaseName.MARIADB, getDatasource(DatabaseName.MARIADB)], ])("/v2/views (%s)", (_, dsProvider) => { const config = setup.getConfig() const isInternal = !dsProvider @@ -42,10 +40,10 @@ describe.each([ let datasource: Datasource function saveTableRequest( - ...overrides: Partial[] + ...overrides: Partial>[] ): SaveTableRequest { const req: SaveTableRequest = { - name: uuid.v4().substring(0, 16), + name: generator.guid().replaceAll("-", "").substring(0, 16), type: "table", sourceType: datasource ? TableSourceType.EXTERNAL @@ -90,16 +88,13 @@ describe.each([ if (dsProvider) { datasource = await config.createDatasource({ - datasource: await dsProvider.datasource(), + datasource: await dsProvider, }) } table = await config.api.table.save(priceTable()) }) afterAll(async () => { - if (dsProvider) { - await dsProvider.stop() - } setup.afterAll() }) @@ -231,7 +226,7 @@ describe.each([ view = await config.api.viewV2.create({ tableId: table._id!, - name: "View A", + name: generator.guid(), }) }) @@ -307,12 +302,13 @@ describe.each([ it("can update an existing view name", async () => { const tableId = table._id! - await config.api.viewV2.update({ ...view, name: "View B" }) + const newName = generator.guid() + await config.api.viewV2.update({ ...view, name: newName }) expect(await config.api.table.get(tableId)).toEqual( expect.objectContaining({ views: { - "View B": { ...view, name: "View B", schema: expect.anything() }, + [newName]: { ...view, name: newName, schema: expect.anything() }, }, }) ) @@ -507,7 +503,6 @@ describe.each([ it("views have extra data trimmed", async () => { const table = await config.api.table.save( saveTableRequest({ - name: "orders", schema: { Country: { type: FieldType.STRING, @@ -523,7 +518,7 @@ describe.each([ const view = await config.api.viewV2.create({ tableId: table._id!, - name: uuid.v4(), + name: generator.guid(), schema: { Country: { visible: true, @@ -853,7 +848,6 @@ describe.each([ beforeAll(async () => { table = await config.api.table.save( saveTableRequest({ - name: `users_${uuid.v4()}`, type: "table", schema: { name: { diff --git a/packages/server/src/automations/tests/executeQuery.spec.js b/packages/server/src/automations/tests/executeQuery.spec.js deleted file mode 100644 index 3b691f48ea..0000000000 --- a/packages/server/src/automations/tests/executeQuery.spec.js +++ /dev/null @@ -1,39 +0,0 @@ -const setup = require("./utilities") - -describe("test the execute query action", () => { - let query - let config = setup.getConfig() - - beforeAll(async () => { - await config.init() - - await config.createDatasource() - query = await config.createQuery() - }) - - afterAll(setup.afterAll) - - it("should be able to execute a query", async () => { - let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { - query: { queryId: query._id }, - }) - expect(res.response).toEqual([{ a: "string", b: 1 }]) - expect(res.success).toEqual(true) - }) - - it("should handle a null query value", async () => { - let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { - query: null, - }) - expect(res.response.message).toEqual("Invalid inputs") - expect(res.success).toEqual(false) - }) - - it("should handle an error executing a query", async () => { - let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { - query: { queryId: "wrong_id" }, - }) - expect(res.response).toEqual("Error: missing") - expect(res.success).toEqual(false) - }) -}) diff --git a/packages/server/src/automations/tests/executeQuery.spec.ts b/packages/server/src/automations/tests/executeQuery.spec.ts new file mode 100644 index 0000000000..996e44af79 --- /dev/null +++ b/packages/server/src/automations/tests/executeQuery.spec.ts @@ -0,0 +1,94 @@ +import { Datasource, Query, SourceName } from "@budibase/types" +import * as setup from "./utilities" +import { DatabaseName, getDatasource } from "../../integrations/tests/utils" +import knex, { Knex } from "knex" +import { generator } from "@budibase/backend-core/tests" + +function getKnexClientName(source: SourceName) { + switch (source) { + case SourceName.MYSQL: + return "mysql2" + case SourceName.SQL_SERVER: + return "mssql" + case SourceName.POSTGRES: + return "pg" + } + throw new Error(`Unsupported source: ${source}`) +} + +describe.each( + [ + DatabaseName.POSTGRES, + DatabaseName.MYSQL, + DatabaseName.SQL_SERVER, + DatabaseName.MARIADB, + ].map(name => [name, getDatasource(name)]) +)("execute query action (%s)", (_, dsProvider) => { + let tableName: string + let client: Knex + let datasource: Datasource + let query: Query + let config = setup.getConfig() + + beforeAll(async () => { + await config.init() + + const ds = await dsProvider + datasource = await config.api.datasource.create(ds) + client = knex({ + client: getKnexClientName(ds.source), + connection: ds.config, + }) + }) + + beforeEach(async () => { + tableName = generator.guid() + await client.schema.createTable(tableName, table => { + table.string("a") + table.integer("b") + }) + await client(tableName).insert({ a: "string", b: 1 }) + query = await config.api.query.save({ + name: "test query", + datasourceId: datasource._id!, + parameters: [], + fields: { + sql: client(tableName).select("*").toSQL().toNative().sql, + }, + transformer: "", + schema: {}, + readable: true, + queryVerb: "read", + }) + }) + + afterEach(async () => { + await client.schema.dropTable(tableName) + }) + + afterAll(setup.afterAll) + + it("should be able to execute a query", async () => { + let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { + query: { queryId: query._id }, + }) + expect(res.response).toEqual([{ a: "string", b: 1 }]) + expect(res.success).toEqual(true) + }) + + it("should handle a null query value", async () => { + let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { + query: null, + }) + expect(res.response.message).toEqual("Invalid inputs") + expect(res.success).toEqual(false) + }) + + it("should handle an error executing a query", async () => { + let res = await setup.runStep(setup.actions.EXECUTE_QUERY.stepId, { + query: { queryId: "wrong_id" }, + }) + expect(res.response).toEqual("Error: missing") + expect(res.success).toEqual(false) + }) +}) diff --git a/packages/server/src/integration-test/mysql.spec.ts b/packages/server/src/integration-test/mysql.spec.ts index 92420fb336..7e54b53b15 100644 --- a/packages/server/src/integration-test/mysql.spec.ts +++ b/packages/server/src/integration-test/mysql.spec.ts @@ -3,7 +3,6 @@ import { generateMakeRequest, MakeRequestResponse, } from "../api/routes/public/tests/utils" -import { v4 as uuidv4 } from "uuid" import * as setup from "../api/routes/tests/utilities" import { Datasource, @@ -12,12 +11,23 @@ import { TableRequest, TableSourceType, } from "@budibase/types" -import { databaseTestProviders } from "../integrations/tests/utils" -import mysql from "mysql2/promise" +import { + DatabaseName, + getDatasource, + rawQuery, +} from "../integrations/tests/utils" import { builderSocket } from "../websockets" +import { generator } from "@budibase/backend-core/tests" // @ts-ignore fetch.mockSearch() +function uniqueTableName(length?: number): string { + return generator + .guid() + .replaceAll("-", "_") + .substring(0, length || 10) +} + const config = setup.getConfig()! jest.mock("../websockets", () => ({ @@ -37,7 +47,8 @@ jest.mock("../websockets", () => ({ describe("mysql integrations", () => { let makeRequest: MakeRequestResponse, - mysqlDatasource: Datasource, + rawDatasource: Datasource, + datasource: Datasource, primaryMySqlTable: Table beforeAll(async () => { @@ -46,18 +57,13 @@ describe("mysql integrations", () => { makeRequest = generateMakeRequest(apiKey, true) - mysqlDatasource = await config.api.datasource.create( - await databaseTestProviders.mysql.datasource() - ) - }) - - afterAll(async () => { - await databaseTestProviders.mysql.stop() + rawDatasource = await getDatasource(DatabaseName.MYSQL) + datasource = await config.api.datasource.create(rawDatasource) }) beforeEach(async () => { primaryMySqlTable = await config.createTable({ - name: uuidv4(), + name: uniqueTableName(), type: "table", primary: ["id"], schema: { @@ -79,7 +85,7 @@ describe("mysql integrations", () => { type: FieldType.NUMBER, }, }, - sourceId: mysqlDatasource._id, + sourceId: datasource._id, sourceType: TableSourceType.EXTERNAL, }) }) @@ -87,18 +93,15 @@ describe("mysql integrations", () => { afterAll(config.end) it("validate table schema", async () => { - const res = await makeRequest( - "get", - `/api/datasources/${mysqlDatasource._id}` - ) + const res = await makeRequest("get", `/api/datasources/${datasource._id}`) expect(res.status).toBe(200) expect(res.body).toEqual({ config: { - database: "mysql", - host: mysqlDatasource.config!.host, + database: expect.any(String), + host: datasource.config!.host, password: "--secret-value--", - port: mysqlDatasource.config!.port, + port: datasource.config!.port, user: "root", }, plus: true, @@ -117,7 +120,7 @@ describe("mysql integrations", () => { it("should be able to verify the connection", async () => { await config.api.datasource.verify( { - datasource: await databaseTestProviders.mysql.datasource(), + datasource: rawDatasource, }, { body: { @@ -128,13 +131,12 @@ describe("mysql integrations", () => { }) it("should state an invalid datasource cannot connect", async () => { - const dbConfig = await databaseTestProviders.mysql.datasource() await config.api.datasource.verify( { datasource: { - ...dbConfig, + ...rawDatasource, config: { - ...dbConfig.config, + ...rawDatasource.config, password: "wrongpassword", }, }, @@ -154,7 +156,7 @@ describe("mysql integrations", () => { it("should fetch information about mysql datasource", async () => { const primaryName = primaryMySqlTable.name const response = await makeRequest("post", "/api/datasources/info", { - datasource: mysqlDatasource, + datasource: datasource, }) expect(response.status).toBe(200) expect(response.body.tableNames).toBeDefined() @@ -163,40 +165,38 @@ describe("mysql integrations", () => { }) describe("Integration compatibility with mysql search_path", () => { - let client: mysql.Connection, pathDatasource: Datasource - const database = "test1" - const database2 = "test-2" + let datasource: Datasource, rawDatasource: Datasource + const database = generator.guid() + const database2 = generator.guid() beforeAll(async () => { - const dsConfig = await databaseTestProviders.mysql.datasource() - const dbConfig = dsConfig.config! + rawDatasource = await getDatasource(DatabaseName.MYSQL) - client = await mysql.createConnection(dbConfig) - await client.query(`CREATE DATABASE \`${database}\`;`) - await client.query(`CREATE DATABASE \`${database2}\`;`) + await rawQuery(rawDatasource, `CREATE DATABASE \`${database}\`;`) + await rawQuery(rawDatasource, `CREATE DATABASE \`${database2}\`;`) const pathConfig: any = { - ...dsConfig, + ...rawDatasource, config: { - ...dbConfig, + ...rawDatasource.config!, database, }, } - pathDatasource = await config.api.datasource.create(pathConfig) + datasource = await config.api.datasource.create(pathConfig) }) afterAll(async () => { - await client.query(`DROP DATABASE \`${database}\`;`) - await client.query(`DROP DATABASE \`${database2}\`;`) - await client.end() + await rawQuery(rawDatasource, `DROP DATABASE \`${database}\`;`) + await rawQuery(rawDatasource, `DROP DATABASE \`${database2}\`;`) }) it("discovers tables from any schema in search path", async () => { - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE \`${database}\`.table1 (id1 SERIAL PRIMARY KEY);` ) const response = await makeRequest("post", "/api/datasources/info", { - datasource: pathDatasource, + datasource: datasource, }) expect(response.status).toBe(200) expect(response.body.tableNames).toBeDefined() @@ -207,15 +207,17 @@ describe("mysql integrations", () => { it("does not mix columns from different tables", async () => { const repeated_table_name = "table_same_name" - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE \`${database}\`.${repeated_table_name} (id SERIAL PRIMARY KEY, val1 TEXT);` ) - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE \`${database2}\`.${repeated_table_name} (id2 SERIAL PRIMARY KEY, val2 TEXT);` ) const response = await makeRequest( "post", - `/api/datasources/${pathDatasource._id}/schema`, + `/api/datasources/${datasource._id}/schema`, { tablesFilter: [repeated_table_name], } @@ -231,30 +233,14 @@ describe("mysql integrations", () => { }) describe("POST /api/tables/", () => { - let client: mysql.Connection const emitDatasourceUpdateMock = jest.fn() - beforeEach(async () => { - client = await mysql.createConnection( - ( - await databaseTestProviders.mysql.datasource() - ).config! - ) - mysqlDatasource = await config.api.datasource.create( - await databaseTestProviders.mysql.datasource() - ) - }) - - afterEach(async () => { - await client.end() - }) - it("will emit the datasource entity schema with externalType to the front-end when adding a new column", async () => { const addColumnToTable: TableRequest = { type: "table", sourceType: TableSourceType.EXTERNAL, - name: "table", - sourceId: mysqlDatasource._id!, + name: uniqueTableName(), + sourceId: datasource._id!, primary: ["id"], schema: { id: { @@ -301,14 +287,16 @@ describe("mysql integrations", () => { }, }, created: true, - _id: `${mysqlDatasource._id}__table`, + _id: `${datasource._id}__${addColumnToTable.name}`, } delete expectedTable._add expect(emitDatasourceUpdateMock).toHaveBeenCalledTimes(1) const emittedDatasource: Datasource = emitDatasourceUpdateMock.mock.calls[0][1] - expect(emittedDatasource.entities!["table"]).toEqual(expectedTable) + expect(emittedDatasource.entities![expectedTable.name]).toEqual( + expectedTable + ) }) it("will rename a column", async () => { @@ -346,17 +334,18 @@ describe("mysql integrations", () => { "/api/tables/", renameColumnOnTable ) - mysqlDatasource = ( - await makeRequest( - "post", - `/api/datasources/${mysqlDatasource._id}/schema` - ) + + const ds = ( + await makeRequest("post", `/api/datasources/${datasource._id}/schema`) ).body.datasource expect(response.status).toEqual(200) - expect( - Object.keys(mysqlDatasource.entities![primaryMySqlTable.name].schema) - ).toEqual(["id", "name", "description", "age"]) + expect(Object.keys(ds.entities![primaryMySqlTable.name].schema)).toEqual([ + "id", + "name", + "description", + "age", + ]) }) }) }) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 107c4ade1e..288489471b 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -16,19 +16,23 @@ import { import _ from "lodash" import { generator } from "@budibase/backend-core/tests" import { utils } from "@budibase/backend-core" -import { databaseTestProviders } from "../integrations/tests/utils" -import { Client } from "pg" +import { + DatabaseName, + getDatasource, + rawQuery, +} from "../integrations/tests/utils" + // @ts-ignore fetch.mockSearch() const config = setup.getConfig()! -jest.unmock("pg") jest.mock("../websockets") describe("postgres integrations", () => { let makeRequest: MakeRequestResponse, - postgresDatasource: Datasource, + rawDatasource: Datasource, + datasource: Datasource, primaryPostgresTable: Table, oneToManyRelationshipInfo: ForeignTableInfo, manyToOneRelationshipInfo: ForeignTableInfo, @@ -40,19 +44,17 @@ describe("postgres integrations", () => { makeRequest = generateMakeRequest(apiKey, true) - postgresDatasource = await config.api.datasource.create( - await databaseTestProviders.postgres.datasource() - ) - }) - - afterAll(async () => { - await databaseTestProviders.postgres.stop() + rawDatasource = await getDatasource(DatabaseName.POSTGRES) + datasource = await config.api.datasource.create(rawDatasource) }) beforeEach(async () => { async function createAuxTable(prefix: string) { return await config.createTable({ - name: `${prefix}_${generator.word({ length: 6 })}`, + name: `${prefix}_${generator + .guid() + .replaceAll("-", "") + .substring(0, 6)}`, type: "table", primary: ["id"], primaryDisplay: "title", @@ -67,7 +69,7 @@ describe("postgres integrations", () => { type: FieldType.STRING, }, }, - sourceId: postgresDatasource._id, + sourceId: datasource._id, sourceType: TableSourceType.EXTERNAL, }) } @@ -89,7 +91,7 @@ describe("postgres integrations", () => { } primaryPostgresTable = await config.createTable({ - name: `p_${generator.word({ length: 6 })}`, + name: `p_${generator.guid().replaceAll("-", "").substring(0, 6)}`, type: "table", primary: ["id"], schema: { @@ -144,7 +146,7 @@ describe("postgres integrations", () => { main: true, }, }, - sourceId: postgresDatasource._id, + sourceId: datasource._id, sourceType: TableSourceType.EXTERNAL, }) }) @@ -251,7 +253,7 @@ describe("postgres integrations", () => { async function createDefaultPgTable() { return await config.createTable({ - name: generator.word({ length: 10 }), + name: generator.guid().replaceAll("-", "").substring(0, 10), type: "table", primary: ["id"], schema: { @@ -261,7 +263,7 @@ describe("postgres integrations", () => { autocolumn: true, }, }, - sourceId: postgresDatasource._id, + sourceId: datasource._id, sourceType: TableSourceType.EXTERNAL, }) } @@ -299,19 +301,16 @@ describe("postgres integrations", () => { } it("validate table schema", async () => { - const res = await makeRequest( - "get", - `/api/datasources/${postgresDatasource._id}` - ) + const res = await makeRequest("get", `/api/datasources/${datasource._id}`) expect(res.status).toBe(200) expect(res.body).toEqual({ config: { ca: false, - database: "postgres", - host: postgresDatasource.config!.host, + database: expect.any(String), + host: datasource.config!.host, password: "--secret-value--", - port: postgresDatasource.config!.port, + port: datasource.config!.port, rejectUnauthorized: false, schema: "public", ssl: false, @@ -1043,7 +1042,7 @@ describe("postgres integrations", () => { it("should be able to verify the connection", async () => { await config.api.datasource.verify( { - datasource: await databaseTestProviders.postgres.datasource(), + datasource: await getDatasource(DatabaseName.POSTGRES), }, { body: { @@ -1054,7 +1053,7 @@ describe("postgres integrations", () => { }) it("should state an invalid datasource cannot connect", async () => { - const dbConfig = await databaseTestProviders.postgres.datasource() + const dbConfig = await getDatasource(DatabaseName.POSTGRES) await config.api.datasource.verify( { datasource: { @@ -1079,7 +1078,7 @@ describe("postgres integrations", () => { it("should fetch information about postgres datasource", async () => { const primaryName = primaryPostgresTable.name const response = await makeRequest("post", "/api/datasources/info", { - datasource: postgresDatasource, + datasource: datasource, }) expect(response.status).toBe(200) expect(response.body.tableNames).toBeDefined() @@ -1088,86 +1087,88 @@ describe("postgres integrations", () => { }) describe("POST /api/datasources/:datasourceId/schema", () => { - let client: Client + let tableName: string beforeEach(async () => { - client = new Client( - (await databaseTestProviders.postgres.datasource()).config! - ) - await client.connect() + tableName = generator.guid().replaceAll("-", "").substring(0, 10) }) afterEach(async () => { - await client.query(`DROP TABLE IF EXISTS "table"`) - await client.end() + await rawQuery(rawDatasource, `DROP TABLE IF EXISTS "${tableName}"`) }) it("recognises when a table has no primary key", async () => { - await client.query(`CREATE TABLE "table" (id SERIAL)`) + await rawQuery(rawDatasource, `CREATE TABLE "${tableName}" (id SERIAL)`) const response = await makeRequest( "post", - `/api/datasources/${postgresDatasource._id}/schema` + `/api/datasources/${datasource._id}/schema` ) expect(response.body.errors).toEqual({ - table: "Table must have a primary key.", + [tableName]: "Table must have a primary key.", }) }) it("recognises when a table is using a reserved column name", async () => { - await client.query(`CREATE TABLE "table" (_id SERIAL PRIMARY KEY) `) + await rawQuery( + rawDatasource, + `CREATE TABLE "${tableName}" (_id SERIAL PRIMARY KEY) ` + ) const response = await makeRequest( "post", - `/api/datasources/${postgresDatasource._id}/schema` + `/api/datasources/${datasource._id}/schema` ) expect(response.body.errors).toEqual({ - table: "Table contains invalid columns.", + [tableName]: "Table contains invalid columns.", }) }) }) describe("Integration compatibility with postgres search_path", () => { - let client: Client, pathDatasource: Datasource - const schema1 = "test1", - schema2 = "test-2" + let rawDatasource: Datasource, + datasource: Datasource, + schema1: string, + schema2: string - beforeAll(async () => { - const dsConfig = await databaseTestProviders.postgres.datasource() - const dbConfig = dsConfig.config! + beforeEach(async () => { + schema1 = generator.guid().replaceAll("-", "") + schema2 = generator.guid().replaceAll("-", "") - client = new Client(dbConfig) - await client.connect() - await client.query(`CREATE SCHEMA "${schema1}";`) - await client.query(`CREATE SCHEMA "${schema2}";`) + rawDatasource = await getDatasource(DatabaseName.POSTGRES) + const dbConfig = rawDatasource.config! + + await rawQuery(rawDatasource, `CREATE SCHEMA "${schema1}";`) + await rawQuery(rawDatasource, `CREATE SCHEMA "${schema2}";`) const pathConfig: any = { - ...dsConfig, + ...rawDatasource, config: { ...dbConfig, schema: `${schema1}, ${schema2}`, }, } - pathDatasource = await config.api.datasource.create(pathConfig) + datasource = await config.api.datasource.create(pathConfig) }) - afterAll(async () => { - await client.query(`DROP SCHEMA "${schema1}" CASCADE;`) - await client.query(`DROP SCHEMA "${schema2}" CASCADE;`) - await client.end() + afterEach(async () => { + await rawQuery(rawDatasource, `DROP SCHEMA "${schema1}" CASCADE;`) + await rawQuery(rawDatasource, `DROP SCHEMA "${schema2}" CASCADE;`) }) it("discovers tables from any schema in search path", async () => { - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE "${schema1}".table1 (id1 SERIAL PRIMARY KEY);` ) - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE "${schema2}".table2 (id2 SERIAL PRIMARY KEY);` ) const response = await makeRequest("post", "/api/datasources/info", { - datasource: pathDatasource, + datasource: datasource, }) expect(response.status).toBe(200) expect(response.body.tableNames).toBeDefined() @@ -1178,15 +1179,17 @@ describe("postgres integrations", () => { it("does not mix columns from different tables", async () => { const repeated_table_name = "table_same_name" - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE "${schema1}".${repeated_table_name} (id SERIAL PRIMARY KEY, val1 TEXT);` ) - await client.query( + await rawQuery( + rawDatasource, `CREATE TABLE "${schema2}".${repeated_table_name} (id2 SERIAL PRIMARY KEY, val2 TEXT);` ) const response = await makeRequest( "post", - `/api/datasources/${pathDatasource._id}/schema`, + `/api/datasources/${datasource._id}/schema`, { tablesFilter: [repeated_table_name], } diff --git a/packages/server/src/integrations/tests/utils/index.ts b/packages/server/src/integrations/tests/utils/index.ts index b2be3df4e0..5034b5a8db 100644 --- a/packages/server/src/integrations/tests/utils/index.ts +++ b/packages/server/src/integrations/tests/utils/index.ts @@ -1,25 +1,88 @@ -jest.unmock("pg") - -import { Datasource } from "@budibase/types" +import { Datasource, SourceName } from "@budibase/types" import * as postgres from "./postgres" import * as mongodb from "./mongodb" import * as mysql from "./mysql" import * as mssql from "./mssql" import * as mariadb from "./mariadb" -import { StartedTestContainer } from "testcontainers" +import { GenericContainer } from "testcontainers" +import { testContainerUtils } from "@budibase/backend-core/tests" -jest.setTimeout(30000) +export type DatasourceProvider = () => Promise -export interface DatabaseProvider { - start(): Promise - stop(): Promise - datasource(): Promise +export enum DatabaseName { + POSTGRES = "postgres", + MONGODB = "mongodb", + MYSQL = "mysql", + SQL_SERVER = "mssql", + MARIADB = "mariadb", } -export const databaseTestProviders = { - postgres, - mongodb, - mysql, - mssql, - mariadb, +const providers: Record = { + [DatabaseName.POSTGRES]: postgres.getDatasource, + [DatabaseName.MONGODB]: mongodb.getDatasource, + [DatabaseName.MYSQL]: mysql.getDatasource, + [DatabaseName.SQL_SERVER]: mssql.getDatasource, + [DatabaseName.MARIADB]: mariadb.getDatasource, +} + +export function getDatasourceProviders( + ...sourceNames: DatabaseName[] +): Promise[] { + return sourceNames.map(sourceName => providers[sourceName]()) +} + +export function getDatasourceProvider( + sourceName: DatabaseName +): DatasourceProvider { + return providers[sourceName] +} + +export function getDatasource(sourceName: DatabaseName): Promise { + return providers[sourceName]() +} + +export async function getDatasources( + ...sourceNames: DatabaseName[] +): Promise { + return Promise.all(sourceNames.map(sourceName => providers[sourceName]())) +} + +export async function rawQuery(ds: Datasource, sql: string): Promise { + switch (ds.source) { + case SourceName.POSTGRES: { + return postgres.rawQuery(ds, sql) + } + case SourceName.MYSQL: { + return mysql.rawQuery(ds, sql) + } + case SourceName.SQL_SERVER: { + return mssql.rawQuery(ds, sql) + } + default: { + throw new Error(`Unsupported source: ${ds.source}`) + } + } +} + +export async function startContainer(container: GenericContainer) { + if (process.env.REUSE_CONTAINERS) { + container = container.withReuse() + } + + const startedContainer = await container.start() + + const info = testContainerUtils.getContainerById(startedContainer.getId()) + if (!info) { + throw new Error("Container not found") + } + + // Some Docker runtimes, when you expose a port, will bind it to both + // 127.0.0.1 and ::1, so ipv4 and ipv6. The port spaces of ipv4 and ipv6 + // addresses are not shared, and testcontainers will sometimes give you back + // the ipv6 port. There's no way to know that this has happened, and if you + // try to then connect to `localhost:port` you may attempt to bind to the v4 + // address which could be unbound or even an entirely different container. For + // that reason, we don't use testcontainers' `getExposedPort` function, + // preferring instead our own method that guaranteed v4 ports. + return testContainerUtils.getExposedV4Ports(info) } diff --git a/packages/server/src/integrations/tests/utils/mariadb.ts b/packages/server/src/integrations/tests/utils/mariadb.ts index a097e0aaa1..fcd79b8e56 100644 --- a/packages/server/src/integrations/tests/utils/mariadb.ts +++ b/packages/server/src/integrations/tests/utils/mariadb.ts @@ -1,8 +1,11 @@ import { Datasource, SourceName } from "@budibase/types" -import { GenericContainer, Wait, StartedTestContainer } from "testcontainers" +import { GenericContainer, Wait } from "testcontainers" import { AbstractWaitStrategy } from "testcontainers/build/wait-strategies/wait-strategy" +import { rawQuery } from "./mysql" +import { generator, testContainerUtils } from "@budibase/backend-core/tests" +import { startContainer } from "." -let container: StartedTestContainer | undefined +let ports: Promise class MariaDBWaitStrategy extends AbstractWaitStrategy { async waitUntilReady(container: any, boundPorts: any, startTime?: Date) { @@ -21,38 +24,38 @@ class MariaDBWaitStrategy extends AbstractWaitStrategy { } } -export async function start(): Promise { - return await new GenericContainer("mariadb:lts") - .withExposedPorts(3306) - .withEnvironment({ MARIADB_ROOT_PASSWORD: "password" }) - .withWaitStrategy(new MariaDBWaitStrategy()) - .start() -} - -export async function datasource(): Promise { - if (!container) { - container = await start() +export async function getDatasource(): Promise { + if (!ports) { + ports = startContainer( + new GenericContainer("mariadb:lts") + .withExposedPorts(3306) + .withEnvironment({ MARIADB_ROOT_PASSWORD: "password" }) + .withWaitStrategy(new MariaDBWaitStrategy()) + ) } - const host = container.getHost() - const port = container.getMappedPort(3306) - return { + const port = (await ports).find(x => x.container === 3306)?.host + if (!port) { + throw new Error("MariaDB port not found") + } + + const config = { + host: "127.0.0.1", + port, + user: "root", + password: "password", + database: "mysql", + } + + const datasource = { type: "datasource_plus", source: SourceName.MYSQL, plus: true, - config: { - host, - port, - user: "root", - password: "password", - database: "mysql", - }, + config, } -} -export async function stop() { - if (container) { - await container.stop() - container = undefined - } + const database = generator.guid().replaceAll("-", "") + await rawQuery(datasource, `CREATE DATABASE \`${database}\``) + datasource.config.database = database + return datasource } diff --git a/packages/server/src/integrations/tests/utils/mongodb.ts b/packages/server/src/integrations/tests/utils/mongodb.ts index 0baafc6276..0bdbb2808c 100644 --- a/packages/server/src/integrations/tests/utils/mongodb.ts +++ b/packages/server/src/integrations/tests/utils/mongodb.ts @@ -1,43 +1,39 @@ +import { generator, testContainerUtils } from "@budibase/backend-core/tests" import { Datasource, SourceName } from "@budibase/types" -import { GenericContainer, Wait, StartedTestContainer } from "testcontainers" +import { GenericContainer, Wait } from "testcontainers" +import { startContainer } from "." -let container: StartedTestContainer | undefined +let ports: Promise -export async function start(): Promise { - return await new GenericContainer("mongo:7.0-jammy") - .withExposedPorts(27017) - .withEnvironment({ - MONGO_INITDB_ROOT_USERNAME: "mongo", - MONGO_INITDB_ROOT_PASSWORD: "password", - }) - .withWaitStrategy( - Wait.forSuccessfulCommand( - `mongosh --eval "db.version()"` - ).withStartupTimeout(10000) +export async function getDatasource(): Promise { + if (!ports) { + ports = startContainer( + new GenericContainer("mongo:7.0-jammy") + .withExposedPorts(27017) + .withEnvironment({ + MONGO_INITDB_ROOT_USERNAME: "mongo", + MONGO_INITDB_ROOT_PASSWORD: "password", + }) + .withWaitStrategy( + Wait.forSuccessfulCommand( + `mongosh --eval "db.version()"` + ).withStartupTimeout(10000) + ) ) - .start() -} - -export async function datasource(): Promise { - if (!container) { - container = await start() } - const host = container.getHost() - const port = container.getMappedPort(27017) + + const port = (await ports).find(x => x.container === 27017) + if (!port) { + throw new Error("MongoDB port not found") + } + return { type: "datasource", source: SourceName.MONGODB, plus: false, config: { - connectionString: `mongodb://mongo:password@${host}:${port}`, - db: "mongo", + connectionString: `mongodb://mongo:password@127.0.0.1:${port.host}`, + db: generator.guid(), }, } } - -export async function stop() { - if (container) { - await container.stop() - container = undefined - } -} diff --git a/packages/server/src/integrations/tests/utils/mssql.ts b/packages/server/src/integrations/tests/utils/mssql.ts index 6bd4290a90..647f461272 100644 --- a/packages/server/src/integrations/tests/utils/mssql.ts +++ b/packages/server/src/integrations/tests/utils/mssql.ts @@ -1,43 +1,41 @@ import { Datasource, SourceName } from "@budibase/types" -import { GenericContainer, Wait, StartedTestContainer } from "testcontainers" +import { GenericContainer, Wait } from "testcontainers" +import mssql from "mssql" +import { generator, testContainerUtils } from "@budibase/backend-core/tests" +import { startContainer } from "." -let container: StartedTestContainer | undefined +let ports: Promise -export async function start(): Promise { - return await new GenericContainer( - "mcr.microsoft.com/mssql/server:2022-latest" - ) - .withExposedPorts(1433) - .withEnvironment({ - ACCEPT_EULA: "Y", - MSSQL_SA_PASSWORD: "Password_123", - // This is important, as Microsoft allow us to use the "Developer" edition - // of SQL Server for development and testing purposes. We can't use other - // versions without a valid license, and we cannot use the Developer - // version in production. - MSSQL_PID: "Developer", - }) - .withWaitStrategy( - Wait.forSuccessfulCommand( - "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" - ) +export async function getDatasource(): Promise { + if (!ports) { + ports = startContainer( + new GenericContainer("mcr.microsoft.com/mssql/server:2022-latest") + .withExposedPorts(1433) + .withEnvironment({ + ACCEPT_EULA: "Y", + MSSQL_SA_PASSWORD: "Password_123", + // This is important, as Microsoft allow us to use the "Developer" edition + // of SQL Server for development and testing purposes. We can't use other + // versions without a valid license, and we cannot use the Developer + // version in production. + MSSQL_PID: "Developer", + }) + .withWaitStrategy( + Wait.forSuccessfulCommand( + "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" + ) + ) ) - .start() -} - -export async function datasource(): Promise { - if (!container) { - container = await start() } - const host = container.getHost() - const port = container.getMappedPort(1433) - return { + const port = (await ports).find(x => x.container === 1433)?.host + + const datasource: Datasource = { type: "datasource_plus", source: SourceName.SQL_SERVER, plus: true, config: { - server: host, + server: "127.0.0.1", port, user: "sa", password: "Password_123", @@ -46,11 +44,28 @@ export async function datasource(): Promise { }, }, } + + const database = generator.guid().replaceAll("-", "") + await rawQuery(datasource, `CREATE DATABASE "${database}"`) + datasource.config!.database = database + + return datasource } -export async function stop() { - if (container) { - await container.stop() - container = undefined +export async function rawQuery(ds: Datasource, sql: string) { + if (!ds.config) { + throw new Error("Datasource config is missing") + } + if (ds.source !== SourceName.SQL_SERVER) { + throw new Error("Datasource source is not SQL Server") + } + + const pool = new mssql.ConnectionPool(ds.config! as mssql.config) + const client = await pool.connect() + try { + const { recordset } = await client.query(sql) + return recordset + } finally { + await pool.close() } } diff --git a/packages/server/src/integrations/tests/utils/mysql.ts b/packages/server/src/integrations/tests/utils/mysql.ts index 5e51478998..a78833e1de 100644 --- a/packages/server/src/integrations/tests/utils/mysql.ts +++ b/packages/server/src/integrations/tests/utils/mysql.ts @@ -1,8 +1,11 @@ import { Datasource, SourceName } from "@budibase/types" -import { GenericContainer, Wait, StartedTestContainer } from "testcontainers" +import { GenericContainer, Wait } from "testcontainers" import { AbstractWaitStrategy } from "testcontainers/build/wait-strategies/wait-strategy" +import mysql from "mysql2/promise" +import { generator, testContainerUtils } from "@budibase/backend-core/tests" +import { startContainer } from "." -let container: StartedTestContainer | undefined +let ports: Promise class MySQLWaitStrategy extends AbstractWaitStrategy { async waitUntilReady(container: any, boundPorts: any, startTime?: Date) { @@ -24,38 +27,50 @@ class MySQLWaitStrategy extends AbstractWaitStrategy { } } -export async function start(): Promise { - return await new GenericContainer("mysql:8.3") - .withExposedPorts(3306) - .withEnvironment({ MYSQL_ROOT_PASSWORD: "password" }) - .withWaitStrategy(new MySQLWaitStrategy().withStartupTimeout(10000)) - .start() -} - -export async function datasource(): Promise { - if (!container) { - container = await start() +export async function getDatasource(): Promise { + if (!ports) { + ports = startContainer( + new GenericContainer("mysql:8.3") + .withExposedPorts(3306) + .withEnvironment({ MYSQL_ROOT_PASSWORD: "password" }) + .withWaitStrategy(new MySQLWaitStrategy().withStartupTimeout(10000)) + ) } - const host = container.getHost() - const port = container.getMappedPort(3306) - return { + const port = (await ports).find(x => x.container === 3306)?.host + + const datasource: Datasource = { type: "datasource_plus", source: SourceName.MYSQL, plus: true, config: { - host, + host: "127.0.0.1", port, user: "root", password: "password", database: "mysql", }, } + + const database = generator.guid().replaceAll("-", "") + await rawQuery(datasource, `CREATE DATABASE \`${database}\``) + datasource.config!.database = database + return datasource } -export async function stop() { - if (container) { - await container.stop() - container = undefined +export async function rawQuery(ds: Datasource, sql: string) { + if (!ds.config) { + throw new Error("Datasource config is missing") + } + if (ds.source !== SourceName.MYSQL) { + throw new Error("Datasource source is not MySQL") + } + + const connection = await mysql.createConnection(ds.config) + try { + const [rows] = await connection.query(sql) + return rows + } finally { + connection.end() } } diff --git a/packages/server/src/integrations/tests/utils/postgres.ts b/packages/server/src/integrations/tests/utils/postgres.ts index 82a62e3916..4191b107e9 100644 --- a/packages/server/src/integrations/tests/utils/postgres.ts +++ b/packages/server/src/integrations/tests/utils/postgres.ts @@ -1,33 +1,33 @@ import { Datasource, SourceName } from "@budibase/types" -import { GenericContainer, Wait, StartedTestContainer } from "testcontainers" +import { GenericContainer, Wait } from "testcontainers" +import pg from "pg" +import { generator, testContainerUtils } from "@budibase/backend-core/tests" +import { startContainer } from "." -let container: StartedTestContainer | undefined +let ports: Promise -export async function start(): Promise { - return await new GenericContainer("postgres:16.1-bullseye") - .withExposedPorts(5432) - .withEnvironment({ POSTGRES_PASSWORD: "password" }) - .withWaitStrategy( - Wait.forSuccessfulCommand( - "pg_isready -h localhost -p 5432" - ).withStartupTimeout(10000) +export async function getDatasource(): Promise { + if (!ports) { + ports = startContainer( + new GenericContainer("postgres:16.1-bullseye") + .withExposedPorts(5432) + .withEnvironment({ POSTGRES_PASSWORD: "password" }) + .withWaitStrategy( + Wait.forSuccessfulCommand( + "pg_isready -h localhost -p 5432" + ).withStartupTimeout(10000) + ) ) - .start() -} - -export async function datasource(): Promise { - if (!container) { - container = await start() } - const host = container.getHost() - const port = container.getMappedPort(5432) - return { + const port = (await ports).find(x => x.container === 5432)?.host + + const datasource: Datasource = { type: "datasource_plus", source: SourceName.POSTGRES, plus: true, config: { - host, + host: "127.0.0.1", port, database: "postgres", user: "postgres", @@ -38,11 +38,28 @@ export async function datasource(): Promise { ca: false, }, } + + const database = generator.guid().replaceAll("-", "") + await rawQuery(datasource, `CREATE DATABASE "${database}"`) + datasource.config!.database = database + + return datasource } -export async function stop() { - if (container) { - await container.stop() - container = undefined +export async function rawQuery(ds: Datasource, sql: string) { + if (!ds.config) { + throw new Error("Datasource config is missing") + } + if (ds.source !== SourceName.POSTGRES) { + throw new Error("Datasource source is not Postgres") + } + + const client = new pg.Client(ds.config) + await client.connect() + try { + const { rows } = await client.query(sql) + return rows + } finally { + await client.end() } } diff --git a/packages/server/src/migrations/tests/index.spec.ts b/packages/server/src/migrations/tests/index.spec.ts index 8eb59b8a0e..d06cd37b69 100644 --- a/packages/server/src/migrations/tests/index.spec.ts +++ b/packages/server/src/migrations/tests/index.spec.ts @@ -25,8 +25,6 @@ const clearMigrations = async () => { } } -jest.setTimeout(10000) - describe("migrations", () => { const config = new TestConfig() diff --git a/packages/server/src/sdk/app/rows/search/tests/external.spec.ts b/packages/server/src/sdk/app/rows/search/tests/external.spec.ts index bae58d6a2c..596e41cece 100644 --- a/packages/server/src/sdk/app/rows/search/tests/external.spec.ts +++ b/packages/server/src/sdk/app/rows/search/tests/external.spec.ts @@ -17,8 +17,6 @@ import { generator, } from "@budibase/backend-core/tests" -jest.setTimeout(30000) - describe("external search", () => { const config = new TestConfiguration() diff --git a/packages/server/src/sdk/tests/attachments.spec.ts b/packages/server/src/sdk/tests/attachments.spec.ts index 0fd43ac5a8..c1736e6f8e 100644 --- a/packages/server/src/sdk/tests/attachments.spec.ts +++ b/packages/server/src/sdk/tests/attachments.spec.ts @@ -1,4 +1,12 @@ -import newid from "../../db/newid" +import TestConfig from "../../tests/utilities/TestConfiguration" +import { db as dbCore } from "@budibase/backend-core" +import sdk from "../index" +import { + FieldType, + INTERNAL_TABLE_SOURCE_ID, + TableSourceType, +} from "@budibase/types" +import { FIND_LIMIT } from "../app/rows/attachments" const attachment = { size: 73479, @@ -8,69 +16,48 @@ const attachment = { key: "app_bbb/attachments/a.png", } -const row = { - _id: "ro_ta_aaa", - photo: [attachment], - otherCol: "string", -} - -const table = { - _id: "ta_aaa", - name: "photos", - schema: { - photo: { - type: "attachment", - name: "photo", - }, - otherCol: { - type: "string", - name: "otherCol", - }, - }, -} - -jest.mock("@budibase/backend-core", () => { - const core = jest.requireActual("@budibase/backend-core") - return { - ...core, - db: { - ...core.db, - directCouchFind: jest.fn(), - }, - } -}) - -import { db as dbCore } from "@budibase/backend-core" -import sdk from "../index" - describe("should be able to re-write attachment URLs", () => { + const config = new TestConfig() + + beforeAll(async () => { + await config.init() + }) + it("should update URLs on a number of rows over the limit", async () => { - const db = dbCore.getDB("app_aaa") - await db.put(table) - const limit = 30 - let rows = [] - for (let i = 0; i < limit; i++) { - const rowToWrite = { - ...row, - _id: `${row._id}_${newid()}`, - } - const { rev } = await db.put(rowToWrite) - rows.push({ - ...rowToWrite, - _rev: rev, + const table = await config.api.table.save({ + name: "photos", + type: "table", + sourceId: INTERNAL_TABLE_SOURCE_ID, + sourceType: TableSourceType.INTERNAL, + schema: { + photo: { + type: FieldType.ATTACHMENT, + name: "photo", + }, + otherCol: { + type: FieldType.STRING, + name: "otherCol", + }, + }, + }) + + for (let i = 0; i < FIND_LIMIT * 4; i++) { + await config.api.row.save(table._id!, { + photo: [attachment], + otherCol: "string", }) } - dbCore.directCouchFind - // @ts-ignore - .mockReturnValueOnce({ rows: rows.slice(0, 25), bookmark: "aaa" }) - .mockReturnValueOnce({ rows: rows.slice(25, limit), bookmark: "bbb" }) + const db = dbCore.getDB(config.getAppId()) await sdk.backups.updateAttachmentColumns(db.name, db) - const finalRows = await sdk.rows.getAllInternalRows(db.name) - for (let rowToCheck of finalRows) { - expect(rowToCheck.otherCol).toBe(row.otherCol) - expect(rowToCheck.photo[0].url).toBe("") - expect(rowToCheck.photo[0].key).toBe(`${db.name}/attachments/a.png`) + + const rows = (await sdk.rows.getAllInternalRows(db.name)).filter( + row => row.tableId === table._id + ) + for (const row of rows) { + expect(row.otherCol).toBe("string") + expect(row.photo[0].url).toBe("") + expect(row.photo[0].key).toBe(`${db.name}/attachments/a.png`) } }) }) diff --git a/packages/server/src/sdk/users/tests/utils.spec.ts b/packages/server/src/sdk/users/tests/utils.spec.ts index 6f1c5afd3d..0aa112094d 100644 --- a/packages/server/src/sdk/users/tests/utils.spec.ts +++ b/packages/server/src/sdk/users/tests/utils.spec.ts @@ -35,11 +35,20 @@ describe("syncGlobalUsers", () => { builder: { global: true }, }) await config.doInContext(config.appId, async () => { - expect(await rawUserMetadata()).toHaveLength(1) + let metadata = await rawUserMetadata() + expect(metadata).not.toContainEqual( + expect.objectContaining({ + _id: db.generateUserMetadataID(user1._id!), + }) + ) + expect(metadata).not.toContainEqual( + expect.objectContaining({ + _id: db.generateUserMetadataID(user2._id!), + }) + ) await syncGlobalUsers() - const metadata = await rawUserMetadata() - expect(metadata).toHaveLength(3) + metadata = await rawUserMetadata() expect(metadata).toContainEqual( expect.objectContaining({ _id: db.generateUserMetadataID(user1._id!), @@ -62,7 +71,6 @@ describe("syncGlobalUsers", () => { await syncGlobalUsers() const metadata = await rawUserMetadata() - expect(metadata).toHaveLength(1) expect(metadata).not.toContainEqual( expect.objectContaining({ _id: db.generateUserMetadataID(user._id!), diff --git a/packages/server/src/tests/jestSetup.ts b/packages/server/src/tests/jestSetup.ts index e233e7152e..c01f415f9e 100644 --- a/packages/server/src/tests/jestSetup.ts +++ b/packages/server/src/tests/jestSetup.ts @@ -2,17 +2,11 @@ import env from "../environment" import { env as coreEnv, timers } from "@budibase/backend-core" import { testContainerUtils } from "@budibase/backend-core/tests" -if (!process.env.DEBUG) { - global.console.log = jest.fn() // console.log are ignored in tests - global.console.warn = jest.fn() // console.warn are ignored in tests -} - if (!process.env.CI) { - // set a longer timeout in dev for debugging - // 100 seconds + // set a longer timeout in dev for debugging 100 seconds jest.setTimeout(100 * 1000) } else { - jest.setTimeout(10 * 1000) + jest.setTimeout(30 * 1000) } testContainerUtils.setupEnv(env, coreEnv) diff --git a/packages/server/src/tests/utilities/api/base.ts b/packages/server/src/tests/utilities/api/base.ts index 4df58ff425..3a5f6529f8 100644 --- a/packages/server/src/tests/utilities/api/base.ts +++ b/packages/server/src/tests/utilities/api/base.ts @@ -1,6 +1,7 @@ import TestConfiguration from "../TestConfiguration" -import { SuperTest, Test, Response } from "supertest" +import request, { SuperTest, Test, Response } from "supertest" import { ReadStream } from "fs" +import { getServer } from "../../../app" type Headers = Record type Method = "get" | "post" | "put" | "patch" | "delete" @@ -76,7 +77,8 @@ export abstract class TestAPI { protected _requestRaw = async ( method: "get" | "post" | "put" | "patch" | "delete", url: string, - opts?: RequestOpts + opts?: RequestOpts, + attempt = 0 ): Promise => { const { headers = {}, @@ -107,26 +109,29 @@ export abstract class TestAPI { const headersFn = publicUser ? this.config.publicHeaders.bind(this.config) : this.config.defaultHeaders.bind(this.config) - let request = this.request[method](url).set( + + const app = getServer() + let req = request(app)[method](url) + req = req.set( headersFn({ "x-budibase-include-stacktrace": "true", }) ) if (headers) { - request = request.set(headers) + req = req.set(headers) } if (body) { - request = request.send(body) + req = req.send(body) } for (const [key, value] of Object.entries(fields)) { - request = request.field(key, value) + req = req.field(key, value) } for (const [key, value] of Object.entries(files)) { if (isAttachedFile(value)) { - request = request.attach(key, value.file, value.name) + req = req.attach(key, value.file, value.name) } else { - request = request.attach(key, value as any) + req = req.attach(key, value as any) } } if (expectations?.headers) { @@ -136,11 +141,25 @@ export abstract class TestAPI { `Got an undefined expected value for header "${key}", if you want to check for the absence of a header, use headersNotPresent` ) } - request = request.expect(key, value as any) + req = req.expect(key, value as any) } } - return await request + try { + return await req + } catch (e: any) { + // We've found that occasionally the connection between supertest and the + // server supertest starts gets reset. Not sure why, but retrying it + // appears to work. I don't particularly like this, but it's better than + // flakiness. + if (e.code === "ECONNRESET") { + if (attempt > 2) { + throw e + } + return await this._requestRaw(method, url, opts, attempt + 1) + } + throw e + } } protected _checkResponse = ( @@ -170,7 +189,18 @@ export abstract class TestAPI { } } - throw new Error(message) + if (response.error) { + // Sometimes the error can be between supertest and the app, and when + // that happens response.error is sometimes populated with `text` that + // gives more detail about the error. The `message` is almost always + // useless from what I've seen. + if (response.error.text) { + response.error.message = response.error.text + } + throw new Error(message, { cause: response.error }) + } else { + throw new Error(message) + } } if (expectations?.headersNotPresent) { diff --git a/packages/server/src/tests/utilities/api/datasource.ts b/packages/server/src/tests/utilities/api/datasource.ts index 06aa9b4e1e..0296f58f7d 100644 --- a/packages/server/src/tests/utilities/api/datasource.ts +++ b/packages/server/src/tests/utilities/api/datasource.ts @@ -4,6 +4,7 @@ import { CreateDatasourceResponse, UpdateDatasourceResponse, UpdateDatasourceRequest, + QueryJson, } from "@budibase/types" import { Expectations, TestAPI } from "./base" @@ -45,4 +46,24 @@ export class DatasourceAPI extends TestAPI { expectations, }) } + + delete = async (datasource: Datasource, expectations?: Expectations) => { + return await this._delete( + `/api/datasources/${datasource._id!}/${datasource._rev!}`, + { expectations } + ) + } + + get = async (id: string, expectations?: Expectations) => { + return await this._get(`/api/datasources/${id}`, { + expectations, + }) + } + + query = async (query: QueryJson, expectations?: Expectations) => { + return await this._post(`/api/datasources/query`, { + body: query, + expectations, + }) + } } diff --git a/packages/server/src/tests/utilities/api/query.ts b/packages/server/src/tests/utilities/api/query.ts index 089132dee8..2d5f7970cd 100644 --- a/packages/server/src/tests/utilities/api/query.ts +++ b/packages/server/src/tests/utilities/api/query.ts @@ -6,10 +6,11 @@ import { PreviewQueryResponse, } from "@budibase/types" import { Expectations, TestAPI } from "./base" +import { constants } from "@budibase/backend-core" export class QueryAPI extends TestAPI { - save = async (body: Query): Promise => { - return await this._post(`/api/queries`, { body }) + save = async (body: Query, expectations?: Expectations): Promise => { + return await this._post(`/api/queries`, { body, expectations }) } execute = async ( @@ -26,9 +27,36 @@ export class QueryAPI extends TestAPI { ) } - previewQuery = async (queryPreview: PreviewQueryRequest) => { + preview = async ( + queryPreview: PreviewQueryRequest, + expectations?: Expectations + ) => { return await this._post(`/api/queries/preview`, { body: queryPreview, + expectations, }) } + + delete = async (query: Query, expectations?: Expectations) => { + return await this._delete(`/api/queries/${query._id!}/${query._rev!}`, { + expectations, + }) + } + + get = async (queryId: string, expectations?: Expectations) => { + return await this._get(`/api/queries/${queryId}`, { expectations }) + } + + getProd = async (queryId: string, expectations?: Expectations) => { + return await this._get(`/api/queries/${queryId}`, { + expectations, + headers: { + [constants.Header.APP_ID]: this.config.getProdAppId(), + }, + }) + } + + fetch = async (expectations?: Expectations) => { + return await this._get(`/api/queries`, { expectations }) + } } diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts index 97e7a05cf7..54322b1156 100644 --- a/packages/server/src/threads/query.ts +++ b/packages/server/src/threads/query.ts @@ -167,7 +167,7 @@ class QueryRunner { this.hasRerun = true } - await threadUtils.invalidateDynamicVariables(this.cachedVariables) + await threadUtils.invalidateCachedVariable(this.cachedVariables) return this.execute() } @@ -254,7 +254,7 @@ class QueryRunner { let { parameters } = this const queryId = variable.queryId, name = variable.name - let value = await threadUtils.checkCacheForDynamicVariable(queryId, name) + let value = await threadUtils.getCachedVariable(queryId, name) if (!value) { value = this.queryResponse[queryId] ? this.queryResponse[queryId] diff --git a/packages/server/src/threads/utils.ts b/packages/server/src/threads/utils.ts index cd547cacae..bf0d8f2231 100644 --- a/packages/server/src/threads/utils.ts +++ b/packages/server/src/threads/utils.ts @@ -5,7 +5,7 @@ import { redis, db as dbCore } from "@budibase/backend-core" import * as jsRunner from "../jsRunner" const VARIABLE_TTL_SECONDS = 3600 -let client: any +let client: redis.Client | null = null async function getClient() { if (!client) { @@ -36,23 +36,15 @@ export function threadSetup() { db.init() } -export async function checkCacheForDynamicVariable( - queryId: string, - variable: string -) { - const cache = await getClient() - return cache.get(makeVariableKey(queryId, variable)) +export async function getCachedVariable(queryId: string, variable: string) { + return (await getClient()).get(makeVariableKey(queryId, variable)) } -export async function invalidateDynamicVariables(cachedVars: QueryVariable[]) { +export async function invalidateCachedVariable(vars: QueryVariable[]) { const cache = await getClient() - let promises = [] - for (let variable of cachedVars) { - promises.push( - cache.delete(makeVariableKey(variable.queryId, variable.name)) - ) - } - await Promise.all(promises) + await Promise.all( + vars.map(v => cache.delete(makeVariableKey(v.queryId, v.name))) + ) } export async function storeDynamicVariable( @@ -93,7 +85,7 @@ export default { hasExtraData, formatResponse, storeDynamicVariable, - invalidateDynamicVariables, - checkCacheForDynamicVariable, + invalidateCachedVariable, + getCachedVariable, threadSetup, } diff --git a/packages/server/src/utilities/schema.ts b/packages/server/src/utilities/schema.ts index 85dfdd3506..34113759ed 100644 --- a/packages/server/src/utilities/schema.ts +++ b/packages/server/src/utilities/schema.ts @@ -54,7 +54,7 @@ export function validate(rows: Rows, schema: TableSchema): ValidationResults { type: columnType, subtype: columnSubtype, autocolumn: isAutoColumn, - } = schema[columnName] + } = schema[columnName] || {} // If the column had an invalid value we don't want to override it if (results.schemaValidation[columnName] === false) { diff --git a/qa-core/.gitignore b/qa-core/.gitignore deleted file mode 100644 index 4c442c31dc..0000000000 --- a/qa-core/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -.env -watchtower-hook.json -dist/ -testResults.json diff --git a/qa-core/README.md b/qa-core/README.md deleted file mode 100644 index 8390f276d9..0000000000 --- a/qa-core/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# QA Core API Tests - -The QA Core API tests are a jest suite that run directly against the budibase backend APIs. - -## Auto Setup - -You can run the whole test suite with one command, that spins up the budibase server and runs the jest tests: - -`yarn test:ci` - -## Setup Server - -You can run the local development stack by following the instructions on the main readme. - -## Run Tests - -If you configured the server using the previous command, you can run the whole test suite by using: - -`yarn test` - -for watch mode, where the tests will run on every change: - -`yarn test:watch` - -To run tests locally against a cloud service you can update the configuration inside the `.env` file and run: - -`yarn test` - diff --git a/qa-core/jest.config.ts b/qa-core/jest.config.ts deleted file mode 100644 index eb942eca97..0000000000 --- a/qa-core/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Config } from "@jest/types" - -const config: Config.InitialOptions = { - preset: "ts-jest", - setupFiles: ["./src/jest/jestSetup.ts"], - setupFilesAfterEnv: ["./src/jest/jest.extends.ts"], - testEnvironment: "node", - transform: { - "^.+\\.ts?$": "@swc/jest", - }, - globalSetup: "./src/jest/globalSetup.ts", - globalTeardown: "./src/jest/globalTeardown.ts", - moduleNameMapper: { - "@budibase/types": "/../packages/types/src", - "@budibase/server": "/../packages/server/src", - "@budibase/backend-core": "/../packages/backend-core/src", - "@budibase/backend-core/(.*)": "/../packages/backend-core/$1", - }, -} - -export default config diff --git a/qa-core/package.json b/qa-core/package.json deleted file mode 100644 index 2d040af0ea..0000000000 --- a/qa-core/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "@budibase/qa-core", - "email": "hi@budibase.com", - "version": "0.0.1", - "main": "index.js", - "description": "Budibase Integration Test Suite", - "repository": { - "type": "git", - "url": "https://github.com/Budibase/budibase.git" - }, - "scripts": { - "setup": "yarn && node scripts/createEnv.js", - "user": "yarn && node scripts/createEnv.js && node scripts/createUser.js", - "test": "jest --runInBand --json --outputFile=testResults.json --forceExit", - "test:watch": "yarn run test --watch", - "test:debug": "DEBUG=1 yarn run test", - "test:notify": "node scripts/testResultsWebhook", - "test:cloud:prod": "yarn run test --testPathIgnorePatterns=\\.integration\\.", - "test:cloud:qa": "yarn run test", - "test:self:ci": "yarn run test --testPathIgnorePatterns=\\.integration\\. \\.cloud\\. \\.licensing\\.", - "serve:test:self:ci": "start-server-and-test dev:built http://localhost:4001/health test:self:ci", - "serve": "start-server-and-test dev:built http://localhost:4001/health", - "dev:built": "cd ../ && DISABLE_RATE_LIMITING=1 yarn dev:built" - }, - "devDependencies": { - "@budibase/types": "^2.3.17", - "@swc/core": "1.3.71", - "@swc/jest": "0.2.27", - "@trendyol/jest-testcontainers": "2.1.1", - "@types/jest": "29.5.3", - "@types/node-fetch": "2.6.4", - "chance": "1.1.8", - "dotenv": "16.0.1", - "jest": "29.7.0", - "prettier": "2.7.1", - "start-server-and-test": "1.14.0", - "timekeeper": "2.2.0", - "ts-jest": "29.1.1", - "ts-node": "10.8.1", - "tsconfig-paths": "4.0.0", - "typescript": "5.2.2" - }, - "dependencies": { - "@budibase/backend-core": "^2.3.17", - "form-data": "^4.0.0", - "node-fetch": "2.6.7", - "stripe": "^14.11.0" - } -} diff --git a/qa-core/scripts/createEnv.js b/qa-core/scripts/createEnv.js deleted file mode 100644 index 64b9664049..0000000000 --- a/qa-core/scripts/createEnv.js +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env node -const path = require("path") -const fs = require("fs") - -function init() { - const envFilePath = path.join(process.cwd(), ".env") - if (!fs.existsSync(envFilePath)) { - const envFileJson = { - BUDIBASE_URL: "http://localhost:10000", - ACCOUNT_PORTAL_URL: "http://localhost:10001", - ACCOUNT_PORTAL_API_KEY: "budibase", - BB_ADMIN_USER_EMAIL: "admin", - BB_ADMIN_USER_PASSWORD: "admin", - LOG_LEVEL: "info", - JEST_TIMEOUT: "60000", - DISABLE_PINO_LOGGER: "1", - } - let envFile = "" - Object.keys(envFileJson).forEach(key => { - envFile += `${key}=${envFileJson[key]}\n` - }) - fs.writeFileSync(envFilePath, envFile) - } -} - -init() diff --git a/qa-core/scripts/createUser.js b/qa-core/scripts/createUser.js deleted file mode 100644 index 200bf91fc4..0000000000 --- a/qa-core/scripts/createUser.js +++ /dev/null @@ -1,49 +0,0 @@ -const dotenv = require("dotenv") -const { join } = require("path") -const fs = require("fs") -const fetch = require("node-fetch") - -function getVarFromDotEnv(path, varName) { - const parsed = dotenv.parse(fs.readFileSync(path)) - return parsed[varName] -} - -async function createUser() { - const serverPath = join(__dirname, "..", "..", "packages", "server", ".env") - const qaCorePath = join(__dirname, "..", ".env") - const apiKey = getVarFromDotEnv(serverPath, "INTERNAL_API_KEY") - const username = getVarFromDotEnv(qaCorePath, "BB_ADMIN_USER_EMAIL") - const password = getVarFromDotEnv(qaCorePath, "BB_ADMIN_USER_PASSWORD") - const url = getVarFromDotEnv(qaCorePath, "BUDIBASE_URL") - const resp = await fetch(`${url}/api/public/v1/users`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "x-budibase-api-key": apiKey, - }, - body: JSON.stringify({ - email: username, - password, - builder: { - global: true, - }, - admin: { - global: true, - }, - roles: {}, - }), - }) - if (resp.status !== 200) { - throw new Error(await resp.text()) - } else { - return await resp.json() - } -} - -createUser() - .then(() => { - console.log("User created - ready to use") - }) - .catch(err => { - console.error("Failed to create user - ", err) - }) diff --git a/qa-core/scripts/testResultsWebhook.js b/qa-core/scripts/testResultsWebhook.js deleted file mode 100644 index 5fbdd3a32e..0000000000 --- a/qa-core/scripts/testResultsWebhook.js +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env node - -const fetch = require("node-fetch") -const path = require("path") -const fs = require("fs") - -const WEBHOOK_URL = process.env.WEBHOOK_URL -const GIT_SHA = process.env.GITHUB_SHA -const GITHUB_ACTIONS_RUN_URL = process.env.GITHUB_ACTIONS_RUN_URL - -async function generateReport() { - // read the report file - const REPORT_PATH = path.resolve(__dirname, "..", "testResults.json") - const report = fs.readFileSync(REPORT_PATH, "utf-8") - return JSON.parse(report) -} - -const env = process.argv.slice(2)[0] - -if (!env) { - throw new Error("environment argument is required") -} - -async function discordResultsNotification(report) { - const { - numTotalTestSuites, - numTotalTests, - numPassedTests, - numPendingTests, - numFailedTests, - success, - startTime, - endTime, - } = report - - const OUTCOME = success ? "success" : "failure" - - const options = { - method: "POST", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify({ - content: `**Tests Status**: ${OUTCOME}`, - embeds: [ - { - title: `Budi QA Bot - ${env}`, - description: `API Integration Tests`, - url: GITHUB_ACTIONS_RUN_URL, - color: OUTCOME === "success" ? 3066993 : 15548997, - timestamp: new Date(), - footer: { - icon_url: "http://bbui.budibase.com/budibase-logo.png", - text: "Budibase QA Bot", - }, - thumbnail: { - url: "http://bbui.budibase.com/budibase-logo.png", - }, - author: { - name: "Budibase QA Bot", - url: "https://discordapp.com", - icon_url: "http://bbui.budibase.com/budibase-logo.png", - }, - fields: [ - { - name: "Commit", - value: `https://github.com/Budibase/budibase/commit/${GIT_SHA}`, - }, - { - name: "Github Actions Run URL", - value: GITHUB_ACTIONS_RUN_URL || "None Supplied", - }, - { - name: "Test Suites", - value: numTotalTestSuites, - }, - { - name: "Tests", - value: numTotalTests, - }, - { - name: "Passed", - value: numPassedTests, - }, - { - name: "Pending", - value: numPendingTests, - }, - { - name: "Failures", - value: numFailedTests, - }, - { - name: "Duration", - value: endTime - ? `${(endTime - startTime) / 1000} Seconds` - : "DNF", - }, - { - name: "Pass Percentage", - value: Math.floor((numPassedTests / numTotalTests) * 100), - }, - ], - }, - ], - }), - } - - // Only post in discord when tests fail - if (success) { - return - } - - const response = await fetch(WEBHOOK_URL, options) - - if (response.status >= 201) { - const text = await response.text() - console.error( - `Error sending discord webhook. \nStatus: ${response.status}. \nResponse Body: ${text}. \nRequest Body: ${options.body}` - ) - } -} - -async function run() { - const report = await generateReport() - await discordResultsNotification(report) -} - -run() diff --git a/qa-core/src/account-api/api/AccountInternalAPI.ts b/qa-core/src/account-api/api/AccountInternalAPI.ts deleted file mode 100644 index f89bf556f2..0000000000 --- a/qa-core/src/account-api/api/AccountInternalAPI.ts +++ /dev/null @@ -1,20 +0,0 @@ -import AccountInternalAPIClient from "./AccountInternalAPIClient" -import { AccountAPI, LicenseAPI, AuthAPI, StripeAPI } from "./apis" -import { State } from "../../types" - -export default class AccountInternalAPI { - client: AccountInternalAPIClient - - auth: AuthAPI - accounts: AccountAPI - licenses: LicenseAPI - stripe: StripeAPI - - constructor(state: State) { - this.client = new AccountInternalAPIClient(state) - this.auth = new AuthAPI(this.client) - this.accounts = new AccountAPI(this.client) - this.licenses = new LicenseAPI(this.client) - this.stripe = new StripeAPI(this.client) - } -} diff --git a/qa-core/src/account-api/api/AccountInternalAPIClient.ts b/qa-core/src/account-api/api/AccountInternalAPIClient.ts deleted file mode 100644 index 9c5fbec3af..0000000000 --- a/qa-core/src/account-api/api/AccountInternalAPIClient.ts +++ /dev/null @@ -1,89 +0,0 @@ -import fetch, { Response, HeadersInit } from "node-fetch" -import env from "../../environment" -import { State } from "../../types" -import { Header } from "@budibase/backend-core" - -type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" - -interface ApiOptions { - method?: APIMethod - body?: object - headers?: HeadersInit | undefined - internal?: boolean -} - -export default class AccountInternalAPIClient { - state: State - host: string - - constructor(state: State) { - if (!env.ACCOUNT_PORTAL_URL) { - throw new Error("Must set ACCOUNT_PORTAL_URL env var") - } - if (!env.ACCOUNT_PORTAL_API_KEY) { - throw new Error("Must set ACCOUNT_PORTAL_API_KEY env var") - } - this.host = `${env.ACCOUNT_PORTAL_URL}` - this.state = state - } - - apiCall = - (method: APIMethod) => - async (url = "", options: ApiOptions = {}): Promise<[Response, any]> => { - const requestOptions = { - method, - body: JSON.stringify(options.body), - headers: { - "Content-Type": "application/json", - Accept: "application/json", - cookie: this.state.cookie, - redirect: "follow", - follow: 20, - ...options.headers, - }, - credentials: "include", - } - - if (options.internal) { - requestOptions.headers = { - ...requestOptions.headers, - ...{ [Header.API_KEY]: env.ACCOUNT_PORTAL_API_KEY }, - cookie: "", - } - } - - // @ts-ignore - const response = await fetch(`${this.host}${url}`, requestOptions) - - let body: any - const contentType = response.headers.get("content-type") - if (contentType && contentType.includes("application/json")) { - body = await response.json() - } else { - body = await response.text() - } - - const data = { - request: requestOptions.body, - response: body, - } - const message = `${method} ${url} - ${response.status}` - - const isDebug = process.env.LOG_LEVEL === "debug" - if (response.status > 499) { - console.error(message, data) - } else if (response.status >= 400) { - console.warn(message, data) - } else if (isDebug) { - console.debug(message, data) - } - - return [response, body] - } - - post = this.apiCall("POST") - get = this.apiCall("GET") - patch = this.apiCall("PATCH") - del = this.apiCall("DELETE") - put = this.apiCall("PUT") -} diff --git a/qa-core/src/account-api/api/apis/AccountAPI.ts b/qa-core/src/account-api/api/apis/AccountAPI.ts deleted file mode 100644 index 13c7e1709d..0000000000 --- a/qa-core/src/account-api/api/apis/AccountAPI.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Response } from "node-fetch" -import { - Account, - CreateAccountRequest, - SearchAccountsRequest, - SearchAccountsResponse, -} from "@budibase/types" -import AccountInternalAPIClient from "../AccountInternalAPIClient" -import { APIRequestOpts } from "../../../types" -import { Header } from "@budibase/backend-core" -import BaseAPI from "./BaseAPI" - -export default class AccountAPI extends BaseAPI { - client: AccountInternalAPIClient - - constructor(client: AccountInternalAPIClient) { - super() - this.client = client - } - - async validateEmail(email: string, opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.post(`/api/accounts/validate/email`, { - body: { email }, - }) - }, opts) - } - - async validateTenantId( - tenantId: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/accounts/validate/tenantId`, { - body: { tenantId }, - }) - }, opts) - } - - async create( - body: CreateAccountRequest, - opts: APIRequestOpts & { autoVerify: boolean } = { - status: 201, - autoVerify: false, - } - ): Promise<[Response, Account]> { - return this.doRequest(() => { - const headers = { - "no-verify": opts.autoVerify ? "1" : "0", - } - return this.client.post(`/api/accounts`, { - body, - headers, - }) - }, opts) - } - - async delete(accountID: string, opts: APIRequestOpts = { status: 204 }) { - return this.doRequest(() => { - return this.client.del(`/api/accounts/${accountID}`, { - internal: true, - }) - }, opts) - } - - async deleteCurrentAccount(opts: APIRequestOpts = { status: 204 }) { - return this.doRequest(() => { - return this.client.del(`/api/accounts`) - }, opts) - } - - async verifyAccount( - verificationCode: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/accounts/verify`, { - body: { verificationCode }, - }) - }, opts) - } - - async sendVerificationEmail( - email: string, - opts: APIRequestOpts = { status: 200 } - ): Promise<[Response, string]> { - return this.doRequest(async () => { - const [response] = await this.client.post(`/api/accounts/verify/send`, { - body: { email }, - headers: { - [Header.RETURN_VERIFICATION_CODE]: "1", - }, - }) - const code = response.headers.get(Header.VERIFICATION_CODE) - return [response, code] - }, opts) - } - - async search( - searchType: string, - search: "email" | "tenantId", - opts: APIRequestOpts = { status: 200 } - ): Promise<[Response, SearchAccountsResponse]> { - return this.doRequest(() => { - let body: SearchAccountsRequest = {} - if (search === "email") { - body.email = searchType - } else if (search === "tenantId") { - body.tenantId = searchType - } - return this.client.post(`/api/accounts/search`, { - body, - internal: true, - }) - }, opts) - } - - async self(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/auth/self`) - }, opts) - } -} diff --git a/qa-core/src/account-api/api/apis/AuthAPI.ts b/qa-core/src/account-api/api/apis/AuthAPI.ts deleted file mode 100644 index 304b13db57..0000000000 --- a/qa-core/src/account-api/api/apis/AuthAPI.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Response } from "node-fetch" -import AccountInternalAPIClient from "../AccountInternalAPIClient" -import { APIRequestOpts } from "../../../types" -import BaseAPI from "./BaseAPI" -import { Header } from "@budibase/backend-core" - -export default class AuthAPI extends BaseAPI { - client: AccountInternalAPIClient - - constructor(client: AccountInternalAPIClient) { - super() - this.client = client - } - - async login( - email: string, - password: string, - opts: APIRequestOpts = { doExpect: true, status: 200 } - ): Promise<[Response, string]> { - return this.doRequest(async () => { - const [res] = await this.client.post(`/api/auth/login`, { - body: { - email: email, - password: password, - }, - }) - const cookie = res.headers.get("set-cookie") - return [res, cookie] - }, opts) - } - - async logout(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.post(`/api/auth/logout`) - }, opts) - } - - async resetPassword( - email: string, - opts: APIRequestOpts = { status: 200 } - ): Promise<[Response, string]> { - return this.doRequest(async () => { - const [response] = await this.client.post(`/api/auth/reset`, { - body: { email }, - headers: { - [Header.RETURN_RESET_PASSWORD_CODE]: "1", - }, - }) - const code = response.headers.get(Header.RESET_PASSWORD_CODE) - return [response, code] - }, opts) - } - - async resetPasswordUpdate( - resetCode: string, - password: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/auth/reset/update`, { - body: { - resetCode: resetCode, - password: password, - }, - }) - }, opts) - } -} diff --git a/qa-core/src/account-api/api/apis/BaseAPI.ts b/qa-core/src/account-api/api/apis/BaseAPI.ts deleted file mode 100644 index ed5d261e9e..0000000000 --- a/qa-core/src/account-api/api/apis/BaseAPI.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Response } from "node-fetch" -import { APIRequestOpts } from "../../../types" - -export default class BaseAPI { - async doRequest( - request: () => Promise<[Response, any]>, - opts: APIRequestOpts - ): Promise<[Response, any]> { - const [response, body] = await request() - - // do expect on by default - if (opts.doExpect === undefined) { - opts.doExpect = true - } - if (opts.doExpect && opts.status) { - expect(response).toHaveStatusCode(opts.status) - } - return [response, body] - } -} diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts deleted file mode 100644 index 8f6e705e5f..0000000000 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ /dev/null @@ -1,140 +0,0 @@ -import AccountInternalAPIClient from "../AccountInternalAPIClient" -import { - Account, - CreateOfflineLicenseRequest, - GetLicenseKeyResponse, - GetOfflineLicenseResponse, - UpdateLicenseRequest, -} from "@budibase/types" -import { Response } from "node-fetch" -import BaseAPI from "./BaseAPI" -import { APIRequestOpts } from "../../../types" - -export default class LicenseAPI extends BaseAPI { - client: AccountInternalAPIClient - constructor(client: AccountInternalAPIClient) { - super() - this.client = client - } - async updateLicense( - accountId: string, - body: UpdateLicenseRequest, - opts: APIRequestOpts = { status: 200 } - ): Promise<[Response, Account]> { - return this.doRequest(() => { - return this.client.put(`/api/accounts/${accountId}/license`, { - body, - internal: true, - }) - }, opts) - } - // TODO: Better approach for setting tenant id header - async createOfflineLicense( - accountId: string, - tenantId: string, - body: CreateOfflineLicenseRequest, - opts: { status?: number } = {} - ): Promise { - const [response, json] = await this.client.post( - `/api/internal/accounts/${accountId}/license/offline`, - { - body, - internal: true, - headers: { - "x-budibase-tenant-id": tenantId, - }, - } - ) - expect(response.status).toBe(opts.status ? opts.status : 201) - return response - } - async getOfflineLicense( - accountId: string, - tenantId: string, - opts: { status?: number } = {} - ): Promise<[Response, GetOfflineLicenseResponse]> { - const [response, json] = await this.client.get( - `/api/internal/accounts/${accountId}/license/offline`, - { - internal: true, - headers: { - "x-budibase-tenant-id": tenantId, - }, - } - ) - expect(response.status).toBe(opts.status ? opts.status : 200) - return [response, json] - } - async getLicenseKey( - opts: { status?: number } = {} - ): Promise<[Response, GetLicenseKeyResponse]> { - const [response, json] = await this.client.get(`/api/license/key`) - expect(response.status).toBe(opts.status || 200) - return [response, json] - } - async activateLicense( - apiKey: string, - tenantId: string, - licenseKey: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/license/activate`, { - body: { - apiKey: apiKey, - tenantId: tenantId, - licenseKey: licenseKey, - }, - }) - }, opts) - } - async regenerateLicenseKey(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.post(`/api/license/key/regenerate`, {}) - }, opts) - } - - async getPlans(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/plans`) - }, opts) - } - - async updatePlan(priceId: string, opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.put(`/api/license/plan`, { - body: { priceId }, - }) - }, opts) - } - - async refreshAccountLicense( - accountId: string, - opts: { status?: number } = {} - ): Promise { - const [response, json] = await this.client.post( - `/api/accounts/${accountId}/license/refresh`, - { - internal: true, - } - ) - expect(response.status).toBe(opts.status ? opts.status : 201) - return response - } - - async getLicenseUsage(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/license/usage`) - }, opts) - } - - async licenseUsageTriggered( - opts: { status?: number } = {} - ): Promise { - const [response, json] = await this.client.post( - `/api/license/usage/triggered` - ) - expect(response.status).toBe(opts.status ? opts.status : 201) - return response - } -} diff --git a/qa-core/src/account-api/api/apis/StripeAPI.ts b/qa-core/src/account-api/api/apis/StripeAPI.ts deleted file mode 100644 index aeb027f428..0000000000 --- a/qa-core/src/account-api/api/apis/StripeAPI.ts +++ /dev/null @@ -1,74 +0,0 @@ -import AccountInternalAPIClient from "../AccountInternalAPIClient" -import BaseAPI from "./BaseAPI" -import { APIRequestOpts } from "../../../types" - -export default class StripeAPI extends BaseAPI { - client: AccountInternalAPIClient - - constructor(client: AccountInternalAPIClient) { - super() - this.client = client - } - - async createCheckoutSession( - price: object, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/checkout-session`, { - body: { prices: [price] }, - }) - }, opts) - } - - async checkoutSuccess(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/checkout-success`) - }, opts) - } - - async createPortalSession( - stripeCustomerId: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/portal-session`, { - body: { stripeCustomerId }, - }) - }, opts) - } - - async linkStripeCustomer( - accountId: string, - stripeCustomerId: string, - opts: APIRequestOpts = { status: 200 } - ) { - return this.doRequest(() => { - return this.client.post(`/api/stripe/link`, { - body: { - accountId, - stripeCustomerId, - }, - internal: true, - }) - }, opts) - } - - async getInvoices(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/stripe/invoices`) - }, opts) - } - - async getUpcomingInvoice(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/stripe/upcoming-invoice`) - }, opts) - } - - async getStripeCustomers(opts: APIRequestOpts = { status: 200 }) { - return this.doRequest(() => { - return this.client.get(`/api/stripe/customers`) - }, opts) - } -} diff --git a/qa-core/src/account-api/api/apis/index.ts b/qa-core/src/account-api/api/apis/index.ts deleted file mode 100644 index 5b0cf55110..0000000000 --- a/qa-core/src/account-api/api/apis/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { default as AuthAPI } from "./AuthAPI" -export { default as AccountAPI } from "./AccountAPI" -export { default as LicenseAPI } from "./LicenseAPI" -export { default as StripeAPI } from "./StripeAPI" diff --git a/qa-core/src/account-api/api/index.ts b/qa-core/src/account-api/api/index.ts deleted file mode 100644 index 7a81f60d0b..0000000000 --- a/qa-core/src/account-api/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as AccountInternalAPI } from "./AccountInternalAPI" diff --git a/qa-core/src/account-api/config/TestConfiguration.ts b/qa-core/src/account-api/config/TestConfiguration.ts deleted file mode 100644 index 66adb85ca2..0000000000 --- a/qa-core/src/account-api/config/TestConfiguration.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AccountInternalAPI } from "../api" -import { BudibaseTestConfiguration } from "../../shared" - -export default class TestConfiguration extends BudibaseTestConfiguration { - // apis - api: AccountInternalAPI - - context: T - - constructor() { - super() - this.api = new AccountInternalAPI(this.state) - this.context = {} - } - - async beforeAll() { - await super.beforeAll() - await this.setApiKey() - } - - async afterAll() { - await super.afterAll() - } - - async setApiKey() { - const apiKeyResponse = await this.internalApi.self.getApiKey() - this.state.apiKey = apiKeyResponse.apiKey - } -} diff --git a/qa-core/src/account-api/fixtures/accounts.ts b/qa-core/src/account-api/fixtures/accounts.ts deleted file mode 100644 index 7a3e0598df..0000000000 --- a/qa-core/src/account-api/fixtures/accounts.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { generator } from "../../shared" -import { Hosting, CreateAccountRequest } from "@budibase/types" - -// TODO: Refactor me to central location -export const generateAccount = ( - partial: Partial -): CreateAccountRequest => { - const uuid = generator.guid() - - const email = `${uuid}@budibase.com` - const tenant = `tenant${uuid.replace(/-/g, "")}` - - return { - email, - hosting: Hosting.CLOUD, - name: email, - password: uuid, - profession: "software_engineer", - size: "10+", - tenantId: tenant, - tenantName: tenant, - ...partial, - } -} diff --git a/qa-core/src/account-api/fixtures/index.ts b/qa-core/src/account-api/fixtures/index.ts deleted file mode 100644 index 952f4a8cc8..0000000000 --- a/qa-core/src/account-api/fixtures/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * as accounts from "./accounts" diff --git a/qa-core/src/account-api/index.ts b/qa-core/src/account-api/index.ts deleted file mode 100644 index e1a716605a..0000000000 --- a/qa-core/src/account-api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./api" diff --git a/qa-core/src/account-api/tests/accounts/accounts.cloud.internal.spec.ts b/qa-core/src/account-api/tests/accounts/accounts.cloud.internal.spec.ts deleted file mode 100644 index 56f9110322..0000000000 --- a/qa-core/src/account-api/tests/accounts/accounts.cloud.internal.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { generator } from "../../../shared" -import { Hosting } from "@budibase/types" - -describe("Account Internal Operations", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("performs account deletion by ID", async () => { - // Deleting by unknown id doesn't work - const accountId = generator.guid() - await config.api.accounts.delete(accountId, { status: 404 }) - - // Create new account - const [_, account] = await config.api.accounts.create({ - ...fixtures.accounts.generateAccount({ - hosting: Hosting.CLOUD, - }), - }) - - // New account can be deleted - await config.api.accounts.delete(account.accountId) - }) -}) diff --git a/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts b/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts deleted file mode 100644 index 01338b609c..0000000000 --- a/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { generator } from "../../../shared" -import { Hosting } from "@budibase/types" - -describe("Accounts", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("performs signup and deletion flow", async () => { - await config.doInNewState(async () => { - // Create account - const createAccountRequest = fixtures.accounts.generateAccount({ - hosting: Hosting.CLOUD, - }) - const email = createAccountRequest.email - const tenantId = createAccountRequest.tenantId - - // Validation - email and tenant ID allowed - await config.api.accounts.validateEmail(email) - await config.api.accounts.validateTenantId(tenantId) - - // Create unverified account - await config.api.accounts.create(createAccountRequest) - - // Validation - email and tenant ID no longer valid - await config.api.accounts.validateEmail(email, { status: 400 }) - await config.api.accounts.validateTenantId(tenantId, { status: 400 }) - - // Attempt to log in using unverified account - await config.loginAsAccount(createAccountRequest, { status: 400 }) - - // Re-send verification email to get access to code - const [_, code] = await config.accountsApi.accounts.sendVerificationEmail( - email - ) - - // Send the verification request - await config.accountsApi.accounts.verifyAccount(code!) - - // Verify self response is unauthorized - await config.api.accounts.self({ status: 403 }) - - // Can now log in to the account - await config.loginAsAccount(createAccountRequest) - - // Verify self response matches account - const [selfRes, selfBody] = await config.api.accounts.self() - expect(selfBody.email).toBe(email) - - // Delete account - await config.api.accounts.deleteCurrentAccount() - - // Can't log in - await config.loginAsAccount(createAccountRequest, { status: 403 }) - }) - }) - - describe("Searching accounts", () => { - it("search by tenant ID", async () => { - const tenantId = generator.string() - - // Empty result - const [_, emptyBody] = await config.api.accounts.search( - tenantId, - "tenantId" - ) - expect(emptyBody.length).toBe(0) - - // Hit result - const [hitRes, hitBody] = await config.api.accounts.search( - config.state.tenantId!, - "tenantId" - ) - expect(hitBody.length).toBe(1) - expect(hitBody[0].tenantId).toBe(config.state.tenantId) - }) - - it("searches by email", async () => { - const email = generator.email({ domain: "example.com" }) - - // Empty result - const [_, emptyBody] = await config.api.accounts.search(email, "email") - expect(emptyBody.length).toBe(0) - - // Hit result - const [hitRes, hitBody] = await config.api.accounts.search( - config.state.email!, - "email" - ) - expect(hitBody.length).toBe(1) - expect(hitBody[0].email).toBe(config.state.email) - }) - }) -}) diff --git a/qa-core/src/account-api/tests/auth/auth.cloud.spec.ts b/qa-core/src/account-api/tests/auth/auth.cloud.spec.ts deleted file mode 100644 index 075a52bef4..0000000000 --- a/qa-core/src/account-api/tests/auth/auth.cloud.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { generator } from "../../../shared" -import { Hosting } from "@budibase/types" - -describe("Password Management", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("performs password reset flow", async () => { - // Create account - const createAccountRequest = fixtures.accounts.generateAccount({ - hosting: Hosting.CLOUD, - }) - await config.api.accounts.create(createAccountRequest, { autoVerify: true }) - - // Request password reset to get code - const [_, code] = await config.api.auth.resetPassword( - createAccountRequest.email - ) - - // Change password using code - const password = generator.string() - await config.api.auth.resetPasswordUpdate(code, password) - - // Login using the new password - await config.api.auth.login(createAccountRequest.email, password) - - // Logout of account - await config.api.auth.logout() - - // Cannot log in using old password - await config.api.auth.login( - createAccountRequest.email, - createAccountRequest.password, - { status: 403 } - ) - }) -}) diff --git a/qa-core/src/account-api/tests/licensing/license.activate.spec.ts b/qa-core/src/account-api/tests/licensing/license.activate.spec.ts deleted file mode 100644 index 96c6eaea2a..0000000000 --- a/qa-core/src/account-api/tests/licensing/license.activate.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixures from "../../fixtures" -import { Feature, Hosting } from "@budibase/types" - -describe("license activation", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("creates, activates and deletes online license - self host", async () => { - // Remove existing license key - await config.internalApi.license.deleteLicenseKey() - - // Verify license key not found - await config.internalApi.license.getLicenseKey({ status: 404 }) - - // Create self host account - const createAccountRequest = fixures.accounts.generateAccount({ - hosting: Hosting.SELF, - }) - const [createAccountRes, account] = - await config.accountsApi.accounts.create(createAccountRequest, { - autoVerify: true, - }) - - let licenseKey: string = " " - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - // Retrieve license key - const [res, body] = await config.accountsApi.licenses.getLicenseKey() - licenseKey = body.licenseKey - }) - - const accountId = account.accountId! - - // Update license to have paid feature - const [res, acc] = await config.accountsApi.licenses.updateLicense( - accountId, - { - overrides: { - features: [Feature.APP_BACKUPS], - }, - } - ) - - // Activate license key - await config.internalApi.license.activateLicenseKey({ licenseKey }) - - // Verify license updated with new feature - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - const [selfRes, body] = await config.api.accounts.self() - expect(body.license.features[0]).toBe("appBackups") - }) - - // Remove license key - await config.internalApi.license.deleteLicenseKey() - - // Verify license key not found - await config.internalApi.license.getLicenseKey({ status: 404 }) - }) -}) diff --git a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts deleted file mode 100644 index 85ee530bb7..0000000000 --- a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts +++ /dev/null @@ -1,116 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { Hosting, PlanType } from "@budibase/types" - -const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY) - -describe("license management", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("retrieves plans, creates checkout session, and updates license", async () => { - // Create cloud account - const createAccountRequest = fixtures.accounts.generateAccount({ - hosting: Hosting.CLOUD, - }) - const [createAccountRes, account] = - await config.accountsApi.accounts.create(createAccountRequest, { - autoVerify: true, - }) - - // Self response has free license - await config.doInNewState(async () => { - await config.loginAsAccount(createAccountRequest) - const [selfRes, selfBody] = await config.api.accounts.self() - expect(selfBody.license.plan.type).toBe(PlanType.FREE) - }) - - // Retrieve plans - const [plansRes, planBody] = await config.api.licenses.getPlans() - - // Select priceId from premium plan - let premiumPrice = null - let businessPriceId: "" - for (const plan of planBody) { - if (plan.type === PlanType.PREMIUM_PLUS) { - premiumPrice = plan.prices[0] - } - if (plan.type === PlanType.ENTERPRISE_BASIC) { - businessPriceId = plan.prices[0].priceId - } - } - - // Create checkout session for price - const checkoutSessionRes = await config.api.stripe.createCheckoutSession({ - id: premiumPrice.priceId, - type: premiumPrice.type, - }) - const checkoutSessionUrl = checkoutSessionRes[1].url - expect(checkoutSessionUrl).toContain("checkout.stripe.com") - - // Create stripe customer - const customer = await stripe.customers.create({ - email: createAccountRequest.email, - }) - - // Create payment method - const paymentMethod = await stripe.paymentMethods.create({ - type: "card", - card: { - token: "tok_visa", // Test Visa Card - }, - }) - - // Attach payment method to customer - await stripe.paymentMethods.attach(paymentMethod.id, { - customer: customer.id, - }) - - // Update customer - await stripe.customers.update(customer.id, { - invoice_settings: { - default_payment_method: paymentMethod.id, - }, - }) - - // Create subscription for premium plan - const subscription = await stripe.subscriptions.create({ - customer: customer.id, - items: [ - { - price: premiumPrice.priceId, - quantity: 1, - }, - ], - default_payment_method: paymentMethod.id, - collection_method: "charge_automatically", - }) - - await config.doInNewState(async () => { - // License updated from Free to Premium - await config.loginAsAccount(createAccountRequest) - await config.api.stripe.linkStripeCustomer(account.accountId, customer.id) - const [_, selfBodyPremium] = await config.api.accounts.self() - expect(selfBodyPremium.license.plan.type).toBe(PlanType.PREMIUM_PLUS) - - // Create portal session - Check URL - const [portalRes, portalSessionBody] = - await config.api.stripe.createPortalSession(customer.id) - expect(portalSessionBody.url).toContain("billing.stripe.com") - - // Update subscription from premium to business license - await config.api.licenses.updatePlan(businessPriceId) - - // License updated to Business - const [selfRes, selfBodyBusiness] = await config.api.accounts.self() - expect(selfBodyBusiness.license.plan.type).toBe(PlanType.ENTERPRISE_BASIC) - }) - }) -}) diff --git a/qa-core/src/account-api/tests/licensing/offline.spec.ts b/qa-core/src/account-api/tests/licensing/offline.spec.ts deleted file mode 100644 index e524048153..0000000000 --- a/qa-core/src/account-api/tests/licensing/offline.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixures from "../../fixtures" -import { Hosting, Feature } from "@budibase/types" - -describe("offline", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - // TODO: Currently requires a self host install + account portal - // Ignored until we set this up - it.skip("creates, activates and deletes offline license", async () => { - // installation: Delete any token - await config.internalApi.license.deleteOfflineLicenseToken() - - // installation: Assert token not found - let [getTokenRes] = await config.internalApi.license.getOfflineLicenseToken( - { status: 404 } - ) - - // installation: Retrieve Identifier - const [getIdentifierRes, identifier] = - await config.internalApi.license.getOfflineIdentifier() - - // account-portal: Create self-host account - const createAccountRequest = fixures.accounts.generateAccount({ - hosting: Hosting.SELF, - }) - const [createAccountRes, account] = - await config.accountsApi.accounts.create(createAccountRequest) - const accountId = account.accountId! - const tenantId = account.tenantId! - - // account-portal: Enable feature on license - await config.accountsApi.licenses.updateLicense(accountId, { - overrides: { - features: [Feature.OFFLINE], - }, - }) - - // account-portal: Create offline token - const expireAt = new Date() - expireAt.setDate(new Date().getDate() + 1) - await config.accountsApi.licenses.createOfflineLicense( - accountId, - tenantId, - { - expireAt: expireAt.toISOString(), - installationIdentifierBase64: identifier.identifierBase64, - } - ) - - // account-portal: Retrieve offline token - const [getLicenseRes, offlineLicense] = - await config.accountsApi.licenses.getOfflineLicense(accountId, tenantId) - - // installation: Activate offline token - await config.internalApi.license.activateOfflineLicenseToken({ - offlineLicenseToken: offlineLicense.offlineLicenseToken, - }) - - // installation: Assert token found - await config.internalApi.license.getOfflineLicenseToken() - - // TODO: Assert on license for current user - - // installation: Remove the token - await config.internalApi.license.deleteOfflineLicenseToken() - - // installation: Assert token not found - await config.internalApi.license.getOfflineLicenseToken({ status: 404 }) - }) -}) diff --git a/qa-core/src/environment.ts b/qa-core/src/environment.ts deleted file mode 100644 index a805503474..0000000000 --- a/qa-core/src/environment.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { join } from "path" - -let LOADED = false -if (!LOADED) { - require("dotenv").config({ - path: join(__dirname, "..", ".env"), - }) - LOADED = true -} - -const env = { - BUDIBASE_URL: process.env.BUDIBASE_URL, - ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL, - ACCOUNT_PORTAL_API_KEY: process.env.ACCOUNT_PORTAL_API_KEY, - BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL, - BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD, - POSTGRES_HOST: process.env.POSTGRES_HOST, - POSTGRES_PORT: process.env.POSTGRES_PORT, - POSTGRES_DB: process.env.POSTGRES_DB, - POSTGRES_USER: process.env.POSTGRES_USER, - POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD, - MONGODB_CONNECTION_STRING: process.env.MONGODB_CONNECTION_STRING, - MONGODB_DB: process.env.MONGODB_DB, - REST_API_BASE_URL: process.env.REST_API_BASE_URL, - REST_API_KEY: process.env.REST_API_KEY, - MARIADB_HOST: process.env.MARIADB_HOST, - MARIADB_PORT: process.env.MARIADB_PORT, - MARIADB_DB: process.env.MARIADB_DB, - MARIADB_USER: process.env.MARIADB_USER, - MARIADB_PASSWORD: process.env.MARIADB_PASSWORD, - STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY, -} - -export = env diff --git a/qa-core/src/integrations/external-schema/mssql.integration.spec.ts b/qa-core/src/integrations/external-schema/mssql.integration.spec.ts deleted file mode 100644 index a43edc4379..0000000000 --- a/qa-core/src/integrations/external-schema/mssql.integration.spec.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { GenericContainer, Wait } from "testcontainers" -import { Duration, TemporalUnit } from "node-duration" -import mssql from "../../../../packages/server/src/integrations/microsoftSqlServer" - -jest.unmock("mssql") - -describe("getExternalSchema", () => { - describe("mssql", () => { - let config: any - - beforeAll(async () => { - const password = "Str0Ng_p@ssW0rd!" - const container = await new GenericContainer( - "mcr.microsoft.com/mssql/server" - ) - .withExposedPorts(1433) - .withEnv("ACCEPT_EULA", "Y") - .withEnv("MSSQL_SA_PASSWORD", password) - .withEnv("MSSQL_PID", "Developer") - .withWaitStrategy(Wait.forHealthCheck()) - .withHealthCheck({ - test: `/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "${password}" -Q "SELECT 1" -b -o /dev/null`, - interval: new Duration(1000, TemporalUnit.MILLISECONDS), - timeout: new Duration(3, TemporalUnit.SECONDS), - retries: 20, - startPeriod: new Duration(100, TemporalUnit.MILLISECONDS), - }) - .start() - - const host = container.getContainerIpAddress() - const port = container.getMappedPort(1433) - config = { - user: "sa", - password, - server: host, - port: port, - database: "master", - schema: "dbo", - } - }) - - it("can export an empty database", async () => { - const integration = new mssql.integration(config) - const result = await integration.getExternalSchema() - expect(result).toMatchInlineSnapshot(`""`) - }) - - it("can export a database with tables", async () => { - const integration = new mssql.integration(config) - - await integration.connect() - await integration.internalQuery({ - sql: ` - CREATE TABLE users ( - id INT IDENTITY(1,1) PRIMARY KEY, - name VARCHAR(100) NOT NULL, - role VARCHAR(15) NOT NULL - ); - - CREATE TABLE products ( - id INT IDENTITY(1,1) PRIMARY KEY, - name VARCHAR(100) NOT NULL, - price DECIMAL(10, 2) NOT NULL - ); - `, - }) - - const result = await integration.getExternalSchema() - expect(result).toMatchInlineSnapshot(` - "CREATE TABLE [products] ( - id int(4) NOT NULL, - name varchar(100) NOT NULL, - price decimal(9) NOT NULL, - CONSTRAINT [PK_products] PRIMARY KEY (id) - ); - CREATE TABLE [users] ( - id int(4) NOT NULL, - name varchar(100) NOT NULL, - role varchar(15) NOT NULL, - CONSTRAINT [PK_users] PRIMARY KEY (id) - );" - `) - }) - - it("does not export a data", async () => { - const integration = new mssql.integration(config) - - await integration.connect() - await integration.internalQuery({ - sql: `INSERT INTO [users] ([name], [role]) VALUES ('John Doe', 'Administrator'); - INSERT INTO [products] ([name], [price]) VALUES ('Book', 7.68); - `, - }) - - const result = await integration.getExternalSchema() - expect(result).toMatchInlineSnapshot(` - "CREATE TABLE [products] ( - id int(4) NOT NULL, - name varchar(100) NOT NULL, - price decimal(9) NOT NULL, - CONSTRAINT [PK_products] PRIMARY KEY (id) - ); - CREATE TABLE [users] ( - id int(4) NOT NULL, - name varchar(100) NOT NULL, - role varchar(15) NOT NULL, - CONSTRAINT [PK_users] PRIMARY KEY (id) - );" - `) - }) - }) -}) diff --git a/qa-core/src/integrations/external-schema/mysql.integration.spec.ts b/qa-core/src/integrations/external-schema/mysql.integration.spec.ts deleted file mode 100644 index c8d285a021..0000000000 --- a/qa-core/src/integrations/external-schema/mysql.integration.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { GenericContainer } from "testcontainers" -import mysql from "../../../../packages/server/src/integrations/mysql" - -describe("datasource validators", () => { - describe("mysql", () => { - let config: any - - beforeAll(async () => { - const container = await new GenericContainer("mysql:8.3") - .withExposedPorts(3306) - .withEnv("MYSQL_ROOT_PASSWORD", "admin") - .withEnv("MYSQL_DATABASE", "db") - .withEnv("MYSQL_USER", "user") - .withEnv("MYSQL_PASSWORD", "password") - .start() - - const host = container.getContainerIpAddress() - const port = container.getMappedPort(3306) - config = { - host, - port, - user: "user", - database: "db", - password: "password", - rejectUnauthorized: true, - } - }) - - it("can export an empty database", async () => { - const integration = new mysql.integration(config) - const result = await integration.getExternalSchema() - expect(result).toMatchInlineSnapshot( - `"CREATE DATABASE \`db\` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */"` - ) - }) - - it("can export a database with tables", async () => { - const integration = new mysql.integration(config) - - await integration.internalQuery({ - sql: ` - CREATE TABLE users ( - id INT AUTO_INCREMENT, - name VARCHAR(100) NOT NULL, - role VARCHAR(15) NOT NULL, - PRIMARY KEY (id) - ); - - - CREATE TABLE products ( - id INT AUTO_INCREMENT, - name VARCHAR(100) NOT NULL, - price DECIMAL, - PRIMARY KEY (id) - ); - `, - }) - - const result = await integration.getExternalSchema() - expect(result).toMatchInlineSnapshot(` - "CREATE DATABASE \`db\` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */ - CREATE TABLE \`products\` ( - \`id\` int NOT NULL AUTO_INCREMENT, - \`name\` varchar(100) NOT NULL, - \`price\` decimal(10,0) DEFAULT NULL, - PRIMARY KEY (\`id\`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci - CREATE TABLE \`users\` ( - \`id\` int NOT NULL AUTO_INCREMENT, - \`name\` varchar(100) NOT NULL, - \`role\` varchar(15) NOT NULL, - PRIMARY KEY (\`id\`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci" - `) - }) - - it("does not export a data", async () => { - const integration = new mysql.integration(config) - - await integration.internalQuery({ - sql: `INSERT INTO users (name, role) VALUES ('John Doe', 'Administrator');`, - }) - - await integration.internalQuery({ - sql: `INSERT INTO products (name, price) VALUES ('Book', 7.68);`, - }) - - const result = await integration.getExternalSchema() - expect(result).toMatchInlineSnapshot(` - "CREATE DATABASE \`db\` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */ - CREATE TABLE \`products\` ( - \`id\` int NOT NULL AUTO_INCREMENT, - \`name\` varchar(100) NOT NULL, - \`price\` decimal(10,0) DEFAULT NULL, - PRIMARY KEY (\`id\`) - ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci - CREATE TABLE \`users\` ( - \`id\` int NOT NULL AUTO_INCREMENT, - \`name\` varchar(100) NOT NULL, - \`role\` varchar(15) NOT NULL, - PRIMARY KEY (\`id\`) - ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci" - `) - }) - }) -}) diff --git a/qa-core/src/integrations/external-schema/postgres.integration.spec.ts b/qa-core/src/integrations/external-schema/postgres.integration.spec.ts deleted file mode 100644 index 7581d7f88a..0000000000 --- a/qa-core/src/integrations/external-schema/postgres.integration.spec.ts +++ /dev/null @@ -1,376 +0,0 @@ -import { GenericContainer } from "testcontainers" -import postgres from "../../../../packages/server/src/integrations/postgres" - -jest.unmock("pg") - -describe("getExternalSchema", () => { - describe("postgres", () => { - let config: any - - // Remove versioning from the outputs to prevent failures when running different pg_dump versions - function stripResultsVersions(sql: string) { - const result = sql - .replace(/\n[^\n]+Dumped from database version[^\n]+\n/, "") - .replace(/\n[^\n]+Dumped by pg_dump version[^\n]+\n/, "") - .toString() - return result - } - - beforeAll(async () => { - const container = await new GenericContainer("postgres:16.1-bullseye") - .withExposedPorts(5432) - .withEnv("POSTGRES_PASSWORD", "password") - .start() - - const host = container.getContainerIpAddress() - const port = container.getMappedPort(5432) - - config = { - host, - port, - database: "postgres", - user: "postgres", - password: "password", - schema: "public", - ssl: false, - rejectUnauthorized: false, - } - }) - - it("can export an empty database", async () => { - const integration = new postgres.integration(config) - const result = await integration.getExternalSchema() - - expect(stripResultsVersions(result)).toMatchInlineSnapshot(` - "-- - -- PostgreSQL database dump - -- - SET statement_timeout = 0; - SET lock_timeout = 0; - SET idle_in_transaction_session_timeout = 0; - SET client_encoding = 'UTF8'; - SET standard_conforming_strings = on; - SELECT pg_catalog.set_config('search_path', '', false); - SET check_function_bodies = false; - SET xmloption = content; - SET client_min_messages = warning; - SET row_security = off; - - -- - -- PostgreSQL database dump complete - -- - - " - `) - }) - - it("can export a database with tables", async () => { - const integration = new postgres.integration(config) - - await integration.internalQuery( - { - sql: ` - CREATE TABLE "users" ( - "id" SERIAL, - "name" VARCHAR(100) NOT NULL, - "role" VARCHAR(15) NOT NULL, - PRIMARY KEY ("id") - ); - CREATE TABLE "products" ( - "id" SERIAL, - "name" VARCHAR(100) NOT NULL, - "price" DECIMAL NOT NULL, - "owner" INTEGER NULL, - PRIMARY KEY ("id") - ); - ALTER TABLE "products" ADD CONSTRAINT "fk_owner" FOREIGN KEY ("owner") REFERENCES "users" ("id");`, - }, - false - ) - - const result = await integration.getExternalSchema() - expect(stripResultsVersions(result)).toMatchInlineSnapshot(` - "-- - -- PostgreSQL database dump - -- - SET statement_timeout = 0; - SET lock_timeout = 0; - SET idle_in_transaction_session_timeout = 0; - SET client_encoding = 'UTF8'; - SET standard_conforming_strings = on; - SELECT pg_catalog.set_config('search_path', '', false); - SET check_function_bodies = false; - SET xmloption = content; - SET client_min_messages = warning; - SET row_security = off; - - SET default_tablespace = ''; - - SET default_table_access_method = heap; - - -- - -- Name: products; Type: TABLE; Schema: public; Owner: postgres - -- - - CREATE TABLE public.products ( - id integer NOT NULL, - name character varying(100) NOT NULL, - price numeric NOT NULL, - owner integer - ); - - - ALTER TABLE public.products OWNER TO postgres; - - -- - -- Name: products_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres - -- - - CREATE SEQUENCE public.products_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - - ALTER TABLE public.products_id_seq OWNER TO postgres; - - -- - -- Name: products_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres - -- - - ALTER SEQUENCE public.products_id_seq OWNED BY public.products.id; - - - -- - -- Name: users; Type: TABLE; Schema: public; Owner: postgres - -- - - CREATE TABLE public.users ( - id integer NOT NULL, - name character varying(100) NOT NULL, - role character varying(15) NOT NULL - ); - - - ALTER TABLE public.users OWNER TO postgres; - - -- - -- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres - -- - - CREATE SEQUENCE public.users_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - - ALTER TABLE public.users_id_seq OWNER TO postgres; - - -- - -- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres - -- - - ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; - - - -- - -- Name: products id; Type: DEFAULT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.products ALTER COLUMN id SET DEFAULT nextval('public.products_id_seq'::regclass); - - - -- - -- Name: users id; Type: DEFAULT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); - - - -- - -- Name: products products_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.products - ADD CONSTRAINT products_pkey PRIMARY KEY (id); - - - -- - -- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.users - ADD CONSTRAINT users_pkey PRIMARY KEY (id); - - - -- - -- Name: products fk_owner; Type: FK CONSTRAINT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.products - ADD CONSTRAINT fk_owner FOREIGN KEY (owner) REFERENCES public.users(id); - - - -- - -- PostgreSQL database dump complete - -- - - " - `) - }) - - it("does not export a data", async () => { - const integration = new postgres.integration(config) - - await integration.internalQuery( - { - sql: `INSERT INTO "users" ("name", "role") VALUES ('John Doe', 'Administrator'); - INSERT INTO "products" ("name", "price") VALUES ('Book', 7.68);`, - }, - false - ) - - const result = await integration.getExternalSchema() - expect(stripResultsVersions(result)).toMatchInlineSnapshot(` - "-- - -- PostgreSQL database dump - -- - SET statement_timeout = 0; - SET lock_timeout = 0; - SET idle_in_transaction_session_timeout = 0; - SET client_encoding = 'UTF8'; - SET standard_conforming_strings = on; - SELECT pg_catalog.set_config('search_path', '', false); - SET check_function_bodies = false; - SET xmloption = content; - SET client_min_messages = warning; - SET row_security = off; - - SET default_tablespace = ''; - - SET default_table_access_method = heap; - - -- - -- Name: products; Type: TABLE; Schema: public; Owner: postgres - -- - - CREATE TABLE public.products ( - id integer NOT NULL, - name character varying(100) NOT NULL, - price numeric NOT NULL, - owner integer - ); - - - ALTER TABLE public.products OWNER TO postgres; - - -- - -- Name: products_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres - -- - - CREATE SEQUENCE public.products_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - - ALTER TABLE public.products_id_seq OWNER TO postgres; - - -- - -- Name: products_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres - -- - - ALTER SEQUENCE public.products_id_seq OWNED BY public.products.id; - - - -- - -- Name: users; Type: TABLE; Schema: public; Owner: postgres - -- - - CREATE TABLE public.users ( - id integer NOT NULL, - name character varying(100) NOT NULL, - role character varying(15) NOT NULL - ); - - - ALTER TABLE public.users OWNER TO postgres; - - -- - -- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres - -- - - CREATE SEQUENCE public.users_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - - ALTER TABLE public.users_id_seq OWNER TO postgres; - - -- - -- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres - -- - - ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; - - - -- - -- Name: products id; Type: DEFAULT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.products ALTER COLUMN id SET DEFAULT nextval('public.products_id_seq'::regclass); - - - -- - -- Name: users id; Type: DEFAULT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); - - - -- - -- Name: products products_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.products - ADD CONSTRAINT products_pkey PRIMARY KEY (id); - - - -- - -- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.users - ADD CONSTRAINT users_pkey PRIMARY KEY (id); - - - -- - -- Name: products fk_owner; Type: FK CONSTRAINT; Schema: public; Owner: postgres - -- - - ALTER TABLE ONLY public.products - ADD CONSTRAINT fk_owner FOREIGN KEY (owner) REFERENCES public.users(id); - - - -- - -- PostgreSQL database dump complete - -- - - " - `) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/arango.integration.spec.ts b/qa-core/src/integrations/validators/arango.integration.spec.ts deleted file mode 100644 index 7c0faafd61..0000000000 --- a/qa-core/src/integrations/validators/arango.integration.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { GenericContainer, Wait } from "testcontainers" -import arangodb from "../../../../packages/server/src/integrations/arangodb" -import { generator } from "../../shared" - -jest.unmock("arangojs") - -describe("datasource validators", () => { - describe("arangodb", () => { - let connectionSettings: { - user: string - password: string - url: string - } - - beforeAll(async () => { - const user = "root" - const password = generator.hash() - const container = await new GenericContainer("arangodb") - .withExposedPorts(8529) - .withEnv("ARANGO_ROOT_PASSWORD", password) - .withWaitStrategy( - Wait.forLogMessage("is ready for business. Have fun!") - ) - .start() - - connectionSettings = { - user, - password, - url: `http://${container.getContainerIpAddress()}:${container.getMappedPort( - 8529 - )}`, - } - }) - - it("test valid connection string", async () => { - const integration = new arangodb.integration({ - url: connectionSettings.url, - username: connectionSettings.user, - password: connectionSettings.password, - databaseName: "", - collection: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test wrong password", async () => { - const integration = new arangodb.integration({ - url: connectionSettings.url, - username: connectionSettings.user, - password: "wrong", - databaseName: "", - collection: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "not authorized to execute this request", - }) - }) - - it("test wrong url", async () => { - const integration = new arangodb.integration({ - url: "http://not.here", - username: connectionSettings.user, - password: connectionSettings.password, - databaseName: "", - collection: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "getaddrinfo ENOTFOUND not.here", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/couch.integration.spec.ts b/qa-core/src/integrations/validators/couch.integration.spec.ts deleted file mode 100644 index b0f4254610..0000000000 --- a/qa-core/src/integrations/validators/couch.integration.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { GenericContainer } from "testcontainers" - -import couchdb from "../../../../packages/server/src/integrations/couchdb" -import { generator } from "../../shared" - -describe("datasource validators", () => { - describe("couchdb", () => { - let url: string - - beforeAll(async () => { - const user = generator.first() - const password = generator.hash() - - const container = await new GenericContainer("budibase/couchdb") - .withExposedPorts(5984) - .withEnv("COUCHDB_USER", user) - .withEnv("COUCHDB_PASSWORD", password) - .start() - - const host = container.getContainerIpAddress() - const port = container.getMappedPort(5984) - - await container.exec([ - `curl`, - `-u`, - `${user}:${password}`, - `-X`, - `PUT`, - `localhost:5984/db`, - ]) - url = `http://${user}:${password}@${host}:${port}` - }) - - it("test valid connection string", async () => { - const integration = new couchdb.integration({ - url, - database: "db", - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test invalid database", async () => { - const integration = new couchdb.integration({ - url, - database: "random_db", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - }) - }) - - it("test invalid url", async () => { - const integration = new couchdb.integration({ - url: "http://invalid:123", - database: "any", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: - "request to http://invalid:123/any failed, reason: getaddrinfo ENOTFOUND invalid", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/dynamodb.integration.spec.ts b/qa-core/src/integrations/validators/dynamodb.integration.spec.ts deleted file mode 100644 index d1cec7bca1..0000000000 --- a/qa-core/src/integrations/validators/dynamodb.integration.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { GenericContainer } from "testcontainers" -import { env } from "@budibase/backend-core" - -import dynamodb from "../../../../packages/server/src/integrations/dynamodb" -import { generator } from "../../shared" - -jest.unmock("aws-sdk") - -describe("datasource validators", () => { - describe("dynamodb", () => { - let connectionSettings: { - user: string - password: string - url: string - } - - beforeAll(async () => { - const user = "root" - const password = generator.hash() - const container = await new GenericContainer("amazon/dynamodb-local") - .withExposedPorts(8000) - .start() - - connectionSettings = { - user, - password, - url: `http://${container.getContainerIpAddress()}:${container.getMappedPort( - 8000 - )}`, - } - env._set("AWS_ACCESS_KEY_ID", "mockedkey") - env._set("AWS_SECRET_ACCESS_KEY", "mockedsecret") - }) - - it("test valid connection string", async () => { - const integration = new dynamodb.integration({ - endpoint: connectionSettings.url, - region: "", - accessKeyId: "", - secretAccessKey: "", - }) - - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test wrong endpoint", async () => { - const integration = new dynamodb.integration({ - endpoint: "http://wrong.url:2880", - region: "", - accessKeyId: "", - secretAccessKey: "", - }) - - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: - "Inaccessible host: `wrong.url' at port `undefined'. This service may not be available in the `eu-west-1' region.", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/elastic.integration.spec.ts b/qa-core/src/integrations/validators/elastic.integration.spec.ts deleted file mode 100644 index 39fd732744..0000000000 --- a/qa-core/src/integrations/validators/elastic.integration.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ElasticsearchContainer } from "testcontainers" -import elastic from "../../../../packages/server/src/integrations/elasticsearch" - -jest.unmock("@elastic/elasticsearch") - -describe("datasource validators", () => { - describe("elastic search", () => { - let url: string - - beforeAll(async () => { - const container = await new ElasticsearchContainer().start() - url = container.getHttpUrl() - }) - - it("test valid connection string", async () => { - const integration = new elastic.integration({ - url, - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test wrong connection string", async () => { - const integration = new elastic.integration({ - url: `http://localhost:5656`, - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "connect ECONNREFUSED 127.0.0.1:5656", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/mongo.integration.spec.ts b/qa-core/src/integrations/validators/mongo.integration.spec.ts deleted file mode 100644 index b1bab3bd1f..0000000000 --- a/qa-core/src/integrations/validators/mongo.integration.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { GenericContainer } from "testcontainers" -import mongo from "../../../../packages/server/src/integrations/mongodb" -import { generator } from "../../shared" - -jest.unmock("mongodb") - -describe("datasource validators", () => { - describe("mongo", () => { - let connectionSettings: { - user: string - password: string - host: string - port: number - } - - function getConnectionString( - settings: Partial = {} - ) { - const { user, password, host, port } = { - ...connectionSettings, - ...settings, - } - return `mongodb://${user}:${password}@${host}:${port}` - } - - beforeAll(async () => { - const user = generator.name() - const password = generator.hash() - const container = await new GenericContainer("mongo:7.0-jammy") - .withExposedPorts(27017) - .withEnv("MONGO_INITDB_ROOT_USERNAME", user) - .withEnv("MONGO_INITDB_ROOT_PASSWORD", password) - .start() - - connectionSettings = { - user, - password, - host: container.getContainerIpAddress(), - port: container.getMappedPort(27017), - } - }) - - it("test valid connection string", async () => { - const integration = new mongo.integration({ - connectionString: getConnectionString(), - db: "", - tlsCertificateFile: "", - tlsCertificateKeyFile: "", - tlsCAFile: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test invalid password", async () => { - const integration = new mongo.integration({ - connectionString: getConnectionString({ password: "wrong" }), - db: "", - tlsCertificateFile: "", - tlsCertificateKeyFile: "", - tlsCAFile: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "Authentication failed.", - }) - }) - - it("test invalid username", async () => { - const integration = new mongo.integration({ - connectionString: getConnectionString({ user: "wrong" }), - db: "", - tlsCertificateFile: "", - tlsCertificateKeyFile: "", - tlsCAFile: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "Authentication failed.", - }) - }) - - it("test invalid connection", async () => { - const integration = new mongo.integration({ - connectionString: getConnectionString({ host: "http://nothinghere" }), - db: "", - tlsCertificateFile: "", - tlsCertificateKeyFile: "", - tlsCAFile: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "getaddrinfo ENOTFOUND http", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/mssql.integration.spec.ts b/qa-core/src/integrations/validators/mssql.integration.spec.ts deleted file mode 100644 index c07f1d1129..0000000000 --- a/qa-core/src/integrations/validators/mssql.integration.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { GenericContainer, Wait } from "testcontainers" -import { Duration, TemporalUnit } from "node-duration" - -import mssql from "../../../../packages/server/src/integrations/microsoftSqlServer" - -jest.unmock("mssql") - -describe("datasource validators", () => { - describe("mssql", () => { - let host: string, port: number - - const password = "Str0Ng_p@ssW0rd!" - - beforeAll(async () => { - const container = await new GenericContainer( - "mcr.microsoft.com/mssql/server:2022-latest" - ) - .withExposedPorts(1433) - .withEnv("ACCEPT_EULA", "Y") - .withEnv("MSSQL_SA_PASSWORD", password) - .withEnv("MSSQL_PID", "Developer") - .withWaitStrategy(Wait.forHealthCheck()) - .withHealthCheck({ - test: `/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "${password}" -Q "SELECT 1" -b -o /dev/null`, - interval: new Duration(1000, TemporalUnit.MILLISECONDS), - timeout: new Duration(3, TemporalUnit.SECONDS), - retries: 20, - startPeriod: new Duration(100, TemporalUnit.MILLISECONDS), - }) - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(1433) - }) - - it("test valid connection string", async () => { - const integration = new mssql.integration({ - user: "sa", - password, - server: host, - port: port, - database: "master", - schema: "dbo", - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test invalid password", async () => { - const integration = new mssql.integration({ - user: "sa", - password: "wrong_pwd", - server: host, - port: port, - database: "master", - schema: "dbo", - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "Login failed for user 'sa'.", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/mysql.integration.spec.ts b/qa-core/src/integrations/validators/mysql.integration.spec.ts deleted file mode 100644 index 95f7d4abbd..0000000000 --- a/qa-core/src/integrations/validators/mysql.integration.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { GenericContainer } from "testcontainers" -import mysql from "../../../../packages/server/src/integrations/mysql" - -describe("datasource validators", () => { - describe("mysql", () => { - let host: string - let port: number - - beforeAll(async () => { - const container = await new GenericContainer("mysql:8.3") - .withExposedPorts(3306) - .withEnv("MYSQL_ROOT_PASSWORD", "admin") - .withEnv("MYSQL_DATABASE", "db") - .withEnv("MYSQL_USER", "user") - .withEnv("MYSQL_PASSWORD", "password") - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(3306) - }) - - it("test valid connection string", async () => { - const integration = new mysql.integration({ - host, - port, - user: "user", - database: "db", - password: "password", - rejectUnauthorized: true, - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test invalid database", async () => { - const integration = new mysql.integration({ - host, - port, - user: "user", - database: "test", - password: "password", - rejectUnauthorized: true, - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: "Access denied for user 'user'@'%' to database 'test'", - }) - }) - - it("test invalid password", async () => { - const integration = new mysql.integration({ - host, - port, - user: "root", - database: "test", - password: "wrong", - rejectUnauthorized: true, - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: - "Access denied for the specified user. User does not have the necessary privileges or the provided credentials are incorrect. Please verify the credentials, and ensure that the user has appropriate permissions.", - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/postgres.integration.spec.ts b/qa-core/src/integrations/validators/postgres.integration.spec.ts deleted file mode 100644 index 9e3e1ab30f..0000000000 --- a/qa-core/src/integrations/validators/postgres.integration.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { GenericContainer } from "testcontainers" -import postgres from "../../../../packages/server/src/integrations/postgres" - -jest.unmock("pg") - -describe("datasource validators", () => { - describe("postgres", () => { - let host: string - let port: number - - beforeAll(async () => { - const container = await new GenericContainer("postgres:16.1-bullseye") - .withExposedPorts(5432) - .withEnv("POSTGRES_PASSWORD", "password") - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(5432) - }) - - it("test valid connection string", async () => { - const integration = new postgres.integration({ - host, - port, - database: "postgres", - user: "postgres", - password: "password", - schema: "public", - ssl: false, - rejectUnauthorized: false, - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test invalid connection string", async () => { - const integration = new postgres.integration({ - host, - port, - database: "postgres", - user: "wrong", - password: "password", - schema: "public", - ssl: false, - rejectUnauthorized: false, - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: 'password authentication failed for user "wrong"', - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/redis.integration.spec.ts b/qa-core/src/integrations/validators/redis.integration.spec.ts deleted file mode 100644 index 89ada2fe2d..0000000000 --- a/qa-core/src/integrations/validators/redis.integration.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import redis from "../../../../packages/server/src/integrations/redis" -import { GenericContainer } from "testcontainers" -import { generator } from "../../shared" - -describe("datasource validators", () => { - describe("redis", () => { - describe("unsecured", () => { - let host: string - let port: number - - beforeAll(async () => { - const container = await new GenericContainer("redis") - .withExposedPorts(6379) - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(6379) - }) - - it("test valid connection", async () => { - const integration = new redis.integration({ - host, - port, - username: "", - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test invalid connection even with wrong user/password", async () => { - const integration = new redis.integration({ - host, - port, - username: generator.name(), - password: generator.hash(), - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: - "WRONGPASS invalid username-password pair or user is disabled.", - }) - }) - }) - - describe("secured", () => { - let host: string - let port: number - - beforeAll(async () => { - const container = await new GenericContainer("redis") - .withExposedPorts(6379) - .withCmd(["redis-server", "--requirepass", "P@ssW0rd!"]) - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(6379) - }) - - it("test valid connection", async () => { - const integration = new redis.integration({ - host, - port, - username: "", - password: "P@ssW0rd!", - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - }) - }) -}) diff --git a/qa-core/src/integrations/validators/s3.integration.spec.ts b/qa-core/src/integrations/validators/s3.integration.spec.ts deleted file mode 100644 index 7bb415ee3d..0000000000 --- a/qa-core/src/integrations/validators/s3.integration.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import s3 from "../../../../packages/server/src/integrations/s3" -import { GenericContainer } from "testcontainers" - -jest.unmock("aws-sdk") - -describe("datasource validators", () => { - describe("s3", () => { - let host: string - let port: number - - beforeAll(async () => { - const container = await new GenericContainer("localstack/localstack") - .withExposedPorts(4566) - .withEnv("SERVICES", "s3") - .withEnv("DEFAULT_REGION", "eu-west-1") - .withEnv("AWS_ACCESS_KEY_ID", "testkey") - .withEnv("AWS_SECRET_ACCESS_KEY", "testsecret") - .start() - - host = container.getContainerIpAddress() - port = container.getMappedPort(4566) - }) - - it("test valid connection", async () => { - const integration = new s3.integration({ - region: "eu-west-1", - accessKeyId: "testkey", - secretAccessKey: "testsecret", - s3ForcePathStyle: false, - endpoint: `http://${host}:${port}`, - }) - const result = await integration.testConnection() - expect(result).toEqual({ connected: true }) - }) - - it("test wrong endpoint", async () => { - const integration = new s3.integration({ - region: "eu-west-2", - accessKeyId: "testkey", - secretAccessKey: "testsecret", - s3ForcePathStyle: false, - endpoint: `http://wrong:123`, - }) - const result = await integration.testConnection() - expect(result).toEqual({ - connected: false, - error: - "Inaccessible host: `wrong' at port `undefined'. This service may not be available in the `eu-west-2' region.", - }) - }) - }) -}) diff --git a/qa-core/src/internal-api/api/BudibaseInternalAPI.ts b/qa-core/src/internal-api/api/BudibaseInternalAPI.ts deleted file mode 100644 index 9b55c22deb..0000000000 --- a/qa-core/src/internal-api/api/BudibaseInternalAPI.ts +++ /dev/null @@ -1,54 +0,0 @@ -import AppAPI from "./apis/AppAPI" -import AuthAPI from "./apis/AuthAPI" -import EnvironmentAPI from "./apis/EnvironmentAPI" -import RoleAPI from "./apis/RoleAPI" -import RowAPI from "./apis/RowAPI" -import ScreenAPI from "./apis/ScreenAPI" -import SelfAPI from "./apis/SelfAPI" -import TableAPI from "./apis/TableAPI" -import UserAPI from "./apis/UserAPI" -import DatasourcesAPI from "./apis/DatasourcesAPI" -import IntegrationsAPI from "./apis/IntegrationsAPI" -import QueriesAPI from "./apis/QueriesAPI" -import PermissionsAPI from "./apis/PermissionsAPI" -import LicenseAPI from "./apis/LicenseAPI" -import BudibaseInternalAPIClient from "./BudibaseInternalAPIClient" -import { State } from "../../types" - -export default class BudibaseInternalAPI { - client: BudibaseInternalAPIClient - - apps: AppAPI - auth: AuthAPI - environment: EnvironmentAPI - roles: RoleAPI - rows: RowAPI - screens: ScreenAPI - self: SelfAPI - tables: TableAPI - users: UserAPI - datasources: DatasourcesAPI - integrations: IntegrationsAPI - queries: QueriesAPI - permissions: PermissionsAPI - license: LicenseAPI - - constructor(state: State) { - this.client = new BudibaseInternalAPIClient(state) - - this.apps = new AppAPI(this.client) - this.auth = new AuthAPI(this.client, state) - this.environment = new EnvironmentAPI(this.client) - this.roles = new RoleAPI(this.client) - this.rows = new RowAPI(this.client) - this.screens = new ScreenAPI(this.client) - this.self = new SelfAPI(this.client) - this.tables = new TableAPI(this.client) - this.users = new UserAPI(this.client) - this.datasources = new DatasourcesAPI(this.client) - this.integrations = new IntegrationsAPI(this.client) - this.queries = new QueriesAPI(this.client) - this.permissions = new PermissionsAPI(this.client) - this.license = new LicenseAPI(this.client) - } -} diff --git a/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts b/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts deleted file mode 100644 index ba70bb5ce0..0000000000 --- a/qa-core/src/internal-api/api/BudibaseInternalAPIClient.ts +++ /dev/null @@ -1,80 +0,0 @@ -import env from "../../environment" -import fetch, { HeadersInit } from "node-fetch" -import { State } from "../../types" - -type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" - -interface ApiOptions { - method?: APIMethod - body?: object - headers?: HeadersInit | undefined -} - -class BudibaseInternalAPIClient { - host: string - state: State - - constructor(state: State) { - if (!env.BUDIBASE_URL) { - throw new Error("Must set BUDIBASE_URL env var") - } - this.host = `${env.BUDIBASE_URL}/api` - this.state = state - } - - apiCall = - (method: APIMethod) => - async (url = "", options: ApiOptions = {}) => { - const requestOptions = { - method, - body: JSON.stringify(options.body), - headers: { - "x-budibase-app-id": this.state.appId, - "Content-Type": "application/json", - Accept: "application/json", - cookie: this.state.cookie, - redirect: "follow", - follow: 20, - ...options.headers, - }, - credentials: "include", - } - - // prettier-ignore - // @ts-ignore - const response = await fetch(`${this.host}${url}`, requestOptions) - - let body: any - const contentType = response.headers.get("content-type") - if (contentType && contentType.includes("application/json")) { - body = await response.json() - } else { - body = await response.text() - } - - const data = { - request: requestOptions.body, - response: body, - } - const message = `${method} ${url} - ${response.status}` - - const isDebug = process.env.LOG_LEVEL === "debug" - if (response.status > 499) { - console.error(message, data) - } else if (response.status >= 400) { - console.warn(message, data) - } else if (isDebug) { - console.debug(message, data) - } - - return [response, body] - } - - post = this.apiCall("POST") - get = this.apiCall("GET") - patch = this.apiCall("PATCH") - del = this.apiCall("DELETE") - put = this.apiCall("PUT") -} - -export default BudibaseInternalAPIClient diff --git a/qa-core/src/internal-api/api/apis/AppAPI.ts b/qa-core/src/internal-api/api/apis/AppAPI.ts deleted file mode 100644 index 8b291a628e..0000000000 --- a/qa-core/src/internal-api/api/apis/AppAPI.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { App, CreateAppRequest } from "@budibase/types" -import { Response } from "node-fetch" -import { - RouteConfig, - AppPackageResponse, - DeployConfig, - MessageResponse, -} from "../../../types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" - -interface RenameAppBody { - name: string -} - -export default class AppAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - // TODO Fix the fetch apps to receive an optional number of apps and compare if the received app is more or less. - // each possible scenario should have its own method. - async fetchEmptyAppList(): Promise<[Response, App[]]> { - const [response, json] = await this.get(`/applications?status=all`) - expect(json.length).toBeGreaterThanOrEqual(0) - return [response, json] - } - - async fetchAllApplications(): Promise<[Response, App[]]> { - const [response, json] = await this.get(`/applications?status=all`) - expect(json.length).toBeGreaterThanOrEqual(1) - return [response, json] - } - - async canRender(): Promise<[Response, boolean]> { - const [response, json] = await this.get("/routing/client") - const publishedAppRenders = Object.keys(json.routes).length > 0 - expect(publishedAppRenders).toBe(true) - return [response, publishedAppRenders] - } - - async getAppPackage(appId: string): Promise<[Response, AppPackageResponse]> { - const [response, json] = await this.get(`/applications/${appId}/appPackage`) - expect(json.application.appId).toEqual(appId) - return [response, json] - } - - async publish(appId: string | undefined): Promise<[Response, DeployConfig]> { - const [response, json] = await this.post(`/applications/${appId}/publish`) - return [response, json] - } - - async create(body: CreateAppRequest): Promise { - const [response, json] = await this.post(`/applications`, body) - expect(json._id).toBeDefined() - return json - } - - async read(id: string): Promise<[Response, App]> { - const [response, json] = await this.get(`/applications/${id}`) - return [response, json.data] - } - - async sync(appId: string): Promise<[Response, MessageResponse]> { - const [response, json] = await this.post(`/applications/${appId}/sync`) - return [response, json] - } - - // TODO - async updateClient(appId: string, body: any): Promise<[Response, App]> { - const [response, json] = await this.put( - `/applications/${appId}/client/update`, - { body } - ) - return [response, json] - } - - async revertPublished(appId: string): Promise<[Response, MessageResponse]> { - const [response, json] = await this.post(`/dev/${appId}/revert`) - expect(json).toEqual({ - message: "Reverted changes successfully.", - }) - return [response, json] - } - - async revertUnpublished(appId: string): Promise<[Response, MessageResponse]> { - const [response, json] = await this.post( - `/dev/${appId}/revert`, - undefined, - 400 - ) - expect(json).toEqual({ - message: "App has not yet been deployed", - status: 400, - }) - return [response, json] - } - - async delete(appId: string): Promise { - const [response, _] = await this.del(`/applications/${appId}`) - return response - } - - async rename( - appId: string, - oldName: string, - body: RenameAppBody - ): Promise<[Response, App]> { - const [response, json] = await this.put(`/applications/${appId}`, body) - expect(json.name).not.toEqual(oldName) - return [response, json] - } - - async getRoutes(screenExists?: boolean): Promise<[Response, RouteConfig]> { - const [response, json] = await this.get(`/routing`) - if (screenExists) { - expect(json.routes["/test"]).toBeTruthy() - } else { - expect(json.routes["/test"]).toBeUndefined() - } - - return [response, json] - } - - async unpublish(appId: string): Promise<[Response]> { - const [response, json] = await this.post( - `/applications/${appId}/unpublish`, - undefined, - 204 - ) - return [response] - } - - async unlock(appId: string): Promise<[Response, MessageResponse]> { - const [response, json] = await this.del(`/dev/${appId}/lock`) - expect(json.message).toEqual("Lock released successfully.") - return [response, json] - } - - async updateIcon(appId: string): Promise<[Response, App]> { - const body = { - icon: { - name: "ConversionFunnel", - color: "var(--spectrum-global-color-red-400)", - }, - } - const [response, json] = await this.put(`/applications/${appId}`, body) - expect(json.icon.name).toEqual(body.icon.name) - expect(json.icon.color).toEqual(body.icon.color) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/AuthAPI.ts b/qa-core/src/internal-api/api/apis/AuthAPI.ts deleted file mode 100644 index fec9f7e503..0000000000 --- a/qa-core/src/internal-api/api/apis/AuthAPI.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Response } from "node-fetch" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import { APIRequestOpts, State } from "../../../types" - -export default class AuthAPI { - state: State - client: BudibaseInternalAPIClient - - constructor(client: BudibaseInternalAPIClient, state: State) { - this.client = client - this.state = state - } - - async login( - tenantId: string, - email: String, - password: String, - opts: APIRequestOpts = { doExpect: true } - ): Promise<[Response, string]> { - const [response, json] = await this.client.post( - `/global/auth/${tenantId}/login`, - { - body: { - username: email, - password: password, - }, - } - ) - if (opts.doExpect) { - expect(response).toHaveStatusCode(200) - } - const cookie = response.headers.get("set-cookie") - return [response, cookie!] - } - - async logout(): Promise { - return this.client.post(`/global/auth/logout`) - } -} diff --git a/qa-core/src/internal-api/api/apis/BaseAPI.ts b/qa-core/src/internal-api/api/apis/BaseAPI.ts deleted file mode 100644 index c0a3b344d6..0000000000 --- a/qa-core/src/internal-api/api/apis/BaseAPI.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Response } from "node-fetch" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" - -export default class BaseAPI { - client: BudibaseInternalAPIClient - - constructor(client: BudibaseInternalAPIClient) { - this.client = client - } - - async get(url: string, status?: number): Promise<[Response, any]> { - const [response, json] = await this.client.get(url) - expect(response).toHaveStatusCode(status ? status : 200) - return [response, json] - } - - async post( - url: string, - body?: any, - statusCode?: number - ): Promise<[Response, any]> { - const [response, json] = await this.client.post(url, { body }) - expect(response).toHaveStatusCode(statusCode ? statusCode : 200) - return [response, json] - } - - async put( - url: string, - body?: any, - statusCode?: number - ): Promise<[Response, any]> { - const [response, json] = await this.client.put(url, { body }) - expect(response).toHaveStatusCode(statusCode ? statusCode : 200) - return [response, json] - } - - async patch( - url: string, - body?: any, - statusCode?: number - ): Promise<[Response, any]> { - const [response, json] = await this.client.patch(url, { body }) - expect(response).toHaveStatusCode(statusCode ? statusCode : 200) - return [response, json] - } - - async del( - url: string, - statusCode?: number, - body?: any - ): Promise<[Response, any]> { - const [response, json] = await this.client.del(url, { body }) - expect(response).toHaveStatusCode(statusCode ? statusCode : 200) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts b/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts deleted file mode 100644 index 9067ed4ab4..0000000000 --- a/qa-core/src/internal-api/api/apis/DatasourcesAPI.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Response } from "node-fetch" -import { - Datasource, - CreateDatasourceResponse, - UpdateDatasourceResponse, -} from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" -import { DatasourceRequest } from "../../../types" - -export default class DatasourcesAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async getIntegrations(): Promise<[Response, any]> { - const [response, json] = await this.get(`/integrations`) - const integrationsCount = Object.keys(json).length - expect(integrationsCount).toBe(16) - return [response, json] - } - - async getAll(): Promise<[Response, Datasource[]]> { - const [response, json] = await this.get(`/datasources`) - expect(json.length).toBeGreaterThan(0) - return [response, json] - } - - async getTable(dataSourceId: string): Promise<[Response, Datasource]> { - const [response, json] = await this.get(`/datasources/${dataSourceId}`) - expect(json._id).toEqual(dataSourceId) - return [response, json] - } - - async add( - body: DatasourceRequest - ): Promise<[Response, CreateDatasourceResponse]> { - const [response, json] = await this.post(`/datasources`, body) - expect(json.datasource._id).toBeDefined() - expect(json.datasource._rev).toBeDefined() - - return [response, json] - } - - async update( - body: Datasource - ): Promise<[Response, UpdateDatasourceResponse]> { - const [response, json] = await this.put(`/datasources/${body._id}`, body) - expect(json.datasource._id).toBeDefined() - expect(json.datasource._rev).toBeDefined() - - return [response, json] - } - - async delete(dataSourceId: string, revId: string): Promise { - const [response, json] = await this.del( - `/datasources/${dataSourceId}/${revId}` - ) - - return response - } -} diff --git a/qa-core/src/internal-api/api/apis/EnvironmentAPI.ts b/qa-core/src/internal-api/api/apis/EnvironmentAPI.ts deleted file mode 100644 index c9458d92a5..0000000000 --- a/qa-core/src/internal-api/api/apis/EnvironmentAPI.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { GetEnvironmentResponse } from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import { APIRequestOpts } from "../../../types" - -export default class EnvironmentAPI { - client: BudibaseInternalAPIClient - - constructor(client: BudibaseInternalAPIClient) { - this.client = client - } - - async getEnvironment( - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.get(`/system/environment`) - if (opts.doExpect) { - expect(response.status).toBe(200) - } - return json - } -} diff --git a/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts b/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts deleted file mode 100644 index 66d086357a..0000000000 --- a/qa-core/src/internal-api/api/apis/IntegrationsAPI.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Response } from "node-fetch" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" - -export default class IntegrationsAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async getAll(): Promise<[Response, any]> { - const [response, json] = await this.get(`/integrations`) - const integrationsCount = Object.keys(json).length - expect(integrationsCount).toBeGreaterThan(0) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/LicenseAPI.ts b/qa-core/src/internal-api/api/apis/LicenseAPI.ts deleted file mode 100644 index ef322e069a..0000000000 --- a/qa-core/src/internal-api/api/apis/LicenseAPI.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Response } from "node-fetch" -import { - ActivateLicenseKeyRequest, - ActivateOfflineLicenseTokenRequest, - GetLicenseKeyResponse, - GetOfflineIdentifierResponse, - GetOfflineLicenseTokenResponse, -} from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" -import { APIRequestOpts } from "../../../types" - -export default class LicenseAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - async getOfflineLicenseToken( - opts: { status?: number } = {} - ): Promise<[Response, GetOfflineLicenseTokenResponse]> { - const [response, body] = await this.get( - `/global/license/offline`, - opts.status - ) - return [response, body] - } - async deleteOfflineLicenseToken(): Promise<[Response]> { - const [response] = await this.del(`/global/license/offline`, 204) - return [response] - } - async activateOfflineLicenseToken( - body: ActivateOfflineLicenseTokenRequest - ): Promise<[Response]> { - const [response] = await this.post(`/global/license/offline`, body) - return [response] - } - async getOfflineIdentifier(): Promise< - [Response, GetOfflineIdentifierResponse] - > { - const [response, body] = await this.get( - `/global/license/offline/identifier` - ) - return [response, body] - } - - async getLicenseKey( - opts: { status?: number } = {} - ): Promise<[Response, GetLicenseKeyResponse]> { - const [response, body] = await this.get(`/global/license/key`, opts.status) - return [response, body] - } - - async activateLicenseKey( - body: ActivateLicenseKeyRequest - ): Promise<[Response]> { - const [response] = await this.post(`/global/license/key`, body) - return [response] - } - - async deleteLicenseKey(): Promise<[Response]> { - const [response] = await this.del(`/global/license/key`, 204) - return [response] - } -} diff --git a/qa-core/src/internal-api/api/apis/PermissionsAPI.ts b/qa-core/src/internal-api/api/apis/PermissionsAPI.ts deleted file mode 100644 index 126d4eb430..0000000000 --- a/qa-core/src/internal-api/api/apis/PermissionsAPI.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Response } from "node-fetch" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" - -export default class PermissionsAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async getAll(id: string): Promise<[Response, any]> { - const [response, json] = await this.get(`/permissions/${id}`) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/QueriesAPI.ts b/qa-core/src/internal-api/api/apis/QueriesAPI.ts deleted file mode 100644 index e3b9d1e474..0000000000 --- a/qa-core/src/internal-api/api/apis/QueriesAPI.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Response } from "node-fetch" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import { PreviewQueryRequest, Query } from "@budibase/types" -import BaseAPI from "./BaseAPI" - -export default class QueriesAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async preview(body: PreviewQueryRequest): Promise<[Response, any]> { - const [response, json] = await this.post(`/queries/preview`, body) - return [response, json] - } - - async save(body: Query): Promise<[Response, any]> { - const [response, json] = await this.post(`/queries`, body) - return [response, json] - } - - async getQuery(queryId: string): Promise<[Response, any]> { - const [response, json] = await this.get(`/queries/${queryId}`) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/RoleAPI.ts b/qa-core/src/internal-api/api/apis/RoleAPI.ts deleted file mode 100644 index 370e287382..0000000000 --- a/qa-core/src/internal-api/api/apis/RoleAPI.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Response } from "node-fetch" -import { Role, UserRoles } from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" - -export default class RoleAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async getRoles(): Promise<[Response, Role[]]> { - const [response, json] = await this.get(`/roles`) - return [response, json] - } - - async createRole(body: Partial): Promise<[Response, UserRoles]> { - const [response, json] = await this.post(`/roles`, body) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/RowAPI.ts b/qa-core/src/internal-api/api/apis/RowAPI.ts deleted file mode 100644 index 18c4874157..0000000000 --- a/qa-core/src/internal-api/api/apis/RowAPI.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Response } from "node-fetch" -import { Row } from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" - -export default class RowAPI extends BaseAPI { - rowAdded: boolean - - constructor(client: BudibaseInternalAPIClient) { - super(client) - this.rowAdded = false - } - - async getAll(tableId: string): Promise<[Response, Row[]]> { - const [response, json] = await this.get(`/${tableId}/rows`) - if (this.rowAdded) { - expect(json.length).toBeGreaterThanOrEqual(1) - } - return [response, json] - } - async add(tableId: string, body: Row): Promise<[Response, Row]> { - const [response, json] = await this.post(`/${tableId}/rows`, body) - expect(json._id).toBeDefined() - expect(json._rev).toBeDefined() - expect(json.tableId).toEqual(tableId) - this.rowAdded = true - return [response, json] - } - - async delete(tableId: string, body: Row): Promise<[Response, Row[]]> { - const [response, json] = await this.del( - `/${tableId}/rows/`, - undefined, - body - ) - return [response, json] - } - - async searchNoPagination( - tableId: string, - body: string - ): Promise<[Response, Row[]]> { - const [response, json] = await this.post(`/${tableId}/search`, body) - expect(json.hasNextPage).toEqual(false) - return [response, json.rows] - } - - async searchWithPagination( - tableId: string, - body: string - ): Promise<[Response, Row[]]> { - const [response, json] = await this.post(`/${tableId}/search`, body) - expect(json.hasNextPage).toEqual(true) - expect(json.rows.length).toEqual(10) - return [response, json.rows] - } -} diff --git a/qa-core/src/internal-api/api/apis/ScreenAPI.ts b/qa-core/src/internal-api/api/apis/ScreenAPI.ts deleted file mode 100644 index df3d699cbd..0000000000 --- a/qa-core/src/internal-api/api/apis/ScreenAPI.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Response } from "node-fetch" -import { Screen } from "@budibase/types" -import { ScreenRequest } from "../../../types/screens" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import BaseAPI from "./BaseAPI" - -export default class ScreenAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async create(body: ScreenRequest): Promise<[Response, Screen]> { - const [response, json] = await this.post(`/screens`, body) - expect(json._id).toBeDefined() - expect(json.routing.roleId).toBe(body.routing.roleId) - return [response, json] - } - - async delete(screenId: string, rev: string): Promise<[Response, Screen]> { - const [response, json] = await this.del(`/screens/${screenId}/${rev}`) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/SelfAPI.ts b/qa-core/src/internal-api/api/apis/SelfAPI.ts deleted file mode 100644 index cd162053a1..0000000000 --- a/qa-core/src/internal-api/api/apis/SelfAPI.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Response } from "node-fetch" -import { User } from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import { ApiKeyResponse } from "../../../types" -import BaseAPI from "./BaseAPI" - -export default class SelfAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async getSelf(): Promise<[Response, Partial]> { - const [response, json] = await this.get(`/global/self`) - return [response, json] - } - - async changeSelfPassword(body: Partial): Promise<[Response, User]> { - const [response, json] = await this.post(`/global/self`, body) - expect(json._id).toEqual(body._id) - expect(json._rev).not.toEqual(body._rev) - return [response, json] - } - - async getApiKey(): Promise { - const [response, json] = await this.get(`/global/self/api_key`) - expect(json).toHaveProperty("apiKey") - return json - } -} diff --git a/qa-core/src/internal-api/api/apis/TableAPI.ts b/qa-core/src/internal-api/api/apis/TableAPI.ts deleted file mode 100644 index 88629381b1..0000000000 --- a/qa-core/src/internal-api/api/apis/TableAPI.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Response } from "node-fetch" -import { Table } from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import { MessageResponse } from "../../../types" -import BaseAPI from "./BaseAPI" - -export default class TableAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async getAll(expectedNumber: Number): Promise<[Response, Table[]]> { - const [response, json] = await this.get(`/tables`) - expect(json.length).toBe(expectedNumber) - return [response, json] - } - - async getTableById(id: string): Promise<[Response, Table]> { - const [response, json] = await this.get(`/tables/${id}`) - expect(json._id).toEqual(id) - return [response, json] - } - - async save(body: any, columnAdded?: boolean): Promise<[Response, Table]> { - const [response, json] = await this.post(`/tables`, body) - expect(json._id).toBeDefined() - expect(json._rev).toBeDefined() - if (columnAdded) { - expect(json.schema.TestColumn).toBeDefined() - } - - return [response, json] - } - - async forbiddenSave(body: any): Promise<[Response, Table]> { - const [response, json] = await this.post(`/tables`, body, 403) - return [response, json] - } - - async delete( - id: string, - revId: string - ): Promise<[Response, MessageResponse]> { - const [response, json] = await this.del(`/tables/${id}/${revId}`) - expect(json.message).toEqual(`Table ${id} deleted.`) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/apis/UserAPI.ts b/qa-core/src/internal-api/api/apis/UserAPI.ts deleted file mode 100644 index 7ecb7da622..0000000000 --- a/qa-core/src/internal-api/api/apis/UserAPI.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Response } from "node-fetch" -import { Role, User, UserDeletedEvent, UserRoles } from "@budibase/types" -import BudibaseInternalAPIClient from "../BudibaseInternalAPIClient" -import { MessageResponse } from "../../../types" -import BaseAPI from "./BaseAPI" - -export default class UserAPI extends BaseAPI { - constructor(client: BudibaseInternalAPIClient) { - super(client) - } - - async search(): Promise<[Response, Partial[]]> { - const [response, json] = await this.post(`/global/users/search`, {}) - - expect(json.data.length).toBeGreaterThan(0) - return [response, json] - } - - async getSelf(): Promise<[Response, Partial]> { - const [response, json] = await this.get(`/global/self`) - - return [response, json] - } - - async getAll(): Promise<[Response, Partial[]]> { - const [response, json] = await this.get(`/global/users`) - - expect(json.length).toBeGreaterThan(0) - return [response, json] - } - - // This endpoint is used for one or more users when we want add users with passwords set. - async addMultiple(userList: Partial[]): Promise<[Response, any]> { - const body = { - create: { - users: userList, - groups: [], - }, - } - const [response, json] = await this.post(`/global/users/bulk`, body) - - expect(json.created.unsuccessful.length).toEqual(0) - expect(json.created.successful.length).toEqual(body.create.users.length) - return [response, json] - } - - async deleteMultiple(userId: string[]): Promise<[Response, MessageResponse]> { - const body = { - delete: { - userIds: [userId], - }, - } - const [response, json] = await this.post(`/global/users/bulk`, body) - expect(json.deleted.successful.length).toEqual(1) - expect(json.deleted.unsuccessful.length).toEqual(0) - expect(json.deleted.successful[0].userId).toEqual(userId) - return [response, json] - } - async delete(userId: string): Promise<[Response, UserDeletedEvent]> { - const [response, json] = await this.del(`/global/users/${userId}`) - expect(json.message).toEqual(`User ${userId} deleted.`) - return [response, json] - } - - async invite(body: any): Promise<[Response, MessageResponse]> { - const [response, json] = await this.post(`/global/users/multi/invite`, body) - expect(json.unsuccessful.length).toEqual(0) - expect(json.successful.length).toEqual(body.length) - return [response, json] - } - - async getRoles(): Promise<[Response, Role[]]> { - const [response, json] = await this.get(`/roles`) - return [response, json] - } - - async updateInfo(body: any): Promise<[Response, User]> { - const [response, json] = await this.post(`/global/users/`, body) - expect(json._id).toEqual(body._id) - expect(json._rev).not.toEqual(body._rev) - return [response, json] - } - - async forcePasswordReset(body: any): Promise<[Response, User]> { - const [response, json] = await this.post(`/global/users/`, body) - expect(json._id).toEqual(body._id) - expect(json._rev).not.toEqual(body._rev) - return [response, json] - } - - async getInfo(userId: string): Promise<[Response, User]> { - const [response, json] = await this.get(`/global/users/${userId}`) - return [response, json] - } - - async changeSelfPassword(body: Partial): Promise<[Response, User]> { - const [response, json] = await this.post(`/global/self`, body) - expect(json._id).toEqual(body._id) - expect(json._rev).not.toEqual(body._rev) - return [response, json] - } - - async createRole(body: Partial): Promise<[Response, UserRoles]> { - const [response, json] = await this.post(`/roles`, body) - return [response, json] - } -} diff --git a/qa-core/src/internal-api/api/index.ts b/qa-core/src/internal-api/api/index.ts deleted file mode 100644 index b6d01a710a..0000000000 --- a/qa-core/src/internal-api/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BudibaseInternalAPI } from "./BudibaseInternalAPI" diff --git a/qa-core/src/internal-api/config/TestConfiguration.ts b/qa-core/src/internal-api/config/TestConfiguration.ts deleted file mode 100644 index dc5fec73dc..0000000000 --- a/qa-core/src/internal-api/config/TestConfiguration.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BudibaseInternalAPI } from "../api" -import { BudibaseTestConfiguration } from "../../shared" - -export default class TestConfiguration extends BudibaseTestConfiguration { - // apis - api: BudibaseInternalAPI - - // context - context: T - - constructor() { - super() - // for brevity - this.api = this.internalApi - this.context = {} - } - - async beforeAll() { - await super.beforeAll() - } - - async afterAll() { - await super.afterAll() - } -} diff --git a/qa-core/src/internal-api/config/index.ts b/qa-core/src/internal-api/config/index.ts deleted file mode 100644 index 182c7825b6..0000000000 --- a/qa-core/src/internal-api/config/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TestConfiguration } from "./TestConfiguration" diff --git a/qa-core/src/internal-api/fixtures/accounts.ts b/qa-core/src/internal-api/fixtures/accounts.ts deleted file mode 100644 index ff7042a1ad..0000000000 --- a/qa-core/src/internal-api/fixtures/accounts.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { generator } from "../../shared" -import { Hosting, CreateAccountRequest } from "@budibase/types" - -export const generateAccount = (): CreateAccountRequest => { - const uuid = generator.guid() - - const email = `qa+${uuid}@budibase.com` - const tenant = `tenant${uuid.replace(/-/g, "")}` - - return { - email, - hosting: Hosting.CLOUD, - name: email, - password: uuid, - profession: "software_engineer", - size: "10+", - tenantId: tenant, - tenantName: tenant, - } -} diff --git a/qa-core/src/internal-api/fixtures/applications.ts b/qa-core/src/internal-api/fixtures/applications.ts deleted file mode 100644 index 59f73ba863..0000000000 --- a/qa-core/src/internal-api/fixtures/applications.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { generator } from "../../shared" -import { CreateAppRequest } from "@budibase/types" - -function uniqueWord() { - return generator.word() + generator.hash() -} - -export const generateApp = ( - overrides: Partial = {} -): CreateAppRequest => ({ - name: uniqueWord(), - url: `/${uniqueWord()}`, - ...overrides, -}) - -// Applications type doesn't work here, save to add useTemplate parameter? -export const appFromTemplate = (): CreateAppRequest => { - return { - name: uniqueWord(), - url: `/${uniqueWord()}`, - // @ts-ignore - useTemplate: "true", - templateName: "Near Miss Register", - templateKey: "app/near-miss-register", - templateFile: undefined, - } -} diff --git a/qa-core/src/internal-api/fixtures/datasources.ts b/qa-core/src/internal-api/fixtures/datasources.ts deleted file mode 100644 index c7f969a98c..0000000000 --- a/qa-core/src/internal-api/fixtures/datasources.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { Datasource } from "@budibase/types" -import { DatasourceRequest } from "../../types" -import { generator } from "../../shared" - -// Add information about the data source to the fixtures file from 1password -export const mongoDB = (): DatasourceRequest => { - return { - datasource: { - name: "MongoDB", - source: "MONGODB", - type: "datasource", - config: { - connectionString: process.env.MONGODB_CONNECTION_STRING, - db: process.env.MONGODB_DB, - }, - }, - - fetchSchema: false, - } -} - -export const postgresSQL = (): DatasourceRequest => { - return { - datasource: { - name: "PostgresSQL", - plus: true, - source: "POSTGRES", - type: "datasource", - config: { - database: process.env.POSTGRES_DB, - host: process.env.POSTGRES_HOST, - password: process.env.POSTGRES_PASSWORD, - port: process.env.POSTGRES_PORT, - schema: "public", - user: process.env.POSTGRES_USER, - }, - }, - fetchSchema: true, - } -} -export const mariaDB = (): DatasourceRequest => { - return { - datasource: { - name: "MariaDB", - plus: true, - source: "MYSQL", - type: "datasource", - config: { - database: process.env.MARIADB_DB, - host: process.env.MARIADB_HOST, - password: process.env.MARIADB_PASSWORD, - port: process.env.MARIADB_PORT, - schema: "public", - user: process.env.MARIADB_USER, - }, - }, - fetchSchema: true, - } -} - -export const restAPI = (): DatasourceRequest => { - return { - datasource: { - name: "RestAPI", - source: "REST", - type: "datasource", - config: { - defaultHeaders: {}, - rejectUnauthorized: true, - url: process.env.REST_API_BASE_URL, - }, - }, - fetchSchema: false, - } -} - -export const generateRelationshipForMySQL = ( - updatedDataSourceJson: any -): Datasource => { - const entities = updatedDataSourceJson!.datasource!.entities! - const datasourceId = updatedDataSourceJson!.datasource!._id! - const relationShipBody = { - ...updatedDataSourceJson.datasource, - entities: { - ...updatedDataSourceJson.datasource.entities, - employees: { - ...entities.employees, - schema: { - ...entities.employees.schema, - salaries: { - tableId: `${datasourceId}__salaries`, - name: "salaries", - relationshipType: "many-to-one", - fieldName: "salary", - type: "link", - main: true, - _id: generator.string(), - foreignKey: "emp_no", - }, - }, - }, - titles: { - ...entities.titles, - schema: { - ...entities.titles.schema, - employees: { - tableId: `${datasourceId}__employees`, - name: "employees", - relationshipType: "one-to-many", - fieldName: "emp_no", - type: "link", - main: true, - _id: generator.string(), - foreignKey: "emp_no", - }, - }, - }, - }, - } - - return relationShipBody -} diff --git a/qa-core/src/internal-api/fixtures/index.ts b/qa-core/src/internal-api/fixtures/index.ts deleted file mode 100644 index 38291052b8..0000000000 --- a/qa-core/src/internal-api/fixtures/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * as accounts from "./accounts" -export * as apps from "./applications" -export * as rows from "./rows" -export * as screens from "./screens" -export * as tables from "./tables" -export * as users from "./users" -export * as datasources from "./datasources" -export * as queries from "./queries" diff --git a/qa-core/src/internal-api/fixtures/queries.ts b/qa-core/src/internal-api/fixtures/queries.ts deleted file mode 100644 index 0a28c23ab7..0000000000 --- a/qa-core/src/internal-api/fixtures/queries.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { PreviewQueryRequest } from "@budibase/types" - -const query = (datasourceId: string, fields: any): any => { - return { - datasourceId: datasourceId, - fields: fields, - name: "Query 1", - parameters: {}, - queryVerb: "read", - schema: {}, - transformer: "return data", - } -} - -export const mariaDB = (datasourceId: string): PreviewQueryRequest => { - const fields = { - sql: "SELECT * FROM employees LIMIT 10;", - } - return query(datasourceId, fields) -} - -export const mongoDB = (datasourceId: string): PreviewQueryRequest => { - const fields = { - extra: { - collection: "movies", - actionType: "find", - }, - json: "", - } - return query(datasourceId, fields) -} - -export const postgres = (datasourceId: string): PreviewQueryRequest => { - const fields = { - sql: "SELECT * FROM customers;", - } - return query(datasourceId, fields) -} - -export const expectedSchemaFields = { - mariaDB: { - birth_date: "string", - emp_no: "number", - first_name: "string", - gender: "string", - hire_date: "string", - last_name: "string", - }, - mongoDB: { - directors: "array", - genres: "array", - image: "string", - plot: "string", - rank: "number", - rating: "number", - release_date: "string", - running_time_secs: "number", - title: "string", - year: "number", - _id: "string", - }, - postgres: { - address: "string", - city: "string", - company_name: "string", - contact_name: "string", - contact_title: "string", - country: "string", - customer_id: "string", - fax: "string", - phone: "string", - postal_code: "string", - region: "string", - }, - restAPI: { - abilities: "array", - base_experience: "number", - forms: "array", - game_indices: "array", - height: "number", - held_items: "array", - id: "number", - is_default: "string", - location_area_encounters: "string", - moves: "array", - name: "string", - order: "number", - past_types: "array", - species: "json", - sprites: "json", - stats: "array", - types: "array", - weight: "number", - }, -} - -const request = (datasourceId: string, fields: any, flags: any): any => { - return { - datasourceId: datasourceId, - fields: fields, - flags: flags, - name: "Query 1", - parameters: {}, - queryVerb: "read", - schema: {}, - transformer: "return data", - } -} -export const restAPI = (datasourceId: string): PreviewQueryRequest => { - const fields = { - authConfigId: null, - bodyType: "none", - disabledHeaders: {}, - headers: {}, - pagination: {}, - path: `${process.env.REST_API_BASE_URL}/pokemon/ditto`, - queryString: "", - } - const flags = { - urlName: true, - } - return request(datasourceId, fields, flags) -} diff --git a/qa-core/src/internal-api/fixtures/rows.ts b/qa-core/src/internal-api/fixtures/rows.ts deleted file mode 100644 index f1f1c00493..0000000000 --- a/qa-core/src/internal-api/fixtures/rows.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Row } from "@budibase/types" - -export const generateNewRowForTable = (tableId: string): Row => { - return { - TestColumn: "TestRow", - tableId: tableId, - } -} - -export const searchBody = (primaryDisplay: string): any => { - return { - bookmark: null, - limit: 10, - paginate: true, - query: { - contains: {}, - containsAny: {}, - empty: {}, - equal: {}, - fuzzy: {}, - notContains: {}, - notEmpty: {}, - notEqual: {}, - oneOf: {}, - range: {}, - string: {}, - }, - sort: primaryDisplay, - sortOrder: "ascending", - sortType: "string", - } -} diff --git a/qa-core/src/internal-api/fixtures/screens.ts b/qa-core/src/internal-api/fixtures/screens.ts deleted file mode 100644 index c28a5ed86f..0000000000 --- a/qa-core/src/internal-api/fixtures/screens.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { generator } from "../../shared" -import { ScreenRequest } from "../../types" - -const randomId = generator.guid() - -export const generateScreen = (roleId: string): ScreenRequest => ({ - showNavigation: true, - width: "Large", - name: randomId, - template: "createFromScratch", - props: { - _id: randomId, - _component: "@budibase/standard-components/container", - _styles: { - normal: {}, - hover: {}, - active: {}, - selected: {}, - }, - _children: [], - _instanceName: "New Screen", - direction: "column", - hAlign: "stretch", - vAlign: "top", - size: "grow", - gap: "M", - }, - routing: { - route: "/test", - roleId: roleId, - homeScreen: false, - }, -}) diff --git a/qa-core/src/internal-api/fixtures/tables.ts b/qa-core/src/internal-api/fixtures/tables.ts deleted file mode 100644 index 3de950fd9f..0000000000 --- a/qa-core/src/internal-api/fixtures/tables.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Table } from "@budibase/types" - -export const generateTable = (): Table => { - return { - name: "Test Table", - schema: {}, - sourceId: "bb_internal", - type: "internal", - } -} - -export const generateNewColumnForTable = (tableData: any): Table => { - const newColumn = tableData - newColumn.schema = { - TestColumn: { - type: "string", - name: "TestColumn", - constraints: { - presence: { allowEmpty: false }, - length: { maximum: null }, - type: "string", - }, - }, - } - newColumn.indexes = { - 0: "TestColumn", - } - newColumn.updatedAt = new Date().toISOString() - return newColumn -} diff --git a/qa-core/src/internal-api/fixtures/users.ts b/qa-core/src/internal-api/fixtures/users.ts deleted file mode 100644 index 9979ef7663..0000000000 --- a/qa-core/src/internal-api/fixtures/users.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { generator } from "../../shared" -import { User } from "@budibase/types" - -const generateDeveloper = (): Partial => { - const randomId = generator.guid() - return { - email: `${randomId}@budibase.com`, - password: randomId, - roles: {}, - forceResetPassword: true, - builder: { - global: true, - }, - } -} - -const generateAdmin = (): Partial => { - const randomId = generator.guid() - return { - email: `${randomId}@budibase.com`, - password: randomId, - roles: {}, - forceResetPassword: true, - admin: { - global: true, - }, - builder: { - global: true, - }, - } -} -const generateAppUser = (): Partial => { - const randomId = generator.guid() - return { - email: `${randomId}@budibase.com`, - password: randomId, - roles: {}, - forceResetPassword: true, - admin: { - global: false, - }, - builder: { - global: false, - }, - } -} - -export const generateInviteUser = (): Object[] => { - const randomId = generator.guid() - return [ - { - email: `${randomId}@budibase.com`, - userInfo: { - userGroups: [], - }, - }, - ] -} - -export const generateUser = ( - amount: number = 1, - role?: string -): Partial[] => { - const userList: Partial[] = [] - for (let i = 0; i < amount; i++) { - switch (role) { - case "admin": - userList.push(generateAdmin()) - break - case "developer": - userList.push(generateDeveloper()) - break - case "appUser": - userList.push(generateAppUser()) - break - default: - userList.push(generateAppUser()) - break - } - } - return userList -} diff --git a/qa-core/src/internal-api/index.ts b/qa-core/src/internal-api/index.ts deleted file mode 100644 index e1a716605a..0000000000 --- a/qa-core/src/internal-api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./api" diff --git a/qa-core/src/internal-api/tests/dataSources/mariaDB.integration.spec.ts b/qa-core/src/internal-api/tests/dataSources/mariaDB.integration.spec.ts deleted file mode 100644 index 24c9cea94b..0000000000 --- a/qa-core/src/internal-api/tests/dataSources/mariaDB.integration.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { Query } from "@budibase/types" - -describe("Internal API - Data Sources: MariaDB", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Create an app with a data source - MariaDB", async () => { - // Create app - await config.createApp() - - // Get all integrations - await config.api.integrations.getAll() - - // Add data source - const [dataSourceResponse, dataSourceJson] = - await config.api.datasources.add(fixtures.datasources.mariaDB()) - - // Update data source - const newDataSourceInfo = { - ...dataSourceJson.datasource, - name: "MariaDB2", - } - const [updatedDataSourceResponse, updatedDataSourceJson] = - await config.api.datasources.update(newDataSourceInfo) - - // Query data source - const [queryResponse, queryJson] = await config.api.queries.preview( - fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!) - ) - - expect(queryJson.rows.length).toEqual(10) - expect(queryJson.schemaFields).toEqual( - fixtures.queries.expectedSchemaFields.mariaDB - ) - - // Save query - const datasourcetoSave: Query = { - ...fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!), - parameters: [], - } - - const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( - datasourcetoSave - ) - // Get Query - const [getQueryResponse, getQueryJson] = await config.api.queries.getQuery( - saveQueryJson._id - ) - - // Get Query permissions - const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.permissions.getAll(saveQueryJson._id!) - - // Delete data source - const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id!, - updatedDataSourceJson.datasource._rev! - ) - }) - - it("Create a relationship", async () => { - // Create app - await config.createApp() - - // Get all integrations - await config.api.integrations.getAll() - - // Add data source - const [dataSourceResponse, dataSourceJson] = - await config.api.datasources.add(fixtures.datasources.mariaDB()) - - // Update data source - const newDataSourceInfo = { - ...dataSourceJson.datasource, - name: "MariaDB2", - } - const [updatedDataSourceResponse, updatedDataSourceJson] = - await config.api.datasources.update(newDataSourceInfo) - - // Query data source - const [queryResponse, queryJson] = await config.api.queries.preview( - fixtures.queries.mariaDB(updatedDataSourceJson.datasource._id!) - ) - - expect(queryJson.rows.length).toBeGreaterThan(9) - expect(queryJson.schemaFields).toEqual( - fixtures.queries.expectedSchemaFields.mariaDB - ) - - // Add relationship - const relationShipBody = fixtures.datasources.generateRelationshipForMySQL( - updatedDataSourceJson - ) - const [relationshipResponse, relationshipJson] = - await config.api.datasources.update(relationShipBody) - }) -}) diff --git a/qa-core/src/internal-api/tests/dataSources/mongoDB.integration.spec.ts b/qa-core/src/internal-api/tests/dataSources/mongoDB.integration.spec.ts deleted file mode 100644 index efa9eb2dd2..0000000000 --- a/qa-core/src/internal-api/tests/dataSources/mongoDB.integration.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { Query } from "@budibase/types" - -describe.skip("Internal API - Data Sources: MongoDB", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Create an app with a data source - MongoDB", async () => { - // Create app - await config.createApp() - - // Get all integrations - await config.api.integrations.getAll() - - // Add data source - const [dataSourceResponse, dataSourceJson] = - await config.api.datasources.add(fixtures.datasources.mongoDB()) - - // Update data source - const newDataSourceInfo = { - ...dataSourceJson.datasource, - name: "MongoDB2", - } - const [updatedDataSourceResponse, updatedDataSourceJson] = - await config.api.datasources.update(newDataSourceInfo) - - // Query data source - const [queryResponse, queryJson] = await config.api.queries.preview( - fixtures.queries.mongoDB(updatedDataSourceJson.datasource._id!) - ) - - expect(queryJson.rows.length).toBeGreaterThan(10) - expect(queryJson.schemaFields).toEqual( - fixtures.queries.expectedSchemaFields.mongoDB - ) - - // Save query - const datasourcetoSave: Query = { - ...fixtures.queries.mongoDB(updatedDataSourceJson.datasource._id!), - parameters: [], - } - - const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( - datasourcetoSave - ) - // Get Query - const [getQueryResponse, getQueryJson] = await config.api.queries.getQuery( - saveQueryJson._id - ) - - // Get Query permissions - const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.permissions.getAll(saveQueryJson._id!) - - // Delete data source - const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id!, - updatedDataSourceJson.datasource._rev! - ) - }) -}) diff --git a/qa-core/src/internal-api/tests/dataSources/postgresSQL.integration.spec.ts b/qa-core/src/internal-api/tests/dataSources/postgresSQL.integration.spec.ts deleted file mode 100644 index 2aabd608bc..0000000000 --- a/qa-core/src/internal-api/tests/dataSources/postgresSQL.integration.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { Query } from "@budibase/types" - -describe("Internal API - Data Sources: PostgresSQL", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Create an app with a data source - PostgresSQL", async () => { - // Create app - await config.createApp() - - // Get all integrations - await config.api.integrations.getAll() - - // Add data source - const [dataSourceResponse, dataSourceJson] = - await config.api.datasources.add(fixtures.datasources.postgresSQL()) - - // Update data source - const newDataSourceInfo = { - ...dataSourceJson.datasource, - name: "PostgresSQL2", - } - const [updatedDataSourceResponse, updatedDataSourceJson] = - await config.api.datasources.update(newDataSourceInfo) - - // Query data source - const [queryResponse, queryJson] = await config.api.queries.preview( - fixtures.queries.postgres(updatedDataSourceJson.datasource._id!) - ) - - expect(queryJson.rows.length).toBeGreaterThan(10) - expect(queryJson.schemaFields).toEqual( - fixtures.queries.expectedSchemaFields.postgres - ) - - // Save query - const datasourcetoSave: Query = { - ...fixtures.queries.postgres(updatedDataSourceJson.datasource._id!), - parameters: [], - } - - const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( - datasourcetoSave - ) - // Get Query - const [getQueryResponse, getQueryJson] = await config.api.queries.getQuery( - saveQueryJson._id! - ) - - // Get Query permissions - const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.permissions.getAll(saveQueryJson._id!) - - // Delete data source - const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id!, - updatedDataSourceJson.datasource._rev! - ) - }) -}) diff --git a/qa-core/src/internal-api/tests/dataSources/restAPI.integration.spec.ts b/qa-core/src/internal-api/tests/dataSources/restAPI.integration.spec.ts deleted file mode 100644 index 649e21db78..0000000000 --- a/qa-core/src/internal-api/tests/dataSources/restAPI.integration.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import * as fixtures from "../../fixtures" -import { Query } from "@budibase/types" - -describe("Internal API - Data Sources: REST API", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Create an app with a data source - REST API", async () => { - // Create app - await config.createApp() - - // Get all integrations - await config.api.integrations.getAll() - - // Add data source - const [dataSourceResponse, dataSourceJson] = - await config.api.datasources.add(fixtures.datasources.restAPI()) - - // Update data source - const newDataSourceInfo = { - ...dataSourceJson.datasource, - name: "RestAPI - Updated", - } - const [updatedDataSourceResponse, updatedDataSourceJson] = - await config.api.datasources.update(newDataSourceInfo) - - // Query data source - const [queryResponse, queryJson] = await config.api.queries.preview( - fixtures.queries.restAPI(updatedDataSourceJson.datasource._id!) - ) - - expect(queryJson.rows.length).toEqual(1) - expect(queryJson.schemaFields).toEqual( - fixtures.queries.expectedSchemaFields.restAPI - ) - - // Save query - const datasourcetoSave: Query = { - ...fixtures.queries.postgres(updatedDataSourceJson.datasource._id!), - parameters: [], - } - - const [saveQueryResponse, saveQueryJson] = await config.api.queries.save( - datasourcetoSave - ) - // Get Query - const [getQueryResponse, getQueryJson] = await config.api.queries.getQuery( - saveQueryJson._id! - ) - - // Get Query permissions - const [getQueryPermissionsResponse, getQueryPermissionsJson] = - await config.api.permissions.getAll(saveQueryJson._id!) - - // Delete data source - const deleteResponse = await config.api.datasources.delete( - updatedDataSourceJson.datasource._id!, - updatedDataSourceJson.datasource._rev! - ) - }) -}) diff --git a/qa-core/src/internal-api/tests/users/customRoles.spec.ts b/qa-core/src/internal-api/tests/users/customRoles.spec.ts deleted file mode 100644 index a02e9f315a..0000000000 --- a/qa-core/src/internal-api/tests/users/customRoles.spec.ts +++ /dev/null @@ -1,315 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import { App, User } from "@budibase/types" -import { db } from "@budibase/backend-core" -import * as fixtures from "./../../fixtures" - -describe.skip("Internal API - App Specific Roles & Permissions", () => { - const config = new TestConfiguration() - let app: Partial - - // Before each test, login as admin. Some tests will require login as a different user - beforeEach(async () => { - await config.beforeAll() - app = await config.createApp() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Custom role access for level 1 permissions", async () => { - // Set up user - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - //Create level 1 role - const role = { - inherits: "BASIC", - permissionId: "public", - name: "level 1", - } - const [createRoleResponse, createRoleJson] = - await config.api.users.createRole(role) - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: createRoleJson._id, - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id) - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with level 1 user - await config.login( - config.state.tenantId!, - appUser[0].email!, - appUser[0].password! - ) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(1) - }) - it("Custom role access for level 2 permissions", async () => { - // Set up user - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - - //Create level 1 role - const role = { - inherits: "BASIC", - permissionId: "read_only", - name: "level 2", - } - const [createRoleResponse, createRoleJson] = - await config.api.users.createRole(role) - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: createRoleJson._id, - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id) - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with level 1 user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(1) - }) - it("Custom role access for level 3 permissions", async () => { - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - - //Create level 1 role - const role = { - inherits: "BASIC", - permissionId: "write", - name: "level 3", - } - const [createRoleResponse, createRoleJson] = - await config.api.users.createRole(role) - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: createRoleJson._id, - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id) - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with level 1 user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(1) - }) - it("Custom role access for level 4 permissions", async () => { - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - - //Create level 1 role - const role = { - inherits: "BASIC", - permissionId: "power", - name: "level 4", - } - const [createRoleResponse, createRoleJson] = - await config.api.users.createRole(role) - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: createRoleJson._id, - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id) - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with level 1 user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(1) - }) - it("Custom role access for level 5 permissions", async () => { - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - - //Create level 1 role - const role = { - inherits: "BASIC", - permissionId: "admin", - name: "level 5", - } - const [createRoleResponse, createRoleJson] = - await config.api.users.createRole(role) - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: createRoleJson._id, - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual(createRoleJson._id) - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with level 1 user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(1) - }) -}) diff --git a/qa-core/src/internal-api/tests/users/screenAccess.spec.ts b/qa-core/src/internal-api/tests/users/screenAccess.spec.ts deleted file mode 100644 index 563eebb6f8..0000000000 --- a/qa-core/src/internal-api/tests/users/screenAccess.spec.ts +++ /dev/null @@ -1,175 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import { User } from "@budibase/types" -import { db } from "@budibase/backend-core" -import * as fixtures from "./../../fixtures" - -describe.skip("Internal API - Role screen access", () => { - const config = new TestConfiguration() - - // Before each test, login as admin. Some tests will require login as a different user - beforeEach(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Check Screen access for BASIC Role", async () => { - // Set up user - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - const app = await config.createApp() - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: "BASIC", - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual("BASIC") - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with BASIC user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(1) - expect(appPackageJson.screens[0].routing.roleId).toEqual("BASIC") - }) - - it("Check Screen access for POWER role", async () => { - // Set up user - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - const app = await config.createApp() - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: "POWER", - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual("POWER") - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with POWER user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(2) - }) - - it("Check Screen access for ADMIN role", async () => { - // Set up user - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - // Create App - const app = await config.createApp() - - // Update user roles - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const prodAppId = db.getProdAppID(app.appId!) - - // Roles must always be set with prod appID - const body: User = { - ...userInfoJson, - roles: { - [prodAppId]: "ADMIN", - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[prodAppId]).toBeDefined() - expect(changedUserInfoJson.roles[prodAppId]).toEqual("ADMIN") - - await config.api.screens.create(fixtures.screens.generateScreen("BASIC")) - await config.api.screens.create(fixtures.screens.generateScreen("POWER")) - await config.api.screens.create(fixtures.screens.generateScreen("ADMIN")) - - await config.api.apps.publish(app.appId) - const [firstappPackageResponse, firstappPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(firstappPackageJson.screens).toBeDefined() - expect(firstappPackageJson.screens.length).toEqual(3) - - // login with ADMIN user - await config.login(appUser[0].email!, appUser[0].password!) - const [selfInfoResponse, selfInfoJson] = await config.api.users.getSelf() - - // fetch app package - const [appPackageResponse, appPackageJson] = - await config.api.apps.getAppPackage(app.appId!) - expect(appPackageJson.screens).toBeDefined() - expect(appPackageJson.screens.length).toEqual(3) - }) -}) diff --git a/qa-core/src/internal-api/tests/users/tableAccess.spec.ts b/qa-core/src/internal-api/tests/users/tableAccess.spec.ts deleted file mode 100644 index 0db3a8a85e..0000000000 --- a/qa-core/src/internal-api/tests/users/tableAccess.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import TestConfiguration from "../../config/TestConfiguration" -import { User } from "@budibase/types" -import * as fixtures from "./../../fixtures" - -describe.skip("Internal API - Role table access", () => { - const config = new TestConfiguration() - - // Before each test, login as admin. Some tests will require login as a different user - beforeEach(async () => { - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - it("Check Table access for app user", async () => { - const appUser = fixtures.users.generateUser() - expect(appUser[0].builder?.global).toEqual(false) - expect(appUser[0].admin?.global).toEqual(false) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(appUser) - - const app = await config.createApp() - - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const body: User = { - ...userInfoJson, - roles: { - [app.appId!]: "BASIC", - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[app.appId!]).toBeDefined() - expect(changedUserInfoJson.roles[app.appId!]).toEqual("BASIC") - - const [createdTableResponse, createdTableData] = - await config.api.tables.save(fixtures.tables.generateTable()) - - await config.login(appUser[0].email!, appUser[0].password!) - - const newColumn = - fixtures.tables.generateNewColumnForTable(createdTableData) - await config.api.tables.forbiddenSave(newColumn) - await config.api.tables.forbiddenSave(fixtures.tables.generateTable()) - }) - - it.skip("Check Table access for developer", async () => { - const developer = fixtures.users.generateUser(1, "developer") - expect(developer[0].builder?.global).toEqual(true) - - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(developer) - - const app = await config.createApp() - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const body: User = { - ...userInfoJson, - roles: { - [app.appId!]: "POWER", - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[app.appId!]).toBeDefined() - expect(changedUserInfoJson.roles[app.appId!]).toEqual("POWER") - - const [createdTableResponse, createdTableData] = - await config.api.tables.save(fixtures.tables.generateTable()) - await config.login(developer[0].email!, developer[0].password!) - const newColumn = - fixtures.tables.generateNewColumnForTable(createdTableData) - const [addColumnResponse, addColumnData] = await config.api.tables.save( - newColumn, - true - ) - }) - - it.skip("Check Table access for admin", async () => { - const adminUser = fixtures.users.generateUser(1, "admin") - expect(adminUser[0].builder?.global).toEqual(true) - expect(adminUser[0].admin?.global).toEqual(true) - const [createUserResponse, createUserJson] = - await config.api.users.addMultiple(adminUser) - - const app = await config.createApp() - - const [userInfoResponse, userInfoJson] = await config.api.users.getInfo( - createUserJson.created.successful[0]._id - ) - const body: User = { - ...userInfoJson, - roles: { - [app.appId!]: "ADMIN", - }, - } - await config.api.users.updateInfo(body) - - const [changedUserInfoResponse, changedUserInfoJson] = - await config.api.users.getInfo(createUserJson.created.successful[0]._id) - expect(changedUserInfoJson.roles[app.appId!]).toBeDefined() - expect(changedUserInfoJson.roles[app.appId!]).toEqual("ADMIN") - - await config.login(adminUser[0].email!, adminUser[0].password!) - const [createdTableResponse, createdTableData] = - await config.api.tables.save(fixtures.tables.generateTable()) - const newColumn = - fixtures.tables.generateNewColumnForTable(createdTableData) - const [addColumnResponse, addColumnData] = await config.api.tables.save( - newColumn, - true - ) - }) -}) diff --git a/qa-core/src/jest/globalSetup.ts b/qa-core/src/jest/globalSetup.ts deleted file mode 100644 index 103126d74c..0000000000 --- a/qa-core/src/jest/globalSetup.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { DEFAULT_TENANT_ID } from "@budibase/backend-core" -import { AccountInternalAPI } from "../account-api" -import * as fixtures from "../internal-api/fixtures" -import { BudibaseInternalAPI } from "../internal-api" -import { Account, CreateAccountRequest, Feature } from "@budibase/types" -import env from "../environment" -import { APIRequestOpts } from "../types" - -const accountsApi = new AccountInternalAPI({}) -const internalApi = new BudibaseInternalAPI({}) - -const API_OPTS: APIRequestOpts = { doExpect: false } - -// @ts-ignore -global.qa = {} - -async function createAccount(): Promise<[CreateAccountRequest, Account]> { - const account = fixtures.accounts.generateAccount() - await accountsApi.accounts.validateEmail(account.email, API_OPTS) - await accountsApi.accounts.validateTenantId(account.tenantId, API_OPTS) - const [res, newAccount] = await accountsApi.accounts.create(account, { - ...API_OPTS, - autoVerify: true, - }) - await updateLicense(newAccount.accountId) - return [account, newAccount] -} - -const UNLIMITED = { value: -1 } - -async function updateLicense(accountId: string) { - const [response] = await accountsApi.licenses.updateLicense( - accountId, - { - overrides: { - // add all features - features: Object.values(Feature), - quotas: { - usage: { - monthly: { - automations: UNLIMITED, - }, - static: { - rows: UNLIMITED, - users: UNLIMITED, - userGroups: UNLIMITED, - plugins: UNLIMITED, - }, - }, - }, - }, - }, - { doExpect: false } - ) - if (response.status !== 200) { - throw new Error( - `Could not update license for accountId=${accountId}: ${response.status}` - ) - } -} - -async function loginAsAdmin() { - const username = env.BB_ADMIN_USER_EMAIL! - const password = env.BB_ADMIN_USER_PASSWORD! - const tenantId = DEFAULT_TENANT_ID - const [res, cookie] = await internalApi.auth.login( - tenantId, - username, - password, - API_OPTS - ) - - // @ts-ignore - global.qa.authCookie = cookie -} - -async function loginAsAccount(account: CreateAccountRequest) { - const [res, cookie] = await accountsApi.auth.login( - account.email, - account.password, - API_OPTS - ) - - // @ts-ignore - global.qa.authCookie = cookie -} - -async function setup() { - console.log("\nGLOBAL SETUP STARTING") - const env = await internalApi.environment.getEnvironment(API_OPTS) - - console.log(`Environment: ${JSON.stringify(env)}`) - - if (env.multiTenancy) { - const [account, newAccount] = await createAccount() - // @ts-ignore - global.qa.tenantId = account.tenantId - // @ts-ignore - global.qa.email = account.email - // @ts-ignore - global.qa.accountId = newAccount.accountId - await loginAsAccount(account) - } else { - // @ts-ignore - global.qa.tenantId = DEFAULT_TENANT_ID - await loginAsAdmin() - } - - // @ts-ignore - console.log(`Tenant: ${global.qa.tenantId}`) - console.log("GLOBAL SETUP COMPLETE") -} - -export default setup diff --git a/qa-core/src/jest/globalTeardown.ts b/qa-core/src/jest/globalTeardown.ts deleted file mode 100644 index ff3fea7b7c..0000000000 --- a/qa-core/src/jest/globalTeardown.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AccountInternalAPI } from "../account-api" -import { BudibaseInternalAPI } from "../internal-api" -import { APIRequestOpts } from "../types" - -const accountsApi = new AccountInternalAPI({}) -const internalApi = new BudibaseInternalAPI({}) - -const API_OPTS: APIRequestOpts = { doExpect: false } - -async function deleteAccount() { - // @ts-ignore - const accountID = global.qa.accountId - - const [response] = await accountsApi.accounts.delete(accountID, { - doExpect: false, - }) - if (response.status !== 204) { - throw new Error(`status: ${response.status} not equal to expected: 201`) - } -} - -async function teardown() { - console.log("\nGLOBAL TEARDOWN STARTING") - const env = await internalApi.environment.getEnvironment(API_OPTS) - if (env.multiTenancy) { - await deleteAccount() - } - - console.log("GLOBAL TEARDOWN COMPLETE") -} - -export default teardown diff --git a/qa-core/src/jest/jest.extends.ts b/qa-core/src/jest/jest.extends.ts deleted file mode 100644 index 653009f5f0..0000000000 --- a/qa-core/src/jest/jest.extends.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Response } from "node-fetch" - -// boilerplate to allow TS updates to the global scope -export {} - -declare global { - namespace jest { - interface Matchers { - toHaveStatusCode(code: number): R - } - } -} - -// Expect extensions -expect.extend({ - toHaveStatusCode(received: Response, code: number) { - const pass = received.status === code - return { - message: () => `expected ${received.status} to match status code ${code}`, - pass, - } - }, -}) diff --git a/qa-core/src/jest/jestSetup.ts b/qa-core/src/jest/jestSetup.ts deleted file mode 100644 index 928e547337..0000000000 --- a/qa-core/src/jest/jestSetup.ts +++ /dev/null @@ -1,3 +0,0 @@ -const envTimeout = process.env.JEST_TIMEOUT -const timeout = envTimeout && parseInt(envTimeout) -jest.setTimeout(timeout || 60000) diff --git a/qa-core/src/public-api/api/BudibasePublicAPI.ts b/qa-core/src/public-api/api/BudibasePublicAPI.ts deleted file mode 100644 index 4a79259d6e..0000000000 --- a/qa-core/src/public-api/api/BudibasePublicAPI.ts +++ /dev/null @@ -1,23 +0,0 @@ -import AppAPI from "./apis/AppAPI" -import UserAPI from "./apis/UserAPI" -import TableAPI from "./apis/TableAPI" -import RowAPI from "./apis/RowAPI" - -import BudibasePublicAPIClient from "./BudibasePublicAPIClient" -import { State } from "../../types" - -export default class BudibasePublicAPI { - client: BudibasePublicAPIClient - apps: AppAPI - users: UserAPI - tables: TableAPI - rows: RowAPI - - constructor(state: State) { - this.client = new BudibasePublicAPIClient(state) - this.apps = new AppAPI(this.client) - this.users = new UserAPI(this.client) - this.tables = new TableAPI(this.client) - this.rows = new RowAPI(this.client, state) - } -} diff --git a/qa-core/src/public-api/api/BudibasePublicAPIClient.ts b/qa-core/src/public-api/api/BudibasePublicAPIClient.ts deleted file mode 100644 index b75393bdaa..0000000000 --- a/qa-core/src/public-api/api/BudibasePublicAPIClient.ts +++ /dev/null @@ -1,79 +0,0 @@ -import env from "../../environment" -import fetch, { HeadersInit } from "node-fetch" -import { State } from "../../types" - -type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" - -interface ApiOptions { - method?: APIMethod - body?: object - headers?: HeadersInit | undefined -} - -class BudibasePublicAPIClient { - state: State - host: string - - constructor(state: State) { - if (!env.BUDIBASE_URL) { - throw new Error("Must set BUDIBASE_URL env var") - } - this.host = `${env.BUDIBASE_URL}/api/public/v1` - this.state = state - } - - apiCall = - (method: APIMethod) => - async (url = "", options: ApiOptions = {}) => { - const requestOptions = { - method, - body: JSON.stringify(options.body), - headers: { - "x-budibase-api-key": this.state.apiKey, - "x-budibase-app-id": this.state.appId, - "Content-Type": "application/json", - Accept: "application/json", - ...options.headers, - redirect: "follow", - follow: 20, - }, - } - - // prettier-ignore - // @ts-ignore - const response = await fetch(`${this.host}${url}`, requestOptions) - - let body: any - const contentType = response.headers.get("content-type") - if (contentType && contentType.includes("application/json")) { - body = await response.json() - } else { - body = await response.text() - } - - const data = { - request: requestOptions.body, - response: body, - } - const message = `${method} ${url} - ${response.status}` - - const isDebug = process.env.LOG_LEVEL === "debug" - if (response.status > 499) { - console.error(message, data) - } else if (response.status >= 400) { - console.warn(message, data) - } else if (isDebug) { - console.debug(message, data) - } - - return [response, body] - } - - post = this.apiCall("POST") - get = this.apiCall("GET") - patch = this.apiCall("PATCH") - del = this.apiCall("DELETE") - put = this.apiCall("PUT") -} - -export default BudibasePublicAPIClient diff --git a/qa-core/src/public-api/api/apis/AppAPI.ts b/qa-core/src/public-api/api/apis/AppAPI.ts deleted file mode 100644 index 71a9b007c6..0000000000 --- a/qa-core/src/public-api/api/apis/AppAPI.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Response } from "node-fetch" -import BudibasePublicAPIClient from "../BudibasePublicAPIClient" -import * as fixtures from "../../fixtures" -import { - Application, - SearchInputParams, - CreateApplicationParams, -} from "../../../types" - -export default class AppAPI { - client: BudibasePublicAPIClient - - constructor(client: BudibasePublicAPIClient) { - this.client = client - } - - async seed(): Promise<[Response, Application]> { - return this.create(fixtures.apps.generateApp()) - } - - async create( - body: CreateApplicationParams - ): Promise<[Response, Application]> { - const [response, json] = await this.client.post(`/applications`, { body }) - return [response, json.data] - } - - async read(id: string): Promise<[Response, Application]> { - const [response, json] = await this.client.get(`/applications/${id}`) - return [response, json.data] - } - - async search(body: SearchInputParams): Promise<[Response, [Application]]> { - const [response, json] = await this.client.post(`/applications/search`, { - body, - }) - return [response, json.data] - } - - async update( - id: string, - body: Application - ): Promise<[Response, Application]> { - const [response, json] = await this.client.put(`/applications/${id}`, { - body, - }) - return [response, json.data] - } - - async delete(id: string): Promise<[Response, Application]> { - const [response, json] = await this.client.del(`/applications/${id}`) - return [response, json.data] - } - - async publish(id: string): Promise<[Response, any]> { - const [response, json] = await this.client.post( - `/applications/${id}/publish` - ) - return [response, json.data] - } - - async unpublish(id: string): Promise<[Response]> { - const [response, json] = await this.client.post( - `/applications/${id}/unpublish` - ) - return [response] - } -} diff --git a/qa-core/src/public-api/api/apis/RowAPI.ts b/qa-core/src/public-api/api/apis/RowAPI.ts deleted file mode 100644 index 8f8e78f365..0000000000 --- a/qa-core/src/public-api/api/apis/RowAPI.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { CreateRowParams, Row, SearchInputParams, State } from "../../../types" -import { HeadersInit, Response } from "node-fetch" -import BudibasePublicAPIClient from "../BudibasePublicAPIClient" -import * as fixtures from "../../fixtures" - -export default class RowAPI { - client: BudibasePublicAPIClient - - headers?: HeadersInit - - state: State - - constructor(client: BudibasePublicAPIClient, state: State) { - this.state = state - this.client = client - } - - async seed(tableId: string) { - return this.create(fixtures.rows.generateRow({ tableId })) - } - - async create(body: CreateRowParams): Promise<[Response, Row]> { - const [response, json] = await this.client.post( - `/tables/${this.state.tableId}/rows`, - { - body, - } - ) - return [response, json.data] - } - - async read(id: string): Promise<[Response, Row]> { - const [response, json] = await this.client.get( - `/tables/${this.state.tableId}/rows/${id}` - ) - return [response, json.data] - } - - async search(body: SearchInputParams): Promise<[Response, [Row]]> { - const [response, json] = await this.client.post( - `/tables/${this.state.tableId}/rows/search`, - { body } - ) - return [response, json.data] - } - - async update(id: string, body: Row): Promise<[Response, Row]> { - const [response, json] = await this.client.put( - `/tables/${this.state.tableId}/rows/${id}`, - { - body, - } - ) - return [response, json.data] - } -} diff --git a/qa-core/src/public-api/api/apis/TableAPI.ts b/qa-core/src/public-api/api/apis/TableAPI.ts deleted file mode 100644 index 4849953211..0000000000 --- a/qa-core/src/public-api/api/apis/TableAPI.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Table, SearchInputParams, CreateTableParams } from "../../../types" -import { HeadersInit, Response } from "node-fetch" -import { generateTable } from "../../fixtures/tables" -import BudibasePublicAPIClient from "../BudibasePublicAPIClient" - -export default class TableAPI { - headers?: HeadersInit - - client: BudibasePublicAPIClient - - constructor(client: BudibasePublicAPIClient) { - this.client = client - } - - async seed() { - return this.create(generateTable()) - } - - async create(body: CreateTableParams): Promise<[Response, Table]> { - const [response, json] = await this.client.post(`/tables`, { - body, - }) - return [response, json.data] - } - - async read(id: string): Promise<[Response, Table]> { - const [response, json] = await this.client.get(`/tables/${id}`) - return [response, json.data] - } - - async search(body: SearchInputParams): Promise<[Response, [Table]]> { - const [response, json] = await this.client.post(`/tables/search`, { body }) - return [response, json.data] - } - - async update(id: string, body: Table): Promise<[Response, Table]> { - const [response, json] = await this.client.put(`/tables/${id}`, { body }) - return [response, json.data] - } -} diff --git a/qa-core/src/public-api/api/apis/UserAPI.ts b/qa-core/src/public-api/api/apis/UserAPI.ts deleted file mode 100644 index 589bec1d40..0000000000 --- a/qa-core/src/public-api/api/apis/UserAPI.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { CreateUserParams, SearchInputParams, User } from "../../../types" -import { Response } from "node-fetch" -import BudibasePublicAPIClient from "../BudibasePublicAPIClient" -import * as fixtures from "../../fixtures" - -export default class UserAPI { - client: BudibasePublicAPIClient - - constructor(client: BudibasePublicAPIClient) { - this.client = client - } - - async seed() { - return this.create(fixtures.users.generateUser()) - } - - async create(body: CreateUserParams): Promise<[Response, User]> { - const [response, json] = await this.client.post(`/users`, { body }) - return [response, json.data] - } - - async read(id: string): Promise<[Response, User]> { - const [response, json] = await this.client.get(`/users/${id}`) - return [response, json.data] - } - - async search(body: SearchInputParams): Promise<[Response, [User]]> { - const [response, json] = await this.client.post(`/users/search`, { body }) - return [response, json.data] - } - - async update(id: string, body: User): Promise<[Response, User]> { - const [response, json] = await this.client.put(`/users/${id}`, { body }) - return [response, json.data] - } -} diff --git a/qa-core/src/public-api/api/index.ts b/qa-core/src/public-api/api/index.ts deleted file mode 100644 index 54d6e44043..0000000000 --- a/qa-core/src/public-api/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BudibasePublicAPI } from "./BudibasePublicAPI" diff --git a/qa-core/src/public-api/config/TestConfiguration.ts b/qa-core/src/public-api/config/TestConfiguration.ts deleted file mode 100644 index d9c12ee267..0000000000 --- a/qa-core/src/public-api/config/TestConfiguration.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { BudibasePublicAPI } from "../api" -import { BudibaseTestConfiguration } from "../../shared" - -export default class TestConfiguration extends BudibaseTestConfiguration { - // apis - api: BudibasePublicAPI - - context: T - - constructor() { - super() - this.api = new BudibasePublicAPI(this.state) - this.context = {} - } - - // LIFECYCLE - - async beforeAll() { - await super.beforeAll() - await this.setApiKey() - } - - async afterAll() { - await super.afterAll() - } - - // AUTH - - async setApiKey() { - const apiKeyResponse = await this.internalApi.self.getApiKey() - this.state.apiKey = apiKeyResponse.apiKey - } -} diff --git a/qa-core/src/public-api/config/index.ts b/qa-core/src/public-api/config/index.ts deleted file mode 100644 index 182c7825b6..0000000000 --- a/qa-core/src/public-api/config/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TestConfiguration } from "./TestConfiguration" diff --git a/qa-core/src/public-api/fixtures/accounts.ts b/qa-core/src/public-api/fixtures/accounts.ts deleted file mode 100644 index 314d7d9176..0000000000 --- a/qa-core/src/public-api/fixtures/accounts.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { generator } from "../../shared" -import { CreateAccountRequest, Hosting } from "@budibase/types" - -export const generateAccount = (): CreateAccountRequest => { - const randomGuid = generator.guid() - //Needs to start with a letter - let tenant: string = "tenant" + randomGuid - tenant = tenant.replace(/-/g, "") - - return { - email: `qa+${randomGuid}@budibase.com`, - hosting: Hosting.CLOUD, - name: `qa+${randomGuid}@budibase.com`, - password: `${randomGuid}`, - profession: "software_engineer", - size: "10+", - tenantId: `${tenant}`, - tenantName: `${tenant}`, - } -} diff --git a/qa-core/src/public-api/fixtures/applications.ts b/qa-core/src/public-api/fixtures/applications.ts deleted file mode 100644 index b8595b4b33..0000000000 --- a/qa-core/src/public-api/fixtures/applications.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { generator } from "../../shared" -import { Application, CreateApplicationParams } from "../../types" - -export const generateApp = ( - overrides: Partial = {} -): CreateApplicationParams => ({ - name: generator.word(), - url: `/${generator.word()}`, - ...overrides, -}) diff --git a/qa-core/src/public-api/fixtures/index.ts b/qa-core/src/public-api/fixtures/index.ts deleted file mode 100644 index 02d48cd628..0000000000 --- a/qa-core/src/public-api/fixtures/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * as accounts from "./accounts" -export * as apps from "./applications" -export * as rows from "./rows" -export * as tables from "./tables" -export * as users from "./users" diff --git a/qa-core/src/public-api/fixtures/rows.ts b/qa-core/src/public-api/fixtures/rows.ts deleted file mode 100644 index 50d999eaa4..0000000000 --- a/qa-core/src/public-api/fixtures/rows.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { CreateRowParams, Row } from "../../types" -import { generator } from "../../shared" - -export const generateRow = (overrides: Partial = {}): CreateRowParams => ({ - type: "row", - tableId: "seed_table", - testColumn: generator.string({ length: 32, alpha: true, numeric: true }), - relationship: [generator.string({ length: 32, alpha: true, numeric: true })], - ...overrides, -}) diff --git a/qa-core/src/public-api/fixtures/tables.ts b/qa-core/src/public-api/fixtures/tables.ts deleted file mode 100644 index 89e3df690a..0000000000 --- a/qa-core/src/public-api/fixtures/tables.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { CreateTableParams, Table } from "../../types" -import { generator } from "../../shared" - -export const generateTable = ( - overrides: Partial = {} -): CreateTableParams => ({ - name: generator.word(), - primaryDisplay: "testColumn", - schema: { - "Auto ID": { - autocolumn: true, - name: "Auto ID", - type: "number", - }, - "Created At": { - autocolumn: true, - name: "Created At", - type: "datetime", - }, - "Created By": { - autocolumn: true, - fieldName: generator.word(), - name: "Created By", - relationshipType: "many-to-many", - tableId: "ta_users", - type: "link", - }, - testColumn: { - name: "testColumn", - type: "string", - }, - "Updated At": { - autocolumn: true, - name: "Updated At", - type: "datetime", - }, - "Updated By": { - autocolumn: true, - fieldName: generator.word(), - name: "Updated By", - relationshipType: "many-to-many", - tableId: "ta_users", - type: "link", - }, - }, - ...overrides, -}) diff --git a/qa-core/src/public-api/fixtures/users.ts b/qa-core/src/public-api/fixtures/users.ts deleted file mode 100644 index 418b565d2a..0000000000 --- a/qa-core/src/public-api/fixtures/users.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { CreateUserParams, User } from "../../types" -import { generator } from "../../shared" - -export const generateUser = ( - overrides: Partial = {} -): CreateUserParams => ({ - email: generator.email({ domain: "example.com" }), - roles: { - [generator.string({ length: 32, alpha: true, numeric: true })]: - generator.word(), - }, - password: generator.word(), - status: "active", - forceResetPassword: generator.bool(), - builder: { - global: generator.bool(), - }, - admin: { - global: generator.bool(), - }, - ...overrides, -}) diff --git a/qa-core/src/public-api/index.ts b/qa-core/src/public-api/index.ts deleted file mode 100644 index e1a716605a..0000000000 --- a/qa-core/src/public-api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./api" diff --git a/qa-core/src/shared/BudibaseTestConfiguration.ts b/qa-core/src/shared/BudibaseTestConfiguration.ts deleted file mode 100644 index 9a12f3e65d..0000000000 --- a/qa-core/src/shared/BudibaseTestConfiguration.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { BudibaseInternalAPI } from "../internal-api" -import { AccountInternalAPI } from "../account-api" -import { APIRequestOpts, State } from "../types" -import * as fixtures from "../internal-api/fixtures" -import { CreateAccountRequest, CreateAppRequest } from "@budibase/types" - -export default class BudibaseTestConfiguration { - // apis - internalApi: BudibaseInternalAPI - accountsApi: AccountInternalAPI - - // state - state: State - - constructor() { - this.state = {} - this.internalApi = new BudibaseInternalAPI(this.state) - this.accountsApi = new AccountInternalAPI(this.state) - } - - // LIFECYCLE - - async beforeAll() { - // @ts-ignore - this.state.tenantId = global.qa.tenantId - // @ts-ignore - this.state.email = global.qa.email - // @ts-ignore - this.state.cookie = global.qa.authCookie - } - - async afterAll() { - // nothing yet - } - - async createApp(overrides: Partial = {}) { - const app = await this.internalApi.apps.create( - fixtures.apps.generateApp(overrides) - ) - this.state.appId = app.appId - return app - } - - // AUTH - - async doInNewState(task: () => Promise) { - return this.doWithState(task, {}) - } - - async doWithState(task: () => Promise, state: State) { - const original = { ...this.state } - - // override the state - this.state.apiKey = state.apiKey - this.state.appId = state.appId - this.state.cookie = state.cookie - this.state.tableId = state.tableId - this.state.tenantId = state.tenantId - this.state.email = state.email - - await task() - - // restore the state - this.state.apiKey = original.apiKey - this.state.appId = original.appId - this.state.cookie = original.cookie - this.state.tableId = original.tableId - this.state.tenantId = original.tenantId - this.state.email = original.email - } - - async loginAsAccount( - account: CreateAccountRequest, - opts: APIRequestOpts = {} - ) { - const [_, cookie] = await this.accountsApi.auth.login( - account.email, - account.password, - opts - ) - this.state.cookie = cookie - } - - async login(email: string, password: string, tenantId?: string) { - if (!tenantId && this.state.tenantId) { - tenantId = this.state.tenantId - } - if (!tenantId) { - throw new Error("Could not determine tenant id") - } - const [res, cookie] = await this.internalApi.auth.login( - tenantId, - email, - password - ) - this.state.cookie = cookie - } -} diff --git a/qa-core/src/shared/generator.ts b/qa-core/src/shared/generator.ts deleted file mode 100644 index 1789fc0f75..0000000000 --- a/qa-core/src/shared/generator.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Chance from "chance" - -export default new Chance() diff --git a/qa-core/src/shared/index.ts b/qa-core/src/shared/index.ts deleted file mode 100644 index 0eba40e7d1..0000000000 --- a/qa-core/src/shared/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as generator } from "./generator" -export { default as BudibaseTestConfiguration } from "./BudibaseTestConfiguration" diff --git a/qa-core/src/types/api.ts b/qa-core/src/types/api.ts deleted file mode 100644 index 3d52445280..0000000000 --- a/qa-core/src/types/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface APIRequestOpts { - // in some cases we need to bypass the expect assertion in an api call - // e.g. during global setup where jest is not available - doExpect?: boolean - status?: number -} diff --git a/qa-core/src/types/apiKeyResponse.ts b/qa-core/src/types/apiKeyResponse.ts deleted file mode 100644 index 4a62d60796..0000000000 --- a/qa-core/src/types/apiKeyResponse.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface ApiKeyResponse { - apiKey: string - createdAt: string - updatedAt: string - userId: string -} diff --git a/qa-core/src/types/appPackage.ts b/qa-core/src/types/appPackage.ts deleted file mode 100644 index 817a4b7414..0000000000 --- a/qa-core/src/types/appPackage.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Application } from "../types" -import { Layout, Screen } from "@budibase/types" -// Create type for getAppPackage response -export interface AppPackageResponse { - application: Partial - layout: Layout - screens: Screen[] -} diff --git a/qa-core/src/types/datasources.ts b/qa-core/src/types/datasources.ts deleted file mode 100644 index f919e4435f..0000000000 --- a/qa-core/src/types/datasources.ts +++ /dev/null @@ -1,22 +0,0 @@ -export interface DatasourceRequest { - datasource: { - name: string - plus?: boolean - source: string - type: string - config: { - connectionString?: string - db?: string - database?: string - host?: string - password?: string - port?: string - schema?: string - user?: string - defaultHeaders?: {} - rejectUnauthorized?: boolean - url?: string - } - } - fetchSchema: boolean -} diff --git a/qa-core/src/types/deploy.ts b/qa-core/src/types/deploy.ts deleted file mode 100644 index 77acb3bb52..0000000000 --- a/qa-core/src/types/deploy.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface DeployConfig { - appUrl: string - status: string - _id: string -} diff --git a/qa-core/src/types/index.ts b/qa-core/src/types/index.ts deleted file mode 100644 index a44df4ef3c..0000000000 --- a/qa-core/src/types/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from "./api" -export * from "./apiKeyResponse" -export * from "./appPackage" -export * from "./deploy" -export * from "./newAccount" -export * from "./responseMessage" -export * from "./routing" -export * from "./state" -export * from "./unpublishAppResponse" -export * from "./screens" -export * from "./datasources" -// re-export public api types -export * from "@budibase/server/api/controllers/public/mapping/types" diff --git a/qa-core/src/types/newAccount.ts b/qa-core/src/types/newAccount.ts deleted file mode 100644 index e7ad88e697..0000000000 --- a/qa-core/src/types/newAccount.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Account } from "@budibase/types" - -export interface NewAccount extends Account { - password: string -} diff --git a/qa-core/src/types/responseMessage.ts b/qa-core/src/types/responseMessage.ts deleted file mode 100644 index 718ac207cc..0000000000 --- a/qa-core/src/types/responseMessage.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface MessageResponse { - message: string -} diff --git a/qa-core/src/types/routing.ts b/qa-core/src/types/routing.ts deleted file mode 100644 index c898d7fecd..0000000000 --- a/qa-core/src/types/routing.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface RouteConfig { - routes: Record -} - -export interface Route { - subpaths: Record -} - -export interface Subpath { - screens: ScreenRouteConfig -} - -export interface ScreenRouteConfig { - BASIC?: string - POWER?: string - ADMIN?: string -} diff --git a/qa-core/src/types/screens.ts b/qa-core/src/types/screens.ts deleted file mode 100644 index fae65e64fa..0000000000 --- a/qa-core/src/types/screens.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface ScreenRequest { - showNavigation: boolean - width: string - name: string - template: string - props: ScreenProps - routing: ScreenRouting -} - -interface ScreenProps { - _id: string - _component: string - _styles: { - normal: {} - hover: {} - active: {} - selected: {} - } - _children: [] - _instanceName: string - direction: string - hAlign: string - vAlign: string - size: string - gap: string -} - -interface ScreenRouting { - route: string - roleId: string - homeScreen: boolean -} diff --git a/qa-core/src/types/state.ts b/qa-core/src/types/state.ts deleted file mode 100644 index 8fab3998ce..0000000000 --- a/qa-core/src/types/state.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface State { - apiKey?: string - appId?: string - cookie?: string - tableId?: string - tenantId?: string - email?: string -} diff --git a/qa-core/src/types/unpublishAppResponse.ts b/qa-core/src/types/unpublishAppResponse.ts deleted file mode 100644 index 277970fccb..0000000000 --- a/qa-core/src/types/unpublishAppResponse.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface UnpublishAppResponse { - data: { - ok: boolean - } - ok: boolean - status: number -} diff --git a/qa-core/tsconfig.json b/qa-core/tsconfig.json deleted file mode 100644 index 68bd3dd87e..0000000000 --- a/qa-core/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "lib": ["es2020"], - "allowJs": true, - "strict": true, - "noImplicitAny": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "incremental": true, - "types": ["node", "jest"], - "outDir": "dist", - "skipLibCheck": true, - "paths": { - "@budibase/types": ["../packages/types/src"], - "@budibase/backend-core": ["../packages/backend-core/src"], - "@budibase/backend-core/*": ["../packages/backend-core/*"], - "@budibase/server/*": ["../packages/server/src/*"] - } - }, - "ts-node": { - "require": ["tsconfig-paths/register"] - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock deleted file mode 100644 index 0eba6dd4d7..0000000000 --- a/qa-core/yarn.lock +++ /dev/null @@ -1,5099 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.2.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.21.4", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/compat-data@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz" - integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz" - integrity sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.4" - "@babel/helper-compilation-targets" "^7.21.4" - "@babel/helper-module-transforms" "^7.21.2" - "@babel/helpers" "^7.21.0" - "@babel/parser" "^7.21.4" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.4" - "@babel/types" "^7.21.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" - -"@babel/generator@^7.21.4", "@babel/generator@^7.23.6", "@babel/generator@^7.7.2": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== - dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.21.4": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz" - integrity sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg== - dependencies: - "@babel/compat-data" "^7.21.4" - "@babel/helper-validator-option" "^7.21.0" - browserslist "^4.21.3" - lru-cache "^5.1.1" - semver "^6.3.0" - -"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-module-imports@^7.18.6": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz" - integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg== - dependencies: - "@babel/types" "^7.21.4" - -"@babel/helper-module-transforms@^7.21.2": - version "7.21.2" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz" - integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.20.2" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.2" - "@babel/types" "^7.21.2" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0": - version "7.20.2" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== - -"@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== - dependencies: - "@babel/types" "^7.20.2" - -"@babel/helper-split-export-declaration@^7.18.6", "@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-validator-identifier@^7.19.1", "@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== - -"@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== - dependencies: - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" - -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.4", "@babel/parser@^7.22.15", "@babel/parser@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" - integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.7.2": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz" - integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz" - integrity sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/runtime@^7.15.4": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz" - integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== - dependencies: - regenerator-runtime "^0.13.11" - -"@babel/template@^7.20.7", "@babel/template@^7.22.15", "@babel/template@^7.3.3": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.6.tgz#b53526a2367a0dd6edc423637f3d2d0f2521abc5" - integrity sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.6" - "@babel/types" "^7.23.6" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" - integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@balena/dockerignore@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz" - integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@budibase/backend-core@^2.3.17": - version "2.3.17" - resolved "https://registry.npmjs.org/@budibase/backend-core/-/backend-core-2.3.17.tgz" - integrity sha512-KcmF2OrNLjLbFtNbYD4ZufnsnwmN2Ez/occgWiecvFRAHOhpkm+Hoy6VggpG1YJBp1DG9kLh3WAZbeYI3QoJbw== - dependencies: - "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.17" - "@shopify/jest-koa-mocks" "5.0.1" - "@techpass/passport-openidconnect" "0.3.2" - aws-cloudfront-sign "2.2.0" - aws-sdk "2.1030.0" - bcrypt "5.0.1" - bcryptjs "2.4.3" - bull "4.10.1" - correlation-id "4.0.0" - dotenv "16.0.1" - emitter-listener "1.1.2" - ioredis "4.28.0" - joi "17.6.0" - jsonwebtoken "9.0.0" - koa-passport "4.1.4" - lodash "4.17.21" - lodash.isarguments "3.1.0" - node-fetch "2.6.7" - passport-google-oauth "2.0.0" - passport-jwt "4.0.0" - passport-local "1.0.0" - passport-oauth2-refresh "^2.1.0" - posthog-node "1.3.0" - pouchdb "7.3.0" - pouchdb-find "7.2.2" - pouchdb-replication-stream "1.2.9" - redlock "4.2.0" - sanitize-s3-objectkey "0.0.1" - semver "7.3.7" - tar-fs "2.1.1" - uuid "8.3.2" - zlib "1.0.5" - -"@budibase/nano@10.1.1": - version "10.1.1" - resolved "https://registry.npmjs.org/@budibase/nano/-/nano-10.1.1.tgz" - integrity sha512-kbMIzMkjVtl+xI0UPwVU0/pn8/ccxTyfzwBz6Z+ZiN2oUSb0fJCe0qwA6o8dxwSa8nZu4MbGAeMJl3CJndmWtA== - dependencies: - "@types/tough-cookie" "^4.0.2" - axios "^1.1.3" - http-cookie-agent "^4.0.2" - node-abort-controller "^3.0.1" - qs "^6.11.0" - tough-cookie "^4.1.2" - -"@budibase/types@^2.3.17": - version "2.3.17" - resolved "https://registry.npmjs.org/@budibase/types/-/types-2.3.17.tgz" - integrity sha512-p/6WgwNjVGfwyNLOofhPEG7S3tt5URxAVs+mPXuLn5bsAqRxxJ5XObvw8chijYXmewhGP0hjONQDkmDJ0FkHuA== - -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - -"@hapi/hoek@^9.0.0": - version "9.3.0" - resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.0.0": - version "5.1.0" - resolved "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" - integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - -"@jest/core@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" - integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== - dependencies: - "@jest/console" "^29.7.0" - "@jest/reporters" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^29.7.0" - jest-config "^29.7.0" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-resolve-dependencies "^29.7.0" - jest-runner "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - jest-watcher "^29.7.0" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/create-cache-key-function@^27.4.2": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz#7448fae15602ea95c828f5eceed35c202a820b31" - integrity sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ== - dependencies: - "@jest/types" "^27.5.1" - -"@jest/environment@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" - integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== - dependencies: - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - -"@jest/expect-utils@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" - integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== - dependencies: - jest-get-type "^29.6.3" - -"@jest/expect@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" - integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== - dependencies: - expect "^29.7.0" - jest-snapshot "^29.7.0" - -"@jest/fake-timers@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" - integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== - dependencies: - "@jest/types" "^29.6.3" - "@sinonjs/fake-timers" "^10.0.2" - "@types/node" "*" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -"@jest/globals@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" - integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/types" "^29.6.3" - jest-mock "^29.7.0" - -"@jest/reporters@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" - integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^6.0.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - jest-worker "^29.7.0" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - v8-to-istanbul "^9.0.1" - -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - -"@jest/source-map@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" - integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - callsites "^3.0.0" - graceful-fs "^4.2.9" - -"@jest/test-result@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" - integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== - dependencies: - "@jest/console" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" - integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== - dependencies: - "@jest/test-result" "^29.7.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - slash "^3.0.0" - -"@jest/transform@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" - integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^2.0.0" - fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.2" - -"@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@jest/types@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" - integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== - dependencies: - "@jest/schemas" "^29.6.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" - -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.14" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@mapbox/node-pre-gyp@^1.0.0": - version "1.0.10" - resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz" - integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA== - dependencies: - detect-libc "^2.0.0" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.7" - nopt "^5.0.0" - npmlog "^5.0.1" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.11" - -"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2": - version "3.0.2" - resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz" - integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ== - -"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3" - integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw== - -"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367" - integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg== - -"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399" - integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA== - -"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f" - integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA== - -"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" - integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== - -"@shopify/jest-koa-mocks@5.0.1": - version "5.0.1" - resolved "https://registry.npmjs.org/@shopify/jest-koa-mocks/-/jest-koa-mocks-5.0.1.tgz" - integrity sha512-4YskS9q8+TEHNoyopmuoy2XyhInyqeOl7CF5ShJs19sm6m0EA/jGGvgf/osv2PeTfuf42/L2G9CzWUSg49yTSg== - dependencies: - koa "^2.13.4" - node-mocks-http "^1.11.0" - -"@sideway/address@^4.1.3": - version "4.1.4" - resolved "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz" - integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.0": - version "3.0.1" - resolved "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz" - integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - -"@sinonjs/commons@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz" - integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.0.2" - resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz" - integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== - dependencies: - "@sinonjs/commons" "^2.0.0" - -"@swc/core-darwin-arm64@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.71.tgz#3cc2bfa7e3f89ec18987af863b2260a5340ff0a7" - integrity sha512-xOm0hDbcO2ShwQu1CjLtq3fwrG9AvhuE0s8vtBc8AsamYExHmR8bo6GQHJUtfPG1FVPk5a8xoQSd1fs09FQjLg== - -"@swc/core-darwin-x64@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.71.tgz#0f5439994013480454dfe2a5aff8861e93316fe3" - integrity sha512-9sbDXBWgM22w/3Ll5kPhXMPkOiHRoqwMOyxLJBfGtIMnFlh5O+NRN3umRerK3pe4Q6/7hj2M5V+crEHYrXmuxg== - -"@swc/core-linux-arm-gnueabihf@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.71.tgz#77ea469736802ce2865fbc4893991b7abf369e3e" - integrity sha512-boKdMZsfKvhBs0FDeqH7KQj0lfYe0wCtrL1lv50oYMEeLajY9o4U5xSmc61Sg4HRXjlbR6dlM2cFfL84t7NpAA== - -"@swc/core-linux-arm64-gnu@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.71.tgz#8a17c17fac03a448484af41fa35e45458da312b5" - integrity sha512-yDatyHYMiOVwhyIA/LBwknPs2CUtLYWEMzPZjgLc+56PbgPs3oiEbNWeVUND5onPrfDQgK7NK1y8JeiXZqTgGQ== - -"@swc/core-linux-arm64-musl@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.71.tgz#bd3bf4310870a8a60a9dc834502d6852cd2b129b" - integrity sha512-xAdCA0L/hoa0ULL5SR4sMZCxkWk7C90DOU7wJalNVG9qNWYICfq3G7AR0E9Ohphzqyahfb5QJED/nA7N0+XwbQ== - -"@swc/core-linux-x64-gnu@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.71.tgz#5c1f5ecb8fa96456195e75ac12c40372896d4b89" - integrity sha512-j94qLXP/yqhu2afnABAq/xrJIU8TEqcNkp1TlsAeO3R2nVLYL1w4XX8GW71SPnXmd2bwF102c3Cfv/2ilf2y2A== - -"@swc/core-linux-x64-musl@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.71.tgz#5fa99bd115d3bf90aebcee8793644f998024fcbe" - integrity sha512-YiyU848ql6dLlmt0BHccGAaZ36Cf61VzCAMDKID/gd72snvzWcMCHrwSRW0gEFNXHsjBJrmNl+SLYZHfqoGwUA== - -"@swc/core-win32-arm64-msvc@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.71.tgz#4e39975a51c56911e1183efd2106c0e74fe89b1c" - integrity sha512-1UsJ+6hnIRe/PVdgDPexvgGaN4KpBncT/bAOqlWc9XC7KeBXAWcGA08LrPUz2Ei00DJXzR622IGZVEYOHNkUOw== - -"@swc/core-win32-ia32-msvc@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.71.tgz#6bb37d9fba8409078376d292711566ccf9a46145" - integrity sha512-KnuI89+zojR9lDFELdQYZpxzPZ6pBfLwJfWTSGatnpL1ZHhIsV3tK1jwqIdJK1zkRxpBwc6p6FzSZdZwCSpnJw== - -"@swc/core-win32-x64-msvc@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.71.tgz#33a53e4d5f93d13bae791451f3746d3da6a39984" - integrity sha512-Pcw7fFirpaBOZsU8fhO48ZCb7NxIjuLnLRPrHqWQ4Mapx1+w9ZNdGya2DKP9n8EAiUrJO20WDsrBNMT2MQSWkA== - -"@swc/core@1.3.71": - version "1.3.71" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.71.tgz#7911038a5577005a5f12b9b2e31f6c804a0c4b7e" - integrity sha512-T8dqj+SV/S8laW/FGmKHhCGw1o4GRUvJ2jHfbYgEwiJpeutT9uavHvG02t39HJvObBJ52EZs/krGtni4U5928Q== - optionalDependencies: - "@swc/core-darwin-arm64" "1.3.71" - "@swc/core-darwin-x64" "1.3.71" - "@swc/core-linux-arm-gnueabihf" "1.3.71" - "@swc/core-linux-arm64-gnu" "1.3.71" - "@swc/core-linux-arm64-musl" "1.3.71" - "@swc/core-linux-x64-gnu" "1.3.71" - "@swc/core-linux-x64-musl" "1.3.71" - "@swc/core-win32-arm64-msvc" "1.3.71" - "@swc/core-win32-ia32-msvc" "1.3.71" - "@swc/core-win32-x64-msvc" "1.3.71" - -"@swc/jest@0.2.27": - version "0.2.27" - resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.27.tgz#f6cbd0b6f95cf689c3344c63fc379fa680cdbf52" - integrity sha512-Xt8EJ6Wy0NYVL8KDPcDMsuUSzyV2UAByamyy28x2iDZCJw2eVz3acedCGBYxxlPR/DNr6QbA35OSymuXhC9QVA== - dependencies: - "@jest/create-cache-key-function" "^27.4.2" - jsonc-parser "^3.2.0" - -"@techpass/passport-openidconnect@0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.2.tgz" - integrity sha512-fnCtEiexXSHA029B//hJcCJlLJrT3lhpNCyA0rnz58Qttz0BLGCVv6yMT8HmOnGThH6vcDOVwdgKM3kbCQtEhw== - dependencies: - base64url "^3.0.1" - oauth "^0.9.15" - passport-strategy "^1.0.0" - request "^2.88.0" - webfinger "^0.4.2" - -"@trendyol/jest-testcontainers@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@trendyol/jest-testcontainers/-/jest-testcontainers-2.1.1.tgz#dced95cf9c37b75efe0a65db9b75ae8912f2f14a" - integrity sha512-4iAc2pMsev4BTUzoA7jO1VvbTOU2N3juQUYa8TwiSPXPuQtxKwV9WB9ZEP+JQ+Pj15YqfGOXp5H0WNMPtapjiA== - dependencies: - cwd "^0.10.0" - node-duration "^1.0.4" - testcontainers "4.7.0" - -"@tsconfig/node10@^1.0.7": - version "1.0.9" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" - integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== - -"@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - -"@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - -"@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== - -"@types/babel__core@^7.1.14": - version "7.20.0" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz" - integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.18.3" - resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz" - integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== - dependencies: - "@babel/types" "^7.3.0" - -"@types/dockerode@^2.5.34": - version "2.5.34" - resolved "https://registry.npmjs.org/@types/dockerode/-/dockerode-2.5.34.tgz" - integrity sha512-LcbLGcvcBwBAvjH9UrUI+4qotY+A5WCer5r43DR5XHv2ZIEByNXFdPLo1XxR+v/BjkGjlggW8qUiXuVEhqfkpA== - dependencies: - "@types/node" "*" - -"@types/graceful-fs@^4.1.3": - version "4.1.6" - resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz" - integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@29.5.3": - version "29.5.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" - integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - -"@types/node-fetch@2.6.4": - version "2.6.4" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" - integrity sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - -"@types/node@*": - version "18.15.1" - resolved "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz" - integrity sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw== - -"@types/node@>=8.1.0": - version "20.11.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.0.tgz#8e0b99e70c0c1ade1a86c4a282f7b7ef87c9552f" - integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ== - dependencies: - undici-types "~5.26.4" - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/tough-cookie@^4.0.2": - version "4.0.2" - resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz" - integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== - -"@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== - -"@types/yargs@^16.0.0": - version "16.0.5" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" - integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ== - dependencies: - "@types/yargs-parser" "*" - -"@types/yargs@^17.0.8": - version "17.0.22" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz" - integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g== - dependencies: - "@types/yargs-parser" "*" - -abbrev@1: - version "1.1.1" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -abort-controller@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -abstract-leveldown@^6.2.1, abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: - version "6.2.3" - resolved "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz" - integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -accepts@^1.3.5, accepts@^1.3.7: - version "1.3.8" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^8.4.1: - version "8.8.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - -agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -ajv@^6.12.3: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -any-promise@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - -anymatch@^3.0.3: - version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argsarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz" - integrity sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg== - -asn1@^0.2.6, asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -aws-cloudfront-sign@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/aws-cloudfront-sign/-/aws-cloudfront-sign-2.2.0.tgz" - integrity sha512-qG+rwZMP3KRTPPbVmWY8DlrT56AkA4iVOeo23vkdK2EXeW/brJFN2haSNKzVz+oYhFMEIzVVloeAcrEzuRkuVQ== - dependencies: - lodash "^3.6.0" - -aws-sdk@2.1030.0: - version "2.1030.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1030.0.tgz" - integrity sha512-to0STOb8DsSGuSsUb/WCbg/UFnMGfIYavnJH5ZlRCHzvCFjTyR+vfE8ku+qIZvfFM4+5MNTQC/Oxfun2X/TuyA== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.15.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - uuid "3.3.2" - xml2js "0.4.19" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" - integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== - -aws4@^1.8.0: - version "1.12.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz" - integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== - -axios-retry@^3.1.9: - version "3.4.0" - resolved "https://registry.npmjs.org/axios-retry/-/axios-retry-3.4.0.tgz" - integrity sha512-VdgaP+gHH4iQYCCNUWF2pcqeciVOdGrBBAYUfTY+wPcO5Ltvp/37MLFNCmJKo7Gj3SHvCSdL8ouI1qLYJN3liA== - dependencies: - "@babel/runtime" "^7.15.4" - is-retry-allowed "^2.2.0" - -axios@0.24.0: - version "0.24.0" - resolved "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz" - integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== - dependencies: - follow-redirects "^1.14.4" - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -axios@^1.1.3: - version "1.6.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" - integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -babel-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" - integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== - dependencies: - "@jest/transform" "^29.7.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.6.3" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" - integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" - integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== - dependencies: - babel-plugin-jest-hoist "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.0.2, base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base64url@3.x.x, base64url@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz" - integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== - -bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" - integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== - dependencies: - tweetnacl "^0.14.3" - -bcrypt@5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz" - integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.0" - node-addon-api "^3.1.0" - -bcryptjs@2.4.3: - version "2.4.3" - resolved "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz" - integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== - -bl@^4.0.3: - version "4.1.0" - resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bluebird@3.7.2, bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -browserslist@^4.21.3: - version "4.21.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== - dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" - integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== - -buffer-from@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-from@1.1.2, buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer@4.9.2: - version "4.9.2" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -buffer@^5.5.0, buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -buildcheck@~0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz" - integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A== - -bull@4.10.1: - version "4.10.1" - resolved "https://registry.npmjs.org/bull/-/bull-4.10.1.tgz" - integrity sha512-Fp21tRPb2EaZPVfmM+ONZKVz2RA+to+zGgaTLyCKt3JMSU8OOBqK8143OQrnGuGpsyE5G+9FevFAGhdZZfQP2g== - dependencies: - cron-parser "^4.2.1" - debuglog "^1.0.0" - get-port "^5.1.1" - ioredis "^4.28.5" - lodash "^4.17.21" - msgpackr "^1.5.2" - p-timeout "^3.2.0" - semver "^7.3.2" - uuid "^8.3.0" - -byline@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz" - integrity sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q== - -cache-content-type@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz" - integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA== - dependencies: - mime-types "^2.1.18" - ylru "^1.2.0" - -call-bind@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001449: - version "1.0.30001474" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz" - integrity sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" - integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chance@1.1.8: - version "1.1.8" - resolved "https://registry.npmjs.org/chance/-/chance-1.1.8.tgz" - integrity sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg== - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -charenc@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz" - integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== - -check-more-types@2.24.0: - version "2.24.0" - resolved "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz" - integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== - -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - -clone-buffer@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz" - integrity sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g== - -cluster-key-slot@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz" - integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-support@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -component-type@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz" - integrity sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -console-control-strings@^1.0.0, console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== - -content-disposition@^0.5.3, content-disposition@~0.5.2: - version "0.5.4" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookies@~0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz" - integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow== - dependencies: - depd "~2.0.0" - keygrip "~1.1.0" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== - -correlation-id@4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/correlation-id/-/correlation-id-4.0.0.tgz" - integrity sha512-WvXtJBlovvOBKqTz/YwWP2gm6CXJZJArfGimp9s/ehmhJMPFbmnPMQe3K60Q9idGNixMvKojMjleyDhZEFdHfg== - dependencies: - uuid "^8.3.1" - -cpu-features@~0.0.8: - version "0.0.8" - resolved "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.8.tgz" - integrity sha512-BbHBvtYhUhksqTjr6bhNOjGgMnhwhGTQmOoZGD+K7BCaQDCuZl/Ve1ZxUSMRwVC4D/rkCPQ2MAIeYzrWyK7eEg== - dependencies: - buildcheck "~0.0.6" - nan "^2.17.0" - -create-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" - integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-config "^29.7.0" - jest-util "^29.7.0" - prompts "^2.0.1" - -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cron-parser@^4.2.1: - version "4.8.1" - resolved "https://registry.npmjs.org/cron-parser/-/cron-parser-4.8.1.tgz" - integrity sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ== - dependencies: - luxon "^3.2.1" - -cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz" - integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== - -cwd@^0.10.0: - version "0.10.0" - resolved "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz" - integrity sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA== - dependencies: - find-pkg "^0.1.2" - fs-exists-sync "^0.1.0" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" - integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== - dependencies: - assert-plus "^1.0.0" - -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@4.3.2: - version "4.3.2" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -debuglog@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz" - integrity sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw== - -dedent@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.3.0.tgz#15d6809eb15b581d5587a2dc208f34118e35bee3" - integrity sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg== - -deep-equal@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz" - integrity sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw== - -deepmerge@^4.2.2: - version "4.3.1" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -deferred-leveldown@~5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz" - integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== - dependencies: - abstract-leveldown "~6.2.1" - inherits "^2.0.3" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - -denque@^1.1.0: - version "1.5.1" - resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - -depd@^1.1.0, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - -depd@^2.0.0, depd@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -destroy@^1.0.4: - version "1.2.0" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - -detect-libc@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" - integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -docker-compose@^0.23.5: - version "0.23.19" - resolved "https://registry.npmjs.org/docker-compose/-/docker-compose-0.23.19.tgz" - integrity sha512-v5vNLIdUqwj4my80wxFDkNH+4S85zsRuH29SO7dCWVWPCMt/ohZBsGN6g6KXWifT0pzQ7uOxqEKCYCDPJ8Vz4g== - dependencies: - yaml "^1.10.2" - -docker-modem@^3.0.0: - version "3.0.8" - resolved "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.8.tgz" - integrity sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ== - dependencies: - debug "^4.1.1" - readable-stream "^3.5.0" - split-ca "^1.0.1" - ssh2 "^1.11.0" - -dockerode@^3.2.1: - version "3.3.5" - resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.5.tgz" - integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA== - dependencies: - "@balena/dockerignore" "^1.0.2" - docker-modem "^3.0.0" - tar-fs "~2.0.1" - -dotenv@16.0.1: - version "16.0.1" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz" - integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== - -double-ended-queue@2.1.0-0: - version "2.1.0-0" - resolved "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz" - integrity sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ== - -duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" - integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ecdsa-sig-formatter@1.0.11: - version "1.0.11" - resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - -electron-to-chromium@^1.4.284: - version "1.4.353" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.353.tgz" - integrity sha512-IdJVpMHJoBT/nn0GQ02wPfbhogDVpd1ud95lP//FTf5l35wzxKJwibB4HBdY7Q+xKPA1nkZ0UDLOMyRj5U5IAQ== - -emitter-listener@1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - -emittery@^0.13.1: - version "0.13.1" - resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" - integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -encodeurl@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - -encoding-down@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz" - integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== - dependencies: - abstract-leveldown "^6.2.1" - inherits "^2.0.3" - level-codec "^9.0.0" - level-errors "^2.0.0" - -end-of-stream@^1.1.0, end-of-stream@^1.4.1: - version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -end-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/end-stream/-/end-stream-0.1.0.tgz" - integrity sha512-Brl10T8kYnc75IepKizW6Y9liyW8ikz1B7n/xoHrJxoVSSjoqPn30sb7XVFfQERK4QfUMYRGs9dhWwtt2eu6uA== - dependencies: - write-stream "~0.4.3" - -errno@~0.1.1: - version "0.1.8" - resolved "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-html@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -event-stream@=3.3.4: - version "3.3.4" - resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz" - integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - -event-target-shim@^5.0.0: - 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== - -events@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz" - integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== - -execa@5.1.1, execa@^5.0.0: - version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - 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" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expand-tilde@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz" - integrity sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q== - dependencies: - os-homedir "^1.0.1" - -expect@^29.0.0, expect@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" - integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== - 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" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0, extsprintf@^1.2.0: - version "1.3.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" - integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fb-watchman@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" - integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== - dependencies: - bser "2.1.1" - -fetch-cookie@0.10.1: - version "0.10.1" - resolved "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.10.1.tgz" - integrity sha512-beB+VEd4cNeVG1PY+ee74+PkuCQnik78pgLi5Ah/7qdUfov8IctU0vLUbBT8/10Ma5GMBeI4wtxhGrEfKNYs2g== - dependencies: - tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" - -fetch-cookie@0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz" - integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== - dependencies: - tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-file-up@^0.1.2: - version "0.1.3" - resolved "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz" - integrity sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A== - dependencies: - fs-exists-sync "^0.1.0" - resolve-dir "^0.1.0" - -find-pkg@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz" - integrity sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw== - dependencies: - find-file-up "^0.1.2" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.15.0: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" - integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fresh@^0.5.2, fresh@~0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - -from@~0: - version "0.1.7" - resolved "https://registry.npmjs.org/from/-/from-0.1.7.tgz" - integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs-exists-sync@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz" - integrity sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg== - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gauge@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz" - integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2: - version "1.2.0" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-port@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" - integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== - dependencies: - assert-plus "^1.0.0" - -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - 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" - -global-modules@^0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz" - integrity sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA== - dependencies: - global-prefix "^0.1.4" - is-windows "^0.2.0" - -global-prefix@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz" - integrity sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw== - dependencies: - homedir-polyfill "^1.0.0" - ini "^1.3.4" - is-windows "^0.2.0" - which "^1.2.12" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" - integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -homedir-polyfill@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz" - integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== - dependencies: - parse-passwd "^1.0.0" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -http-assert@^1.3.0: - version "1.5.0" - resolved "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz" - integrity sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w== - dependencies: - deep-equal "~1.0.1" - http-errors "~1.8.0" - -http-cookie-agent@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-4.0.2.tgz" - integrity sha512-noTmxdH5CuytTnLj/Qv3Z84e/YFq8yLXAw3pqIYZ25Edhb9pQErIAC+ednw40Cic6Le/h9ryph5/TqsvkOaUCw== - dependencies: - agent-base "^6.0.2" - -http-errors@^1.6.3, http-errors@~1.8.0: - version "1.8.1" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" - integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -ieee754@1.1.13, ieee754@^1.1.13, ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -immediate@3.3.0, immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz" - integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== - -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" - integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== - -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@^1.3.4: - version "1.3.8" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -ioredis@4.28.0: - version "4.28.0" - resolved "https://registry.npmjs.org/ioredis/-/ioredis-4.28.0.tgz" - integrity sha512-I+zkeeWp3XFgPT2CtJKxvaF5FjGBGt4yGYljRjQecdQKteThuAsKqffeF1lgHVlYnuNeozRbPOCDNZ7tDWPeig== - dependencies: - cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" - lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" - lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - -ioredis@^4.28.5: - version "4.28.5" - resolved "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz" - integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== - dependencies: - cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" - lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" - lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-buffer@~1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-core-module@^2.11.0: - version "2.11.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-retry-allowed@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz" - integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - -is-windows@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz" - integrity sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" - integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-instrument@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf" - integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^7.5.4" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.5" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jest-changed-files@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" - integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== - dependencies: - execa "^5.0.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - -jest-circus@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" - integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^1.0.0" - is-generator-fn "^2.0.0" - jest-each "^29.7.0" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - p-limit "^3.1.0" - pretty-format "^29.7.0" - pure-rand "^6.0.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-cli@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" - integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== - dependencies: - "@jest/core" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - chalk "^4.0.0" - create-jest "^29.7.0" - exit "^0.1.2" - import-local "^3.0.2" - jest-config "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - yargs "^17.3.1" - -jest-config@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" - integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.7.0" - "@jest/types" "^29.6.3" - babel-jest "^29.7.0" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^29.7.0" - jest-environment-node "^29.7.0" - jest-get-type "^29.6.3" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-runner "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^29.7.0" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -jest-diff@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" - integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.6.3" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-docblock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" - integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== - dependencies: - detect-newline "^3.0.0" - -jest-each@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" - integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - jest-get-type "^29.6.3" - jest-util "^29.7.0" - pretty-format "^29.7.0" - -jest-environment-node@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" - integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -jest-get-type@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" - integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== - -jest-haste-map@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" - integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== - dependencies: - "@jest/types" "^29.6.3" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - jest-worker "^29.7.0" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-leak-detector@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" - integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== - dependencies: - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-matcher-utils@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" - integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== - dependencies: - chalk "^4.0.0" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - pretty-format "^29.7.0" - -jest-message-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" - integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.6.3" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^29.7.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" - integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - jest-util "^29.7.0" - -jest-pnp-resolver@^1.2.2: - version "1.2.3" - resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" - integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== - -jest-regex-util@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" - integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== - -jest-resolve-dependencies@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" - integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== - dependencies: - jest-regex-util "^29.6.3" - jest-snapshot "^29.7.0" - -jest-resolve@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" - integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-pnp-resolver "^1.2.2" - jest-util "^29.7.0" - jest-validate "^29.7.0" - resolve "^1.20.0" - resolve.exports "^2.0.0" - slash "^3.0.0" - -jest-runner@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" - integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== - dependencies: - "@jest/console" "^29.7.0" - "@jest/environment" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.13.1" - graceful-fs "^4.2.9" - jest-docblock "^29.7.0" - jest-environment-node "^29.7.0" - jest-haste-map "^29.7.0" - jest-leak-detector "^29.7.0" - jest-message-util "^29.7.0" - jest-resolve "^29.7.0" - jest-runtime "^29.7.0" - jest-util "^29.7.0" - jest-watcher "^29.7.0" - jest-worker "^29.7.0" - p-limit "^3.1.0" - source-map-support "0.5.13" - -jest-runtime@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" - integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/globals" "^29.7.0" - "@jest/source-map" "^29.6.3" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-snapshot@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" - integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-jsx" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^29.7.0" - graceful-fs "^4.2.9" - jest-diff "^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" - natural-compare "^1.4.0" - pretty-format "^29.7.0" - semver "^7.5.3" - -jest-util@^29.0.0, jest-util@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" - integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== - dependencies: - "@jest/types" "^29.6.3" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" - integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== - dependencies: - "@jest/types" "^29.6.3" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^29.6.3" - leven "^3.1.0" - pretty-format "^29.7.0" - -jest-watcher@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" - integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== - dependencies: - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.13.1" - jest-util "^29.7.0" - string-length "^4.0.1" - -jest-worker@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" - integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== - dependencies: - "@types/node" "*" - jest-util "^29.7.0" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" - integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== - dependencies: - "@jest/core" "^29.7.0" - "@jest/types" "^29.6.3" - import-local "^3.0.2" - jest-cli "^29.7.0" - -jmespath@0.15.0: - version "0.15.0" - resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz" - integrity sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w== - -joi@17.6.0, joi@^17.4.0: - version "17.6.0" - resolved "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz" - integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" - "@sideway/pinpoint" "^2.0.0" - -join-component@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz" - integrity sha512-bF7vcQxbODoGK1imE2P9GS9aw4zD0Sd+Hni68IMZLj7zRnquH7dXUmMw9hDI5S/Jzt7q+IyTXN0rSg2GI0IKhQ== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" - integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -jsonc-parser@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" - integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== - -jsonwebtoken@9.0.0: - version "9.0.0" - resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz" - integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== - dependencies: - jws "^3.2.2" - lodash "^4.17.21" - ms "^2.1.1" - semver "^7.3.8" - -jsonwebtoken@^8.2.0: - version "8.5.1" - resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz" - integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^5.6.0" - -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - -jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - -jws@^3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz" - integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== - dependencies: - jwa "^1.4.1" - safe-buffer "^5.0.1" - -keygrip@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz" - integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== - dependencies: - tsscmp "1.0.6" - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -koa-compose@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz" - integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== - -koa-convert@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz" - integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA== - dependencies: - co "^4.6.0" - koa-compose "^4.1.0" - -koa-passport@4.1.4: - version "4.1.4" - resolved "https://registry.npmjs.org/koa-passport/-/koa-passport-4.1.4.tgz" - integrity sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg== - dependencies: - passport "^0.4.0" - -koa@^2.13.4: - version "2.14.1" - resolved "https://registry.npmjs.org/koa/-/koa-2.14.1.tgz" - integrity sha512-USJFyZgi2l0wDgqkfD27gL4YGno7TfUkcmOe6UOLFOVuN+J7FwnNu4Dydl4CUQzraM1lBAiGed0M9OVJoT0Kqw== - dependencies: - accepts "^1.3.5" - cache-content-type "^1.0.0" - content-disposition "~0.5.2" - content-type "^1.0.4" - cookies "~0.8.0" - debug "^4.3.2" - delegates "^1.0.0" - depd "^2.0.0" - destroy "^1.0.4" - encodeurl "^1.0.2" - escape-html "^1.0.3" - fresh "~0.5.2" - http-assert "^1.3.0" - http-errors "^1.6.3" - is-generator-function "^1.0.7" - koa-compose "^4.1.0" - koa-convert "^2.0.0" - on-finished "^2.3.0" - only "~0.0.2" - parseurl "^1.3.2" - statuses "^1.5.0" - type-is "^1.6.16" - vary "^1.1.2" - -lazy-ass@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz" - integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== - -level-codec@9.0.2, level-codec@^9.0.0: - version "9.0.2" - resolved "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz" - integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== - dependencies: - buffer "^5.6.0" - -level-concat-iterator@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz" - integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== - -level-errors@^2.0.0, level-errors@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz" - integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== - dependencies: - errno "~0.1.1" - -level-iterator-stream@~4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz" - integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== - dependencies: - inherits "^2.0.4" - readable-stream "^3.4.0" - xtend "^4.0.2" - -level-js@^5.0.0: - version "5.0.2" - resolved "https://registry.npmjs.org/level-js/-/level-js-5.0.2.tgz" - integrity sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg== - dependencies: - abstract-leveldown "~6.2.3" - buffer "^5.5.0" - inherits "^2.0.3" - ltgt "^2.1.2" - -level-packager@^5.1.0: - version "5.1.1" - resolved "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz" - integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== - dependencies: - encoding-down "^6.3.0" - levelup "^4.3.2" - -level-supports@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz" - integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== - dependencies: - xtend "^4.0.2" - -level-write-stream@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/level-write-stream/-/level-write-stream-1.0.0.tgz" - integrity sha512-bBNKOEOMl8msO+uIM9YX/gUO6ckokZ/4pCwTm/lwvs46x6Xs8Zy0sn3Vh37eDqse4mhy4fOMIb/JsSM2nyQFtw== - dependencies: - end-stream "~0.1.0" - -level@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/level/-/level-6.0.1.tgz" - integrity sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw== - dependencies: - level-js "^5.0.0" - level-packager "^5.1.0" - leveldown "^5.4.0" - -leveldown@5.6.0, leveldown@^5.4.0: - version "5.6.0" - resolved "https://registry.npmjs.org/leveldown/-/leveldown-5.6.0.tgz" - integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== - dependencies: - abstract-leveldown "~6.2.1" - napi-macros "~2.0.0" - node-gyp-build "~4.1.0" - -levelup@4.4.0, levelup@^4.3.2: - version "4.4.0" - resolved "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz" - integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== - dependencies: - deferred-leveldown "~5.3.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -lie@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz" - integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== - dependencies: - immediate "~3.0.5" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz" - integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== - -lodash.isarguments@3.1.0, lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" - integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" - integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== - -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz" - integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz" - integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" - integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz" - integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== - -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz" - integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== - -lodash.pick@^4.0.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz" - integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== - -lodash@4.17.21, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lodash@^3.6.0: - version "3.10.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" - integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -ltgt@2.2.1, ltgt@^2.1.2: - version "2.2.1" - resolved "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz" - integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== - -luxon@^3.2.1: - version "3.3.0" - resolved "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz" - integrity sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg== - -make-dir@^3.0.0, make-dir@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz" - integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== - -md5@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -merge-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -methods@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" - integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mime@^1.3.4: - version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@^3.0.4, minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -minipass@^3.0.0: - version "3.3.6" - resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz" - integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== - dependencies: - yallist "^4.0.0" - -minipass@^4.0.0: - version "4.2.5" - resolved "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz" - integrity sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q== - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - -mkdirp@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1, ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -msgpackr-extract@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz" - integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A== - dependencies: - node-gyp-build-optional-packages "5.0.7" - optionalDependencies: - "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2" - "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" - -msgpackr@^1.5.2: - version "1.8.5" - resolved "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz" - integrity sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg== - optionalDependencies: - msgpackr-extract "^3.0.1" - -nan@^2.17.0: - version "2.17.0" - resolved "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== - -napi-macros@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz" - integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -ndjson@^1.4.3: - version "1.5.0" - resolved "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz" - integrity sha512-hUPLuaziboGjNF7wHngkgVc0FOclR8dDk/HfEvTtDr/iUrqBWiRcRSTK3/nLOqKH33th714BrMmTPtObI9gZxQ== - dependencies: - json-stringify-safe "^5.0.1" - minimist "^1.2.0" - split2 "^2.1.0" - through2 "^2.0.3" - -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - -node-abort-controller@^3.0.1: - version "3.1.1" - resolved "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz" - integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== - -node-addon-api@^3.1.0: - version "3.2.1" - resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz" - integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== - -node-duration@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/node-duration/-/node-duration-1.0.4.tgz" - integrity sha512-eUXYNSY7DL53vqfTosggWkvyIW3bhAcqBDIlolgNYlZhianXTrCL50rlUJWD1eRqkIxMppXTfiFbp+9SjpPrgA== - -node-fetch@2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== - -node-fetch@2.6.7, node-fetch@^2.6.7: - version "2.6.7" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build-optional-packages@5.0.7: - version "5.0.7" - resolved "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz" - integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== - -node-gyp-build@~4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz" - integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-mocks-http@^1.11.0: - version "1.12.2" - resolved "https://registry.npmjs.org/node-mocks-http/-/node-mocks-http-1.12.2.tgz" - integrity sha512-xhWwC0dh35R9rf0j3bRZXuISXdHxxtMx0ywZQBwjrg3yl7KpRETzogfeCamUIjltpn0Fxvs/ZhGJul1vPLrdJQ== - dependencies: - accepts "^1.3.7" - content-disposition "^0.5.3" - depd "^1.1.0" - fresh "^0.5.2" - merge-descriptors "^1.0.1" - methods "^1.1.2" - mime "^1.3.4" - parseurl "^1.3.3" - range-parser "^1.2.0" - type-is "^1.6.18" - -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -npmlog@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz" - integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^3.0.0" - set-blocking "^2.0.0" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -oauth@0.9.x, oauth@^0.9.15: - version "0.9.15" - resolved "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz" - integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA== - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -on-finished@^2.3.0: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -only@~0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/only/-/only-0.0.2.tgz" - integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ== - -os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" - integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-timeout@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz" - integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== - -parseurl@^1.3.2, parseurl@^1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -passport-google-oauth1@1.x.x: - version "1.0.0" - resolved "https://registry.npmjs.org/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz" - integrity sha512-qpCEhuflJgYrdg5zZIpAq/K3gTqa1CtHjbubsEsidIdpBPLkEVq6tB1I8kBNcH89RdSiYbnKpCBXAZXX/dtx1Q== - dependencies: - passport-oauth1 "1.x.x" - -passport-google-oauth20@2.x.x: - version "2.0.0" - resolved "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz" - integrity sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ== - dependencies: - passport-oauth2 "1.x.x" - -passport-google-oauth@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz" - integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA== - dependencies: - passport-google-oauth1 "1.x.x" - passport-google-oauth20 "2.x.x" - -passport-jwt@4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz" - integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== - dependencies: - jsonwebtoken "^8.2.0" - passport-strategy "^1.0.0" - -passport-local@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz" - integrity sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow== - dependencies: - passport-strategy "1.x.x" - -passport-oauth1@1.x.x: - version "1.3.0" - resolved "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.3.0.tgz" - integrity sha512-8T/nX4gwKTw0PjxP1xfD0QhrydQNakzeOpZ6M5Uqdgz9/a/Ag62RmJxnZQ4LkbdXGrRehQHIAHNAu11rCP46Sw== - dependencies: - oauth "0.9.x" - passport-strategy "1.x.x" - utils-merge "1.x.x" - -passport-oauth2-refresh@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/passport-oauth2-refresh/-/passport-oauth2-refresh-2.1.0.tgz" - integrity sha512-4ML7ooCESCqiTgdDBzNUFTBcPR8zQq9iM6eppEUGMMvLdsjqRL93jKwWm4Az3OJcI+Q2eIVyI8sVRcPFvxcF/A== - -passport-oauth2@1.x.x: - version "1.7.0" - resolved "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.7.0.tgz" - integrity sha512-j2gf34szdTF2Onw3+76alNnaAExlUmHvkc7cL+cmaS5NzHzDP/BvFHJruueQ9XAeNOdpI+CH+PWid8RA7KCwAQ== - dependencies: - base64url "3.x.x" - oauth "0.9.x" - passport-strategy "1.x.x" - uid2 "0.0.x" - utils-merge "1.x.x" - -passport-strategy@1.x.x, passport-strategy@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz" - integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== - -passport@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz" - integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== - dependencies: - passport-strategy "1.x.x" - pause "0.0.1" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz" - integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== - dependencies: - through "~2.3" - -pause@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz" - integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -posthog-node@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/posthog-node/-/posthog-node-1.3.0.tgz" - integrity sha512-2+VhqiY/rKIqKIXyvemBFHbeijHE25sP7eKltnqcFqAssUE6+sX6vusN9A4luzToOqHQkUZexiCKxvuGagh7JA== - dependencies: - axios "0.24.0" - axios-retry "^3.1.9" - component-type "^1.2.1" - join-component "^1.1.0" - md5 "^2.3.0" - ms "^2.1.3" - remove-trailing-slash "^0.1.1" - uuid "^8.3.2" - -pouch-stream@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/pouch-stream/-/pouch-stream-0.4.1.tgz" - integrity sha512-RAWFhsGDbG4xZQpvrrQlhrITVUNVCKmglfe5WWDnJaDf1u9DMaRLHv//m65tBZevuo4QTGjwcyggwYxd7AGLsg== - dependencies: - inherits "^2.0.1" - readable-stream "^1.0.27-1" - -pouchdb-abstract-mapreduce@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-7.2.2.tgz" - integrity sha512-7HWN/2yV2JkwMnGnlp84lGvFtnm0Q55NiBUdbBcaT810+clCGKvhssBCrXnmwShD1SXTwT83aszsgiSfW+SnBA== - dependencies: - pouchdb-binary-utils "7.2.2" - pouchdb-collate "7.2.2" - pouchdb-collections "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-fetch "7.2.2" - pouchdb-mapreduce-utils "7.2.2" - pouchdb-md5 "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-binary-utils@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-binary-utils/-/pouchdb-binary-utils-7.2.2.tgz" - integrity sha512-shacxlmyHbUrNfE6FGYpfyAJx7Q0m91lDdEAaPoKZM3SzAmbtB1i+OaDNtYFztXjJl16yeudkDb3xOeokVL3Qw== - dependencies: - buffer-from "1.1.1" - -pouchdb-collate@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-collate/-/pouchdb-collate-7.2.2.tgz" - integrity sha512-/SMY9GGasslknivWlCVwXMRMnQ8myKHs4WryQ5535nq1Wj/ehpqWloMwxEQGvZE1Sda3LOm7/5HwLTcB8Our+w== - -pouchdb-collections@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-collections/-/pouchdb-collections-7.2.2.tgz" - integrity sha512-6O9zyAYlp3UdtfneiMYuOCWdUCQNo2bgdjvNsMSacQX+3g8WvIoFQCYJjZZCpTttQGb+MHeRMr8m2U95lhJTew== - -pouchdb-errors@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-errors/-/pouchdb-errors-7.2.2.tgz" - integrity sha512-6GQsiWc+7uPfgEHeavG+7wuzH3JZW29Dnrvz8eVbDFE50kVFxNDVm3EkYHskvo5isG7/IkOx7PV7RPTA3keG3g== - dependencies: - inherits "2.0.4" - -pouchdb-fetch@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-fetch/-/pouchdb-fetch-7.2.2.tgz" - integrity sha512-lUHmaG6U3zjdMkh8Vob9GvEiRGwJfXKE02aZfjiVQgew+9SLkuOxNw3y2q4d1B6mBd273y1k2Lm0IAziRNxQnA== - dependencies: - abort-controller "3.0.0" - fetch-cookie "0.10.1" - node-fetch "2.6.0" - -pouchdb-find@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-find/-/pouchdb-find-7.2.2.tgz" - integrity sha512-BmFeFVQ0kHmDehvJxNZl9OmIztCjPlZlVSdpijuFbk/Fi1EFPU1BAv3kLC+6DhZuOqU/BCoaUBY9sn66pPY2ag== - dependencies: - pouchdb-abstract-mapreduce "7.2.2" - pouchdb-collate "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-fetch "7.2.2" - pouchdb-md5 "7.2.2" - pouchdb-selector-core "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-mapreduce-utils@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-7.2.2.tgz" - integrity sha512-rAllb73hIkU8rU2LJNbzlcj91KuulpwQu804/F6xF3fhZKC/4JQMClahk+N/+VATkpmLxp1zWmvmgdlwVU4HtQ== - dependencies: - argsarray "0.0.1" - inherits "2.0.4" - pouchdb-collections "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-md5@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-md5/-/pouchdb-md5-7.2.2.tgz" - integrity sha512-c/RvLp2oSh8PLAWU5vFBnp6ejJABIdKqboZwRRUrWcfGDf+oyX8RgmJFlYlzMMOh4XQLUT1IoaDV8cwlsuryZw== - dependencies: - pouchdb-binary-utils "7.2.2" - spark-md5 "3.0.1" - -pouchdb-promise@^6.0.4: - version "6.4.3" - resolved "https://registry.npmjs.org/pouchdb-promise/-/pouchdb-promise-6.4.3.tgz" - integrity sha512-ruJaSFXwzsxRHQfwNHjQfsj58LBOY1RzGzde4PM5CWINZwFjCQAhZwfMrch2o/0oZT6d+Xtt0HTWhq35p3b0qw== - dependencies: - lie "3.1.1" - -pouchdb-replication-stream@1.2.9: - version "1.2.9" - resolved "https://registry.npmjs.org/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.9.tgz" - integrity sha512-hM8XRBfamTTUwRhKwLS/jSNouBhn9R/4ugdHNRD1EvJzwV8iImh6sDYbCU9PGuznjyOjXz6vpFRzKeI2KYfwnQ== - dependencies: - argsarray "0.0.1" - inherits "^2.0.3" - lodash.pick "^4.0.0" - ndjson "^1.4.3" - pouch-stream "^0.4.0" - pouchdb-promise "^6.0.4" - through2 "^2.0.0" - -pouchdb-selector-core@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-selector-core/-/pouchdb-selector-core-7.2.2.tgz" - integrity sha512-XYKCNv9oiNmSXV5+CgR9pkEkTFqxQGWplnVhO3W9P154H08lU0ZoNH02+uf+NjZ2kjse7Q1fxV4r401LEcGMMg== - dependencies: - pouchdb-collate "7.2.2" - pouchdb-utils "7.2.2" - -pouchdb-utils@7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/pouchdb-utils/-/pouchdb-utils-7.2.2.tgz" - integrity sha512-XmeM5ioB4KCfyB2MGZXu1Bb2xkElNwF1qG+zVFbQsKQij0zvepdOUfGuWvLRHxTOmt4muIuSOmWZObZa3NOgzQ== - dependencies: - argsarray "0.0.1" - clone-buffer "1.0.0" - immediate "3.3.0" - inherits "2.0.4" - pouchdb-collections "7.2.2" - pouchdb-errors "7.2.2" - pouchdb-md5 "7.2.2" - uuid "8.1.0" - -pouchdb@7.3.0: - version "7.3.0" - resolved "https://registry.npmjs.org/pouchdb/-/pouchdb-7.3.0.tgz" - integrity sha512-OwsIQGXsfx3TrU1pLruj6PGSwFH+h5k4hGNxFkZ76Um7/ZI8F5TzUHFrpldVVIhfXYi2vP31q0q7ot1FSLFYOw== - dependencies: - abort-controller "3.0.0" - argsarray "0.0.1" - buffer-from "1.1.2" - clone-buffer "1.0.0" - double-ended-queue "2.1.0-0" - fetch-cookie "0.11.0" - immediate "3.3.0" - inherits "2.0.4" - level "6.0.1" - level-codec "9.0.2" - level-write-stream "1.0.0" - leveldown "5.6.0" - levelup "4.4.0" - ltgt "2.2.1" - node-fetch "2.6.7" - readable-stream "1.1.14" - spark-md5 "3.0.2" - through2 "3.0.2" - uuid "8.3.2" - vuvuzela "1.0.3" - -prettier@2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== - -pretty-format@^29.0.0, pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== - dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" - integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== - -ps-tree@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz" - integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== - dependencies: - event-stream "=3.3.4" - -psl@^1.1.28, psl@^1.1.33: - version "1.9.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" - integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== - -punycode@^2.1.0, punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== - -pure-rand@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz" - integrity sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg== - -qs@^6.11.0: - version "6.11.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz" - integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ== - dependencies: - side-channel "^1.0.4" - -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" - integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -range-parser@^1.2.0: - version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -readable-stream@1.1.14, readable-stream@^1.0.27-1: - version "1.1.14" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~0.0.2: - version "0.0.4" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-0.0.4.tgz" - integrity sha512-azrivNydKRYt7zwLV5wWUK7YzKTWs3q87xSmY6DlHapPrCvaT6ZrukvM5erV+yCSSPmZT8zkSdttOHQpWWm9zw== - -readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - 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" - -redis-commands@1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz" - integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== - -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" - integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" - integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== - dependencies: - redis-errors "^1.0.0" - -redlock@4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/redlock/-/redlock-4.2.0.tgz" - integrity sha512-j+oQlG+dOwcetUt2WJWttu4CZVeRzUrcVcISFmEmfyuwCVSJ93rDT7YSgg7H7rnxwoRyk/jU46kycVka5tW7jA== - dependencies: - bluebird "^3.7.2" - -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -remove-trailing-slash@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz" - integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== - -request@^2.88.0: - version "2.88.2" - resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-dir@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz" - integrity sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA== - dependencies: - expand-tilde "^1.2.2" - global-modules "^0.2.3" - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve.exports@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" - integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== - -resolve@^1.20.0: - version "1.22.2" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== - dependencies: - is-core-module "^2.11.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rxjs@^7.1.0: - version "7.8.0" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz" - integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== - dependencies: - tslib "^2.1.0" - -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sanitize-s3-objectkey@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz" - integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ== - -sax@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz" - integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== - -sax@>=0.1.1, sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -semver@7.3.7: - version "7.3.7" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -semver@^5.6.0: - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: - version "7.5.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spark-md5@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.1.tgz" - integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig== - -spark-md5@3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz" - integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== - -split-ca@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz" - integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== - -split2@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz" - integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw== - dependencies: - through2 "^2.0.2" - -split@0.3: - version "0.3.3" - resolved "https://registry.npmjs.org/split/-/split-0.3.3.tgz" - integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== - dependencies: - through "2" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -ssh2@^1.11.0: - version "1.14.0" - resolved "https://registry.npmjs.org/ssh2/-/ssh2-1.14.0.tgz" - integrity sha512-AqzD1UCqit8tbOKoj6ztDDi1ffJZ2rV2SwlgrVVrHPkV5vWqGJOVp5pmtj18PunkPJAuKQsnInyKV+/Nb2bUnA== - dependencies: - asn1 "^0.2.6" - bcrypt-pbkdf "^1.0.2" - optionalDependencies: - cpu-features "~0.0.8" - nan "^2.17.0" - -sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stack-utils@^2.0.3: - version "2.0.6" - resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" - integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== - dependencies: - escape-string-regexp "^2.0.0" - -standard-as-callback@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz" - integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== - -start-server-and-test@1.14.0: - version "1.14.0" - resolved "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz" - integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== - dependencies: - bluebird "3.7.2" - check-more-types "2.24.0" - debug "4.3.2" - execa "5.1.1" - lazy-ass "1.6.0" - ps-tree "1.2.0" - wait-on "6.0.0" - -"statuses@>= 1.5.0 < 2", statuses@^1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -step@0.0.x: - version "0.0.6" - resolved "https://registry.npmjs.org/step/-/step-0.0.6.tgz" - integrity sha512-qSSeQinUJk2w38vUFobjFoE307GqsozMC8VisOCkJLpklvKPT0ptPHwWOrENoag8rgLudvTkfP3bancwP93/Jw== - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz" - integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== - dependencies: - duplexer "~0.1.1" - -stream-to-array@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz" - integrity sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA== - dependencies: - any-promise "^1.1.0" - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -stripe@^14.11.0: - version "14.11.0" - resolved "https://registry.yarnpkg.com/stripe/-/stripe-14.11.0.tgz#1df63c31bcff3b136457c2b7584f917509e8030c" - integrity sha512-NmFEkDC0PldP7CQtdPgKs5dVZA/pF+IepldbmB+Kk9B4d7EBkWnbANp0y+/zJcbRGul48s8hmQzeqNWUlWW0wg== - dependencies: - "@types/node" ">=8.1.0" - qs "^6.11.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -tar-fs@2.1.1, tar-fs@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-fs@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz" - integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.0.0" - -tar-stream@^2.0.0, tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - -tar@^6.1.11: - version "6.1.13" - resolved "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz" - integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^4.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -testcontainers@4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/testcontainers/-/testcontainers-4.7.0.tgz" - integrity sha512-5SrG9RMfDRRZig34fDZeMcGD5i3lHCOJzn0kjouyK4TiEWjZB3h7kCk8524lwNRHROFE1j6DGjceonv/5hl5ag== - dependencies: - "@types/dockerode" "^2.5.34" - byline "^5.0.0" - debug "^4.1.1" - docker-compose "^0.23.5" - dockerode "^3.2.1" - get-port "^5.1.1" - glob "^7.1.6" - node-duration "^1.0.4" - slash "^3.0.0" - stream-to-array "^2.3.0" - tar-fs "^2.1.0" - -through2@3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz" - integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== - dependencies: - inherits "^2.0.4" - readable-stream "2 || 3" - -through2@^2.0.0, through2@^2.0.2, through2@^2.0.3: - version "2.0.5" - resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@2, through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -timekeeper@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/timekeeper/-/timekeeper-2.2.0.tgz" - integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A== - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -ts-jest@29.1.1: - version "29.1.1" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" - integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^29.0.0" - json5 "^2.2.3" - lodash.memoize "4.x" - make-error "1.x" - semver "^7.5.3" - yargs-parser "^21.0.1" - -ts-node@10.8.1: - version "10.8.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz" - integrity sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tsconfig-paths@4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.0.0.tgz" - integrity sha512-SLBg2GBKlR6bVtMgJJlud/o3waplKtL7skmLkExomIiaAtLGtVsoXIqP3SYdjbcH9lq/KVv7pMZeCBpLYOit6Q== - dependencies: - json5 "^2.2.1" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^2.1.0: - version "2.5.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - -tsscmp@1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz" - integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-is@^1.6.16, type-is@^1.6.18: - version "1.6.18" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typescript@5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== - -uid2@0.0.x: - version "0.0.4" - resolved "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz" - integrity sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA== - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - -update-browserslist-db@^1.0.10: - version "1.0.10" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url@0.10.3: - version "0.10.3" - resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz" - integrity sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ== - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -utils-merge@1.x.x: - version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - -uuid@8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz" - integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== - -uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.1, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-to-istanbul@^9.0.1: - version "9.1.0" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz" - integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - -vary@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vuvuzela@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz" - integrity sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ== - -wait-on@6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz" - integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== - dependencies: - axios "^0.21.1" - joi "^17.4.0" - lodash "^4.17.21" - minimist "^1.2.5" - rxjs "^7.1.0" - -walker@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -webfinger@^0.4.2: - version "0.4.2" - resolved "https://registry.npmjs.org/webfinger/-/webfinger-0.4.2.tgz" - integrity sha512-PvvQ/k74HkC3q5G7bGu4VYeKDt3ePZMzT5qFPtEnOL8eyIU1/06OtDn9X5vlkQ23BlegA3eN89rDLiYUife3xQ== - dependencies: - step "0.0.x" - xml2js "0.1.x" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which@^1.2.12: - version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.2: - version "1.1.5" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -write-stream@~0.4.3: - version "0.4.3" - resolved "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz" - integrity sha512-IJrvkhbAnj89W/GAVdVgbnPiVw5Ntg/B4tc/MUCIEwj/g6JIww1DWJyB/yBMT3yw2/TkT6IUZ0+IYef3flEw8A== - dependencies: - readable-stream "~0.0.2" - -xml2js@0.1.x: - version "0.1.14" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.1.14.tgz" - integrity sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA== - dependencies: - sax ">=0.1.1" - -xml2js@0.4.19: - version "0.4.19" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz" - integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz" - integrity sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ== - -xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yargs-parser@^21.0.1, yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs@^17.3.1: - version "17.7.1" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -ylru@^1.2.0: - version "1.3.2" - resolved "https://registry.npmjs.org/ylru/-/ylru-1.3.2.tgz" - integrity sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA== - -yn@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zlib@1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz" - integrity sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w== diff --git a/yarn.lock b/yarn.lock index 6acdcce3b6..3497a55b0a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5098,6 +5098,15 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== +"@trendyol/jest-testcontainers@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@trendyol/jest-testcontainers/-/jest-testcontainers-2.1.1.tgz#dced95cf9c37b75efe0a65db9b75ae8912f2f14a" + integrity sha512-4iAc2pMsev4BTUzoA7jO1VvbTOU2N3juQUYa8TwiSPXPuQtxKwV9WB9ZEP+JQ+Pj15YqfGOXp5H0WNMPtapjiA== + dependencies: + cwd "^0.10.0" + node-duration "^1.0.4" + testcontainers "4.7.0" + "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -5287,6 +5296,13 @@ "@types/node" "*" "@types/ssh2" "*" +"@types/dockerode@^2.5.34": + version "2.5.34" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-2.5.34.tgz#9adb884f7cc6c012a6eb4b2ad794cc5d01439959" + integrity sha512-LcbLGcvcBwBAvjH9UrUI+4qotY+A5WCer5r43DR5XHv2ZIEByNXFdPLo1XxR+v/BjkGjlggW8qUiXuVEhqfkpA== + dependencies: + "@types/node" "*" + "@types/dockerode@^3.3.24": version "3.3.24" resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.24.tgz#bea354a4fcd0824a80fd5ea5ede3e8cda71137a7" @@ -5875,6 +5891,13 @@ "@types/pouchdb-node" "*" "@types/pouchdb-replication" "*" +"@types/proper-lockfile@^4.1.4": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@types/proper-lockfile/-/proper-lockfile-4.1.4.tgz#cd9fab92bdb04730c1ada542c356f03620f84008" + integrity sha512-uo2ABllncSqg9F1D4nugVl9v93RmjxF6LJzQLMLDdPaXCUIDPeOJ21Gbqi43xNKzBi/WQ0Q0dICqufzQbMjipQ== + dependencies: + "@types/retry" "*" + "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -5937,6 +5960,11 @@ dependencies: "@types/node" "*" +"@types/retry@*": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.5.tgz#f090ff4bd8d2e5b940ff270ab39fd5ca1834a07e" + integrity sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw== + "@types/rimraf@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.2.tgz#a63d175b331748e5220ad48c901d7bbf1f44eef8" @@ -9124,6 +9152,14 @@ curlconverter@3.21.0: string.prototype.startswith "^1.0.0" yamljs "^0.3.0" +cwd@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/cwd/-/cwd-0.10.0.tgz#172400694057c22a13b0cf16162c7e4b7a7fe567" + integrity sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA== + dependencies: + find-pkg "^0.1.2" + fs-exists-sync "^0.1.0" + dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -9745,7 +9781,7 @@ docker-compose@0.24.0: dependencies: yaml "^1.10.2" -docker-compose@^0.23.6: +docker-compose@^0.23.5, docker-compose@^0.23.6: version "0.23.19" resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.23.19.tgz#9947726e2fe67bdfa9e8efe1ff15aa0de2e10eb8" integrity sha512-v5vNLIdUqwj4my80wxFDkNH+4S85zsRuH29SO7dCWVWPCMt/ohZBsGN6g6KXWifT0pzQ7uOxqEKCYCDPJ8Vz4g== @@ -9769,7 +9805,7 @@ docker-modem@^3.0.0: split-ca "^1.0.1" ssh2 "^1.11.0" -dockerode@^3.3.5: +dockerode@^3.2.1, dockerode@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.5.tgz#7ae3f40f2bec53ae5e9a741ce655fff459745629" integrity sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA== @@ -10794,6 +10830,13 @@ expand-template@^2.0.3: resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== +expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + integrity sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q== + dependencies: + os-homedir "^1.0.1" + expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" @@ -11022,7 +11065,7 @@ fetch-cookie@0.11.0: dependencies: tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" -fflate@^0.4.1, fflate@^0.4.8: +fflate@^0.4.8: version "0.4.8" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== @@ -11132,11 +11175,26 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== +find-file-up@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/find-file-up/-/find-file-up-0.1.3.tgz#cf68091bcf9f300a40da411b37da5cce5a2fbea0" + integrity sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A== + dependencies: + fs-exists-sync "^0.1.0" + resolve-dir "^0.1.0" + find-free-port@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/find-free-port/-/find-free-port-2.0.0.tgz#4b22e5f6579eb1a38c41ac6bcb3efed1b6da9b1b" integrity sha512-J1j8gfEVf5FN4PR5w5wrZZ7NYs2IvqsHcd03cAeQx3Ec/mo+lKceaVNhpsRKoZpZKbId88o8qh+dwUwzBV6WCg== +find-pkg@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/find-pkg/-/find-pkg-0.1.2.tgz#1bdc22c06e36365532e2a248046854b9788da557" + integrity sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw== + dependencies: + find-file-up "^0.1.2" + find-up@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -11304,6 +11362,11 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + integrity sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg== + fs-extra@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -11800,6 +11863,24 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" +global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + integrity sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA== + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + +global-prefix@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + integrity sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw== + dependencies: + homedir-polyfill "^1.0.0" + ini "^1.3.4" + is-windows "^0.2.0" + which "^1.2.12" + global@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" @@ -12230,7 +12311,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -homedir-polyfill@^1.0.1: +homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== @@ -13204,6 +13285,11 @@ is-whitespace@^0.3.0: resolved "https://registry.yarnpkg.com/is-whitespace/-/is-whitespace-0.3.0.tgz#1639ecb1be036aec69a54cbb401cfbed7114ab7f" integrity sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg== +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + integrity sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q== + is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -16066,6 +16152,11 @@ node-addon-api@^6.1.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== +node-duration@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/node-duration/-/node-duration-1.0.4.tgz#3e94ecc0e473691c89c4560074503362071cecac" + integrity sha512-eUXYNSY7DL53vqfTosggWkvyIW3bhAcqBDIlolgNYlZhianXTrCL50rlUJWD1eRqkIxMppXTfiFbp+9SjpPrgA== + node-fetch@2.6.0, node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9, node-fetch@^2.7.0: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -16812,6 +16903,11 @@ oracledb@5.3.0: resolved "https://registry.yarnpkg.com/oracledb/-/oracledb-5.3.0.tgz#a15e6cd16757d8711a2c006a28bd7ecd3b8466f7" integrity sha512-HMJzQ6lCf287ztvvehTEmjCWA21FQ3RMvM+mgoqd4i8pkREuqFWO+y3ovsGR9moJUg4T0xjcwS8rl4mggWPxmg== +os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== + os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -17935,6 +18031,14 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" +posthog-js@^1.116.6: + version "1.117.0" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.117.0.tgz#59c3e520f6269f76ea82dce8760fbc33cdd7f48f" + integrity sha512-+I8q5G9YG6r6wOLKPT+C+AV7MRhyVFJMTJS7dfwLmmT+mkVxQ5bfC59hBkJUObOR+YRn5jn2JT/sgIslU94EZg== + dependencies: + fflate "^0.4.8" + preact "^10.19.3" + posthog-js@^1.13.4: version "1.103.1" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.103.1.tgz#f846c413c28aca204dc1527f49d39f651348f3c4" @@ -17943,13 +18047,6 @@ posthog-js@^1.13.4: fflate "^0.4.8" preact "^10.19.3" -posthog-js@^1.36.0: - version "1.96.1" - resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.96.1.tgz#4f9719a24e4e14037b0e72d430194d7cdb576447" - integrity sha512-kv1vQqYMt2BV3YHS+wxsbGuP+tz+M3y1AzNhz8TfkpY1HT8W/ONT0i0eQpeRr9Y+d4x/fZ6M4cXG5GMvi9lRCA== - dependencies: - fflate "^0.4.1" - posthog-node@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-1.3.0.tgz#804ed2f213a2f05253f798bf9569d55a9cad94f7" @@ -19130,6 +19227,14 @@ resolve-dependency-path@^2.0.0: resolved "https://registry.yarnpkg.com/resolve-dependency-path/-/resolve-dependency-path-2.0.0.tgz#11700e340717b865d216c66cabeb4a2a3c696736" integrity sha512-DIgu+0Dv+6v2XwRaNWnumKu7GPufBBOr5I1gRPJHkvghrfCGOooJODFvgFimX/KRxk9j0whD2MnKHzM1jYvk9w== +resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + integrity sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA== + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + resolve-from@5.0.0, resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" @@ -20819,7 +20924,7 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar-fs@2.1.1, tar-fs@^2.0.0: +tar-fs@2.1.1, tar-fs@^2.0.0, tar-fs@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -20997,6 +21102,23 @@ testcontainers@10.7.2, testcontainers@^10.7.2: tar-fs "^3.0.5" tmp "^0.2.1" +testcontainers@4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/testcontainers/-/testcontainers-4.7.0.tgz#5a9a864b1b0cc86984086dcc737c2f5e73490cf3" + integrity sha512-5SrG9RMfDRRZig34fDZeMcGD5i3lHCOJzn0kjouyK4TiEWjZB3h7kCk8524lwNRHROFE1j6DGjceonv/5hl5ag== + dependencies: + "@types/dockerode" "^2.5.34" + byline "^5.0.0" + debug "^4.1.1" + docker-compose "^0.23.5" + dockerode "^3.2.1" + get-port "^5.1.1" + glob "^7.1.6" + node-duration "^1.0.4" + slash "^3.0.0" + stream-to-array "^2.3.0" + tar-fs "^2.1.0" + text-extensions@^1.0.0: version "1.9.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" @@ -22235,7 +22357,7 @@ which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" -which@^1.2.9: +which@^1.2.12, which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==