From 94d0b51ad75da5093fbced986f044113fb493141 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 13:49:32 +0200 Subject: [PATCH 01/17] add custom domain support for containers --- README.md | 7 ++- deploy/lib/createContainers.js | 90 ++++++++++++++++++++++++++++++++++ deploy/lib/createFunctions.js | 4 +- deploy/lib/deployContainers.js | 33 ++++++++++--- deploy/lib/deployFunctions.js | 2 +- shared/api/domain.js | 65 +++++++++++++++++++++--- 6 files changed, 180 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ab43d5b5..9e3c801d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,9 @@ serverless invoke --function first Serverless Framework handles everything from creating namespaces to function/code deployment by calling APIs endpoint under the hood. -- [Serverless Framework: Deploy on Scaleway Functions](#serverless-framework-deploy-on-scaleway-functions) +- [Scaleway Plugin for Serverless Framework](#scaleway-plugin-for-serverless-framework) + - [Quick-start](#quick-start) + - [Contents](#contents) - [Requirements](#requirements) - [Create a Project](#create-a-project) - [Configure your functions](#configure-your-functions) @@ -341,7 +343,8 @@ You may refer to the follow examples: Custom domains allows users to use their own domains. -For domain configuration please [Refer to Scaleway Documentation](https://www.scaleway.com/en/docs/compute/functions/how-to/add-a-custom-domain-name-to-a-function/) +For domain configuration please refer to [custom domains on Function](https://www.scaleway.com/en/docs/compute/functions/how-to/add-a-custom-domain-name-to-a-function/) or +[custom domains on Container](https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/) Integration with serverless framework example : diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index 4acad60b..dcfc9f64 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -24,6 +24,84 @@ module.exports = { }); }, + applyDomains(containerId, customDomains) { + // we make a diff to know which domains to add or delete + const domainsToCreate = []; + const domainsIdToDelete = []; + const existingDomains = []; + + this.listDomainsContainer(containerId).then((domains) => { + domains.forEach((domain) => { + existingDomains.push({ hostname: domain.hostname, id: domain.id }); + }); + + if ( + customDomains !== undefined && + customDomains !== null && + customDomains.length > 0 + ) { + customDomains.forEach((customDomain) => { + domainsIdToDelete.push(customDomain.id); + + let domainFound = false; + + existingDomains.forEach((existingDom) => { + if (existingDom.hostname === customDomain) { + domainFound = true; + return false; + } + }); + if (!domainFound) { + domainsToCreate.push(customDomain); + } + }); + } + + existingDomains.forEach((existingDomain) => { + if ( + (customDomains === undefined || customDomains === null) && + existingDomain.id !== undefined + ) { + domainsIdToDelete.push(existingDomain.id); + } else if (!customDomains.includes(existingDomain.hostname)) { + domainsIdToDelete.push(existingDomain.id); + } + }); + + domainsToCreate.forEach((newDomain) => { + const createDomainParams = { container_id: containerId, hostname: newDomain }; + + this.createDomain(createDomainParams) + .then((res) => { + this.serverless.cli.log(`Creating domain ${res.hostname}`); + }) + .then( + () => {}, + (reason) => { + this.serverless.cli.log( + `Error on domain : ${newDomain}, reason : ${reason.message}` + ); + + if (reason.message.includes("could not validate")) { + this.serverless.cli.log( + "Ensure CNAME configuration is ok, it can take some time for a record to propagate" + ); + } + } + ); + }); + + domainsIdToDelete.forEach((domainId) => { + if (domainId === undefined) { + return; + } + this.deleteDomain(domainId).then((res) => { + this.serverless.cli.log(`Deleting domain ${res.hostname}`); + }); + }); + }); + }, + createOrUpdateContainers(foundContainers) { const { containers } = this.provider.serverless.service.custom; @@ -67,6 +145,14 @@ module.exports = { port: container.port, }; + // checking if there is custom_domains set on container creation. + if (container.custom_domains && container.custom_domains.length > 0) { + this.serverless.cli.log("WARNING: custom_domains are available on container update only. "+ + "Redeploy your container to apply custom domains. Doc : https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/") + } + + this.serverless.cli.log(`Creating function ${func.name}...`); + this.serverless.cli.log(`Creating container ${container.name}...`); return this.createContainer(params) @@ -91,6 +177,10 @@ module.exports = { }; this.serverless.cli.log(`Updating container ${container.name}...`); + + // assign domains + this.applyDomains(foundContainer.id, container.custom_domains); + return this.updateContainer(foundContainer.id, params) .then(response => Object.assign(response, { directory: container.directory })); }, diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index 1ccb3d0c..285fe982 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -59,7 +59,7 @@ module.exports = { const domainsIdToDelete = []; const existingDomains = []; - this.listDomains(funcId).then((domains) => { + this.listDomainsFunction(funcId).then((domains) => { domains.forEach((domain) => { existingDomains.push({ hostname: domain.hostname, id: domain.id }); }); @@ -201,7 +201,7 @@ module.exports = { params.runtime = this.validateRuntime( func, availableRuntimes, - this.serverless.cli + this.serverless.cli, ); // checking if there is custom_domains set on function creation. diff --git a/deploy/lib/deployContainers.js b/deploy/lib/deployContainers.js index a77c667f..b2823330 100644 --- a/deploy/lib/deployContainers.js +++ b/deploy/lib/deployContainers.js @@ -4,24 +4,41 @@ const BbPromise = require('bluebird'); module.exports = { deployContainers() { - this.serverless.cli.log('Deploying Containers...'); + this.serverless.cli.log("Deploying Containers..."); return BbPromise.bind(this) .then(this.deployEachContainer) - .then(() => this.serverless.cli.log('Waiting for container deployments, this may take multiple minutes...')) + .then(() => + this.serverless.cli.log( + "Waiting for container deployments, this may take multiple minutes..." + ) + ) .then(this.printContainerEndpointsAfterDeployment); }, deployEachContainer() { - const promises = this.containers.map( - container => this.deployContainer(container.id), + const promises = this.containers.map((container) => + this.deployContainer(container.id) ); return Promise.all(promises); }, printContainerEndpointsAfterDeployment() { - return this.waitContainersAreDeployed(this.namespace.id) - .then(containers => containers.forEach( - container => this.serverless.cli.log(`Container ${container.name} has been deployed to: https://${container.domain_name}`), - )); + return this.waitContainersAreDeployed(this.namespace.id).then( + (containers) => { + containers.forEach((container) => { + this.serverless.cli.log( + `Container ${container.name} has been deployed to: https://${container.domain_name}` + ); + + this.serverless.cli.log("Waiting for domains deployment..."); + + this.waitDomainsAreDeployedContainer(container.id).then((domains) => { + domains.forEach((domain) => { + this.serverless.cli.log(`Domain ready : ${domain.hostname}`); + }); + }); + }); + } + ); }, }; diff --git a/deploy/lib/deployFunctions.js b/deploy/lib/deployFunctions.js index 491211b7..5f73db03 100644 --- a/deploy/lib/deployFunctions.js +++ b/deploy/lib/deployFunctions.js @@ -40,7 +40,7 @@ module.exports = { 'Waiting for domains deployment...', ); - this.waitDomainsAreDeployed(func.id) + this.waitDomainsAreDeployedFunction(func.id) .then((domains) => { domains.forEach((domain) => { this.serverless.cli.log(`Domain ready : ${domain.hostname}`); diff --git a/shared/api/domain.js b/shared/api/domain.js index 9d171423..901731ed 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -5,10 +5,10 @@ const { manageError } = require("./utils"); module.exports = { /** * listDomains is used to read all domains of a wanted function. - * @param {Number} functionId the id of the function to read domains. + * @param {Number} functionId the id of the function to read domains. * @returns a Promise with request result. */ - listDomains(functionId) { + listDomainsFunction(functionId) { const domainsUrl = `domains?function_id=${functionId}`; return this.apiManager @@ -17,6 +17,20 @@ module.exports = { .catch(manageError); }, + /** + * listDomains is used to read all domains of a wanted container. + * @param {Number} containerId the id of the container to read domains. + * @returns a Promise with request result. + */ + listDomainsContainer(containerId) { + const domainsUrl = `domains?container_id=${containerId}`; + + return this.apiManager + .get(domainsUrl) + .then((response) => response.data.domains) + .catch(manageError); + }, + /** * createDomain is used to call for domain creation, warning : this * function does not wait for the domain @@ -48,29 +62,64 @@ module.exports = { /** * Waiting for all domains to be ready on a function - * @param {Number} functionId + * @param {UUID} functionId * @returns */ - waitDomainsAreDeployed(functionId) { + waitDomainsAreDeployedFunction(functionId) { return this.listDomains(functionId) .then((domains) => { - let domainssAreReady = true; + let domainsAreReady = true; + + for (let i = 0; i < domains.length; i += 1) { + const domain = domains[i]; + + if (domain.status === 'error') { + throw new Error(domain.error_message); + } + + if (domain.status !== 'ready') { + domainsAreReady = false; + break; + } + } + if (!domainsAreReady) { + return new Promise((resolve) => { + setTimeout(() => resolve(this.waitDomainsAreDeployedFunction(functionId)), 5000); + }); + } + return domains; + }); + }, + + /** + * Waiting for all domains to be ready on a container + * @param {UUID} containerId + * @returns + */ + waitDomainsAreDeployedContainer(containerId) { + return this.listDomains(containerId) + .then((domains) => { + let domainsAreReady = true; + for (let i = 0; i < domains.length; i += 1) { const domain = domains[i]; + if (domain.status === 'error') { throw new Error(domain.error_message); } + if (domain.status !== 'ready') { - domainssAreReady = false; + domainsAreReady = false; break; } } - if (!domainssAreReady) { + if (!domainsAreReady) { return new Promise((resolve) => { - setTimeout(() => resolve(this.waitDomainsAreDeployed(functionId)), 5000); + setTimeout(() => resolve(this.waitDomainsAreDeployedContainer(containerId)), 5000); }); } return domains; }); }, + }; From 4c17db9ce381268926b46e0451efa33f901c03f5 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 13:55:26 +0200 Subject: [PATCH 02/17] Revert "During container build, authenticate to registry to pull private images (#103)" This reverts commit a728ad397ab6c879e16a4741f9aa57d3a569f3be. --- deploy/lib/buildAndPushContainers.js | 18 +-- shared/api/registry.js | 6 - .../containers_private_registry.test.js | 111 ------------------ 3 files changed, 2 insertions(+), 133 deletions(-) delete mode 100644 tests/containers/containers_private_registry.test.js diff --git a/deploy/lib/buildAndPushContainers.js b/deploy/lib/buildAndPushContainers.js index 01a05083..7d3c5d07 100644 --- a/deploy/lib/buildAndPushContainers.js +++ b/deploy/lib/buildAndPushContainers.js @@ -45,26 +45,12 @@ function findErrorInBuildOutput(buildOutput) { } module.exports = { - async buildAndPushContainers() { - // used for pushing + buildAndPushContainers() { const auth = { username: 'any', password: this.provider.scwToken, }; - // used for building: see https://docs.docker.com/engine/api/v1.37/#tag/Image/operation/ImageBuild - const registryAuth = {}; - registryAuth['rg.' + this.provider.scwRegion + '.scw.cloud'] = { - username: 'any', - password: this.provider.scwToken, - }; - - try { - await docker.checkAuth(registryAuth); - } catch (err) { - throw new Error(`Authentication to registry failed`); - } - const containerNames = Object.keys(this.containers); const promises = containerNames.map((containerName) => { const container = this.containers[containerName]; @@ -74,7 +60,7 @@ module.exports = { this.serverless.cli.log(`Building and pushing container ${container.name} to: ${imageName} ...`); return new Promise(async (resolve, reject) => { - const buildStream = await docker.buildImage(tarStream, { t: imageName, registryconfig: registryAuth }) + const buildStream = await docker.buildImage(tarStream, { t: imageName }) const buildStreamEvents = await extractStreamContents(buildStream, this.provider.options.verbose); const buildError = findErrorInBuildOutput(buildStreamEvents); diff --git a/shared/api/registry.js b/shared/api/registry.js index 372ee8d8..1d12ef2c 100644 --- a/shared/api/registry.js +++ b/shared/api/registry.js @@ -21,12 +21,6 @@ class RegistryApi { return this.apiManager.delete(`namespaces/${namespaceId}`) .catch(manageError); } - - createRegistryNamespace(params) { - return this.apiManager.post("namespaces", params) - .then(response => response.data) - .catch(manageError); - } } module.exports = RegistryApi; diff --git a/tests/containers/containers_private_registry.test.js b/tests/containers/containers_private_registry.test.js deleted file mode 100644 index ea176bc3..00000000 --- a/tests/containers/containers_private_registry.test.js +++ /dev/null @@ -1,111 +0,0 @@ -'use strict'; - -const crypto = require('crypto'); -const Docker = require('dockerode'); - -const docker = new Docker(); - -const path = require('path'); -const fs = require('fs'); -const { expect } = require('chai'); - -const { getTmpDirPath, replaceTextInFile } = require('../utils/fs'); -const { getServiceName, sleep, serverlessDeploy, serverlessRemove} = require('../utils/misc'); -const { ContainerApi, RegistryApi } = require('../../shared/api'); -const { CONTAINERS_API_URL, REGISTRY_API_URL } = require('../../shared/constants'); -const { execSync, execCaptureOutput } = require('../../shared/child-process'); - -const serverlessExec = path.join('serverless'); - -describe('Build and deploy on container with a base image private', () => { - const templateName = path.resolve(__dirname, '..', '..', 'examples', 'container'); - const tmpDir = getTmpDirPath(); - let oldCwd; - let serviceName; - const scwRegion = process.env.SCW_REGION; - const scwProject = process.env.SCW_DEFAULT_PROJECT_ID || process.env.SCW_PROJECT; - const scwToken = process.env.SCW_SECRET_KEY || process.env.SCW_TOKEN; - const apiUrl = `${CONTAINERS_API_URL}/${scwRegion}`; - const registryApiUrl = `${REGISTRY_API_URL}/${scwRegion}/`; - let api; - let registryApi; - let namespace; - let containerName; - - const originalImageRepo = 'python'; - const imageTag = '3-alpine'; - let privateRegistryImageRepo; - let privateRegistryNamespaceId; - - beforeAll(async () => { - oldCwd = process.cwd(); - serviceName = getServiceName(); - api = new ContainerApi(apiUrl, scwToken); - registryApi = new RegistryApi(registryApiUrl, scwToken); - - // pull the base image, create a private registry, push it into that registry, and remove the image locally - // to check that the image is pulled at build time - const registryName = `private-registry-${crypto.randomBytes(16).toString('hex')}`; - const privateRegistryNamespace = await registryApi.createRegistryNamespace({name: registryName, project_id: scwProject}); - privateRegistryNamespaceId = privateRegistryNamespace.id; - - privateRegistryImageRepo = `rg.${scwRegion}.scw.cloud/${registryName}/python`; - - await docker.pull(`${originalImageRepo}:${imageTag}`); - const originalImage = docker.getImage(`${originalImageRepo}:${imageTag}`); - await originalImage.tag({repo: privateRegistryImageRepo, tag: imageTag}); - const privateRegistryImage = docker.getImage(`${privateRegistryImageRepo}:${imageTag}`); - await privateRegistryImage.push({ - stream: false, - username: 'nologin', - password: scwToken - }); - await privateRegistryImage.remove(); - }); - - afterAll(async () => { - await registryApi.deleteRegistryNamespace(privateRegistryNamespaceId); - process.chdir(oldCwd); - }); - - it('should create service in tmp directory', () => { - execSync(`${serverlessExec} create --template-path ${templateName} --path ${tmpDir}`); - process.chdir(tmpDir); - execSync(`npm link ${oldCwd}`); - replaceTextInFile('serverless.yml', 'scaleway-container', serviceName); - replaceTextInFile('serverless.yml', '', scwToken); - replaceTextInFile('serverless.yml', '', scwProject); - replaceTextInFile(path.join('my-container', 'Dockerfile'), 'FROM python:3-alpine', `FROM ${privateRegistryImageRepo}:${imageTag}`); - expect(fs.existsSync(path.join(tmpDir, 'serverless.yml'))).to.be.equal(true); - expect(fs.existsSync(path.join(tmpDir, 'my-container'))).to.be.equal(true); - }); - - it('should deploy service/container to scaleway', async () => { - serverlessDeploy(); - namespace = await api.getNamespaceFromList(serviceName); - namespace.containers = await api.listContainers(namespace.id); - containerName = namespace.containers[0].name; - }); - - it('should invoke container from scaleway', async () => { - // TODO query function status instead of having an arbitrary sleep - await sleep(30000); - - let output = execCaptureOutput(serverlessExec, ['invoke', '--function', containerName]); - expect(output).to.be.equal('{"message":"Hello, World from Scaleway Container !"}'); - }); - - it('should remove service from scaleway', async () => { - serverlessRemove(); - try { - await api.getNamespace(namespace.id); - } catch (err) { - expect(err.response.status).to.be.equal(404); - } - }); - - it('should remove registry namespace properly', async () => { - const response = await registryApi.deleteRegistryNamespace(namespace.registry_namespace_id); - expect(response.status).to.be.equal(200); - }); -}); From 3d2fbbe6a7e46d78f01bebc2bb26843d665a19ca Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 13:57:28 +0200 Subject: [PATCH 03/17] Revert "Revert "During container build, authenticate to registry to pull private images (#103)"" This reverts commit 4c17db9ce381268926b46e0451efa33f901c03f5. --- deploy/lib/buildAndPushContainers.js | 18 ++- shared/api/registry.js | 6 + .../containers_private_registry.test.js | 111 ++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 tests/containers/containers_private_registry.test.js diff --git a/deploy/lib/buildAndPushContainers.js b/deploy/lib/buildAndPushContainers.js index 7d3c5d07..01a05083 100644 --- a/deploy/lib/buildAndPushContainers.js +++ b/deploy/lib/buildAndPushContainers.js @@ -45,12 +45,26 @@ function findErrorInBuildOutput(buildOutput) { } module.exports = { - buildAndPushContainers() { + async buildAndPushContainers() { + // used for pushing const auth = { username: 'any', password: this.provider.scwToken, }; + // used for building: see https://docs.docker.com/engine/api/v1.37/#tag/Image/operation/ImageBuild + const registryAuth = {}; + registryAuth['rg.' + this.provider.scwRegion + '.scw.cloud'] = { + username: 'any', + password: this.provider.scwToken, + }; + + try { + await docker.checkAuth(registryAuth); + } catch (err) { + throw new Error(`Authentication to registry failed`); + } + const containerNames = Object.keys(this.containers); const promises = containerNames.map((containerName) => { const container = this.containers[containerName]; @@ -60,7 +74,7 @@ module.exports = { this.serverless.cli.log(`Building and pushing container ${container.name} to: ${imageName} ...`); return new Promise(async (resolve, reject) => { - const buildStream = await docker.buildImage(tarStream, { t: imageName }) + const buildStream = await docker.buildImage(tarStream, { t: imageName, registryconfig: registryAuth }) const buildStreamEvents = await extractStreamContents(buildStream, this.provider.options.verbose); const buildError = findErrorInBuildOutput(buildStreamEvents); diff --git a/shared/api/registry.js b/shared/api/registry.js index 1d12ef2c..372ee8d8 100644 --- a/shared/api/registry.js +++ b/shared/api/registry.js @@ -21,6 +21,12 @@ class RegistryApi { return this.apiManager.delete(`namespaces/${namespaceId}`) .catch(manageError); } + + createRegistryNamespace(params) { + return this.apiManager.post("namespaces", params) + .then(response => response.data) + .catch(manageError); + } } module.exports = RegistryApi; diff --git a/tests/containers/containers_private_registry.test.js b/tests/containers/containers_private_registry.test.js new file mode 100644 index 00000000..ea176bc3 --- /dev/null +++ b/tests/containers/containers_private_registry.test.js @@ -0,0 +1,111 @@ +'use strict'; + +const crypto = require('crypto'); +const Docker = require('dockerode'); + +const docker = new Docker(); + +const path = require('path'); +const fs = require('fs'); +const { expect } = require('chai'); + +const { getTmpDirPath, replaceTextInFile } = require('../utils/fs'); +const { getServiceName, sleep, serverlessDeploy, serverlessRemove} = require('../utils/misc'); +const { ContainerApi, RegistryApi } = require('../../shared/api'); +const { CONTAINERS_API_URL, REGISTRY_API_URL } = require('../../shared/constants'); +const { execSync, execCaptureOutput } = require('../../shared/child-process'); + +const serverlessExec = path.join('serverless'); + +describe('Build and deploy on container with a base image private', () => { + const templateName = path.resolve(__dirname, '..', '..', 'examples', 'container'); + const tmpDir = getTmpDirPath(); + let oldCwd; + let serviceName; + const scwRegion = process.env.SCW_REGION; + const scwProject = process.env.SCW_DEFAULT_PROJECT_ID || process.env.SCW_PROJECT; + const scwToken = process.env.SCW_SECRET_KEY || process.env.SCW_TOKEN; + const apiUrl = `${CONTAINERS_API_URL}/${scwRegion}`; + const registryApiUrl = `${REGISTRY_API_URL}/${scwRegion}/`; + let api; + let registryApi; + let namespace; + let containerName; + + const originalImageRepo = 'python'; + const imageTag = '3-alpine'; + let privateRegistryImageRepo; + let privateRegistryNamespaceId; + + beforeAll(async () => { + oldCwd = process.cwd(); + serviceName = getServiceName(); + api = new ContainerApi(apiUrl, scwToken); + registryApi = new RegistryApi(registryApiUrl, scwToken); + + // pull the base image, create a private registry, push it into that registry, and remove the image locally + // to check that the image is pulled at build time + const registryName = `private-registry-${crypto.randomBytes(16).toString('hex')}`; + const privateRegistryNamespace = await registryApi.createRegistryNamespace({name: registryName, project_id: scwProject}); + privateRegistryNamespaceId = privateRegistryNamespace.id; + + privateRegistryImageRepo = `rg.${scwRegion}.scw.cloud/${registryName}/python`; + + await docker.pull(`${originalImageRepo}:${imageTag}`); + const originalImage = docker.getImage(`${originalImageRepo}:${imageTag}`); + await originalImage.tag({repo: privateRegistryImageRepo, tag: imageTag}); + const privateRegistryImage = docker.getImage(`${privateRegistryImageRepo}:${imageTag}`); + await privateRegistryImage.push({ + stream: false, + username: 'nologin', + password: scwToken + }); + await privateRegistryImage.remove(); + }); + + afterAll(async () => { + await registryApi.deleteRegistryNamespace(privateRegistryNamespaceId); + process.chdir(oldCwd); + }); + + it('should create service in tmp directory', () => { + execSync(`${serverlessExec} create --template-path ${templateName} --path ${tmpDir}`); + process.chdir(tmpDir); + execSync(`npm link ${oldCwd}`); + replaceTextInFile('serverless.yml', 'scaleway-container', serviceName); + replaceTextInFile('serverless.yml', '', scwToken); + replaceTextInFile('serverless.yml', '', scwProject); + replaceTextInFile(path.join('my-container', 'Dockerfile'), 'FROM python:3-alpine', `FROM ${privateRegistryImageRepo}:${imageTag}`); + expect(fs.existsSync(path.join(tmpDir, 'serverless.yml'))).to.be.equal(true); + expect(fs.existsSync(path.join(tmpDir, 'my-container'))).to.be.equal(true); + }); + + it('should deploy service/container to scaleway', async () => { + serverlessDeploy(); + namespace = await api.getNamespaceFromList(serviceName); + namespace.containers = await api.listContainers(namespace.id); + containerName = namespace.containers[0].name; + }); + + it('should invoke container from scaleway', async () => { + // TODO query function status instead of having an arbitrary sleep + await sleep(30000); + + let output = execCaptureOutput(serverlessExec, ['invoke', '--function', containerName]); + expect(output).to.be.equal('{"message":"Hello, World from Scaleway Container !"}'); + }); + + it('should remove service from scaleway', async () => { + serverlessRemove(); + try { + await api.getNamespace(namespace.id); + } catch (err) { + expect(err.response.status).to.be.equal(404); + } + }); + + it('should remove registry namespace properly', async () => { + const response = await registryApi.deleteRegistryNamespace(namespace.registry_namespace_id); + expect(response.status).to.be.equal(200); + }); +}); From e65ef055bcd7db6d7c3ff5ca30b3917135e76cb4 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 13:58:27 +0200 Subject: [PATCH 04/17] Revert "add custom domain support for containers" This reverts commit 94d0b51ad75da5093fbced986f044113fb493141. --- README.md | 7 +-- deploy/lib/createContainers.js | 90 ---------------------------------- deploy/lib/createFunctions.js | 4 +- deploy/lib/deployContainers.js | 33 +++---------- deploy/lib/deployFunctions.js | 2 +- shared/api/domain.js | 65 +++--------------------- 6 files changed, 21 insertions(+), 180 deletions(-) diff --git a/README.md b/README.md index 9e3c801d..ab43d5b5 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,7 @@ serverless invoke --function first Serverless Framework handles everything from creating namespaces to function/code deployment by calling APIs endpoint under the hood. -- [Scaleway Plugin for Serverless Framework](#scaleway-plugin-for-serverless-framework) - - [Quick-start](#quick-start) - - [Contents](#contents) +- [Serverless Framework: Deploy on Scaleway Functions](#serverless-framework-deploy-on-scaleway-functions) - [Requirements](#requirements) - [Create a Project](#create-a-project) - [Configure your functions](#configure-your-functions) @@ -343,8 +341,7 @@ You may refer to the follow examples: Custom domains allows users to use their own domains. -For domain configuration please refer to [custom domains on Function](https://www.scaleway.com/en/docs/compute/functions/how-to/add-a-custom-domain-name-to-a-function/) or -[custom domains on Container](https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/) +For domain configuration please [Refer to Scaleway Documentation](https://www.scaleway.com/en/docs/compute/functions/how-to/add-a-custom-domain-name-to-a-function/) Integration with serverless framework example : diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index dcfc9f64..4acad60b 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -24,84 +24,6 @@ module.exports = { }); }, - applyDomains(containerId, customDomains) { - // we make a diff to know which domains to add or delete - const domainsToCreate = []; - const domainsIdToDelete = []; - const existingDomains = []; - - this.listDomainsContainer(containerId).then((domains) => { - domains.forEach((domain) => { - existingDomains.push({ hostname: domain.hostname, id: domain.id }); - }); - - if ( - customDomains !== undefined && - customDomains !== null && - customDomains.length > 0 - ) { - customDomains.forEach((customDomain) => { - domainsIdToDelete.push(customDomain.id); - - let domainFound = false; - - existingDomains.forEach((existingDom) => { - if (existingDom.hostname === customDomain) { - domainFound = true; - return false; - } - }); - if (!domainFound) { - domainsToCreate.push(customDomain); - } - }); - } - - existingDomains.forEach((existingDomain) => { - if ( - (customDomains === undefined || customDomains === null) && - existingDomain.id !== undefined - ) { - domainsIdToDelete.push(existingDomain.id); - } else if (!customDomains.includes(existingDomain.hostname)) { - domainsIdToDelete.push(existingDomain.id); - } - }); - - domainsToCreate.forEach((newDomain) => { - const createDomainParams = { container_id: containerId, hostname: newDomain }; - - this.createDomain(createDomainParams) - .then((res) => { - this.serverless.cli.log(`Creating domain ${res.hostname}`); - }) - .then( - () => {}, - (reason) => { - this.serverless.cli.log( - `Error on domain : ${newDomain}, reason : ${reason.message}` - ); - - if (reason.message.includes("could not validate")) { - this.serverless.cli.log( - "Ensure CNAME configuration is ok, it can take some time for a record to propagate" - ); - } - } - ); - }); - - domainsIdToDelete.forEach((domainId) => { - if (domainId === undefined) { - return; - } - this.deleteDomain(domainId).then((res) => { - this.serverless.cli.log(`Deleting domain ${res.hostname}`); - }); - }); - }); - }, - createOrUpdateContainers(foundContainers) { const { containers } = this.provider.serverless.service.custom; @@ -145,14 +67,6 @@ module.exports = { port: container.port, }; - // checking if there is custom_domains set on container creation. - if (container.custom_domains && container.custom_domains.length > 0) { - this.serverless.cli.log("WARNING: custom_domains are available on container update only. "+ - "Redeploy your container to apply custom domains. Doc : https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/") - } - - this.serverless.cli.log(`Creating function ${func.name}...`); - this.serverless.cli.log(`Creating container ${container.name}...`); return this.createContainer(params) @@ -177,10 +91,6 @@ module.exports = { }; this.serverless.cli.log(`Updating container ${container.name}...`); - - // assign domains - this.applyDomains(foundContainer.id, container.custom_domains); - return this.updateContainer(foundContainer.id, params) .then(response => Object.assign(response, { directory: container.directory })); }, diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index 285fe982..1ccb3d0c 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -59,7 +59,7 @@ module.exports = { const domainsIdToDelete = []; const existingDomains = []; - this.listDomainsFunction(funcId).then((domains) => { + this.listDomains(funcId).then((domains) => { domains.forEach((domain) => { existingDomains.push({ hostname: domain.hostname, id: domain.id }); }); @@ -201,7 +201,7 @@ module.exports = { params.runtime = this.validateRuntime( func, availableRuntimes, - this.serverless.cli, + this.serverless.cli ); // checking if there is custom_domains set on function creation. diff --git a/deploy/lib/deployContainers.js b/deploy/lib/deployContainers.js index b2823330..a77c667f 100644 --- a/deploy/lib/deployContainers.js +++ b/deploy/lib/deployContainers.js @@ -4,41 +4,24 @@ const BbPromise = require('bluebird'); module.exports = { deployContainers() { - this.serverless.cli.log("Deploying Containers..."); + this.serverless.cli.log('Deploying Containers...'); return BbPromise.bind(this) .then(this.deployEachContainer) - .then(() => - this.serverless.cli.log( - "Waiting for container deployments, this may take multiple minutes..." - ) - ) + .then(() => this.serverless.cli.log('Waiting for container deployments, this may take multiple minutes...')) .then(this.printContainerEndpointsAfterDeployment); }, deployEachContainer() { - const promises = this.containers.map((container) => - this.deployContainer(container.id) + const promises = this.containers.map( + container => this.deployContainer(container.id), ); return Promise.all(promises); }, printContainerEndpointsAfterDeployment() { - return this.waitContainersAreDeployed(this.namespace.id).then( - (containers) => { - containers.forEach((container) => { - this.serverless.cli.log( - `Container ${container.name} has been deployed to: https://${container.domain_name}` - ); - - this.serverless.cli.log("Waiting for domains deployment..."); - - this.waitDomainsAreDeployedContainer(container.id).then((domains) => { - domains.forEach((domain) => { - this.serverless.cli.log(`Domain ready : ${domain.hostname}`); - }); - }); - }); - } - ); + return this.waitContainersAreDeployed(this.namespace.id) + .then(containers => containers.forEach( + container => this.serverless.cli.log(`Container ${container.name} has been deployed to: https://${container.domain_name}`), + )); }, }; diff --git a/deploy/lib/deployFunctions.js b/deploy/lib/deployFunctions.js index 5f73db03..491211b7 100644 --- a/deploy/lib/deployFunctions.js +++ b/deploy/lib/deployFunctions.js @@ -40,7 +40,7 @@ module.exports = { 'Waiting for domains deployment...', ); - this.waitDomainsAreDeployedFunction(func.id) + this.waitDomainsAreDeployed(func.id) .then((domains) => { domains.forEach((domain) => { this.serverless.cli.log(`Domain ready : ${domain.hostname}`); diff --git a/shared/api/domain.js b/shared/api/domain.js index 901731ed..9d171423 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -5,10 +5,10 @@ const { manageError } = require("./utils"); module.exports = { /** * listDomains is used to read all domains of a wanted function. - * @param {Number} functionId the id of the function to read domains. + * @param {Number} functionId the id of the function to read domains. * @returns a Promise with request result. */ - listDomainsFunction(functionId) { + listDomains(functionId) { const domainsUrl = `domains?function_id=${functionId}`; return this.apiManager @@ -17,20 +17,6 @@ module.exports = { .catch(manageError); }, - /** - * listDomains is used to read all domains of a wanted container. - * @param {Number} containerId the id of the container to read domains. - * @returns a Promise with request result. - */ - listDomainsContainer(containerId) { - const domainsUrl = `domains?container_id=${containerId}`; - - return this.apiManager - .get(domainsUrl) - .then((response) => response.data.domains) - .catch(manageError); - }, - /** * createDomain is used to call for domain creation, warning : this * function does not wait for the domain @@ -62,64 +48,29 @@ module.exports = { /** * Waiting for all domains to be ready on a function - * @param {UUID} functionId + * @param {Number} functionId * @returns */ - waitDomainsAreDeployedFunction(functionId) { + waitDomainsAreDeployed(functionId) { return this.listDomains(functionId) .then((domains) => { - let domainsAreReady = true; - - for (let i = 0; i < domains.length; i += 1) { - const domain = domains[i]; - - if (domain.status === 'error') { - throw new Error(domain.error_message); - } - - if (domain.status !== 'ready') { - domainsAreReady = false; - break; - } - } - if (!domainsAreReady) { - return new Promise((resolve) => { - setTimeout(() => resolve(this.waitDomainsAreDeployedFunction(functionId)), 5000); - }); - } - return domains; - }); - }, - - /** - * Waiting for all domains to be ready on a container - * @param {UUID} containerId - * @returns - */ - waitDomainsAreDeployedContainer(containerId) { - return this.listDomains(containerId) - .then((domains) => { - let domainsAreReady = true; - + let domainssAreReady = true; for (let i = 0; i < domains.length; i += 1) { const domain = domains[i]; - if (domain.status === 'error') { throw new Error(domain.error_message); } - if (domain.status !== 'ready') { - domainsAreReady = false; + domainssAreReady = false; break; } } - if (!domainsAreReady) { + if (!domainssAreReady) { return new Promise((resolve) => { - setTimeout(() => resolve(this.waitDomainsAreDeployedContainer(containerId)), 5000); + setTimeout(() => resolve(this.waitDomainsAreDeployed(functionId)), 5000); }); } return domains; }); }, - }; From 99455a61cbd5f686637beb0f4cd0bac2945abc8e Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 13:59:10 +0200 Subject: [PATCH 05/17] add support for custom domains on containers --- README.md | 7 ++- deploy/lib/createContainers.js | 90 ++++++++++++++++++++++++++++++++++ deploy/lib/createFunctions.js | 4 +- deploy/lib/deployContainers.js | 33 ++++++++++--- deploy/lib/deployFunctions.js | 2 +- shared/api/domain.js | 65 +++++++++++++++++++++--- 6 files changed, 180 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ab43d5b5..9e3c801d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,9 @@ serverless invoke --function first Serverless Framework handles everything from creating namespaces to function/code deployment by calling APIs endpoint under the hood. -- [Serverless Framework: Deploy on Scaleway Functions](#serverless-framework-deploy-on-scaleway-functions) +- [Scaleway Plugin for Serverless Framework](#scaleway-plugin-for-serverless-framework) + - [Quick-start](#quick-start) + - [Contents](#contents) - [Requirements](#requirements) - [Create a Project](#create-a-project) - [Configure your functions](#configure-your-functions) @@ -341,7 +343,8 @@ You may refer to the follow examples: Custom domains allows users to use their own domains. -For domain configuration please [Refer to Scaleway Documentation](https://www.scaleway.com/en/docs/compute/functions/how-to/add-a-custom-domain-name-to-a-function/) +For domain configuration please refer to [custom domains on Function](https://www.scaleway.com/en/docs/compute/functions/how-to/add-a-custom-domain-name-to-a-function/) or +[custom domains on Container](https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/) Integration with serverless framework example : diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index 4acad60b..dcfc9f64 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -24,6 +24,84 @@ module.exports = { }); }, + applyDomains(containerId, customDomains) { + // we make a diff to know which domains to add or delete + const domainsToCreate = []; + const domainsIdToDelete = []; + const existingDomains = []; + + this.listDomainsContainer(containerId).then((domains) => { + domains.forEach((domain) => { + existingDomains.push({ hostname: domain.hostname, id: domain.id }); + }); + + if ( + customDomains !== undefined && + customDomains !== null && + customDomains.length > 0 + ) { + customDomains.forEach((customDomain) => { + domainsIdToDelete.push(customDomain.id); + + let domainFound = false; + + existingDomains.forEach((existingDom) => { + if (existingDom.hostname === customDomain) { + domainFound = true; + return false; + } + }); + if (!domainFound) { + domainsToCreate.push(customDomain); + } + }); + } + + existingDomains.forEach((existingDomain) => { + if ( + (customDomains === undefined || customDomains === null) && + existingDomain.id !== undefined + ) { + domainsIdToDelete.push(existingDomain.id); + } else if (!customDomains.includes(existingDomain.hostname)) { + domainsIdToDelete.push(existingDomain.id); + } + }); + + domainsToCreate.forEach((newDomain) => { + const createDomainParams = { container_id: containerId, hostname: newDomain }; + + this.createDomain(createDomainParams) + .then((res) => { + this.serverless.cli.log(`Creating domain ${res.hostname}`); + }) + .then( + () => {}, + (reason) => { + this.serverless.cli.log( + `Error on domain : ${newDomain}, reason : ${reason.message}` + ); + + if (reason.message.includes("could not validate")) { + this.serverless.cli.log( + "Ensure CNAME configuration is ok, it can take some time for a record to propagate" + ); + } + } + ); + }); + + domainsIdToDelete.forEach((domainId) => { + if (domainId === undefined) { + return; + } + this.deleteDomain(domainId).then((res) => { + this.serverless.cli.log(`Deleting domain ${res.hostname}`); + }); + }); + }); + }, + createOrUpdateContainers(foundContainers) { const { containers } = this.provider.serverless.service.custom; @@ -67,6 +145,14 @@ module.exports = { port: container.port, }; + // checking if there is custom_domains set on container creation. + if (container.custom_domains && container.custom_domains.length > 0) { + this.serverless.cli.log("WARNING: custom_domains are available on container update only. "+ + "Redeploy your container to apply custom domains. Doc : https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/") + } + + this.serverless.cli.log(`Creating function ${func.name}...`); + this.serverless.cli.log(`Creating container ${container.name}...`); return this.createContainer(params) @@ -91,6 +177,10 @@ module.exports = { }; this.serverless.cli.log(`Updating container ${container.name}...`); + + // assign domains + this.applyDomains(foundContainer.id, container.custom_domains); + return this.updateContainer(foundContainer.id, params) .then(response => Object.assign(response, { directory: container.directory })); }, diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index 1ccb3d0c..285fe982 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -59,7 +59,7 @@ module.exports = { const domainsIdToDelete = []; const existingDomains = []; - this.listDomains(funcId).then((domains) => { + this.listDomainsFunction(funcId).then((domains) => { domains.forEach((domain) => { existingDomains.push({ hostname: domain.hostname, id: domain.id }); }); @@ -201,7 +201,7 @@ module.exports = { params.runtime = this.validateRuntime( func, availableRuntimes, - this.serverless.cli + this.serverless.cli, ); // checking if there is custom_domains set on function creation. diff --git a/deploy/lib/deployContainers.js b/deploy/lib/deployContainers.js index a77c667f..b2823330 100644 --- a/deploy/lib/deployContainers.js +++ b/deploy/lib/deployContainers.js @@ -4,24 +4,41 @@ const BbPromise = require('bluebird'); module.exports = { deployContainers() { - this.serverless.cli.log('Deploying Containers...'); + this.serverless.cli.log("Deploying Containers..."); return BbPromise.bind(this) .then(this.deployEachContainer) - .then(() => this.serverless.cli.log('Waiting for container deployments, this may take multiple minutes...')) + .then(() => + this.serverless.cli.log( + "Waiting for container deployments, this may take multiple minutes..." + ) + ) .then(this.printContainerEndpointsAfterDeployment); }, deployEachContainer() { - const promises = this.containers.map( - container => this.deployContainer(container.id), + const promises = this.containers.map((container) => + this.deployContainer(container.id) ); return Promise.all(promises); }, printContainerEndpointsAfterDeployment() { - return this.waitContainersAreDeployed(this.namespace.id) - .then(containers => containers.forEach( - container => this.serverless.cli.log(`Container ${container.name} has been deployed to: https://${container.domain_name}`), - )); + return this.waitContainersAreDeployed(this.namespace.id).then( + (containers) => { + containers.forEach((container) => { + this.serverless.cli.log( + `Container ${container.name} has been deployed to: https://${container.domain_name}` + ); + + this.serverless.cli.log("Waiting for domains deployment..."); + + this.waitDomainsAreDeployedContainer(container.id).then((domains) => { + domains.forEach((domain) => { + this.serverless.cli.log(`Domain ready : ${domain.hostname}`); + }); + }); + }); + } + ); }, }; diff --git a/deploy/lib/deployFunctions.js b/deploy/lib/deployFunctions.js index 491211b7..5f73db03 100644 --- a/deploy/lib/deployFunctions.js +++ b/deploy/lib/deployFunctions.js @@ -40,7 +40,7 @@ module.exports = { 'Waiting for domains deployment...', ); - this.waitDomainsAreDeployed(func.id) + this.waitDomainsAreDeployedFunction(func.id) .then((domains) => { domains.forEach((domain) => { this.serverless.cli.log(`Domain ready : ${domain.hostname}`); diff --git a/shared/api/domain.js b/shared/api/domain.js index 9d171423..901731ed 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -5,10 +5,10 @@ const { manageError } = require("./utils"); module.exports = { /** * listDomains is used to read all domains of a wanted function. - * @param {Number} functionId the id of the function to read domains. + * @param {Number} functionId the id of the function to read domains. * @returns a Promise with request result. */ - listDomains(functionId) { + listDomainsFunction(functionId) { const domainsUrl = `domains?function_id=${functionId}`; return this.apiManager @@ -17,6 +17,20 @@ module.exports = { .catch(manageError); }, + /** + * listDomains is used to read all domains of a wanted container. + * @param {Number} containerId the id of the container to read domains. + * @returns a Promise with request result. + */ + listDomainsContainer(containerId) { + const domainsUrl = `domains?container_id=${containerId}`; + + return this.apiManager + .get(domainsUrl) + .then((response) => response.data.domains) + .catch(manageError); + }, + /** * createDomain is used to call for domain creation, warning : this * function does not wait for the domain @@ -48,29 +62,64 @@ module.exports = { /** * Waiting for all domains to be ready on a function - * @param {Number} functionId + * @param {UUID} functionId * @returns */ - waitDomainsAreDeployed(functionId) { + waitDomainsAreDeployedFunction(functionId) { return this.listDomains(functionId) .then((domains) => { - let domainssAreReady = true; + let domainsAreReady = true; + + for (let i = 0; i < domains.length; i += 1) { + const domain = domains[i]; + + if (domain.status === 'error') { + throw new Error(domain.error_message); + } + + if (domain.status !== 'ready') { + domainsAreReady = false; + break; + } + } + if (!domainsAreReady) { + return new Promise((resolve) => { + setTimeout(() => resolve(this.waitDomainsAreDeployedFunction(functionId)), 5000); + }); + } + return domains; + }); + }, + + /** + * Waiting for all domains to be ready on a container + * @param {UUID} containerId + * @returns + */ + waitDomainsAreDeployedContainer(containerId) { + return this.listDomains(containerId) + .then((domains) => { + let domainsAreReady = true; + for (let i = 0; i < domains.length; i += 1) { const domain = domains[i]; + if (domain.status === 'error') { throw new Error(domain.error_message); } + if (domain.status !== 'ready') { - domainssAreReady = false; + domainsAreReady = false; break; } } - if (!domainssAreReady) { + if (!domainsAreReady) { return new Promise((resolve) => { - setTimeout(() => resolve(this.waitDomainsAreDeployed(functionId)), 5000); + setTimeout(() => resolve(this.waitDomainsAreDeployedContainer(containerId)), 5000); }); } return domains; }); }, + }; From fa865e65849e63a10e649fe45a55e53a01c2be14 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 15:03:40 +0200 Subject: [PATCH 06/17] upgrade deps --- package-lock.json | 1386 +++++++++++++++++++++++---------------------- package.json | 12 +- 2 files changed, 711 insertions(+), 687 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8264653d..1c072b66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,21 +9,21 @@ "version": "0.4.1", "license": "MIT", "dependencies": { - "@serverless/utils": "^6.6.0", - "argon2": "^0.28.5", + "@serverless/utils": "^6.7.0", + "argon2": "^0.29.1", "axios": "^0.27.2", "bluebird": "^3.7.2", - "dockerode": "^3.3.2", + "dockerode": "^3.3.4", "tar-fs": "^2.1.1" }, "devDependencies": { - "@jest/globals": "^28.1.1", + "@jest/globals": "^29.0.2", "chai": "^4.3.6", - "eslint": "^8.18.0", + "eslint": "^8.23.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.26.0", "fs-extra": "^10.1.0", - "jest": "^28.1.1", + "jest": "^29.0.2", "js-yaml": "^4.1.0", "rewire": "^6.0.0" } @@ -452,6 +452,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -798,60 +813,59 @@ } }, "node_modules/@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.2.tgz", + "integrity": "sha512-Fv02ijyhF4D/Wb3DvZO3iBJQz5DnzpJEIDBDbvje8Em099N889tNMUnBw7SalmSuOI+NflNG40RA1iK71kImPw==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/core": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", - "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.2.tgz", + "integrity": "sha512-imP5M6cdpHEOkmcuFYZuM5cTG1DAF7ZlVNCq1+F7kbqme2Jcl+Kh4M78hihM76DJHNkurbv4UVOnejGxBKEmww==", "dev": true, "dependencies": { - "@jest/console": "^28.1.3", - "@jest/reporters": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/console": "^29.0.2", + "@jest/reporters": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", "@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": "^28.1.3", - "jest-config": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-resolve-dependencies": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "jest-watcher": "^28.1.3", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.0.2", + "jest-haste-map": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.2", + "jest-resolve-dependencies": "^29.0.2", + "jest-runner": "^29.0.2", + "jest-runtime": "^29.0.2", + "jest-snapshot": "^29.0.2", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", + "jest-watcher": "^29.0.2", "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "rimraf": "^3.0.0", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -863,88 +877,89 @@ } }, "node_modules/@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.2.tgz", + "integrity": "sha512-Yf+EYaLOrVCgts/aTS5nGznU4prZUPa5k9S63Yct8YSOKj2jkdS17hHSUKhk5jxDFMyCy1PXknypDw7vfgc/mA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/fake-timers": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", - "jest-mock": "^28.1.3" + "jest-mock": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.2.tgz", + "integrity": "sha512-y/3geZ92p2/zovBm/F+ZjXUJ3thvT9IRzD6igqaWskFE2aR0idD+N/p5Lj/ZautEox/9RwEc6nqergebeh72uQ==", "dev": true, "dependencies": { - "expect": "^28.1.3", - "jest-snapshot": "^28.1.3" + "expect": "^29.0.2", + "jest-snapshot": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.2.tgz", + "integrity": "sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw==", "dev": true, "dependencies": { - "jest-get-type": "^28.0.2" + "jest-get-type": "^29.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.2.tgz", + "integrity": "sha512-2JhQeWU28fvmM5r33lxg6BxxkTKaVXs6KMaJ6eXSM8ml/MaWkt2BvbIO8G9KWAJFMdBXWbn+2h9OK1/s5urKZA==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@sinonjs/fake-timers": "^9.1.2", "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "jest-message-util": "^29.0.2", + "jest-mock": "^29.0.2", + "jest-util": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", - "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.2.tgz", + "integrity": "sha512-4hcooSNJCVXuTu07/VJwCWW6HTnjLtQdqlcGisK6JST7z2ixa8emw4SkYsOk7j36WRc2ZUEydlUePnOIOTCNXg==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/types": "^28.1.3" + "@jest/environment": "^29.0.2", + "@jest/expect": "^29.0.2", + "@jest/types": "^29.0.2", + "jest-mock": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", - "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.2.tgz", + "integrity": "sha512-Kr41qejRQHHkCgWHC9YwSe7D5xivqP4XML+PvgwsnRFaykKdNflDUb4+xLXySOU+O/bPkVdFpGzUpVNSJChCrw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", + "@jest/console": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", + "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -956,9 +971,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2", + "jest-worker": "^29.0.2", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -966,7 +981,7 @@ "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -978,94 +993,94 @@ } }, "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", "dev": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/source-map": { - "version": "28.1.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", - "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.13", + "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", "graceful-fs": "^4.2.9" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.2.tgz", + "integrity": "sha512-b5rDc0lLL6Kx73LyCx6370k9uZ8o5UKdCpMS6Za3ke7H9y8PtAU305y6TeghpBmf2In8p/qqi3GpftgzijSsNw==", "dev": true, "dependencies": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/console": "^29.0.2", + "@jest/types": "^29.0.2", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/test-sequencer": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", - "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.2.tgz", + "integrity": "sha512-fsyZqHBlXNMv5ZqjQwCuYa2pskXCO0DVxh5aaVCuAtwzHuYEGrhordyEncBLQNuCGQSYgElrEEmS+7wwFnnMKw==", "dev": true, "dependencies": { - "@jest/test-result": "^28.1.3", + "@jest/test-result": "^29.0.2", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", + "jest-haste-map": "^29.0.2", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/transform": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", - "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", + "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", + "@jest/types": "^29.0.2", + "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", + "jest-haste-map": "^29.0.2", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.2", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", "write-file-atomic": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.2.tgz", + "integrity": "sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew==", "dev": true, "dependencies": { - "@jest/schemas": "^28.1.3", + "@jest/schemas": "^29.0.0", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -1073,7 +1088,7 @@ "chalk": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jridgewell/gen-mapping": { @@ -1581,9 +1596,9 @@ } }, "node_modules/argon2": { - "version": "0.28.7", - "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.28.7.tgz", - "integrity": "sha512-pvsScM3Fq7b+jolXkZHh8nRQx0uD/WeelnwYPMRpn4pAydoa1gqeL/KRdWAag4Hnu1TJNBTAfqyTjV+ZHwNnYA==", + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.29.1.tgz", + "integrity": "sha512-bWXzAsQA0B6EFWZh5li+YBk+muoknAb8KacAi1h/bC6Gigy9p5ANbrPvpnjTIb7i9I11/8Df6FeSxpJDK3vy4g==", "hasInstallScript": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.9", @@ -1686,21 +1701,21 @@ } }, "node_modules/babel-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", - "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.2.tgz", + "integrity": "sha512-yTu4/WSi/HzarjQtrJSwV+/0maoNt+iP0DmpvFJdv9yY+5BuNle8TbheHzzcSWj5gIHfuhpbLYHWRDYhWKyeKQ==", "dev": true, "dependencies": { - "@jest/transform": "^28.1.3", + "@jest/transform": "^29.0.2", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.1.3", + "babel-preset-jest": "^29.0.2", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" @@ -1723,9 +1738,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", - "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -1734,7 +1749,7 @@ "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/babel-preset-current-node-syntax": { @@ -1761,16 +1776,16 @@ } }, "node_modules/babel-preset-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", - "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^28.1.3", + "babel-plugin-jest-hoist": "^29.0.2", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -2684,12 +2699,12 @@ } }, "node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/dir-glob": { @@ -3346,19 +3361,19 @@ } }, "node_modules/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.2.tgz", + "integrity": "sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw==", "dev": true, "dependencies": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" + "@jest/expect-utils": "^29.0.2", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/ext": { @@ -4581,21 +4596,21 @@ } }, "node_modules/jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", - "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.2.tgz", + "integrity": "sha512-enziNbNUmXTcTaTP/Uq5rV91r0Yqy2UKzLUIabxMpGm9YHz8qpbJhiRnNVNvm6vzWfzt/0o97NEHH8/3udoClA==", "dev": true, "dependencies": { - "@jest/core": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/core": "^29.0.2", + "@jest/types": "^29.0.2", "import-local": "^3.0.2", - "jest-cli": "^28.1.3" + "jest-cli": "^29.0.2" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -4607,64 +4622,64 @@ } }, "node_modules/jest-changed-files": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", - "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", "dev": true, "dependencies": { "execa": "^5.0.0", "p-limit": "^3.1.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-circus": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", - "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.2.tgz", + "integrity": "sha512-YTPEsoE1P1X0bcyDQi3QIkpt2Wl9om9k2DQRuLFdS5x8VvAKSdYAVJufgvudhnKgM8WHvvAzhBE+1DRQB8x1CQ==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/environment": "^29.0.2", + "@jest/expect": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", + "jest-each": "^29.0.2", + "jest-matcher-utils": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-runtime": "^29.0.2", + "jest-snapshot": "^29.0.2", + "jest-util": "^29.0.2", "p-limit": "^3.1.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-cli": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", - "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.2.tgz", + "integrity": "sha512-tlf8b+4KcUbBGr25cywIi3+rbZ4+G+SiG8SvY552m9sRZbXPafdmQRyeVE/C/R8K+TiBAMrTIUmV2SlStRJ40g==", "dev": true, "dependencies": { - "@jest/core": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/core": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/types": "^29.0.2", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", + "jest-config": "^29.0.2", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -4672,7 +4687,7 @@ "jest": "bin/jest.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -4684,36 +4699,36 @@ } }, "node_modules/jest-config": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", - "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.2.tgz", + "integrity": "sha512-RU4gzeUNZAFktYVzDGimDxeYoaiTnH100jkYYZgldqFamaZukF0IqmFx8+QrzVeEWccYg10EEJT3ox1Dq5b74w==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.3", - "@jest/types": "^28.1.3", - "babel-jest": "^28.1.3", + "@jest/test-sequencer": "^29.0.2", + "@jest/types": "^29.0.2", + "babel-jest": "^29.0.2", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.3", - "jest-environment-node": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", + "jest-circus": "^29.0.2", + "jest-environment-node": "^29.0.2", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.2", + "jest-runner": "^29.0.2", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@types/node": "*", @@ -4729,158 +4744,158 @@ } }, "node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.2.tgz", + "integrity": "sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-docblock": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", - "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-each": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", - "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.2.tgz", + "integrity": "sha512-+sA9YjrJl35iCg0W0VCrgCVj+wGhDrrKQ+YAqJ/DHBC4gcDFAeePtRRhpJnX9gvOZ63G7gt52pwp2PesuSEx0Q==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.3", - "pretty-format": "^28.1.3" + "jest-get-type": "^29.0.0", + "jest-util": "^29.0.2", + "pretty-format": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-environment-node": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", - "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.2.tgz", + "integrity": "sha512-4Fv8GXVCToRlMzDO94gvA8iOzKxQ7rhAbs8L+j8GPyTxGuUiYkV+63LecGeVdVhsL2KXih1sKnoqmH6tp89J7Q==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/environment": "^29.0.2", + "@jest/fake-timers": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "jest-mock": "^29.0.2", + "jest-util": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", - "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", + "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@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": "^28.0.2", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.2", + "jest-worker": "^29.0.2", "micromatch": "^4.0.4", "walker": "^1.0.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "optionalDependencies": { "fsevents": "^2.3.2" } }, "node_modules/jest-leak-detector": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", - "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.2.tgz", + "integrity": "sha512-5f0493qDeAxjUldkBSQg5D1cLadRgZVyWpTQvfJeQwQUpHQInE21AyVHVv64M7P2Ue8Z5EZ4BAcoDS/dSPPgMw==", "dev": true, "dependencies": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz", + "integrity": "sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "jest-diff": "^29.0.2", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.2.tgz", + "integrity": "sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.2.tgz", + "integrity": "sha512-giWXOIT23UCxHCN2VUfUJ0Q7SmiqQwfSFXlCaIhW5anITpNQ+3vuLPQdKt5wkuwM37GrbFyHIClce8AAK9ft9g==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/node": "*" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-pnp-resolver": { @@ -4901,153 +4916,154 @@ } }, "node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", - "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.2.tgz", + "integrity": "sha512-V3uLjSA+EHxLtjIDKTBXnY71hyx+8lusCqPXvqzkFO1uCGvVpjBfuOyp+KOLBNSuY61kM2jhepiMwt4eiJS+Vw==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", + "jest-haste-map": "^29.0.2", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", - "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.2.tgz", + "integrity": "sha512-fSAu6eIG7wtGdnPJUkVVdILGzYAP9Dj/4+zvC8BrGe8msaUMJ9JeygU0Hf9+Uor6/icbuuzQn5See1uajLnAqg==", "dev": true, "dependencies": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.3" + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-runner": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", - "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.2.tgz", + "integrity": "sha512-+D82iPZejI8t+SfduOO1deahC/QgLFf8aJBO++Znz3l2ETtOMdM7K4ATsGWzCFnTGio5yHaRifg1Su5Ybza5Nw==", "dev": true, "dependencies": { - "@jest/console": "^28.1.3", - "@jest/environment": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/console": "^29.0.2", + "@jest/environment": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.10.2", "graceful-fs": "^4.2.9", - "jest-docblock": "^28.1.1", - "jest-environment-node": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-leak-detector": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-resolve": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-util": "^28.1.3", - "jest-watcher": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.0.2", + "jest-haste-map": "^29.0.2", + "jest-leak-detector": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-resolve": "^29.0.2", + "jest-runtime": "^29.0.2", + "jest-util": "^29.0.2", + "jest-watcher": "^29.0.2", + "jest-worker": "^29.0.2", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-runtime": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", - "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/globals": "^28.1.3", - "@jest/source-map": "^28.1.2", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.2.tgz", + "integrity": "sha512-DO6F81LX4okOgjJLkLySv10E5YcV5NHUbY1ZqAUtofxdQE+q4hjH0P2gNsY8x3z3sqgw7O/+919SU4r18Fcuig==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.2", + "@jest/fake-timers": "^29.0.2", + "@jest/globals": "^29.0.2", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", + "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", + "jest-haste-map": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-mock": "^29.0.2", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.2", + "jest-snapshot": "^29.0.2", + "jest-util": "^29.0.2", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-snapshot": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", - "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.2.tgz", + "integrity": "sha512-26C4PzGKaX5gkoKg8UzYGVy2HPVcTaROSkf0gwnHu3lGeTB7bAIJBovvVPZoiJ20IximJELQs/r8WSDRCuGX2A==", "dev": true, "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/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/expect-utils": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^28.1.3", + "expect": "^29.0.2", "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", + "jest-diff": "^29.0.2", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.0.2", + "jest-matcher-utils": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2", "natural-compare": "^1.4.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.2.tgz", + "integrity": "sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -5055,24 +5071,24 @@ "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-validate": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", - "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.2.tgz", + "integrity": "sha512-AeRKm7cEucSy7tr54r3LhiGIXYvOILUwBM1S7jQkKs6YelwAlWKsmZGVrQR7uwsd31rBTnR5NQkODi1Z+6TKIQ==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", + "jest-get-type": "^29.0.0", "leven": "^3.1.0", - "pretty-format": "^28.1.3" + "pretty-format": "^29.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-validate/node_modules/camelcase": { @@ -5088,28 +5104,28 @@ } }, "node_modules/jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.2.tgz", + "integrity": "sha512-ds2bV0oyUdYoyrUTv4Ga5uptz4cEvmmP/JzqDyzZZanvrIn8ipxg5l3SDOAIiyuAx1VdHd2FBzeXPFO5KPH8vQ==", "dev": true, "dependencies": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/test-result": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.10.2", - "jest-util": "^28.1.3", + "jest-util": "^29.0.2", "string-length": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", + "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", "dev": true, "dependencies": { "@types/node": "*", @@ -5117,7 +5133,7 @@ "supports-color": "^8.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/js-tokens": { @@ -6128,18 +6144,17 @@ } }, "node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.2.tgz", + "integrity": "sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg==", "dev": true, "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", + "@jest/schemas": "^29.0.0", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/pretty-format/node_modules/ansi-styles": { @@ -8104,6 +8119,15 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, "@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -8365,124 +8389,124 @@ "dev": true }, "@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.2.tgz", + "integrity": "sha512-Fv02ijyhF4D/Wb3DvZO3iBJQz5DnzpJEIDBDbvje8Em099N889tNMUnBw7SalmSuOI+NflNG40RA1iK71kImPw==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2", "slash": "^3.0.0" } }, "@jest/core": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", - "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.2.tgz", + "integrity": "sha512-imP5M6cdpHEOkmcuFYZuM5cTG1DAF7ZlVNCq1+F7kbqme2Jcl+Kh4M78hihM76DJHNkurbv4UVOnejGxBKEmww==", "dev": true, "requires": { - "@jest/console": "^28.1.3", - "@jest/reporters": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/console": "^29.0.2", + "@jest/reporters": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", "@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": "^28.1.3", - "jest-config": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-resolve-dependencies": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "jest-watcher": "^28.1.3", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.0.2", + "jest-haste-map": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.2", + "jest-resolve-dependencies": "^29.0.2", + "jest-runner": "^29.0.2", + "jest-runtime": "^29.0.2", + "jest-snapshot": "^29.0.2", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", + "jest-watcher": "^29.0.2", "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "rimraf": "^3.0.0", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "strip-ansi": "^6.0.0" } }, "@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.2.tgz", + "integrity": "sha512-Yf+EYaLOrVCgts/aTS5nGznU4prZUPa5k9S63Yct8YSOKj2jkdS17hHSUKhk5jxDFMyCy1PXknypDw7vfgc/mA==", "dev": true, "requires": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/fake-timers": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", - "jest-mock": "^28.1.3" + "jest-mock": "^29.0.2" } }, "@jest/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.2.tgz", + "integrity": "sha512-y/3geZ92p2/zovBm/F+ZjXUJ3thvT9IRzD6igqaWskFE2aR0idD+N/p5Lj/ZautEox/9RwEc6nqergebeh72uQ==", "dev": true, "requires": { - "expect": "^28.1.3", - "jest-snapshot": "^28.1.3" + "expect": "^29.0.2", + "jest-snapshot": "^29.0.2" } }, "@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.2.tgz", + "integrity": "sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw==", "dev": true, "requires": { - "jest-get-type": "^28.0.2" + "jest-get-type": "^29.0.0" } }, "@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.2.tgz", + "integrity": "sha512-2JhQeWU28fvmM5r33lxg6BxxkTKaVXs6KMaJ6eXSM8ml/MaWkt2BvbIO8G9KWAJFMdBXWbn+2h9OK1/s5urKZA==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@sinonjs/fake-timers": "^9.1.2", "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "jest-message-util": "^29.0.2", + "jest-mock": "^29.0.2", + "jest-util": "^29.0.2" } }, "@jest/globals": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", - "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.2.tgz", + "integrity": "sha512-4hcooSNJCVXuTu07/VJwCWW6HTnjLtQdqlcGisK6JST7z2ixa8emw4SkYsOk7j36WRc2ZUEydlUePnOIOTCNXg==", "dev": true, "requires": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/types": "^28.1.3" + "@jest/environment": "^29.0.2", + "@jest/expect": "^29.0.2", + "@jest/types": "^29.0.2", + "jest-mock": "^29.0.2" } }, "@jest/reporters": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", - "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.2.tgz", + "integrity": "sha512-Kr41qejRQHHkCgWHC9YwSe7D5xivqP4XML+PvgwsnRFaykKdNflDUb4+xLXySOU+O/bPkVdFpGzUpVNSJChCrw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", + "@jest/console": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", + "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -8494,9 +8518,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2", + "jest-worker": "^29.0.2", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -8505,66 +8529,66 @@ } }, "@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", "dev": true, "requires": { "@sinclair/typebox": "^0.24.1" } }, "@jest/source-map": { - "version": "28.1.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", - "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.13", + "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", "graceful-fs": "^4.2.9" } }, "@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.2.tgz", + "integrity": "sha512-b5rDc0lLL6Kx73LyCx6370k9uZ8o5UKdCpMS6Za3ke7H9y8PtAU305y6TeghpBmf2In8p/qqi3GpftgzijSsNw==", "dev": true, "requires": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/console": "^29.0.2", + "@jest/types": "^29.0.2", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", - "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.2.tgz", + "integrity": "sha512-fsyZqHBlXNMv5ZqjQwCuYa2pskXCO0DVxh5aaVCuAtwzHuYEGrhordyEncBLQNuCGQSYgElrEEmS+7wwFnnMKw==", "dev": true, "requires": { - "@jest/test-result": "^28.1.3", + "@jest/test-result": "^29.0.2", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", + "jest-haste-map": "^29.0.2", "slash": "^3.0.0" } }, "@jest/transform": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", - "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.2.tgz", + "integrity": "sha512-lajVQx2AnsR+Pa17q2zR7eikz2PkPs1+g/qPbZkqQATeS/s6eT55H+yHcsLfuI/0YQ/4VSBepSu3bOX+44q0aA==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", + "@jest/types": "^29.0.2", + "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", + "jest-haste-map": "^29.0.2", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.2", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -8572,12 +8596,12 @@ } }, "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.2.tgz", + "integrity": "sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew==", "dev": true, "requires": { - "@jest/schemas": "^28.1.3", + "@jest/schemas": "^29.0.0", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -9007,9 +9031,9 @@ } }, "argon2": { - "version": "0.28.7", - "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.28.7.tgz", - "integrity": "sha512-pvsScM3Fq7b+jolXkZHh8nRQx0uD/WeelnwYPMRpn4pAydoa1gqeL/KRdWAag4Hnu1TJNBTAfqyTjV+ZHwNnYA==", + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.29.1.tgz", + "integrity": "sha512-bWXzAsQA0B6EFWZh5li+YBk+muoknAb8KacAi1h/bC6Gigy9p5ANbrPvpnjTIb7i9I11/8Df6FeSxpJDK3vy4g==", "requires": { "@mapbox/node-pre-gyp": "^1.0.9", "@phc/format": "^1.0.0", @@ -9087,15 +9111,15 @@ } }, "babel-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", - "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.2.tgz", + "integrity": "sha512-yTu4/WSi/HzarjQtrJSwV+/0maoNt+iP0DmpvFJdv9yY+5BuNle8TbheHzzcSWj5gIHfuhpbLYHWRDYhWKyeKQ==", "dev": true, "requires": { - "@jest/transform": "^28.1.3", + "@jest/transform": "^29.0.2", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.1.3", + "babel-preset-jest": "^29.0.2", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -9115,9 +9139,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", - "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -9147,12 +9171,12 @@ } }, "babel-preset-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", - "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^28.1.3", + "babel-plugin-jest-hoist": "^29.0.2", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -9841,9 +9865,9 @@ "dev": true }, "diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", "dev": true }, "dir-glob": { @@ -10368,16 +10392,16 @@ "dev": true }, "expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.2.tgz", + "integrity": "sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw==", "dev": true, "requires": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" + "@jest/expect-utils": "^29.0.2", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2" } }, "ext": { @@ -11252,21 +11276,21 @@ } }, "jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", - "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.2.tgz", + "integrity": "sha512-enziNbNUmXTcTaTP/Uq5rV91r0Yqy2UKzLUIabxMpGm9YHz8qpbJhiRnNVNvm6vzWfzt/0o97NEHH8/3udoClA==", "dev": true, "requires": { - "@jest/core": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/core": "^29.0.2", + "@jest/types": "^29.0.2", "import-local": "^3.0.2", - "jest-cli": "^28.1.3" + "jest-cli": "^29.0.2" } }, "jest-changed-files": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", - "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", "dev": true, "requires": { "execa": "^5.0.0", @@ -11274,202 +11298,202 @@ } }, "jest-circus": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", - "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.2.tgz", + "integrity": "sha512-YTPEsoE1P1X0bcyDQi3QIkpt2Wl9om9k2DQRuLFdS5x8VvAKSdYAVJufgvudhnKgM8WHvvAzhBE+1DRQB8x1CQ==", "dev": true, "requires": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/environment": "^29.0.2", + "@jest/expect": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", + "jest-each": "^29.0.2", + "jest-matcher-utils": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-runtime": "^29.0.2", + "jest-snapshot": "^29.0.2", + "jest-util": "^29.0.2", "p-limit": "^3.1.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-cli": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", - "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.2.tgz", + "integrity": "sha512-tlf8b+4KcUbBGr25cywIi3+rbZ4+G+SiG8SvY552m9sRZbXPafdmQRyeVE/C/R8K+TiBAMrTIUmV2SlStRJ40g==", "dev": true, "requires": { - "@jest/core": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/core": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/types": "^29.0.2", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", + "jest-config": "^29.0.2", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", "prompts": "^2.0.1", "yargs": "^17.3.1" } }, "jest-config": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", - "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.2.tgz", + "integrity": "sha512-RU4gzeUNZAFktYVzDGimDxeYoaiTnH100jkYYZgldqFamaZukF0IqmFx8+QrzVeEWccYg10EEJT3ox1Dq5b74w==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.3", - "@jest/types": "^28.1.3", - "babel-jest": "^28.1.3", + "@jest/test-sequencer": "^29.0.2", + "@jest/types": "^29.0.2", + "babel-jest": "^29.0.2", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.3", - "jest-environment-node": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", + "jest-circus": "^29.0.2", + "jest-environment-node": "^29.0.2", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.2", + "jest-runner": "^29.0.2", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" } }, "jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.2.tgz", + "integrity": "sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.2" } }, "jest-docblock": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", - "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", - "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.2.tgz", + "integrity": "sha512-+sA9YjrJl35iCg0W0VCrgCVj+wGhDrrKQ+YAqJ/DHBC4gcDFAeePtRRhpJnX9gvOZ63G7gt52pwp2PesuSEx0Q==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.3", - "pretty-format": "^28.1.3" + "jest-get-type": "^29.0.0", + "jest-util": "^29.0.2", + "pretty-format": "^29.0.2" } }, "jest-environment-node": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", - "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.2.tgz", + "integrity": "sha512-4Fv8GXVCToRlMzDO94gvA8iOzKxQ7rhAbs8L+j8GPyTxGuUiYkV+63LecGeVdVhsL2KXih1sKnoqmH6tp89J7Q==", "dev": true, "requires": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/environment": "^29.0.2", + "@jest/fake-timers": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "jest-mock": "^29.0.2", + "jest-util": "^29.0.2" } }, "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", "dev": true }, "jest-haste-map": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", - "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.2.tgz", + "integrity": "sha512-SOorh2ysQ0fe8gsF4gaUDhoMIWAvi2hXOkwThEO48qT3JqA8GLAUieQcIvdSEd6M0scRDe1PVmKc5tXR3Z0U0A==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.2", + "jest-worker": "^29.0.2", "micromatch": "^4.0.4", "walker": "^1.0.8" } }, "jest-leak-detector": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", - "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.2.tgz", + "integrity": "sha512-5f0493qDeAxjUldkBSQg5D1cLadRgZVyWpTQvfJeQwQUpHQInE21AyVHVv64M7P2Ue8Z5EZ4BAcoDS/dSPPgMw==", "dev": true, "requires": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.2" } }, "jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz", + "integrity": "sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "jest-diff": "^29.0.2", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.2" } }, "jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.2.tgz", + "integrity": "sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.2.tgz", + "integrity": "sha512-giWXOIT23UCxHCN2VUfUJ0Q7SmiqQwfSFXlCaIhW5anITpNQ+3vuLPQdKt5wkuwM37GrbFyHIClce8AAK9ft9g==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/node": "*" } }, @@ -11481,135 +11505,136 @@ "requires": {} }, "jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", "dev": true }, "jest-resolve": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", - "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.2.tgz", + "integrity": "sha512-V3uLjSA+EHxLtjIDKTBXnY71hyx+8lusCqPXvqzkFO1uCGvVpjBfuOyp+KOLBNSuY61kM2jhepiMwt4eiJS+Vw==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", + "jest-haste-map": "^29.0.2", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", + "jest-util": "^29.0.2", + "jest-validate": "^29.0.2", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" } }, "jest-resolve-dependencies": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", - "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.2.tgz", + "integrity": "sha512-fSAu6eIG7wtGdnPJUkVVdILGzYAP9Dj/4+zvC8BrGe8msaUMJ9JeygU0Hf9+Uor6/icbuuzQn5See1uajLnAqg==", "dev": true, "requires": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.3" + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.0.2" } }, "jest-runner": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", - "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.2.tgz", + "integrity": "sha512-+D82iPZejI8t+SfduOO1deahC/QgLFf8aJBO++Znz3l2ETtOMdM7K4ATsGWzCFnTGio5yHaRifg1Su5Ybza5Nw==", "dev": true, "requires": { - "@jest/console": "^28.1.3", - "@jest/environment": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/console": "^29.0.2", + "@jest/environment": "^29.0.2", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.10.2", "graceful-fs": "^4.2.9", - "jest-docblock": "^28.1.1", - "jest-environment-node": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-leak-detector": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-resolve": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-util": "^28.1.3", - "jest-watcher": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.0.2", + "jest-haste-map": "^29.0.2", + "jest-leak-detector": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-resolve": "^29.0.2", + "jest-runtime": "^29.0.2", + "jest-util": "^29.0.2", + "jest-watcher": "^29.0.2", + "jest-worker": "^29.0.2", "p-limit": "^3.1.0", "source-map-support": "0.5.13" } }, "jest-runtime": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", - "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", - "dev": true, - "requires": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/globals": "^28.1.3", - "@jest/source-map": "^28.1.2", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.2.tgz", + "integrity": "sha512-DO6F81LX4okOgjJLkLySv10E5YcV5NHUbY1ZqAUtofxdQE+q4hjH0P2gNsY8x3z3sqgw7O/+919SU4r18Fcuig==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.2", + "@jest/fake-timers": "^29.0.2", + "@jest/globals": "^29.0.2", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", + "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", + "jest-haste-map": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-mock": "^29.0.2", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.2", + "jest-snapshot": "^29.0.2", + "jest-util": "^29.0.2", "slash": "^3.0.0", "strip-bom": "^4.0.0" } }, "jest-snapshot": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", - "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.2.tgz", + "integrity": "sha512-26C4PzGKaX5gkoKg8UzYGVy2HPVcTaROSkf0gwnHu3lGeTB7bAIJBovvVPZoiJ20IximJELQs/r8WSDRCuGX2A==", "dev": true, "requires": { "@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/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/expect-utils": "^29.0.2", + "@jest/transform": "^29.0.2", + "@jest/types": "^29.0.2", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^28.1.3", + "expect": "^29.0.2", "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", + "jest-diff": "^29.0.2", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.0.2", + "jest-matcher-utils": "^29.0.2", + "jest-message-util": "^29.0.2", + "jest-util": "^29.0.2", "natural-compare": "^1.4.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.0.2", "semver": "^7.3.5" } }, "jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.2.tgz", + "integrity": "sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -11618,17 +11643,17 @@ } }, "jest-validate": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", - "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.2.tgz", + "integrity": "sha512-AeRKm7cEucSy7tr54r3LhiGIXYvOILUwBM1S7jQkKs6YelwAlWKsmZGVrQR7uwsd31rBTnR5NQkODi1Z+6TKIQ==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.0.2", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", + "jest-get-type": "^29.0.0", "leven": "^3.1.0", - "pretty-format": "^28.1.3" + "pretty-format": "^29.0.2" }, "dependencies": { "camelcase": { @@ -11640,25 +11665,25 @@ } }, "jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.2.tgz", + "integrity": "sha512-ds2bV0oyUdYoyrUTv4Ga5uptz4cEvmmP/JzqDyzZZanvrIn8ipxg5l3SDOAIiyuAx1VdHd2FBzeXPFO5KPH8vQ==", "dev": true, "requires": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/test-result": "^29.0.2", + "@jest/types": "^29.0.2", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.10.2", - "jest-util": "^28.1.3", + "jest-util": "^29.0.2", "string-length": "^4.0.1" } }, "jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.2.tgz", + "integrity": "sha512-EyvBlYcvd2pg28yg5A3OODQnqK9LI1kitnGUZUG5/NYIeaRgewtYBKB5wlr7oXj8zPCkzev7EmnTCsrXK7V+Xw==", "dev": true, "requires": { "@types/node": "*", @@ -12409,13 +12434,12 @@ "dev": true }, "pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.2.tgz", + "integrity": "sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg==", "dev": true, "requires": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", + "@jest/schemas": "^29.0.0", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, diff --git a/package.json b/package.json index 858477fc..265df14e 100644 --- a/package.json +++ b/package.json @@ -45,21 +45,21 @@ "verbose": true }, "dependencies": { - "@serverless/utils": "^6.6.0", - "argon2": "^0.28.5", + "@serverless/utils": "^6.7.0", + "argon2": "^0.29.1", "axios": "^0.27.2", "bluebird": "^3.7.2", - "dockerode": "^3.3.2", + "dockerode": "^3.3.4", "tar-fs": "^2.1.1" }, "devDependencies": { - "@jest/globals": "^28.1.1", + "@jest/globals": "^29.0.2", "chai": "^4.3.6", - "eslint": "^8.18.0", + "eslint": "^8.23.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.26.0", "fs-extra": "^10.1.0", - "jest": "^28.1.1", + "jest": "^29.0.2", "js-yaml": "^4.1.0", "rewire": "^6.0.0" } From aeeee4ec51542903a6953e20b9dad513a4d62d71 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 16:45:33 +0200 Subject: [PATCH 07/17] fix domain/func --- deploy/lib/createContainers.js | 2 -- shared/api/domain.js | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index dcfc9f64..d67e0919 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -151,8 +151,6 @@ module.exports = { "Redeploy your container to apply custom domains. Doc : https://www.scaleway.com/en/docs/compute/containers/how-to/add-a-custom-domain-to-a-container/") } - this.serverless.cli.log(`Creating function ${func.name}...`); - this.serverless.cli.log(`Creating container ${container.name}...`); return this.createContainer(params) diff --git a/shared/api/domain.js b/shared/api/domain.js index 901731ed..567c0156 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -66,7 +66,7 @@ module.exports = { * @returns */ waitDomainsAreDeployedFunction(functionId) { - return this.listDomains(functionId) + return this.listDomainsFunction(functionId) .then((domains) => { let domainsAreReady = true; @@ -97,7 +97,7 @@ module.exports = { * @returns */ waitDomainsAreDeployedContainer(containerId) { - return this.listDomains(containerId) + return this.listDomainsContainer(containerId) .then((domains) => { let domainsAreReady = true; From 67873748e610a93d192b321d8a130dffe4475379 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 17:11:23 +0200 Subject: [PATCH 08/17] refracto code between functions and containers --- shared/api/containers.js | 93 ++++++++++++++++++++++++++++++++------- shared/api/domain.js | 95 +--------------------------------------- shared/api/functions.js | 45 +++++++++++++++++++ 3 files changed, 124 insertions(+), 109 deletions(-) diff --git a/shared/api/containers.js b/shared/api/containers.js index 352bedd5..719d269f 100644 --- a/shared/api/containers.js +++ b/shared/api/containers.js @@ -5,27 +5,31 @@ const { manageError } = require('./utils'); module.exports = { listContainers(namespaceId) { const containersUrl = `namespaces/${namespaceId}/containers`; - return this.apiManager.get(containersUrl) - .then(response => response.data.containers || []) + return this.apiManager + .get(containersUrl) + .then((response) => response.data.containers || []) .catch(manageError); }, createContainer(params) { - return this.apiManager.post('containers', params) - .then(response => response.data) + return this.apiManager + .post("containers", params) + .then((response) => response.data) .catch(manageError); }, updateContainer(containerId, params) { const updateUrl = `containers/${containerId}`; - return this.apiManager.patch(updateUrl, params) - .then(response => response.data) + return this.apiManager + .patch(updateUrl, params) + .then((response) => response.data) .catch(manageError); }, deployContainer(containerId) { - return this.apiManager.post(`containers/${containerId}/deploy`, {}) - .then(response => response.data) + return this.apiManager + .post(`containers/${containerId}/deploy`, {}) + .then((response) => response.data) .catch(manageError); }, @@ -35,7 +39,8 @@ module.exports = { * @returns container with status deleting */ deleteContainer(containerId) { - return this.apiManager.delete(`/containers/${containerId}`) + return this.apiManager + .delete(`/containers/${containerId}`) .then((response) => response.data) .catch(manageError); }, @@ -46,29 +51,34 @@ module.exports = { * @returns container. */ getContainer(containerId) { - return this.apiManager.get(`containers/${containerId}`) + return this.apiManager + .get(`containers/${containerId}`) .then((response) => response.data) .catch(manageError); }, waitContainersAreDeployed(namespaceId) { - return this.apiManager.get(`namespaces/${namespaceId}/containers`) + return this.apiManager + .get(`namespaces/${namespaceId}/containers`) .then((response) => { const containers = response.data.containers || []; let containersAreReady = true; for (let i = 0; i < containers.length; i += 1) { const container = response.data.containers[i]; - if (container.status === 'error') { + if (container.status === "error") { throw new Error(container.error_message); } - if (container.status !== 'ready') { + if (container.status !== "ready") { containersAreReady = false; break; } } if (!containersAreReady) { return new Promise((resolve) => { - setTimeout(() => resolve(this.waitContainersAreDeployed(namespaceId)), 5000); + setTimeout( + () => resolve(this.waitContainersAreDeployed(namespaceId)), + 5000 + ); }); } return containers; @@ -85,13 +95,17 @@ module.exports = { waitForContainerStatus(containerId, wantedStatus) { return this.getContainer(containerId) .then((func) => { - if (func.status === 'error') { + if (func.status === "error") { throw new Error(func.error_message); } if (func.status !== wantedStatus) { return new Promise((resolve) => { - setTimeout(() => resolve(this.waitForContainerStatus(containerId, wantedStatus)), 5000); + setTimeout( + () => + resolve(this.waitForContainerStatus(containerId, wantedStatus)), + 5000 + ); }); } @@ -105,4 +119,51 @@ module.exports = { } }); }, + + /** + * Waiting for all domains to be ready on a container + * @param {UUID} containerId + * @returns + */ + waitDomainsAreDeployedContainer(containerId) { + return this.listDomainsContainer(containerId).then((domains) => { + let domainsAreReady = true; + + for (let i = 0; i < domains.length; i += 1) { + const domain = domains[i]; + + if (domain.status === "error") { + throw new Error(domain.error_message); + } + + if (domain.status !== "ready") { + domainsAreReady = false; + break; + } + } + if (!domainsAreReady) { + return new Promise((resolve) => { + setTimeout( + () => resolve(this.waitDomainsAreDeployedContainer(containerId)), + 5000 + ); + }); + } + return domains; + }); + }, + + /** + * listDomains is used to read all domains of a wanted container. + * @param {Number} containerId the id of the container to read domains. + * @returns a Promise with request result. + */ + listDomainsContainer(containerId) { + const domainsUrl = `domains?container_id=${containerId}`; + + return this.apiManager + .get(domainsUrl) + .then((response) => response.data.domains) + .catch(manageError); + }, }; diff --git a/shared/api/domain.js b/shared/api/domain.js index 567c0156..d5b2ca7c 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -3,34 +3,6 @@ const { manageError } = require("./utils"); module.exports = { - /** - * listDomains is used to read all domains of a wanted function. - * @param {Number} functionId the id of the function to read domains. - * @returns a Promise with request result. - */ - listDomainsFunction(functionId) { - const domainsUrl = `domains?function_id=${functionId}`; - - return this.apiManager - .get(domainsUrl) - .then((response) => response.data.domains) - .catch(manageError); - }, - - /** - * listDomains is used to read all domains of a wanted container. - * @param {Number} containerId the id of the container to read domains. - * @returns a Promise with request result. - */ - listDomainsContainer(containerId) { - const domainsUrl = `domains?container_id=${containerId}`; - - return this.apiManager - .get(domainsUrl) - .then((response) => response.data.domains) - .catch(manageError); - }, - /** * createDomain is used to call for domain creation, warning : this * function does not wait for the domain @@ -48,8 +20,8 @@ module.exports = { /** * deleteDomains is used to destroy an existing domain by it's ID. - * @param {Number} domainID ID of the selected domain. - * @returns + * @param {Number} domainID ID of the selected domain. + * @returns */ deleteDomain(domainID) { const updateUrl = `domains/${domainID}`; @@ -59,67 +31,4 @@ module.exports = { .then((response) => response.data) .catch(manageError); }, - - /** - * Waiting for all domains to be ready on a function - * @param {UUID} functionId - * @returns - */ - waitDomainsAreDeployedFunction(functionId) { - return this.listDomainsFunction(functionId) - .then((domains) => { - let domainsAreReady = true; - - for (let i = 0; i < domains.length; i += 1) { - const domain = domains[i]; - - if (domain.status === 'error') { - throw new Error(domain.error_message); - } - - if (domain.status !== 'ready') { - domainsAreReady = false; - break; - } - } - if (!domainsAreReady) { - return new Promise((resolve) => { - setTimeout(() => resolve(this.waitDomainsAreDeployedFunction(functionId)), 5000); - }); - } - return domains; - }); - }, - - /** - * Waiting for all domains to be ready on a container - * @param {UUID} containerId - * @returns - */ - waitDomainsAreDeployedContainer(containerId) { - return this.listDomainsContainer(containerId) - .then((domains) => { - let domainsAreReady = true; - - for (let i = 0; i < domains.length; i += 1) { - const domain = domains[i]; - - if (domain.status === 'error') { - throw new Error(domain.error_message); - } - - if (domain.status !== 'ready') { - domainsAreReady = false; - break; - } - } - if (!domainsAreReady) { - return new Promise((resolve) => { - setTimeout(() => resolve(this.waitDomainsAreDeployedContainer(containerId)), 5000); - }); - } - return domains; - }); - }, - }; diff --git a/shared/api/functions.js b/shared/api/functions.js index 936d0381..c839c586 100644 --- a/shared/api/functions.js +++ b/shared/api/functions.js @@ -109,4 +109,49 @@ module.exports = { } }); }, + + /** + * listDomains is used to read all domains of a wanted function. + * @param {Number} functionId the id of the function to read domains. + * @returns a Promise with request result. + */ + listDomainsFunction(functionId) { + const domainsUrl = `domains?function_id=${functionId}`; + + return this.apiManager + .get(domainsUrl) + .then((response) => response.data.domains) + .catch(manageError); + }, + + /** + * Waiting for all domains to be ready on a function + * @param {UUID} functionId + * @returns + */ + waitDomainsAreDeployedFunction(functionId) { + return this.listDomainsFunction(functionId) + .then((domains) => { + let domainsAreReady = true; + + for (let i = 0; i < domains.length; i += 1) { + const domain = domains[i]; + + if (domain.status === 'error') { + throw new Error(domain.error_message); + } + + if (domain.status !== 'ready') { + domainsAreReady = false; + break; + } + } + if (!domainsAreReady) { + return new Promise((resolve) => { + setTimeout(() => resolve(this.waitDomainsAreDeployedFunction(functionId)), 5000); + }); + } + return domains; + }); + }, }; From 767182bff473ef80fb9f41bfef9a2bcf29ebae55 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Mon, 5 Sep 2022 17:26:51 +0200 Subject: [PATCH 09/17] fix name collision --- deploy/lib/createContainers.js | 5 +++-- deploy/lib/createFunctions.js | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index d67e0919..b0133396 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -3,6 +3,7 @@ const BbPromise = require('bluebird'); const singleSource = require('../../shared/singleSource'); const secrets = require('../../shared/secrets'); +const containersApi = require('../../shared/api/containers'); module.exports = { createContainers() { @@ -24,7 +25,7 @@ module.exports = { }); }, - applyDomains(containerId, customDomains) { + applyDomainsContainer(containerId, customDomains) { // we make a diff to know which domains to add or delete const domainsToCreate = []; const domainsIdToDelete = []; @@ -177,7 +178,7 @@ module.exports = { this.serverless.cli.log(`Updating container ${container.name}...`); // assign domains - this.applyDomains(foundContainer.id, container.custom_domains); + this.applyDomainsContainer(foundContainer.id, container.custom_domains); return this.updateContainer(foundContainer.id, params) .then(response => Object.assign(response, { directory: container.directory })); diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index 285fe982..80ef94f8 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -53,7 +53,7 @@ module.exports = { }); }, - applyDomains(funcId, customDomains) { + applyDomainsFunc(funcId, customDomains) { // we make a diff to know which domains to add or delete const domainsToCreate = []; const domainsIdToDelete = []; @@ -245,7 +245,7 @@ module.exports = { this.serverless.cli.log(`Updating function ${func.name}...`); // assign domains - this.applyDomains(foundFunc.id, func.custom_domains); + this.applyDomainsFunc(foundFunc.id, func.custom_domains); return this.updateFunction(foundFunc.id, params).then((response) => Object.assign(response, { handler: func.handler }) From e57edac433e3aceac5c3fffc34e5e5367e07f3a0 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Tue, 6 Sep 2022 10:03:31 +0200 Subject: [PATCH 10/17] unused import --- deploy/lib/createContainers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index b0133396..c7ca2012 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -3,7 +3,6 @@ const BbPromise = require('bluebird'); const singleSource = require('../../shared/singleSource'); const secrets = require('../../shared/secrets'); -const containersApi = require('../../shared/api/containers'); module.exports = { createContainers() { From 672ce0295afa338b8bd09399a1f30a3d818593ac Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Wed, 7 Sep 2022 19:20:02 +0200 Subject: [PATCH 11/17] review nested for --- deploy/lib/createContainers.js | 14 +++++--------- deploy/lib/createFunctions.js | 12 ++++-------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index 9edd39d8..bd9197ec 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -18,7 +18,7 @@ module.exports = { `Container ${res.name} removed from config file, deleting it...` ); this.waitForContainerStatus(containerIdToDelete, "deleted").then( - this.serverless.cli.log(`Container ${res.name} deleted`) + this.serverless.cli.log(`Container ${res.name} deleted`), ); }); }); @@ -43,15 +43,11 @@ module.exports = { customDomains.forEach((customDomain) => { domainsIdToDelete.push(customDomain.id); - let domainFound = false; + const domainFounds = existingDomains.filter( + (existingDomain) => existingDomain.hostname === customDomain, + ); - existingDomains.forEach((existingDom) => { - if (existingDom.hostname === customDomain) { - domainFound = true; - return false; - } - }); - if (!domainFound) { + if (domainFounds.length === 0) { domainsToCreate.push(customDomain); } }); diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index 5569c130..b7649f0b 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -72,15 +72,11 @@ module.exports = { customDomains.forEach((customDomain) => { domainsIdToDelete.push(customDomain.id); - let domainFound = false; + const domainFounds = existingDomains.filter( + (existingDomain) => existingDomain.hostname === customDomain, + ); - existingDomains.forEach((existingDom) => { - if (existingDom.hostname === customDomain) { - domainFound = true; - return false; - } - }); - if (!domainFound) { + if (domainFounds.length === 0) { domainsToCreate.push(customDomain); } }); From 214a423294d03da522758f2db7153ccd2bcc4220 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Wed, 7 Sep 2022 22:09:24 +0200 Subject: [PATCH 12/17] remove unecessary check flow --- deploy/lib/createContainers.js | 5 ----- deploy/lib/createFunctions.js | 5 ----- 2 files changed, 10 deletions(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index bd9197ec..9f56d464 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -41,8 +41,6 @@ module.exports = { customDomains.length > 0 ) { customDomains.forEach((customDomain) => { - domainsIdToDelete.push(customDomain.id); - const domainFounds = existingDomains.filter( (existingDomain) => existingDomain.hostname === customDomain, ); @@ -88,9 +86,6 @@ module.exports = { }); domainsIdToDelete.forEach((domainId) => { - if (domainId === undefined) { - return; - } this.deleteDomain(domainId).then((res) => { this.serverless.cli.log(`Deleting domain ${res.hostname}`); }); diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index b7649f0b..e6232c43 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -70,8 +70,6 @@ module.exports = { customDomains.length > 0 ) { customDomains.forEach((customDomain) => { - domainsIdToDelete.push(customDomain.id); - const domainFounds = existingDomains.filter( (existingDomain) => existingDomain.hostname === customDomain, ); @@ -117,9 +115,6 @@ module.exports = { }); domainsIdToDelete.forEach((domainId) => { - if (domainId === undefined) { - return; - } this.deleteDomain(domainId).then((res) => { this.serverless.cli.log(`Deleting domain ${res.hostname}`); }); From 5ac4f8f91b5cc1197694e5c7b1b0d99da9005918 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Thu, 8 Sep 2022 16:24:07 +0200 Subject: [PATCH 13/17] factorize domain code --- deploy/lib/createContainers.js | 42 ++++----------------------- deploy/lib/createFunctions.js | 37 +++--------------------- shared/domains.js | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 69 deletions(-) create mode 100644 shared/domains.js diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index 9f56d464..b13e3c8f 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -3,6 +3,7 @@ const BbPromise = require('bluebird'); const singleSource = require('../../shared/singleSource'); const secrets = require('../../shared/secrets'); +const domainUtils = require('../../shared/domains'); module.exports = { createContainers() { @@ -24,43 +25,12 @@ module.exports = { }); }, - applyDomainsContainer(containerId, customDomains) { - // we make a diff to know which domains to add or delete - const domainsToCreate = []; - const domainsIdToDelete = []; - const existingDomains = []; + applyDomainsContainer(containerId, customDomains) { this.listDomainsContainer(containerId).then((domains) => { - domains.forEach((domain) => { - existingDomains.push({ hostname: domain.hostname, id: domain.id }); - }); - - if ( - customDomains !== undefined && - customDomains !== null && - customDomains.length > 0 - ) { - customDomains.forEach((customDomain) => { - const domainFounds = existingDomains.filter( - (existingDomain) => existingDomain.hostname === customDomain, - ); - - if (domainFounds.length === 0) { - domainsToCreate.push(customDomain); - } - }); - } - - existingDomains.forEach((existingDomain) => { - if ( - (customDomains === undefined || customDomains === null) && - existingDomain.id !== undefined - ) { - domainsIdToDelete.push(existingDomain.id); - } else if (!customDomains.includes(existingDomain.hostname)) { - domainsIdToDelete.push(existingDomain.id); - } - }); + const existingDomains = domainUtils.formatDomainsStructure(domains); + const domainsToCreate = domainUtils.getDomainsToCreate(customDomains, existingDomains); + const domainsIdToDelete = domainUtils.getDomainsToDelete(customDomains, existingDomains); domainsToCreate.forEach((newDomain) => { const createDomainParams = { container_id: containerId, hostname: newDomain }; @@ -81,7 +51,7 @@ module.exports = { "Ensure CNAME configuration is ok, it can take some time for a record to propagate" ); } - } + }, ); }); diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index e6232c43..dde29f4c 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -3,6 +3,7 @@ const BbPromise = require('bluebird'); const secrets = require('../../shared/secrets'); const singleSource = require('../../shared/singleSource'); +const domainUtils = require('../../shared/domains'); const { RUNTIME_STATUS_AVAILABLE, RUNTIME_STATUS_EOL, RUNTIME_STATUS_EOS } = require('../../shared/runtimes'); module.exports = { @@ -55,41 +56,11 @@ module.exports = { applyDomainsFunc(funcId, customDomains) { // we make a diff to know which domains to add or delete - const domainsToCreate = []; - const domainsIdToDelete = []; - const existingDomains = []; this.listDomainsFunction(funcId).then((domains) => { - domains.forEach((domain) => { - existingDomains.push({ hostname: domain.hostname, id: domain.id }); - }); - - if ( - customDomains !== undefined && - customDomains !== null && - customDomains.length > 0 - ) { - customDomains.forEach((customDomain) => { - const domainFounds = existingDomains.filter( - (existingDomain) => existingDomain.hostname === customDomain, - ); - - if (domainFounds.length === 0) { - domainsToCreate.push(customDomain); - } - }); - } - - existingDomains.forEach((existingDomain) => { - if ( - (customDomains === undefined || customDomains === null) && - existingDomain.id !== undefined - ) { - domainsIdToDelete.push(existingDomain.id); - } else if (!customDomains.includes(existingDomain.hostname)) { - domainsIdToDelete.push(existingDomain.id); - } - }); + const existingDomains = domainUtils.formatDomainsStructure(domains); + const domainsToCreate = domainUtils.getDomainsToCreate(customDomains, existingDomains); + const domainsIdToDelete = domainUtils.getDomainsToDelete(customDomains, existingDomains); domainsToCreate.forEach((newDomain) => { const createDomainParams = { function_id: funcId, hostname: newDomain }; diff --git a/shared/domains.js b/shared/domains.js new file mode 100644 index 00000000..507723d9 --- /dev/null +++ b/shared/domains.js @@ -0,0 +1,52 @@ +'use strict'; + +module.exports = { + getDomainsToCreate(customDomains, existingDomains) { + const domainsToCreate = []; + + if ( + customDomains !== undefined && + customDomains !== null && + customDomains.length > 0 + ) { + customDomains.forEach((customDomain) => { + const domainFounds = existingDomains.filter( + (existingDomain) => existingDomain.hostname === customDomain, + ); + + if (domainFounds.length === 0) { + domainsToCreate.push(customDomain); + } + }); + } + + return domainsToCreate; + }, + + getDomainsToDelete(customDomains, existingDomains) { + const domainsIdToDelete = []; + existingDomains.forEach((existingDomain) => { + if ( + (customDomains === undefined || customDomains === null) && + existingDomain.id !== undefined + ) { + domainsIdToDelete.push(existingDomain.id); + } else if (!customDomains.includes(existingDomain.hostname)) { + domainsIdToDelete.push(existingDomain.id); + } + }); + + return domainsIdToDelete; + }, + + formatDomainsStructure(domains) { + const formattedDomains = []; + + domains.forEach((domain) => { + formattedDomains.push({ hostname: domain.hostname, id: domain.id }); + }); + + return formattedDomains; + } + +} \ No newline at end of file From def896810fa175881144b78a13fb8dbe9f7640e0 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Thu, 8 Sep 2022 17:48:59 +0200 Subject: [PATCH 14/17] add tests for domains manipulation --- tests/domains/domains.tests.js | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/domains/domains.tests.js diff --git a/tests/domains/domains.tests.js b/tests/domains/domains.tests.js new file mode 100644 index 00000000..f218bfcd --- /dev/null +++ b/tests/domains/domains.tests.js @@ -0,0 +1,57 @@ +const { describe, it } = require("@jest/globals"); +const { expect } = require("chai"); +const domainUtils = require("../../shared/domains"); + +describe("Domain utils tests ", () => { + // represents the data from serverless.yml file + const hostnamesInput = ["host1", "host2" ]; + + // represents the struct of domains from the API + const structInput = [ + { id: "id1", hostname: "host1" }, + { id: "id2", hostname: "host2" }, + ]; + + it("should format domains", () => { + const res = domainUtils.formatDomainsStructure(structInput); + expect(res.length).to.be.eq(2); + + expect(res[0].id).to.be.eq("id1"); + expect(res[0].hostname).to.be.eq("host1"); + + expect(res[1].id).to.be.eq("id2"); + expect(res[1].hostname).to.be.eq("host2"); + }); + + it("should filters domains that need to be created", () => { + // existing domains and domains to create are the same so should not return elements + const domainsToCreateEmpty = domainUtils.getDomainsToCreate( + hostnamesInput, + structInput + ); + + expect(domainsToCreateEmpty.length).to.be.eq(0); + + // adding host3 + const domainsToCreateOne = domainUtils.getDomainsToCreate(["host1", "host2", "host3"], structInput); + + expect(domainsToCreateOne.length).to.be.eq(1); + expect(domainsToCreateOne[0]).to.be.eq("host3"); + }); + + it("should filters domains that need to be deleted", () => { + // existing domains and domains to delete are the same so should not delete anything + const domainsToDeleteEmpty = domainUtils.getDomainsToDelete( + hostnamesInput, + structInput + ); + + expect(domainsToDeleteEmpty.length).to.be.eq(0); + + // removing host 2 + const domainsToDeleteOne = domainUtils.getDomainsToDelete(["host1"], structInput); + + expect(domainsToDeleteOne.length).to.be.eq(1); + expect(domainsToDeleteOne[0]).to.be.eq("id2"); + }); +}); From 7e1fef498b1751c353edceaf6b2711095a7c50da Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Thu, 8 Sep 2022 17:52:24 +0200 Subject: [PATCH 15/17] package.json to add domain test --- package.json | 1 + tests/domains/{domains.tests.js => domains.test.js} | 0 2 files changed, 1 insertion(+) rename tests/domains/{domains.tests.js => domains.test.js} (100%) diff --git a/package.json b/package.json index 265df14e..c2d7304a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "test:containers": "jest --maxWorkers 5 tests/containers", "test:multi-region": "jest --maxWorkers 5 tests/multi-region", "test:provider": "jest --maxWorkers 5 tests/provider", + "test:domain": "jest --maxWorkers 5 tests/domain", "test:runtimes": "jest --maxWorkers 5 tests/runtimes", "test:triggers": "jest --maxWorkers 5 tests/triggers", "coverage": "jest --coverage", diff --git a/tests/domains/domains.tests.js b/tests/domains/domains.test.js similarity index 100% rename from tests/domains/domains.tests.js rename to tests/domains/domains.test.js From 13d6674cfdd4d771f5bea81d186d78cb4ccd4916 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Thu, 8 Sep 2022 18:16:27 +0200 Subject: [PATCH 16/17] refracto domain create func --- deploy/lib/createContainers.js | 19 +------------------ deploy/lib/createFunctions.js | 19 +------------------ shared/api/domain.js | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index b13e3c8f..841fe020 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -35,24 +35,7 @@ module.exports = { domainsToCreate.forEach((newDomain) => { const createDomainParams = { container_id: containerId, hostname: newDomain }; - this.createDomain(createDomainParams) - .then((res) => { - this.serverless.cli.log(`Creating domain ${res.hostname}`); - }) - .then( - () => {}, - (reason) => { - this.serverless.cli.log( - `Error on domain : ${newDomain}, reason : ${reason.message}` - ); - - if (reason.message.includes("could not validate")) { - this.serverless.cli.log( - "Ensure CNAME configuration is ok, it can take some time for a record to propagate" - ); - } - }, - ); + this.createDomainAndLog(createDomainParams, this.serverless.cli); }); domainsIdToDelete.forEach((domainId) => { diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index dde29f4c..54ead5ef 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -65,24 +65,7 @@ module.exports = { domainsToCreate.forEach((newDomain) => { const createDomainParams = { function_id: funcId, hostname: newDomain }; - this.createDomain(createDomainParams) - .then((res) => { - this.serverless.cli.log(`Creating domain ${res.hostname}`); - }) - .then( - () => {}, - (reason) => { - this.serverless.cli.log( - `Error on domain : ${newDomain}, reason : ${reason.message}` - ); - - if (reason.message.includes("could not validate")) { - this.serverless.cli.log( - "Ensure CNAME configuration is ok, it can take some time for a record to propagate" - ); - } - } - ); + this.createDomainAndLog(createDomainParams, this.serverless.cli); }); domainsIdToDelete.forEach((domainId) => { diff --git a/shared/api/domain.js b/shared/api/domain.js index d5b2ca7c..556397aa 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -31,4 +31,25 @@ module.exports = { .then((response) => response.data) .catch(manageError); }, + + createDomainAndLog(createDomainParams, slscli) { + this.createDomain(createDomainParams) + .then((res) => { + slscli.log(`Creating domain ${res.hostname}`); + }) + .then( + () => {}, + (reason) => { + slscli.log( + `Error on domain : ${createDomainParams.hostname}, reason : ${reason.message}` + ); + + if (reason.message.includes("could not validate")) { + slscli.log( + "Ensure CNAME configuration is ok, it can take some time for a record to propagate" + ); + } + } + ); + }, }; From 0fb6b154c5702ddeb5235cfffcfc506408b72167 Mon Sep 17 00:00:00 2001 From: thomas-tacquet Date: Thu, 8 Sep 2022 18:23:33 +0200 Subject: [PATCH 17/17] no need sls cli --- deploy/lib/createContainers.js | 2 +- deploy/lib/createFunctions.js | 2 +- shared/api/domain.js | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/deploy/lib/createContainers.js b/deploy/lib/createContainers.js index 841fe020..add785d9 100644 --- a/deploy/lib/createContainers.js +++ b/deploy/lib/createContainers.js @@ -35,7 +35,7 @@ module.exports = { domainsToCreate.forEach((newDomain) => { const createDomainParams = { container_id: containerId, hostname: newDomain }; - this.createDomainAndLog(createDomainParams, this.serverless.cli); + this.createDomainAndLog(createDomainParams); }); domainsIdToDelete.forEach((domainId) => { diff --git a/deploy/lib/createFunctions.js b/deploy/lib/createFunctions.js index 54ead5ef..256ac1c2 100644 --- a/deploy/lib/createFunctions.js +++ b/deploy/lib/createFunctions.js @@ -65,7 +65,7 @@ module.exports = { domainsToCreate.forEach((newDomain) => { const createDomainParams = { function_id: funcId, hostname: newDomain }; - this.createDomainAndLog(createDomainParams, this.serverless.cli); + this.createDomainAndLog(createDomainParams); }); domainsIdToDelete.forEach((domainId) => { diff --git a/shared/api/domain.js b/shared/api/domain.js index 556397aa..f8067522 100644 --- a/shared/api/domain.js +++ b/shared/api/domain.js @@ -32,20 +32,20 @@ module.exports = { .catch(manageError); }, - createDomainAndLog(createDomainParams, slscli) { + createDomainAndLog(createDomainParams) { this.createDomain(createDomainParams) .then((res) => { - slscli.log(`Creating domain ${res.hostname}`); + this.serverless.cli.log(`Creating domain ${res.hostname}`); }) .then( () => {}, (reason) => { - slscli.log( + this.serverless.cli.log( `Error on domain : ${createDomainParams.hostname}, reason : ${reason.message}` ); if (reason.message.includes("could not validate")) { - slscli.log( + this.serverless.cli.log( "Ensure CNAME configuration is ok, it can take some time for a record to propagate" ); }