From 59c3670268cb35a81eba33dd305ee4b2a2769b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Tue, 19 Apr 2022 10:24:49 +0100 Subject: [PATCH] feat!: add support for Edge Functions (#4550) --- .github/workflows/codeql.yml | 2 + .github/workflows/main.yml | 4 + README.md | 11 +- docs/README.md | 10 +- docs/commands/dev.md | 36 - docs/commands/index.md | 10 +- npm-shrinkwrap.json | 4130 +++-------------- package.json | 9 +- src/commands/base-command.js | 3 +- src/commands/deploy/deploy.js | 7 - src/commands/dev/dev-trace.js | 47 - src/commands/dev/dev.js | 79 +- src/commands/main.js | 3 + src/commands/recipes/common.js | 33 + src/commands/recipes/index.js | 8 + src/commands/recipes/recipes-list.js | 34 + src/commands/recipes/recipes.js | 85 + src/lib/api.js | 73 +- src/lib/edge-functions/consts.js | 21 + src/lib/edge-functions/deploy.js | 41 + src/lib/edge-functions/editor-helper.js | 41 + src/lib/edge-functions/headers.js | 6 + src/lib/edge-functions/index.js | 7 + src/lib/edge-functions/internal.js | 75 + src/lib/edge-functions/proxy.js | 133 + src/lib/edge-functions/registry.js | 312 ++ src/lib/functions/registry.js | 2 +- src/recipes/vscode/index.js | 61 + src/recipes/vscode/settings.js | 66 + src/utils/command-helpers.js | 10 + src/utils/deploy/deploy-site.js | 30 +- src/utils/deploy/hash-files.js | 19 +- src/utils/deploy/hasher-segments.js | 12 +- src/utils/functions/edge-handlers.js | 88 - src/utils/functions/index.js | 5 +- src/utils/index.js | 2 - src/utils/proxy.js | 98 +- src/utils/traffic-mesh.js | 219 - tests/integration/0.command.dev.test.js | 499 +- tests/integration/100.command.dev.test.js | 521 +-- tests/integration/200.command.dev.test.js | 9 +- tests/integration/210.command.deploy.test.js | 54 +- tests/integration/300.command.dev.test.js | 413 +- tests/integration/400.command.dev.test.js | 1050 +++-- .../integration/410.command.dev.trace.test.js | 31 - tests/integration/500.command.dev.test.js | 577 ++- tests/integration/640.command.recipes.test.js | 103 + .../snapshots/320.command.help.test.js.md | 4 +- .../snapshots/320.command.help.test.js.snap | Bin 928 -> 963 bytes .../snapshots/640.command.generate.test.js.md | 29 + .../640.command.generate.test.js.snap | Bin 0 -> 310 bytes .../snapshots/640.command.recipes.test.js.md | 17 + .../640.command.recipes.test.js.snap | Bin 0 -> 291 bytes tests/integration/utils/dev-server.js | 11 +- tests/integration/utils/handle-questions.js | 14 +- tests/integration/utils/site-builder.js | 8 +- tests/unit/utils/deploy/hash-files.test.js | 3 +- 57 files changed, 3590 insertions(+), 5585 deletions(-) delete mode 100644 src/commands/dev/dev-trace.js create mode 100644 src/commands/recipes/common.js create mode 100644 src/commands/recipes/index.js create mode 100644 src/commands/recipes/recipes-list.js create mode 100644 src/commands/recipes/recipes.js create mode 100644 src/lib/edge-functions/consts.js create mode 100644 src/lib/edge-functions/deploy.js create mode 100644 src/lib/edge-functions/editor-helper.js create mode 100644 src/lib/edge-functions/headers.js create mode 100644 src/lib/edge-functions/index.js create mode 100644 src/lib/edge-functions/internal.js create mode 100644 src/lib/edge-functions/proxy.js create mode 100644 src/lib/edge-functions/registry.js create mode 100644 src/recipes/vscode/index.js create mode 100644 src/recipes/vscode/settings.js delete mode 100644 src/utils/functions/edge-handlers.js delete mode 100644 src/utils/traffic-mesh.js delete mode 100644 tests/integration/410.command.dev.trace.test.js create mode 100644 tests/integration/640.command.recipes.test.js create mode 100644 tests/integration/snapshots/640.command.generate.test.js.md create mode 100644 tests/integration/snapshots/640.command.generate.test.js.snap create mode 100644 tests/integration/snapshots/640.command.recipes.test.js.md create mode 100644 tests/integration/snapshots/640.command.recipes.test.js.snap diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2513d961684..1239325e3ef 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -28,6 +28,8 @@ jobs: uses: github/codeql-action/init@v1 with: languages: 'javascript' + paths-ignore: + - '**/*.test.js' - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 37f2270a9ab..b80f81ad11d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -82,6 +82,10 @@ jobs: cache-dependency-path: 'npm-shrinkwrap.json' check-latest: true if: '${{!steps.release-check.outputs.IS_RELEASE}}' + - name: Setup Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v1.x - name: Install core dependencies run: npm ci --no-audit if: '${{!steps.release-check.outputs.IS_RELEASE}}' diff --git a/README.md b/README.md index 4d5c1690628..3e9db892ff1 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ See the [CLI command line reference](https://cli.netlify.com/commands/) to get s - [lm](#lm) - [login](#login) - [open](#open) + - [recipes](#recipes) - [sites](#sites) - [status](#status) - [switch](#switch) @@ -123,7 +124,6 @@ Local dev server | Subcommand | description | |:--------------------------- |:-----| | [`dev:exec`](/docs/commands/dev.md#devexec) | Exec command | -| [`dev:trace`](/docs/commands/dev.md#devtrace) | Trace command | ### [env](/docs/commands/env.md) @@ -200,6 +200,15 @@ Open settings for the site linked to the current folder | [`open:site`](/docs/commands/open.md#opensite) | Opens current site url in browser | +### [recipes](/docs/commands/recipes.md) + +(Beta) Create and modify files in a project using pre-defined recipes + +| Subcommand | description | +|:--------------------------- |:-----| +| [`recipes:list`](/docs/commands/recipes.md#recipeslist) | (Beta) List the recipes available to create and modify files in a project | + + ### [sites](/docs/commands/sites.md) Handle various site operations diff --git a/docs/README.md b/docs/README.md index f90e5fbd3a5..5012d93e2c3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -80,7 +80,6 @@ Local dev server | Subcommand | description | |:--------------------------- |:-----| | [`dev:exec`](/docs/commands/dev.md#devexec) | Exec command | -| [`dev:trace`](/docs/commands/dev.md#devtrace) | Trace command | ### [env](/docs/commands/env.md) @@ -157,6 +156,15 @@ Open settings for the site linked to the current folder | [`open:site`](/docs/commands/open.md#opensite) | Opens current site url in browser | +### [recipes](/docs/commands/recipes.md) + +(Beta) Create and modify files in a project using pre-defined recipes + +| Subcommand | description | +|:--------------------------- |:-----| +| [`recipes:list`](/docs/commands/recipes.md#recipeslist) | (Beta) List the recipes available to create and modify files in a project | + + ### [sites](/docs/commands/sites.md) Handle various site operations diff --git a/docs/commands/dev.md b/docs/commands/dev.md index a6bf3e00d3a..f418d058000 100644 --- a/docs/commands/dev.md +++ b/docs/commands/dev.md @@ -33,7 +33,6 @@ netlify dev | Subcommand | description | |:--------------------------- |:-----| | [`dev:exec`](/docs/commands/dev.md#devexec) | Exec command | -| [`dev:trace`](/docs/commands/dev.md#devtrace) | Trace command | **Examples** @@ -74,41 +73,6 @@ netlify dev:exec netlify dev:exec npm run bootstrap ``` ---- -## `dev:trace` - -Trace command - -**Usage** - -```bash -netlify dev:trace -``` - -**Arguments** - -- url - Sets the request URL - -**Flags** - -- `cookie` (*string*) - Request cookie, this flag can be used multiple times. Example: "nf_jwt=token" -- `header` (*string*) - Request header, this flag can be used multiple times. Example: "Host: netlify.test" -- `request` (*string*) - Specifies a custom request method [default: GET] -- `watch` (*string*) - Path to the publish directory -- `debug` (*boolean*) - Print debugging information -- `httpProxy` (*string*) - Proxy server address to route requests through. -- `httpProxyCertificateFilename` (*string*) - Certificate file to use when connecting using a proxy server - -**Examples** - -```bash -netlify dev:trace http://localhost/routing-path -netlify dev:trace -w dist-directory http://localhost/routing-path -netlify dev:trace -X POST http://localhost/routing-path -netlify dev:trace -H "Accept-Language es" http://localhost/routing-path -netlify dev:trace --cookie nf_jwt=token http://localhost/routing-path -``` - --- diff --git a/docs/commands/index.md b/docs/commands/index.md index e180bde2e3c..91d012582ce 100644 --- a/docs/commands/index.md +++ b/docs/commands/index.md @@ -61,7 +61,6 @@ Local dev server | Subcommand | description | |:--------------------------- |:-----| | [`dev:exec`](/docs/commands/dev.md#devexec) | Exec command | -| [`dev:trace`](/docs/commands/dev.md#devtrace) | Trace command | ### [env](/docs/commands/env.md) @@ -138,6 +137,15 @@ Open settings for the site linked to the current folder | [`open:site`](/docs/commands/open.md#opensite) | Opens current site url in browser | +### [recipes](/docs/commands/recipes.md) + +(Beta) Create and modify files in a project using pre-defined recipes + +| Subcommand | description | +|:--------------------------- |:-----| +| [`recipes:list`](/docs/commands/recipes.md#recipeslist) | (Beta) List the recipes available to create and modify files in a project | + + ### [sites](/docs/commands/sites.md) Handle various site operations diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index dfdfd6211b6..49a06447684 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -10,13 +10,12 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@netlify/build": "^26.5.3", - "@netlify/config": "^17.0.20", + "@netlify/build": "^27.0.0", + "@netlify/config": "^18.0.0", + "@netlify/edge-bundler": "^0.12.0", "@netlify/framework-info": "^9.0.2", "@netlify/local-functions-proxy": "^1.1.1", - "@netlify/plugin-edge-handlers": "^3.0.7", "@netlify/plugins-list": "^6.19.0", - "@netlify/routing-local-proxy": "^0.34.1", "@netlify/zip-it-and-ship-it": "^5.9.0", "@octokit/rest": "^18.0.0", "@sindresorhus/slugify": "^1.1.0", @@ -45,6 +44,7 @@ "dotenv": "^16.0.0", "env-paths": "^2.2.0", "envinfo": "^7.3.1", + "etag": "^1.8.1", "execa": "^5.0.0", "express": "^4.17.1", "express-logging": "^1.1.1", @@ -114,6 +114,7 @@ "through2-map": "^3.0.0", "to-readable-stream": "^2.1.0", "toml": "^3.0.0", + "unixify": "^1.0.0", "update-notifier": "^5.0.0", "uuid": "^8.0.0", "wait-port": "^0.2.2", @@ -159,6 +160,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.0.2.tgz", "integrity": "sha512-sE8Gx+qSDMLoJvb3QarJJlDQK7SSY4rK3hxp4XsiANeFOmjU46ZI7Y9adAQRJrmbz8zbtZkp3mJTT+rGxtF0XA==", + "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.2.2", "sourcemap-codec": "1.4.8" @@ -182,6 +184,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -190,6 +193,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.0.tgz", "integrity": "sha512-x/5Ea+RO5MvF9ize5DeVICJoVrNv0Mi2RnIABrZEKYvPEpldXwauPkgvYA17cKa6WpU3LoYvYbuEMFtSNFsarA==", + "dev": true, "dependencies": { "@ampproject/remapping": "^2.0.0", "@babel/code-frame": "^7.16.7", @@ -219,6 +223,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, "bin": { "semver": "bin/semver.js" } @@ -254,6 +259,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", + "dev": true, "dependencies": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -267,6 +273,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -274,22 +281,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, "dependencies": { "@babel/compat-data": "^7.16.4", "@babel/helper-validator-option": "^7.16.7", @@ -307,83 +303,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", - "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, "bin": { "semver": "bin/semver.js" } @@ -392,17 +312,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -414,6 +324,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, "dependencies": { "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", @@ -427,6 +338,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -438,17 +350,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -460,6 +362,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -471,6 +374,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", @@ -485,49 +389,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, + "dev": true, "engines": { "node": ">=6.9.0" } @@ -536,6 +402,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -543,21 +410,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dependencies": { - "@babel/types": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, "dependencies": { "@babel/types": "^7.16.7" }, @@ -577,20 +434,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - }, + "dev": true, "engines": { "node": ">=6.9.0" } @@ -599,6 +443,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.0.tgz", "integrity": "sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ==", + "dev": true, "dependencies": { "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.0", @@ -683,338 +528,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", @@ -1030,446 +543,6 @@ "@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", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-react-display-name": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", @@ -1535,244 +608,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/preset-react": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", @@ -1793,21 +628,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", - "integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/parser": "^7.16.7", @@ -1821,6 +646,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", + "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.17.0", @@ -1841,6 +667,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -1856,9 +683,9 @@ "dev": true }, "node_modules/@bugsnag/browser": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@bugsnag/browser/-/browser-7.16.1.tgz", - "integrity": "sha512-Tq9fWpwmqdOsbedYL67GzsTKrG5MERIKtnKCi5FyvFjTj143b6as0pwj7LWQ+Eh8grWlR7S11+VvJmb8xnY8Tg==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@bugsnag/browser/-/browser-7.16.2.tgz", + "integrity": "sha512-iBbAmjTDe0I6WPTHi3wIcmKu3ykydtT6fc8atJA65rzgDLMlTM1Wnwz4Ny1cn0bVouLGa48BRiOJ27Rwy7QRYA==", "dependencies": { "@bugsnag/core": "^7.16.1" } @@ -1881,18 +708,18 @@ "integrity": "sha512-LOt8aaBI+KvOQGneBtpuCz3YqzyEAehd1f3nC5yr9TIYW1+IzYKa2xWS4EiMz5pPOnRPHkyyS5t/wmSmN51Gjg==" }, "node_modules/@bugsnag/js": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@bugsnag/js/-/js-7.16.1.tgz", - "integrity": "sha512-yb83OmsbIMDJhX3hHhbHl5StN72feqdr/Ctq7gqsdcfOHNb2121Edf2EbegPJKZhFqSik66vWwiVbGJ6CdS/UQ==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@bugsnag/js/-/js-7.16.2.tgz", + "integrity": "sha512-AzV0PtG3SZt+HnA2JmRJeI60aDNZsIJbEEAZIWZeATvWBt5RdVdsWKllM1SkTvURfxfdAVd4Xry3BgVrh8nEbg==", "dependencies": { - "@bugsnag/browser": "^7.16.1", - "@bugsnag/node": "^7.16.1" + "@bugsnag/browser": "^7.16.2", + "@bugsnag/node": "^7.16.2" } }, "node_modules/@bugsnag/node": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@bugsnag/node/-/node-7.16.1.tgz", - "integrity": "sha512-9zBA1IfDTbLKMoDltdhELpTd1e+b5+vUW4j40zGA+4SYIe64XNZKShfqRdvij7embvC1iHQ9UpuPRSk60P6Dng==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@bugsnag/node/-/node-7.16.2.tgz", + "integrity": "sha512-V5pND701cIYGzjjTwt0tuvAU1YyPB9h7vo5F/DzrDHRPmCINA/oVbc0Twco87knc2VPe8ntGFqTicTY65iOWzg==", "dependencies": { "@bugsnag/core": "^7.16.1", "byline": "^5.0.0", @@ -2299,6 +1126,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz", "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==", + "dev": true, "engines": { "node": ">=6.0.0" } @@ -2307,6 +1135,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.2.5.tgz", "integrity": "sha512-K+Eths78fXDFOvQ2hgJhCiI5s+g81r2yXmACBpbn+f2+Qt94PNoTgUcAXPT8DZkhXCsZRsHVWVtY5KIBMcpDqQ==", + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "sourcemap-codec": "1.4.8" @@ -2344,16 +1173,16 @@ } }, "node_modules/@netlify/build": { - "version": "26.5.3", - "resolved": "https://registry.npmjs.org/@netlify/build/-/build-26.5.3.tgz", - "integrity": "sha512-O16lFUI6/uooWIvgrO/fQphx4vAGTW9GDAQ3hvo5M64XFdu+9W/OU0fB0fAPAJp+wGM+/hZI5JSS6rCG+TWifg==", + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.0.0.tgz", + "integrity": "sha512-VH4auAKu6pyvGR1KwpezbbXB7tYnKkC7YnhoOXpeFPuHZH6cirVsmHaRHoTAQ+txdpT9MiYKLOYP3vJEnFFR4w==", "dependencies": { "@bugsnag/js": "^7.0.0", "@netlify/cache-utils": "^4.0.0", - "@netlify/config": "^17.0.0", + "@netlify/config": "^17.0.20", + "@netlify/edge-bundler": "^0.12.0", "@netlify/functions-utils": "^4.0.0", "@netlify/git-utils": "^4.0.0", - "@netlify/plugin-edge-handlers": "^3.0.7", "@netlify/plugins-list": "^6.19.0", "@netlify/run-utils": "^4.0.0", "@netlify/zip-it-and-ship-it": "5.9.0", @@ -2409,6 +1238,43 @@ "node": "^12.20.0 || ^14.14.0 || >=16.0.0" } }, + "node_modules/@netlify/build/node_modules/@netlify/config": { + "version": "17.0.20", + "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.20.tgz", + "integrity": "sha512-X5dZe3ALUoxw2p9NVvraoMrZF73FlHdPhopW0nJItBmiA/y8LyKupa/KVCBxKf6R02KnYORr0YUnIeZbIO3syw==", + "dependencies": { + "chalk": "^5.0.0", + "cron-parser": "^4.1.0", + "deepmerge": "^4.2.2", + "dot-prop": "^7.0.0", + "execa": "^6.0.0", + "fast-safe-stringify": "^2.0.7", + "figures": "^4.0.0", + "filter-obj": "^3.0.0", + "find-up": "^6.0.0", + "indent-string": "^5.0.0", + "is-plain-obj": "^4.0.0", + "js-yaml": "^4.0.0", + "map-obj": "^5.0.0", + "netlify": "^11.0.1", + "netlify-headers-parser": "^6.0.2", + "netlify-redirect-parser": "13.0.5", + "omit.js": "^2.0.2", + "p-locate": "^6.0.0", + "path-exists": "^5.0.0", + "path-type": "^5.0.0", + "toml": "^3.0.0", + "tomlify-j0.4": "^3.0.0", + "validate-npm-package-name": "^4.0.0", + "yargs": "^17.3.1" + }, + "bin": { + "netlify-config": "src/bin/main.js" + }, + "engines": { + "node": "^12.20.0 || ^14.14.0 || >=16.0.0" + } + }, "node_modules/@netlify/build/node_modules/@sindresorhus/is": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", @@ -2510,6 +1376,20 @@ "node": ">=10" } }, + "node_modules/@netlify/build/node_modules/dot-prop": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz", + "integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==", + "dependencies": { + "type-fest": "^2.11.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@netlify/build/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2656,6 +1536,17 @@ "node": ">=8" } }, + "node_modules/@netlify/build/node_modules/got/node_modules/type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@netlify/build/node_modules/human-signals": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", @@ -2930,28 +1821,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@netlify/build/node_modules/read-pkg-up/node_modules/type-fest": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", - "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@netlify/build/node_modules/read-pkg/node_modules/type-fest": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", - "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/build/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -2994,11 +1863,11 @@ } }, "node_modules/@netlify/build/node_modules/type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", + "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==", "engines": { - "node": ">=8" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3016,17 +1885,17 @@ } }, "node_modules/@netlify/cache-utils": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@netlify/cache-utils/-/cache-utils-4.1.3.tgz", - "integrity": "sha512-fpLCCyHA+i+ZkoIDnEy0woVXHEuhGheYcpzAB9FTbWuf4zBbt364pCOcq+OlSBbM/O4zQO6N36AmOIECGSL/Dw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@netlify/cache-utils/-/cache-utils-4.1.4.tgz", + "integrity": "sha512-O31A0G5CelEAQ0ffkV6adscCP9/+0X4L3ABaxpBL02cr6XktOJd+imm+MiYF+9h/EYe8qRdwFeghjtlohXhcsQ==", "dependencies": { "cpy": "^8.1.0", "del": "^6.0.0", "get-stream": "^6.0.0", - "globby": "^11.0.0", - "junk": "^3.1.0", + "globby": "^13.0.0", + "junk": "^4.0.0", "locate-path": "^7.0.0", - "move-file": "^2.0.0", + "move-file": "^3.0.0", "path-exists": "^5.0.0", "readdirp": "^3.4.0" }, @@ -3034,6 +1903,35 @@ "node": "^12.20.0 || ^14.14.0 || >=16.0.0" } }, + "node_modules/@netlify/cache-utils/node_modules/globby": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", + "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/cache-utils/node_modules/junk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.0.tgz", + "integrity": "sha512-ojtSU++zLJ3jQG9bAYjg94w+/DOJtRyD7nPaerMFrBhmdVmiV5/exYH5t4uHga4G/95nT6hr1OJoKIFbYbrW5w==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@netlify/cache-utils/node_modules/locate-path": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.0.tgz", @@ -3084,6 +1982,17 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/@netlify/cache-utils/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@netlify/cache-utils/node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", @@ -3096,9 +2005,9 @@ } }, "node_modules/@netlify/config": { - "version": "17.0.20", - "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.20.tgz", - "integrity": "sha512-X5dZe3ALUoxw2p9NVvraoMrZF73FlHdPhopW0nJItBmiA/y8LyKupa/KVCBxKf6R02KnYORr0YUnIeZbIO3syw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@netlify/config/-/config-18.0.0.tgz", + "integrity": "sha512-bhVRlWANKr28xf6HaRjc72ihUB1hiyF32xgaRUraoKyQg9srM4qB1FhfQuNLuF2uAwdGmUEeqFap3AC56qBiLw==", "dependencies": { "chalk": "^5.0.0", "cron-parser": "^4.1.0", @@ -3427,6 +2336,176 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@netlify/edge-bundler": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-0.12.0.tgz", + "integrity": "sha512-4AB3GSVeg5Qyh3A47oySKfRTNPNelI7UPgOONhOG4dCNr1fcVUJH0Fdm4rljRnaoQ1Vfy1dPVvMAT5dQVjK77w==", + "dependencies": { + "common-path-prefix": "^3.0.0", + "del": "^6.0.0", + "env-paths": "^3.0.0", + "execa": "^6.0.0", + "glob-to-regexp": "^0.4.1", + "node-fetch": "^3.1.1", + "node-stream-zip": "^1.15.0", + "p-wait-for": "^4.1.0", + "semver": "^7.3.5", + "tmp-promise": "^3.0.3", + "uuid": "^8.3.2" + }, + "engines": { + "node": "^12.20.0 || ^14.14.0 || >=16.0.0" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/@netlify/edge-bundler/node_modules/human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/node-fetch": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.3.tgz", + "integrity": "sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/p-timeout": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.0.2.tgz", + "integrity": "sha512-sEmji9Yaq+Tw+STwsGAE56hf7gMy9p0tQfJojIAamB7WHJYJKf1qlsg9jqBWG8q9VCxKPhZaP/AcXwEoBcYQhQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/p-wait-for": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-4.1.0.tgz", + "integrity": "sha512-i8nE5q++9h8oaQHWltS1Tnnv4IoMDOlqN7C0KFG2OdbK0iFJIt6CROZ8wfBM+K4Pxqfnq4C4lkkpXqTEpB5DZw==", + "dependencies": { + "p-timeout": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@netlify/edge-bundler/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@netlify/esbuild": { "version": "0.13.6", "resolved": "https://registry.npmjs.org/@netlify/esbuild/-/esbuild-0.13.6.tgz", @@ -3816,11 +2895,11 @@ } }, "node_modules/@netlify/functions-utils": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@netlify/functions-utils/-/functions-utils-4.1.9.tgz", - "integrity": "sha512-wPmtkT8W3TXxdHQgWPwwGv182/XPDrCE7uQtZkv5zmUJRaVVLnCh3JJHzijnN7gzhFSuqsl9C3Wz2OD7wxT+oQ==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@netlify/functions-utils/-/functions-utils-4.1.12.tgz", + "integrity": "sha512-zuZijlXFXsRkDoosZPwccmaGDHd5HUJyZWEoxAgRfjzG9wGog2CdkJghEtAH8W+wTudgcowwpSj8F3a+dfbOjg==", "dependencies": { - "@netlify/zip-it-and-ship-it": "5.7.4", + "@netlify/zip-it-and-ship-it": "5.9.0", "cpy": "^8.1.0", "path-exists": "^5.0.0" }, @@ -3828,70 +2907,6 @@ "node": "^12.20.0 || ^14.14.0 || >=16.0.0" } }, - "node_modules/@netlify/functions-utils/node_modules/@babel/parser": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", - "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@netlify/functions-utils/node_modules/@netlify/zip-it-and-ship-it": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.4.tgz", - "integrity": "sha512-HMPf4pX561H5d59h8Y20Qjzo+5BbFkvpnTSWnzdSjQR85dhT8CVKeX9NdLKoKHG82+M75ErfOCY5Db7VsgKAWA==", - "dependencies": { - "@babel/parser": "7.16.8", - "@netlify/esbuild": "^0.13.6", - "@vercel/nft": "^0.17.0", - "archiver": "^5.3.0", - "common-path-prefix": "^3.0.0", - "cp-file": "^9.0.0", - "del": "^6.0.0", - "elf-cam": "^0.1.1", - "end-of-stream": "^1.4.4", - "es-module-lexer": "^0.9.0", - "execa": "^5.0.0", - "filter-obj": "^2.0.1", - "find-up": "^5.0.0", - "glob": "^7.1.6", - "is-builtin-module": "^3.1.0", - "junk": "^3.1.0", - "locate-path": "^6.0.0", - "merge-options": "^3.0.4", - "minimatch": "^3.0.4", - "p-map": "^4.0.0", - "path-exists": "^4.0.0", - "pkg-dir": "^5.0.0", - "precinct": "^8.2.0", - "read-package-json-fast": "^2.0.2", - "require-package-name": "^2.0.1", - "resolve": "^2.0.0-next.1", - "semver": "^7.0.0", - "tmp-promise": "^3.0.2", - "toml": "^3.0.0", - "typescript": "^4.6.0-beta", - "unixify": "^1.0.0", - "yargs": "^16.0.0" - }, - "bin": { - "zip-it-and-ship-it": "dist/bin.js" - }, - "engines": { - "node": "^12.20.0 || ^14.14.0 || >=16.0.0" - } - }, - "node_modules/@netlify/functions-utils/node_modules/@netlify/zip-it-and-ship-it/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, "node_modules/@netlify/functions-utils/node_modules/path-exists": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", @@ -3900,23 +2915,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/@netlify/functions-utils/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@netlify/git-utils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/@netlify/git-utils/-/git-utils-4.1.1.tgz", @@ -3933,18 +2931,18 @@ } }, "node_modules/@netlify/git-utils/node_modules/execa": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-6.0.0.tgz", - "integrity": "sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^3.0.1", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^5.0.1", + "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.5", + "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" }, "engines": { @@ -3974,9 +2972,9 @@ } }, "node_modules/@netlify/git-utils/node_modules/map-obj": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", - "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.1.tgz", + "integrity": "sha512-p3Qoax94q4c4Pb4etNi2lQSQGlqOA4PoD3ARovo7NllRoObZHwNEYd40fz4qgX1zTFK4geU/R1kbowl5hU5OVg==", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -4246,62 +3244,6 @@ "resolved": "https://registry.npmjs.org/@netlify/open-api/-/open-api-2.8.0.tgz", "integrity": "sha512-lfNB/QYDgaP07pwm/nWEaWPvRAAGyhxvJqNzvxMijc7A4uwquMjlbYve8yYyd0LJXPwgBpGobwiQj5RA76xzUQ==" }, - "node_modules/@netlify/plugin-edge-handlers": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@netlify/plugin-edge-handlers/-/plugin-edge-handlers-3.0.7.tgz", - "integrity": "sha512-ThceMAZ7M0k6WVcZwszVh9qozZKveQCnmQtWZW69Qf+g1pGHFkGIt9Vclt5op+Dd8bIdk0kcu1NnX9Ll7eZL1w==", - "dependencies": { - "@babel/core": "^7.11.4", - "@babel/preset-env": "^7.11.5", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-commonjs": "^21.0.0", - "@rollup/plugin-inject": "^4.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^11.0.0", - "buffer-es6": "^4.9.3", - "del": "^6.0.0", - "node-fetch": "^3.0.0", - "path-type": "^5.0.0", - "process-es6": "^0.11.6", - "rollup": "^2.23.1", - "rollup-plugin-node-polyfills": "^0.2.1", - "rollup-plugin-terser": "^7.0.2" - }, - "bin": { - "plugin-build-edge-handlers": "src/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.14.0 || >=16.0.0" - } - }, - "node_modules/@netlify/plugin-edge-handlers/node_modules/node-fetch": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.1.tgz", - "integrity": "sha512-Ef3SPFtRWFCDyhvcwCSvacLpkwmYZcD57mmZzAsMiks9TpHpIghe32U9H06tMICnr+X7YCpzH7WvUlUoml2urA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/@netlify/plugin-edge-handlers/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@netlify/plugins-list": { "version": "6.19.0", "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.19.0.tgz", @@ -4310,65 +3252,6 @@ "node": "^12.20.0 || ^14.14.0 || >=16.0.0" } }, - "node_modules/@netlify/routing-local-proxy": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy/-/routing-local-proxy-0.34.1.tgz", - "integrity": "sha512-FuzgxdxC7wJXUT08qPTtHiKwjFDHh3ViCDZwxwjm8CjOKYz+9NjhmIffkbEFl6R+uH6IV/3R6gVDL5Fb5hwRbQ==", - "optionalDependencies": { - "@netlify/routing-local-proxy-darwin-arm64": "^0.34.1", - "@netlify/routing-local-proxy-darwin-x64": "^0.34.1", - "@netlify/routing-local-proxy-linux-x64": "^0.34.1", - "@netlify/routing-local-proxy-win32-x64": "^0.34.1" - } - }, - "node_modules/@netlify/routing-local-proxy-darwin-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-darwin-arm64/-/routing-local-proxy-darwin-arm64-0.34.1.tgz", - "integrity": "sha512-QswoXdmvmwx76bNdA0TcwfbK1NUIo5BjcS4bpE96wtUPr3SNn4pSoOip9/Tae2JbLGl7efdEkgBE1J6rMiu/kA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@netlify/routing-local-proxy-darwin-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-darwin-x64/-/routing-local-proxy-darwin-x64-0.34.1.tgz", - "integrity": "sha512-x5mukoDWGl+jpVsyNZjRBrP1m93AFrVI/afodQbu45nyW78fpNALhqJPGoI2ixe/Z5HKaYl+ItvI+J4wAVFseQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@netlify/routing-local-proxy-linux-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-linux-x64/-/routing-local-proxy-linux-x64-0.34.1.tgz", - "integrity": "sha512-dquodOP1VC2RtJcr2bp/DzTq0JXtk2cZDtJmaasMxxbxZmwL9R+63ypWsgdvGTSdZDKkwzzHAg3a7qGHVIl4ow==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@netlify/routing-local-proxy-win32-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-win32-x64/-/routing-local-proxy-win32-x64-0.34.1.tgz", - "integrity": "sha512-Dy1OPqlHXCDIJoEor709Ysx76UiAgrse1GF5wdieTVtWnQ7culo8+LVCwubwQezVCCbdjTke9LfMWbP91zBojg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@netlify/run-utils": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@netlify/run-utils/-/run-utils-4.0.1.tgz", @@ -4381,18 +3264,18 @@ } }, "node_modules/@netlify/run-utils/node_modules/execa": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-6.0.0.tgz", - "integrity": "sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^3.0.1", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^5.0.1", + "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.5", + "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" }, "engines": { @@ -4706,144 +3589,6 @@ "@octokit/openapi-types": "^11.2.0" } }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", - "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^2.38.3" - } - }, - "node_modules/@rollup/plugin-commonjs/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@rollup/plugin-inject": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz", - "integrity": "sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "estree-walker": "^2.0.1", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "dependencies": { - "@rollup/pluginutils": "^3.0.8" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" - }, "node_modules/@samverschueren/stream-to-observable": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz", @@ -5029,11 +3774,6 @@ "@types/node": "*" } }, - "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" - }, "node_modules/@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -5209,14 +3949,6 @@ "optional": true, "peer": true }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -6647,58 +5379,6 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -7058,6 +5738,7 @@ "version": "4.19.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, "dependencies": { "caniuse-lite": "^1.0.30001286", "electron-to-chromium": "^1.4.17", @@ -7126,11 +5807,6 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "node_modules/buffer-es6": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/buffer-es6/-/buffer-es6-4.9.3.tgz", - "integrity": "sha1-8mNHuC33b9N+GLy1KIxJcM/VxAQ=" - }, "node_modules/buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", @@ -7304,6 +5980,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -7387,6 +6064,7 @@ "version": "1.0.30001306", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001306.tgz", "integrity": "sha512-Wd1OuggRzg1rbnM5hv1wXs2VkxJH/AA+LuudlIqvZiCvivF+wJJe2mgBZC8gPMgI7D76PP5CTx8Luvaqc1V6OQ==", + "dev": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/browserslist" @@ -7967,9 +6645,9 @@ } }, "node_modules/colors-option/node_modules/chalk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz", - "integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -8032,11 +6710,6 @@ "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, "node_modules/compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -8305,6 +6978,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, "dependencies": { "safe-buffer": "~5.1.1" } @@ -8556,27 +7230,6 @@ "dev": true, "hasInstallScript": true }, - "node_modules/core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", - "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -9654,6 +8307,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, "dependencies": { "object-keys": "^1.0.12" }, @@ -10370,7 +9024,8 @@ "node_modules/electron-to-chromium": { "version": "1.4.64", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.64.tgz", - "integrity": "sha512-8mec/99xgLUZCIZZq3wt61Tpxg55jnOSpxGYapE/1Ma9MpFEYYaz4QNYm0CM1rrnCo7i3FRHhbaWjeCLsveGjQ==" + "integrity": "sha512-8mec/99xgLUZCIZZq3wt61Tpxg55jnOSpxGYapE/1Ma9MpFEYYaz4QNYm0CM1rrnCo7i3FRHhbaWjeCLsveGjQ==", + "dev": true }, "node_modules/elegant-spinner": { "version": "1.0.1", @@ -10496,9 +9151,9 @@ } }, "node_modules/error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", - "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz", + "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", "dependencies": { "stackframe": "^1.1.1" } @@ -12862,6 +11517,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -12890,6 +11546,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -13084,6 +11741,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, "engines": { "node": ">=4" } @@ -13314,6 +11972,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -14392,11 +13051,6 @@ "node": ">=8" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" - }, "node_modules/is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", @@ -14516,14 +13170,6 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -14783,30 +13429,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -15010,6 +13632,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -15061,6 +13684,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, "dependencies": { "minimist": "^1.2.5" }, @@ -15749,11 +14373,6 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, "node_modules/lodash.deburr": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", @@ -15902,12 +14521,12 @@ } }, "node_modules/log-process-errors/node_modules/figures": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.0.tgz", - "integrity": "sha512-VnYcWq6H6F0qDN0QnorznBr0abEovifzUokmnezpKZBUbDmbLAt7LMryOp1TKFVxLxyNYkxEkCEADZR58U9oSw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.1.tgz", + "integrity": "sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==", "dependencies": { "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.0.0" + "is-unicode-supported": "^1.2.0" }, "engines": { "node": ">=12" @@ -15928,9 +14547,9 @@ } }, "node_modules/log-process-errors/node_modules/is-unicode-supported": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.1.0.tgz", - "integrity": "sha512-lDcxivp8TJpLG75/DpatAqNzOpDPSpED8XNtrpBHTdQ2InQ1PbW78jhwSxyxhhu+xbVSast2X38bwj8atwoUQA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.2.0.tgz", + "integrity": "sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==", "engines": { "node": ">=12" }, @@ -15939,9 +14558,9 @@ } }, "node_modules/log-process-errors/node_modules/map-obj": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", - "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.1.tgz", + "integrity": "sha512-p3Qoax94q4c4Pb4etNi2lQSQGlqOA4PoD3ARovo7NllRoObZHwNEYd40fz4qgX1zTFK4geU/R1kbowl5hU5OVg==", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -16200,14 +14819,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -16837,19 +15448,27 @@ } }, "node_modules/move-file": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/move-file/-/move-file-2.1.0.tgz", - "integrity": "sha512-i9qLW6gqboJ5Ht8bauZi7KlTnQ3QFpBCvMvFfEcHADKgHGeJ9BZMO7SFCTwHPV9Qa0du9DYY1Yx3oqlGt30nXA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/move-file/-/move-file-3.0.0.tgz", + "integrity": "sha512-v6u4XjX3MFW6Jo1V/YfbhC7eiGSgvYPJ/NM+aGtTtB9/Y6IYj7YViaHu6dkgDsZFB7MbnAoSI5+Z26XZXnP0vg==", "dependencies": { - "path-exists": "^4.0.0" + "path-exists": "^5.0.0" }, "engines": { - "node": ">=10.17" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/move-file/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -17602,7 +16221,8 @@ "node_modules/node-releases": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true }, "node_modules/node-source-walk": { "version": "4.2.0", @@ -17615,6 +16235,18 @@ "node": ">=6.0" } }, + "node_modules/node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==", + "engines": { + "node": ">=0.12.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/antelle" + } + }, "node_modules/node-version-alias": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/node-version-alias/-/node-version-alias-1.0.1.tgz", @@ -18275,6 +16907,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -18294,6 +16927,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -19613,11 +18247,6 @@ "node": ">= 0.6.0" } }, - "node_modules/process-es6": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/process-es6/-/process-es6-0.11.6.tgz", - "integrity": "sha1-xrs4n5qVH4K9TrFpYAEFvS/5x3g=" - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -19825,6 +18454,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -20230,35 +18860,6 @@ "node": ">=8" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -20316,22 +18917,6 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -20354,30 +18939,6 @@ "node": ">=8" } }, - "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" - }, - "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -20721,66 +19282,6 @@ "inherits": "^2.0.1" } }, - "node_modules/rollup": { - "version": "2.67.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.0.tgz", - "integrity": "sha512-W83AaERwvDiHwHEF/dfAfS3z1Be5wf7n+pO3ZAO5IQadCT2lBTr7WQ2MwZZe+nodbD+n3HtC4OCOAdsOPPcKZQ==", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-inject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", - "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", - "dependencies": { - "estree-walker": "^0.6.1", - "magic-string": "^0.25.3", - "rollup-pluginutils": "^2.8.1" - } - }, - "node_modules/rollup-plugin-inject/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" - }, - "node_modules/rollup-plugin-node-polyfills": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", - "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", - "dependencies": { - "rollup-plugin-inject": "^3.0.0" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/rollup-pluginutils": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", @@ -21529,7 +20030,8 @@ "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true }, "node_modules/spdx-correct": { "version": "3.1.1", @@ -21648,9 +20150,9 @@ } }, "node_modules/stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", - "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", + "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" }, "node_modules/static-extend": { "version": "0.1.2", @@ -22290,9 +20792,9 @@ } }, "node_modules/supports-color": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz", - "integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", "engines": { "node": ">=12" }, @@ -22489,43 +20991,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "engines": { - "node": ">= 8" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -22737,6 +21202,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, "engines": { "node": ">=4" } @@ -23131,42 +21597,6 @@ "through": "^2.3.8" } }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -24512,6 +22942,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.0.2.tgz", "integrity": "sha512-sE8Gx+qSDMLoJvb3QarJJlDQK7SSY4rK3hxp4XsiANeFOmjU46ZI7Y9adAQRJrmbz8zbtZkp3mJTT+rGxtF0XA==", + "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.2.2", "sourcemap-codec": "1.4.8" @@ -24528,12 +22959,14 @@ "@babel/compat-data": { "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true }, "@babel/core": { "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.0.tgz", "integrity": "sha512-x/5Ea+RO5MvF9ize5DeVICJoVrNv0Mi2RnIABrZEKYvPEpldXwauPkgvYA17cKa6WpU3LoYvYbuEMFtSNFsarA==", + "dev": true, "requires": { "@ampproject/remapping": "^2.0.0", "@babel/code-frame": "^7.16.7", @@ -24555,7 +22988,8 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, @@ -24582,6 +23016,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", + "dev": true, "requires": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", @@ -24592,23 +23027,16 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, "@babel/helper-compilation-targets": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, "requires": { "@babel/compat-data": "^7.16.4", "@babel/helper-validator-option": "^7.16.7", @@ -24619,62 +23047,8 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", - "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, @@ -24682,14 +23056,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -24698,6 +23065,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", @@ -24708,6 +23076,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -24716,14 +23085,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -24732,6 +23094,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -24740,6 +23103,7 @@ "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", @@ -24751,61 +23115,26 @@ "@babel/types": "^7.16.7" } }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "requires": { - "@babel/types": "^7.16.7" - } - }, "@babel/helper-plugin-utils": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true }, "@babel/helper-simple-access": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "requires": { - "@babel/types": "^7.16.0" - } - }, "@babel/helper-split-export-declaration": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, "requires": { "@babel/types": "^7.16.7" } @@ -24818,23 +23147,14 @@ "@babel/helper-validator-option": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" - }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - } + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true }, "@babel/helpers": { "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.0.tgz", "integrity": "sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ==", + "dev": true, "requires": { "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.0", @@ -24894,215 +23214,6 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==" }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, "@babel/plugin-syntax-jsx": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", @@ -25112,278 +23223,6 @@ "@babel/helper-plugin-utils": "^7.16.7" } }, - "@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", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, "@babel/plugin-transform-react-display-name": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", @@ -25425,180 +23264,6 @@ "@babel/helper-plugin-utils": "^7.16.7" } }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, "@babel/preset-react": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", @@ -25613,18 +23278,11 @@ "@babel/plugin-transform-react-pure-annotations": "^7.16.7" } }, - "@babel/runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", - "integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "@babel/template": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, "requires": { "@babel/code-frame": "^7.16.7", "@babel/parser": "^7.16.7", @@ -25635,6 +23293,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", + "dev": true, "requires": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.17.0", @@ -25652,6 +23311,7 @@ "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -25664,9 +23324,9 @@ "dev": true }, "@bugsnag/browser": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@bugsnag/browser/-/browser-7.16.1.tgz", - "integrity": "sha512-Tq9fWpwmqdOsbedYL67GzsTKrG5MERIKtnKCi5FyvFjTj143b6as0pwj7LWQ+Eh8grWlR7S11+VvJmb8xnY8Tg==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@bugsnag/browser/-/browser-7.16.2.tgz", + "integrity": "sha512-iBbAmjTDe0I6WPTHi3wIcmKu3ykydtT6fc8atJA65rzgDLMlTM1Wnwz4Ny1cn0bVouLGa48BRiOJ27Rwy7QRYA==", "requires": { "@bugsnag/core": "^7.16.1" } @@ -25689,18 +23349,18 @@ "integrity": "sha512-LOt8aaBI+KvOQGneBtpuCz3YqzyEAehd1f3nC5yr9TIYW1+IzYKa2xWS4EiMz5pPOnRPHkyyS5t/wmSmN51Gjg==" }, "@bugsnag/js": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@bugsnag/js/-/js-7.16.1.tgz", - "integrity": "sha512-yb83OmsbIMDJhX3hHhbHl5StN72feqdr/Ctq7gqsdcfOHNb2121Edf2EbegPJKZhFqSik66vWwiVbGJ6CdS/UQ==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@bugsnag/js/-/js-7.16.2.tgz", + "integrity": "sha512-AzV0PtG3SZt+HnA2JmRJeI60aDNZsIJbEEAZIWZeATvWBt5RdVdsWKllM1SkTvURfxfdAVd4Xry3BgVrh8nEbg==", "requires": { - "@bugsnag/browser": "^7.16.1", - "@bugsnag/node": "^7.16.1" + "@bugsnag/browser": "^7.16.2", + "@bugsnag/node": "^7.16.2" } }, "@bugsnag/node": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@bugsnag/node/-/node-7.16.1.tgz", - "integrity": "sha512-9zBA1IfDTbLKMoDltdhELpTd1e+b5+vUW4j40zGA+4SYIe64XNZKShfqRdvij7embvC1iHQ9UpuPRSk60P6Dng==", + "version": "7.16.2", + "resolved": "https://registry.npmjs.org/@bugsnag/node/-/node-7.16.2.tgz", + "integrity": "sha512-V5pND701cIYGzjjTwt0tuvAU1YyPB9h7vo5F/DzrDHRPmCINA/oVbc0Twco87knc2VPe8ntGFqTicTY65iOWzg==", "requires": { "@bugsnag/core": "^7.16.1", "byline": "^5.0.0", @@ -26019,12 +23679,14 @@ "@jridgewell/resolve-uri": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz", - "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==" + "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==", + "dev": true }, "@jridgewell/trace-mapping": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.2.5.tgz", "integrity": "sha512-K+Eths78fXDFOvQ2hgJhCiI5s+g81r2yXmACBpbn+f2+Qt94PNoTgUcAXPT8DZkhXCsZRsHVWVtY5KIBMcpDqQ==", + "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", "sourcemap-codec": "1.4.8" @@ -26056,16 +23718,16 @@ } }, "@netlify/build": { - "version": "26.5.3", - "resolved": "https://registry.npmjs.org/@netlify/build/-/build-26.5.3.tgz", - "integrity": "sha512-O16lFUI6/uooWIvgrO/fQphx4vAGTW9GDAQ3hvo5M64XFdu+9W/OU0fB0fAPAJp+wGM+/hZI5JSS6rCG+TWifg==", + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.0.0.tgz", + "integrity": "sha512-VH4auAKu6pyvGR1KwpezbbXB7tYnKkC7YnhoOXpeFPuHZH6cirVsmHaRHoTAQ+txdpT9MiYKLOYP3vJEnFFR4w==", "requires": { "@bugsnag/js": "^7.0.0", "@netlify/cache-utils": "^4.0.0", - "@netlify/config": "^17.0.0", + "@netlify/config": "^17.0.20", + "@netlify/edge-bundler": "^0.12.0", "@netlify/functions-utils": "^4.0.0", "@netlify/git-utils": "^4.0.0", - "@netlify/plugin-edge-handlers": "^3.0.7", "@netlify/plugins-list": "^6.19.0", "@netlify/run-utils": "^4.0.0", "@netlify/zip-it-and-ship-it": "5.9.0", @@ -26115,6 +23777,37 @@ "yargs": "^17.3.1" }, "dependencies": { + "@netlify/config": { + "version": "17.0.20", + "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.20.tgz", + "integrity": "sha512-X5dZe3ALUoxw2p9NVvraoMrZF73FlHdPhopW0nJItBmiA/y8LyKupa/KVCBxKf6R02KnYORr0YUnIeZbIO3syw==", + "requires": { + "chalk": "^5.0.0", + "cron-parser": "^4.1.0", + "deepmerge": "^4.2.2", + "dot-prop": "^7.0.0", + "execa": "^6.0.0", + "fast-safe-stringify": "^2.0.7", + "figures": "^4.0.0", + "filter-obj": "^3.0.0", + "find-up": "^6.0.0", + "indent-string": "^5.0.0", + "is-plain-obj": "^4.0.0", + "js-yaml": "^4.0.0", + "map-obj": "^5.0.0", + "netlify": "^11.0.1", + "netlify-headers-parser": "^6.0.2", + "netlify-redirect-parser": "13.0.5", + "omit.js": "^2.0.2", + "p-locate": "^6.0.0", + "path-exists": "^5.0.0", + "path-type": "^5.0.0", + "toml": "^3.0.0", + "tomlify-j0.4": "^3.0.0", + "validate-npm-package-name": "^4.0.0", + "yargs": "^17.3.1" + } + }, "@sindresorhus/is": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", @@ -26174,6 +23867,14 @@ "mimic-response": "^2.0.0" } }, + "dot-prop": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz", + "integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==", + "requires": { + "type-fest": "^2.11.2" + } + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -26268,6 +23969,11 @@ "requires": { "p-finally": "^1.0.0" } + }, + "type-fest": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", + "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" } } }, @@ -26407,13 +24113,6 @@ "normalize-package-data": "^3.0.2", "parse-json": "^5.2.0", "type-fest": "^2.0.0" - }, - "dependencies": { - "type-fest": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", - "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==" - } } }, "read-pkg-up": { @@ -26424,13 +24123,6 @@ "find-up": "^6.3.0", "read-pkg": "^7.1.0", "type-fest": "^2.5.0" - }, - "dependencies": { - "type-fest": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", - "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==" - } } }, "string-width": { @@ -26457,9 +24149,9 @@ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==" }, "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", + "integrity": "sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ==" }, "yocto-queue": { "version": "1.0.0", @@ -26469,21 +24161,38 @@ } }, "@netlify/cache-utils": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@netlify/cache-utils/-/cache-utils-4.1.3.tgz", - "integrity": "sha512-fpLCCyHA+i+ZkoIDnEy0woVXHEuhGheYcpzAB9FTbWuf4zBbt364pCOcq+OlSBbM/O4zQO6N36AmOIECGSL/Dw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@netlify/cache-utils/-/cache-utils-4.1.4.tgz", + "integrity": "sha512-O31A0G5CelEAQ0ffkV6adscCP9/+0X4L3ABaxpBL02cr6XktOJd+imm+MiYF+9h/EYe8qRdwFeghjtlohXhcsQ==", "requires": { "cpy": "^8.1.0", "del": "^6.0.0", "get-stream": "^6.0.0", - "globby": "^11.0.0", - "junk": "^3.1.0", + "globby": "^13.0.0", + "junk": "^4.0.0", "locate-path": "^7.0.0", - "move-file": "^2.0.0", + "move-file": "^3.0.0", "path-exists": "^5.0.0", "readdirp": "^3.4.0" }, "dependencies": { + "globby": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", + "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "junk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.0.tgz", + "integrity": "sha512-ojtSU++zLJ3jQG9bAYjg94w+/DOJtRyD7nPaerMFrBhmdVmiV5/exYH5t4uHga4G/95nT6hr1OJoKIFbYbrW5w==" + }, "locate-path": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.0.tgz", @@ -26513,6 +24222,11 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + }, "yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", @@ -26521,9 +24235,9 @@ } }, "@netlify/config": { - "version": "17.0.20", - "resolved": "https://registry.npmjs.org/@netlify/config/-/config-17.0.20.tgz", - "integrity": "sha512-X5dZe3ALUoxw2p9NVvraoMrZF73FlHdPhopW0nJItBmiA/y8LyKupa/KVCBxKf6R02KnYORr0YUnIeZbIO3syw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@netlify/config/-/config-18.0.0.tgz", + "integrity": "sha512-bhVRlWANKr28xf6HaRjc72ihUB1hiyF32xgaRUraoKyQg9srM4qB1FhfQuNLuF2uAwdGmUEeqFap3AC56qBiLw==", "requires": { "chalk": "^5.0.0", "cron-parser": "^4.1.0", @@ -26710,6 +24424,111 @@ } } }, + "@netlify/edge-bundler": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-0.12.0.tgz", + "integrity": "sha512-4AB3GSVeg5Qyh3A47oySKfRTNPNelI7UPgOONhOG4dCNr1fcVUJH0Fdm4rljRnaoQ1Vfy1dPVvMAT5dQVjK77w==", + "requires": { + "common-path-prefix": "^3.0.0", + "del": "^6.0.0", + "env-paths": "^3.0.0", + "execa": "^6.0.0", + "glob-to-regexp": "^0.4.1", + "node-fetch": "^3.1.1", + "node-stream-zip": "^1.15.0", + "p-wait-for": "^4.1.0", + "semver": "^7.3.5", + "tmp-promise": "^3.0.3", + "uuid": "^8.3.2" + }, + "dependencies": { + "env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==" + }, + "execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==" + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" + }, + "node-fetch": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.3.tgz", + "integrity": "sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "p-timeout": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.0.2.tgz", + "integrity": "sha512-sEmji9Yaq+Tw+STwsGAE56hf7gMy9p0tQfJojIAamB7WHJYJKf1qlsg9jqBWG8q9VCxKPhZaP/AcXwEoBcYQhQ==" + }, + "p-wait-for": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-4.1.0.tgz", + "integrity": "sha512-i8nE5q++9h8oaQHWltS1Tnnv4IoMDOlqN7C0KFG2OdbK0iFJIt6CROZ8wfBM+K4Pxqfnq4C4lkkpXqTEpB5DZw==", + "requires": { + "p-timeout": "^5.0.0" + } + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==" + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==" + } + } + }, "@netlify/esbuild": { "version": "0.13.6", "resolved": "https://registry.npmjs.org/@netlify/esbuild/-/esbuild-0.13.6.tgz", @@ -26958,84 +24777,19 @@ } }, "@netlify/functions-utils": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@netlify/functions-utils/-/functions-utils-4.1.9.tgz", - "integrity": "sha512-wPmtkT8W3TXxdHQgWPwwGv182/XPDrCE7uQtZkv5zmUJRaVVLnCh3JJHzijnN7gzhFSuqsl9C3Wz2OD7wxT+oQ==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@netlify/functions-utils/-/functions-utils-4.1.12.tgz", + "integrity": "sha512-zuZijlXFXsRkDoosZPwccmaGDHd5HUJyZWEoxAgRfjzG9wGog2CdkJghEtAH8W+wTudgcowwpSj8F3a+dfbOjg==", "requires": { - "@netlify/zip-it-and-ship-it": "5.7.4", + "@netlify/zip-it-and-ship-it": "5.9.0", "cpy": "^8.1.0", "path-exists": "^5.0.0" }, "dependencies": { - "@babel/parser": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", - "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==" - }, - "@netlify/zip-it-and-ship-it": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-5.7.4.tgz", - "integrity": "sha512-HMPf4pX561H5d59h8Y20Qjzo+5BbFkvpnTSWnzdSjQR85dhT8CVKeX9NdLKoKHG82+M75ErfOCY5Db7VsgKAWA==", - "requires": { - "@babel/parser": "7.16.8", - "@netlify/esbuild": "^0.13.6", - "@vercel/nft": "^0.17.0", - "archiver": "^5.3.0", - "common-path-prefix": "^3.0.0", - "cp-file": "^9.0.0", - "del": "^6.0.0", - "elf-cam": "^0.1.1", - "end-of-stream": "^1.4.4", - "es-module-lexer": "^0.9.0", - "execa": "^5.0.0", - "filter-obj": "^2.0.1", - "find-up": "^5.0.0", - "glob": "^7.1.6", - "is-builtin-module": "^3.1.0", - "junk": "^3.1.0", - "locate-path": "^6.0.0", - "merge-options": "^3.0.4", - "minimatch": "^3.0.4", - "p-map": "^4.0.0", - "path-exists": "^4.0.0", - "pkg-dir": "^5.0.0", - "precinct": "^8.2.0", - "read-package-json-fast": "^2.0.2", - "require-package-name": "^2.0.1", - "resolve": "^2.0.0-next.1", - "semver": "^7.0.0", - "tmp-promise": "^3.0.2", - "toml": "^3.0.0", - "typescript": "^4.6.0-beta", - "unixify": "^1.0.0", - "yargs": "^16.0.0" - }, - "dependencies": { - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - } - } - }, "path-exists": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } } } }, @@ -27052,18 +24806,18 @@ }, "dependencies": { "execa": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-6.0.0.tgz", - "integrity": "sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", "requires": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^3.0.1", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^5.0.1", + "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.5", + "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, @@ -27078,9 +24832,9 @@ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" }, "map-obj": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", - "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.1.tgz", + "integrity": "sha512-p3Qoax94q4c4Pb4etNi2lQSQGlqOA4PoD3ARovo7NllRoObZHwNEYd40fz4qgX1zTFK4geU/R1kbowl5hU5OVg==" }, "npm-run-path": { "version": "5.1.0", @@ -27211,85 +24965,11 @@ "resolved": "https://registry.npmjs.org/@netlify/open-api/-/open-api-2.8.0.tgz", "integrity": "sha512-lfNB/QYDgaP07pwm/nWEaWPvRAAGyhxvJqNzvxMijc7A4uwquMjlbYve8yYyd0LJXPwgBpGobwiQj5RA76xzUQ==" }, - "@netlify/plugin-edge-handlers": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@netlify/plugin-edge-handlers/-/plugin-edge-handlers-3.0.7.tgz", - "integrity": "sha512-ThceMAZ7M0k6WVcZwszVh9qozZKveQCnmQtWZW69Qf+g1pGHFkGIt9Vclt5op+Dd8bIdk0kcu1NnX9Ll7eZL1w==", - "requires": { - "@babel/core": "^7.11.4", - "@babel/preset-env": "^7.11.5", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-commonjs": "^21.0.0", - "@rollup/plugin-inject": "^4.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^11.0.0", - "buffer-es6": "^4.9.3", - "del": "^6.0.0", - "node-fetch": "^3.0.0", - "path-type": "^5.0.0", - "process-es6": "^0.11.6", - "rollup": "^2.23.1", - "rollup-plugin-node-polyfills": "^0.2.1", - "rollup-plugin-terser": "^7.0.2" - }, - "dependencies": { - "node-fetch": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.1.tgz", - "integrity": "sha512-Ef3SPFtRWFCDyhvcwCSvacLpkwmYZcD57mmZzAsMiks9TpHpIghe32U9H06tMICnr+X7YCpzH7WvUlUoml2urA==", - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, - "path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==" - } - } - }, "@netlify/plugins-list": { "version": "6.19.0", "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.19.0.tgz", "integrity": "sha512-EuRZgOhP7QE0H5Sn4+LvsOKL+rcUn+ny6dzwK1V+Rj2HV0cBW2JMGxWj2IEAI1Qb0xU/Gy+Ib+bX23dCvm5LdQ==" }, - "@netlify/routing-local-proxy": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy/-/routing-local-proxy-0.34.1.tgz", - "integrity": "sha512-FuzgxdxC7wJXUT08qPTtHiKwjFDHh3ViCDZwxwjm8CjOKYz+9NjhmIffkbEFl6R+uH6IV/3R6gVDL5Fb5hwRbQ==", - "requires": { - "@netlify/routing-local-proxy-darwin-arm64": "^0.34.1", - "@netlify/routing-local-proxy-darwin-x64": "^0.34.1", - "@netlify/routing-local-proxy-linux-x64": "^0.34.1", - "@netlify/routing-local-proxy-win32-x64": "^0.34.1" - } - }, - "@netlify/routing-local-proxy-darwin-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-darwin-arm64/-/routing-local-proxy-darwin-arm64-0.34.1.tgz", - "integrity": "sha512-QswoXdmvmwx76bNdA0TcwfbK1NUIo5BjcS4bpE96wtUPr3SNn4pSoOip9/Tae2JbLGl7efdEkgBE1J6rMiu/kA==", - "optional": true - }, - "@netlify/routing-local-proxy-darwin-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-darwin-x64/-/routing-local-proxy-darwin-x64-0.34.1.tgz", - "integrity": "sha512-x5mukoDWGl+jpVsyNZjRBrP1m93AFrVI/afodQbu45nyW78fpNALhqJPGoI2ixe/Z5HKaYl+ItvI+J4wAVFseQ==", - "optional": true - }, - "@netlify/routing-local-proxy-linux-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-linux-x64/-/routing-local-proxy-linux-x64-0.34.1.tgz", - "integrity": "sha512-dquodOP1VC2RtJcr2bp/DzTq0JXtk2cZDtJmaasMxxbxZmwL9R+63ypWsgdvGTSdZDKkwzzHAg3a7qGHVIl4ow==", - "optional": true - }, - "@netlify/routing-local-proxy-win32-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@netlify/routing-local-proxy-win32-x64/-/routing-local-proxy-win32-x64-0.34.1.tgz", - "integrity": "sha512-Dy1OPqlHXCDIJoEor709Ysx76UiAgrse1GF5wdieTVtWnQ7culo8+LVCwubwQezVCCbdjTke9LfMWbP91zBojg==", - "optional": true - }, "@netlify/run-utils": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@netlify/run-utils/-/run-utils-4.0.1.tgz", @@ -27299,18 +24979,18 @@ }, "dependencies": { "execa": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-6.0.0.tgz", - "integrity": "sha512-m4wU9j4Z9nXXoqT8RSfl28JSwmMNLFF69OON8H/lL3NeU0tNpGz313bcOfYoBBHokB0dC2tMl3VUcKgHELhL2Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", "requires": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^3.0.1", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^5.0.1", + "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.5", + "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, @@ -27554,101 +25234,6 @@ "@octokit/openapi-types": "^11.2.0" } }, - "@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - } - }, - "@rollup/plugin-commonjs": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.1.tgz", - "integrity": "sha512-EA+g22lbNJ8p5kuZJUYyhhDK7WgJckW5g4pNN7n4mAFUM96VuwUnNT3xr2Db2iCZPI1pJPbGyfT5mS9T1dHfMg==", - "requires": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, - "dependencies": { - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "@rollup/plugin-inject": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz", - "integrity": "sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==", - "requires": { - "@rollup/pluginutils": "^3.1.0", - "estree-walker": "^2.0.1", - "magic-string": "^0.25.7" - } - }, - "@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "requires": { - "@rollup/pluginutils": "^3.0.8" - } - }, - "@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "dependencies": { - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" - } - } - }, "@samverschueren/stream-to-observable": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz", @@ -27801,11 +25386,6 @@ "@types/node": "*" } }, - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" - }, "@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -27980,14 +25560,6 @@ "optional": true, "peer": true }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "requires": { - "@types/node": "*" - } - }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -29010,48 +26582,6 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -29357,6 +26887,7 @@ "version": "4.19.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, "requires": { "caniuse-lite": "^1.0.30001286", "electron-to-chromium": "^1.4.17", @@ -29398,11 +26929,6 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "buffer-es6": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/buffer-es6/-/buffer-es6-4.9.3.tgz", - "integrity": "sha1-8mNHuC33b9N+GLy1KIxJcM/VxAQ=" - }, "buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", @@ -29541,6 +27067,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -29595,7 +27122,8 @@ "caniuse-lite": { "version": "1.0.30001306", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001306.tgz", - "integrity": "sha512-Wd1OuggRzg1rbnM5hv1wXs2VkxJH/AA+LuudlIqvZiCvivF+wJJe2mgBZC8gPMgI7D76PP5CTx8Luvaqc1V6OQ==" + "integrity": "sha512-Wd1OuggRzg1rbnM5hv1wXs2VkxJH/AA+LuudlIqvZiCvivF+wJJe2mgBZC8gPMgI7D76PP5CTx8Luvaqc1V6OQ==", + "dev": true }, "caseless": { "version": "0.12.0", @@ -30025,9 +27553,9 @@ }, "dependencies": { "chalk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz", - "integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==" }, "filter-obj": { "version": "3.0.0", @@ -30068,11 +27596,6 @@ "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, "compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -30293,6 +27816,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -30507,22 +28031,6 @@ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "dev": true }, - "core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", - "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } - } - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -31371,6 +28879,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -31918,7 +29427,8 @@ "electron-to-chromium": { "version": "1.4.64", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.64.tgz", - "integrity": "sha512-8mec/99xgLUZCIZZq3wt61Tpxg55jnOSpxGYapE/1Ma9MpFEYYaz4QNYm0CM1rrnCo7i3FRHhbaWjeCLsveGjQ==" + "integrity": "sha512-8mec/99xgLUZCIZZq3wt61Tpxg55jnOSpxGYapE/1Ma9MpFEYYaz4QNYm0CM1rrnCo7i3FRHhbaWjeCLsveGjQ==", + "dev": true }, "elegant-spinner": { "version": "1.0.1", @@ -32016,9 +29526,9 @@ } }, "error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", - "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz", + "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", "requires": { "stackframe": "^1.1.1" } @@ -33818,7 +31328,8 @@ "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true }, "get-amd-module-type": { "version": "3.0.0", @@ -33838,6 +31349,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -33984,7 +31496,8 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true }, "globby": { "version": "11.1.0", @@ -34148,7 +31661,8 @@ "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true }, "has-to-string-tag-x": { "version": "1.4.1", @@ -34909,11 +32423,6 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" - }, "is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", @@ -34988,14 +32497,6 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true }, - "is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "requires": { - "@types/estree": "*" - } - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -35185,26 +32686,6 @@ "pretty-format": "^27.5.1" } }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -35359,7 +32840,8 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true }, "json-buffer": { "version": "3.0.1", @@ -35405,6 +32887,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -35931,11 +33414,6 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, "lodash.deburr": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", @@ -36075,12 +33553,12 @@ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" }, "figures": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.0.tgz", - "integrity": "sha512-VnYcWq6H6F0qDN0QnorznBr0abEovifzUokmnezpKZBUbDmbLAt7LMryOp1TKFVxLxyNYkxEkCEADZR58U9oSw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.1.tgz", + "integrity": "sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==", "requires": { "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.0.0" + "is-unicode-supported": "^1.2.0" } }, "filter-obj": { @@ -36089,14 +33567,14 @@ "integrity": "sha512-oQZM+QmVni8MsYzcq9lgTHD/qeLqaG8XaOPOW7dzuSafVxSUlH1+1ZDefj2OD9f2XsmG5lFl2Euc9NI4jgwFWg==" }, "is-unicode-supported": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.1.0.tgz", - "integrity": "sha512-lDcxivp8TJpLG75/DpatAqNzOpDPSpED8XNtrpBHTdQ2InQ1PbW78jhwSxyxhhu+xbVSast2X38bwj8atwoUQA==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.2.0.tgz", + "integrity": "sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==" }, "map-obj": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", - "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.1.tgz", + "integrity": "sha512-p3Qoax94q4c4Pb4etNi2lQSQGlqOA4PoD3ARovo7NllRoObZHwNEYd40fz4qgX1zTFK4geU/R1kbowl5hU5OVg==" } } }, @@ -36277,14 +33755,6 @@ "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.0.1.tgz", "integrity": "sha512-3l6OrhdDg2H2SigtuN3jBh+5dRJRWxNKuJTPBbGeNJTsmt/pj9PO25wYaNb05NuNmAsl435j4rDP6rgNXz7s7g==" }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -36768,11 +34238,18 @@ } }, "move-file": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/move-file/-/move-file-2.1.0.tgz", - "integrity": "sha512-i9qLW6gqboJ5Ht8bauZi7KlTnQ3QFpBCvMvFfEcHADKgHGeJ9BZMO7SFCTwHPV9Qa0du9DYY1Yx3oqlGt30nXA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/move-file/-/move-file-3.0.0.tgz", + "integrity": "sha512-v6u4XjX3MFW6Jo1V/YfbhC7eiGSgvYPJ/NM+aGtTtB9/Y6IYj7YViaHu6dkgDsZFB7MbnAoSI5+Z26XZXnP0vg==", "requires": { - "path-exists": "^4.0.0" + "path-exists": "^5.0.0" + }, + "dependencies": { + "path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" + } } }, "ms": { @@ -37364,7 +34841,8 @@ "node-releases": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true }, "node-source-walk": { "version": "4.2.0", @@ -37374,6 +34852,11 @@ "@babel/parser": "^7.0.0" } }, + "node-stream-zip": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", + "integrity": "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==" + }, "node-version-alias": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/node-version-alias/-/node-version-alias-1.0.1.tgz", @@ -37879,7 +35362,8 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", @@ -37893,6 +35377,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -38855,11 +36340,6 @@ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "dev": true }, - "process-es6": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/process-es6/-/process-es6-0.11.6.tgz", - "integrity": "sha1-xrs4n5qVH4K9TrFpYAEFvS/5x3g=" - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -39013,6 +36493,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -39329,32 +36810,6 @@ "strip-indent": "^3.0.0" } }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -39396,19 +36851,6 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, - "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, "registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -39425,26 +36867,6 @@ "rc": "^1.2.8" } }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" - }, - "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -39711,60 +37133,6 @@ "inherits": "^2.0.1" } }, - "rollup": { - "version": "2.67.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.0.tgz", - "integrity": "sha512-W83AaERwvDiHwHEF/dfAfS3z1Be5wf7n+pO3ZAO5IQadCT2lBTr7WQ2MwZZe+nodbD+n3HtC4OCOAdsOPPcKZQ==", - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-inject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", - "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", - "requires": { - "estree-walker": "^0.6.1", - "magic-string": "^0.25.3", - "rollup-pluginutils": "^2.8.1" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" - } - } - }, - "rollup-plugin-node-polyfills": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", - "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", - "requires": { - "rollup-plugin-inject": "^3.0.0" - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "dependencies": { - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "requires": { - "randombytes": "^2.1.0" - } - } - } - }, "rollup-pluginutils": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", @@ -40369,7 +37737,8 @@ "sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true }, "spdx-correct": { "version": "3.1.1", @@ -40470,9 +37839,9 @@ } }, "stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", - "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", + "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==" }, "static-extend": { "version": "0.1.2", @@ -40963,9 +38332,9 @@ } }, "supports-color": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz", - "integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==" + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==" }, "supports-hyperlinks": { "version": "2.2.0", @@ -41101,28 +38470,6 @@ } } }, - "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", - "requires": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -41318,7 +38665,8 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true }, "to-object-path": { "version": "0.3.0", @@ -41614,30 +38962,6 @@ "through": "^2.3.8" } }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" - }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", diff --git a/package.json b/package.json index e7dc541f6e7..6037b8bf8dc 100644 --- a/package.json +++ b/package.json @@ -206,13 +206,12 @@ "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,yml,json,html}\" \"*.{mjs,cjs,js,yml,json,html}\" \".*.{mjs,cjs,js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!**/*/package-lock.json\" \"!.github/**/*.md\"" }, "dependencies": { - "@netlify/build": "^26.5.3", - "@netlify/config": "^17.0.20", + "@netlify/build": "^27.0.0", + "@netlify/config": "^18.0.0", + "@netlify/edge-bundler": "^0.12.0", "@netlify/framework-info": "^9.0.2", "@netlify/local-functions-proxy": "^1.1.1", - "@netlify/plugin-edge-handlers": "^3.0.7", "@netlify/plugins-list": "^6.19.0", - "@netlify/routing-local-proxy": "^0.34.1", "@netlify/zip-it-and-ship-it": "^5.9.0", "@octokit/rest": "^18.0.0", "@sindresorhus/slugify": "^1.1.0", @@ -241,6 +240,7 @@ "dotenv": "^16.0.0", "env-paths": "^2.2.0", "envinfo": "^7.3.1", + "etag": "^1.8.1", "execa": "^5.0.0", "express": "^4.17.1", "express-logging": "^1.1.1", @@ -310,6 +310,7 @@ "through2-map": "^3.0.0", "to-readable-stream": "^2.1.0", "toml": "^3.0.0", + "unixify": "^1.0.0", "update-notifier": "^5.0.0", "uuid": "^8.0.0", "wait-port": "^0.2.2", diff --git a/src/commands/base-command.js b/src/commands/base-command.js index 35645500e92..35ad24ff677 100644 --- a/src/commands/base-command.js +++ b/src/commands/base-command.js @@ -421,7 +421,6 @@ class BaseCommand extends Command { const cachedConfig = await actionCommand.getConfig({ cwd, state, token, ...apiUrlOpts }) const { buildDir, config, configPath, repositoryRoot, siteInfo } = cachedConfig const normalizedConfig = normalizeConfig(config) - const agent = await getAgent({ httpProxy: options.httpProxy, certificateFile: options.httpProxyCertificateFilename, @@ -478,7 +477,7 @@ class BaseCommand extends Command { options.context || process.env.CONTEXT || // Dev commands have a default context of `dev`, otherwise we let netlify/config handle default behavior - (['dev', 'dev:exec', 'dev:trace'].includes(this.name()) ? 'dev' : undefined), + (['dev', 'dev:exec'].includes(this.name()) ? 'dev' : undefined), debug: this.opts().debug, siteId: options.siteId || (typeof options.site === 'string' && options.site) || state.get('siteId'), token, diff --git a/src/commands/deploy/deploy.js b/src/commands/deploy/deploy.js index d66b246d3b9..bfafd2c75dd 100644 --- a/src/commands/deploy/deploy.js +++ b/src/commands/deploy/deploy.js @@ -20,7 +20,6 @@ const { NETLIFYDEVERR, NETLIFYDEVLOG, chalk, - deployEdgeHandlers, deploySite, error, exit, @@ -314,12 +313,6 @@ const runDeploy = async ({ results = await api.createSiteDeploy({ siteId, title, body: { draft, branch: alias } }) deployId = results.id - await deployEdgeHandlers({ - site, - deployId, - api, - silent, - }) const internalFunctionsFolder = await getInternalFunctionsDir({ base: site.root }) // The order of the directories matter: zip-it-and-ship-it will prioritize diff --git a/src/commands/dev/dev-trace.js b/src/commands/dev/dev-trace.js deleted file mode 100644 index f1e0ea0b4fe..00000000000 --- a/src/commands/dev/dev-trace.js +++ /dev/null @@ -1,47 +0,0 @@ -// @ts-check -const process = require('process') - -const { runProcess } = require('../../utils') - -/** - * The dev:trace command - * @returns {Promise} - */ -const devTrace = async () => { - const args = ['trace', ...process.argv.slice(3)] - const { subprocess } = runProcess({ args }) - await subprocess -} - -/** - * Creates the `netlify dev:trace` command - * @param {import('../base-command').BaseCommand} program - * @returns - */ -const createDevTraceCommand = (program) => - program - .command('dev:trace') - .argument('', 'Sets the request URL') - .description('Trace command') - .option('-X, --request ', 'Specifies a custom request method [default: GET]') - .option('-b, --cookie ', 'Request cookie, this flag can be used multiple times. Example: "nf_jwt=token"') - .option( - '-H, --header
', - 'Request header, this flag can be used multiple times. Example: "Host: netlify.test"', - ) - .option('-w, --watch ', 'Path to the publish directory') - .addHelpText( - 'after', - `Simulates Netlify's Edge routing logic to match specific requests. -This command is designed to mimic cURL's command line, so the flags are more familiar.`, - ) - .addExamples([ - 'netlify dev:trace http://localhost/routing-path', - 'netlify dev:trace -w dist-directory http://localhost/routing-path', - 'netlify dev:trace -X POST http://localhost/routing-path', - 'netlify dev:trace -H "Accept-Language es" http://localhost/routing-path', - 'netlify dev:trace --cookie nf_jwt=token http://localhost/routing-path', - ]) - .action(devTrace) - -module.exports = { createDevTraceCommand } diff --git a/src/commands/dev/dev.js b/src/commands/dev/dev.js index 89e091392e9..c5f6c290b6c 100644 --- a/src/commands/dev/dev.js +++ b/src/commands/dev/dev.js @@ -11,6 +11,7 @@ const StaticServer = require('static-server') const stripAnsiCc = require('strip-ansi-control-characters') const waitPort = require('wait-port') +const { promptEditorHelper } = require('../../lib/edge-functions') const { startFunctionsServer } = require('../../lib/functions/server') const { OneGraphCliClient, @@ -42,7 +43,6 @@ const { normalizeConfig, openBrowser, processOnExit, - startForwardProxy, startLiveTunnel, startProxy, warn, @@ -50,7 +50,6 @@ const { } = require('../../utils') const { createDevExecCommand } = require('./dev-exec') -const { createDevTraceCommand } = require('./dev-trace') const startStaticServer = async ({ settings }) => { const server = new StaticServer({ @@ -198,37 +197,29 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5 /** * - * @param {object} config - * @param {*} config.addonsUrls - * @param {import('commander').OptionValues} config.options - * @param {*} config.settings - * @param {*} config.site + * @param {object} params + * @param {*} params.addonsUrls + * @param {import('../base-command').NetlifyOptions["config"]} params.config + * @param {() => Promise} params.getUpdatedConfig + * @param {*} params.settings + * @param {*} params.site * @returns */ -const startProxyServer = async ({ addonsUrls, options, settings, site }) => { - let url - if (options.edgeHandlers || options.trafficMesh) { - url = await startForwardProxy({ - port: settings.port, - frameworkPort: settings.frameworkPort, - functionsPort: settings.functionsPort, - publishDir: settings.dist, - debug: options.debug, - locationDb: options.locationDb, - jwtRolesPath: settings.jwtRolePath, - jwtSecret: settings.jwtSecret, - }) - if (!url) { - log(NETLIFYDEVERR, `Unable to start forward proxy on port '${settings.port}'`) - exit(1) - } - } else { - url = await startProxy(settings, addonsUrls, site.configPath, site.root) - if (!url) { - log(NETLIFYDEVERR, `Unable to start proxy server on port '${settings.port}'`) - exit(1) - } +const startProxyServer = async ({ addonsUrls, config, getUpdatedConfig, settings, site }) => { + const url = await startProxy({ + addonsUrls, + config, + configPath: site.configPath, + getUpdatedConfig, + projectDir: site.root, + settings, + }) + + if (!url) { + log(NETLIFYDEVERR, `Unable to start proxy server on port '${settings.port}'`) + exit(1) } + return url } @@ -313,7 +304,7 @@ const startPollingForAPIAuthentication = async function (options) { */ const dev = async (options, command) => { log(`${NETLIFYDEV}`) - const { api, config, site, siteInfo, state } = command.netlify + const { api, config, repositoryRoot, site, siteInfo, state } = command.netlify config.dev = { ...config.dev } config.build = { ...config.build } /** @type {import('./types').DevConfig} */ @@ -325,13 +316,8 @@ const dev = async (options, command) => { ...options, } - if (options.trafficMesh) { - warn( - '--trafficMesh and -t are deprecated and will be removed in the near future. Please use --edgeHandlers or -e instead.', - ) - } - await injectEnvVariables({ devConfig, env: command.netlify.cachedConfig.env, site }) + await promptEditorHelper({ chalk, config, log, NETLIFYDEVLOG, repositoryRoot, state }) const { addonsUrls, capabilities, siteUrl, timeouts } = await getSiteInformation({ // inherited from base command --offline @@ -370,7 +356,16 @@ const dev = async (options, command) => { }) await startFrameworkServer({ settings }) - let url = await startProxyServer({ options, settings, site, addonsUrls }) + // TODO: We should consolidate this with the existing config watcher. + const getUpdatedConfig = async () => { + const cwd = options.cwd || process.cwd() + const { config: newConfig } = await command.getConfig({ cwd, offline: true, state }) + const normalizedNewConfig = normalizeConfig(newConfig) + + return normalizedNewConfig + } + + let url = await startProxyServer({ settings, site, addonsUrls, config, getUpdatedConfig }) const liveTunnelUrl = await handleLiveTunnel({ options, site, api, settings }) url = liveTunnelUrl || url @@ -474,7 +469,6 @@ const dev = async (options, command) => { */ const createDevCommand = (program) => { createDevExecCommand(program) - createDevTraceCommand(program) return program .command('dev') @@ -495,13 +489,6 @@ const createDevCommand = (program) => { .argParser((value) => Number.parseInt(value)) .hideHelp(), ) - .addOption(new Option('-e ,--edgeHandlers', 'activates the Edge Handlers runtime').hideHelp()) - .addOption( - new Option( - '-t ,--trafficMesh', - '(DEPRECATED: use --edgeHandlers or -e instead) uses Traffic Mesh for proxying requests', - ).hideHelp(), - ) .addOption( new Option( '-g ,--locationDb ', diff --git a/src/commands/main.js b/src/commands/main.js index bff654d6c88..0aa501ecb78 100644 --- a/src/commands/main.js +++ b/src/commands/main.js @@ -36,6 +36,7 @@ const { createLmCommand } = require('./lm') const { createLoginCommand } = require('./login') const { createLogoutCommand } = require('./logout') const { createOpenCommand } = require('./open') +const { createRecipesCommand, createRecipesListCommand } = require('./recipes') const { createSitesCommand } = require('./sites') const { createStatusCommand } = require('./status') const { createSwitchCommand } = require('./switch') @@ -171,6 +172,8 @@ const createMainCommand = () => { createDevCommand(program) createEnvCommand(program) createFunctionsCommand(program) + createRecipesCommand(program) + createRecipesListCommand(program) createGraphCommand(program) createInitCommand(program) createLinkCommand(program) diff --git a/src/commands/recipes/common.js b/src/commands/recipes/common.js new file mode 100644 index 00000000000..20944aa215f --- /dev/null +++ b/src/commands/recipes/common.js @@ -0,0 +1,33 @@ +const { promises: fs } = require('fs') +const { join, resolve } = require('path') + +const getRecipe = (name) => { + const recipePath = resolve(__dirname, '../../recipes', name) + + // eslint-disable-next-line import/no-dynamic-require, n/global-require + const recipe = require(recipePath) + + return recipe +} + +const listRecipes = async () => { + const recipesPath = resolve(__dirname, '../../recipes') + const recipeNames = await fs.readdir(recipesPath) + const recipes = await Promise.all( + recipeNames.map((name) => { + const recipePath = join(recipesPath, name) + + // eslint-disable-next-line import/no-dynamic-require, n/global-require + const recipe = require(recipePath) + + return { + ...recipe, + name, + } + }), + ) + + return recipes +} + +module.exports = { getRecipe, listRecipes } diff --git a/src/commands/recipes/index.js b/src/commands/recipes/index.js new file mode 100644 index 00000000000..bd772308fe4 --- /dev/null +++ b/src/commands/recipes/index.js @@ -0,0 +1,8 @@ +const { createRecipesCommand, runRecipe } = require('./recipes') +const { createRecipesListCommand } = require('./recipes-list') + +module.exports = { + createRecipesCommand, + createRecipesListCommand, + runRecipe, +} diff --git a/src/commands/recipes/recipes-list.js b/src/commands/recipes/recipes-list.js new file mode 100644 index 00000000000..067c3d9f522 --- /dev/null +++ b/src/commands/recipes/recipes-list.js @@ -0,0 +1,34 @@ +// @ts-check +const AsciiTable = require('ascii-table') + +const { listRecipes } = require('./common') + +/** + * The recipes:list command + */ +const recipesListCommand = async () => { + const recipes = await listRecipes() + const table = new AsciiTable(`Usage: netlify recipes `) + + table.setHeading('Name', 'Description') + + recipes.forEach(({ description, name }) => { + table.addRow(name, description) + }) + + console.log(table.toString()) +} + +/** + * Creates the `netlify recipes:list` command + * @param {import('../base-command').BaseCommand} program + * @returns + */ +const createRecipesListCommand = (program) => + program + .command('recipes:list') + .description(`(Beta) List the recipes available to create and modify files in a project`) + .addExamples(['netlify recipes:list']) + .action(recipesListCommand) + +module.exports = { createRecipesListCommand } diff --git a/src/commands/recipes/recipes.js b/src/commands/recipes/recipes.js new file mode 100644 index 00000000000..a8f731ba3ab --- /dev/null +++ b/src/commands/recipes/recipes.js @@ -0,0 +1,85 @@ +// @ts-check +const { basename } = require('path') + +const inquirer = require('inquirer') +const { findBestMatch } = require('string-similarity') + +const utils = require('../../utils/command-helpers') + +const { getRecipe, listRecipes } = require('./common') + +const SUGGESTION_TIMEOUT = 1e4 + +/** + * The recipes command + * @param {string} recipeName + * @param {import('commander').OptionValues} options + * @param {import('../base-command').BaseCommand} command + */ +const recipesCommand = async (recipeName, options, command) => { + const { config, repositoryRoot } = command.netlify + const sanitizedRecipeName = basename(recipeName || '').toLowerCase() + + if (sanitizedRecipeName.length === 0) { + return command.help() + } + + try { + return await runRecipe({ config, recipeName: sanitizedRecipeName, repositoryRoot }) + } catch (error) { + if (error.code !== 'MODULE_NOT_FOUND') { + throw error + } + + utils.log(`${utils.NETLIFYDEVERR} ${utils.chalk.yellow(recipeName)} is not a valid recipe name.`) + + const recipes = await listRecipes() + const recipeNames = recipes.map(({ name }) => name) + const { + bestMatch: { target: suggestion }, + } = findBestMatch(recipeName, recipeNames) + const applySuggestion = await new Promise((resolve) => { + const prompt = inquirer.prompt({ + type: 'confirm', + name: 'suggestion', + message: `Did you mean ${utils.chalk.blue(suggestion)}`, + default: false, + }) + + setTimeout(() => { + // @ts-ignore + prompt.ui.close() + resolve(false) + }, SUGGESTION_TIMEOUT) + + // eslint-disable-next-line promise/catch-or-return + prompt.then((value) => resolve(value.suggestion)) + }) + + if (applySuggestion) { + return recipesCommand(suggestion, options, command) + } + } +} + +const runRecipe = ({ config, recipeName, repositoryRoot }) => { + const recipe = getRecipe(recipeName) + + return recipe.run({ config, repositoryRoot }) +} + +/** + * Creates the `netlify recipes` command + * @param {import('../base-command').BaseCommand} program + * @returns + */ +const createRecipesCommand = (program) => + program + .command('recipes') + .argument('[name]', 'name of the recipe') + .description(`(Beta) Create and modify files in a project using pre-defined recipes`) + .option('-n, --name ', 'recipe name to use') + .addExamples(['netlify recipes my-recipe', 'netlify recipes --name my-recipe']) + .action(recipesCommand) + +module.exports = { createRecipesCommand, runRecipe } diff --git a/src/lib/api.js b/src/lib/api.js index 3072e4b3a18..f6f6dadf32c 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -1,76 +1,5 @@ -const fetch = require('node-fetch') - const { warn } = require('../utils/command-helpers') -const getHeaders = ({ token }) => ({ - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, -}) - -const getErrorMessage = async ({ response }) => { - const contentType = response.headers.get('content-type') - if (contentType && contentType.includes('application/json')) { - const json = await response.json() - return json.message - } - const text = await response.text() - return text -} - -const checkResponse = async ({ response }) => { - if (!response.ok) { - const message = await getErrorMessage({ response }).catch(() => {}) - const errorPostfix = message ? ` and message '${message}'` : '' - throw new Error(`Request failed with status '${response.status}'${errorPostfix}`) - } -} - -const getApiUrl = ({ api }) => `${api.scheme}://${api.host}${api.pathPrefix}` - -const apiPost = async ({ api, data, path }) => { - const apiUrl = getApiUrl({ api }) - const response = await fetch(`${apiUrl}/${path}`, { - method: 'POST', - body: JSON.stringify(data), - headers: getHeaders({ token: api.accessToken }), - agent: api.agent, - }) - - await checkResponse({ response }) - - return response -} - -const uploadEdgeHandlers = async ({ api, bundleBuffer, deployId, manifest }) => { - // TODO: use open-api spec via api when it is exposed - const response = await apiPost({ api, path: `deploys/${deployId}/edge_handlers`, data: manifest }) - const { error, exists, upload_url: uploadUrl } = await response.json() - if (error) { - throw new Error(error) - } - - if (exists) { - return false - } - - if (!uploadUrl) { - throw new Error('Missing upload URL') - } - - const putResponse = await fetch(uploadUrl, { - method: 'PUT', - body: bundleBuffer, - headers: { - 'Content-Type': 'application/javascript', - }, - agent: api.agent, - }) - - await checkResponse({ response: putResponse }) - - return true -} - const cancelDeploy = async ({ api, deployId }) => { try { await api.cancelSiteDeploy({ deploy_id: deployId }) @@ -92,4 +21,4 @@ const listSites = async ({ api, options }) => { return sites } -module.exports = { uploadEdgeHandlers, cancelDeploy, listSites } +module.exports = { cancelDeploy, listSites } diff --git a/src/lib/edge-functions/consts.js b/src/lib/edge-functions/consts.js new file mode 100644 index 00000000000..fa273808850 --- /dev/null +++ b/src/lib/edge-functions/consts.js @@ -0,0 +1,21 @@ +const DEFAULT_SRC_DIR = 'netlify/edge-functions' +const DIST_IMPORT_MAP_PATH = 'edge-functions-import-map.json' +const INTERNAL_EDGE_FUNCTIONS_FOLDER = 'edge-functions' +const EDGE_FUNCTIONS_FOLDER = 'edge-functions-dist' +const PUBLIC_URL_PATH = '.netlify/internal/edge-functions' + +// 1 second +const SERVER_POLL_INTERNAL = 1e3 + +// 10 seconds +const SERVER_POLL_TIMEOUT = 1e4 + +module.exports = { + DEFAULT_SRC_DIR, + DIST_IMPORT_MAP_PATH, + INTERNAL_EDGE_FUNCTIONS_FOLDER, + EDGE_FUNCTIONS_FOLDER, + PUBLIC_URL_PATH, + SERVER_POLL_INTERNAL, + SERVER_POLL_TIMEOUT, +} diff --git a/src/lib/edge-functions/deploy.js b/src/lib/edge-functions/deploy.js new file mode 100644 index 00000000000..571e5678ed1 --- /dev/null +++ b/src/lib/edge-functions/deploy.js @@ -0,0 +1,41 @@ +// @ts-check +const { stat } = require('fs').promises +const path = require('path') + +const { getPathInProject } = require('../settings') + +const { EDGE_FUNCTIONS_FOLDER, PUBLIC_URL_PATH } = require('./consts') + +const distPath = getPathInProject([EDGE_FUNCTIONS_FOLDER]) + +const deployFileNormalizer = (file) => { + const isEdgeFunction = file.root === distPath + const normalizedPath = isEdgeFunction ? path.join(PUBLIC_URL_PATH, file.normalizedPath) : file.normalizedPath + + return { + ...file, + normalizedPath, + } +} + +const getDistPathIfExists = async () => { + try { + const stats = await stat(distPath) + + if (!stats.isDirectory()) { + throw new Error(`Path ${distPath} must be a directory.`) + } + + return distPath + } catch { + // no-op + } +} + +const isEdgeFunctionFile = (filePath) => filePath.startsWith(`${PUBLIC_URL_PATH}${path.sep}`) + +module.exports = { + deployFileNormalizer, + getDistPathIfExists, + isEdgeFunctionFile, +} diff --git a/src/lib/edge-functions/editor-helper.js b/src/lib/edge-functions/editor-helper.js new file mode 100644 index 00000000000..5b6ceafc421 --- /dev/null +++ b/src/lib/edge-functions/editor-helper.js @@ -0,0 +1,41 @@ +const { env } = require('process') + +const inquirer = require('inquirer') + +const { runRecipe } = require('../../commands/recipes') + +const STATE_PROMPT_PROPERTY = 'promptVSCodeSettings' + +const promptEditorHelper = async ({ NETLIFYDEVLOG, chalk, config, log, repositoryRoot, state }) => { + const isVSCode = env.TERM_PROGRAM === 'vscode' + const hasShownPrompt = Boolean(state.get(STATE_PROMPT_PROPERTY)) + const hasEdgeFunctions = Boolean(config.edge_functions && config.edge_functions.length !== 0) + + if (!isVSCode || hasShownPrompt || !hasEdgeFunctions) { + return + } + + state.set(STATE_PROMPT_PROPERTY, true) + + const message = 'Would you like to configure VS Code to use Edge Functions?' + const { confirm } = await inquirer.prompt({ + type: 'confirm', + name: 'confirm', + message, + default: true, + }) + + if (!confirm) { + log( + `${NETLIFYDEVLOG} You can start this configuration manually by running ${chalk.magenta.bold( + 'netlify recipes vscode', + )}.`, + ) + + return + } + + await runRecipe({ config, recipeName: 'vscode', repositoryRoot }) +} + +module.exports = { promptEditorHelper } diff --git a/src/lib/edge-functions/headers.js b/src/lib/edge-functions/headers.js new file mode 100644 index 00000000000..b6be4e18905 --- /dev/null +++ b/src/lib/edge-functions/headers.js @@ -0,0 +1,6 @@ +module.exports = { + Functions: 'x-deno-functions', + PassHost: 'X-NF-Pass-Host', + Passthrough: 'x-deno-pass', + RequestID: 'X-NF-Request-ID', +} diff --git a/src/lib/edge-functions/index.js b/src/lib/edge-functions/index.js new file mode 100644 index 00000000000..0a50bddb412 --- /dev/null +++ b/src/lib/edge-functions/index.js @@ -0,0 +1,7 @@ +// @ts-check +const constants = require('./consts') +const deploy = require('./deploy') +const editorHelper = require('./editor-helper') +const proxy = require('./proxy') + +module.exports = { ...constants, ...deploy, ...editorHelper, ...proxy } diff --git a/src/lib/edge-functions/internal.js b/src/lib/edge-functions/internal.js new file mode 100644 index 00000000000..5f1aef3044e --- /dev/null +++ b/src/lib/edge-functions/internal.js @@ -0,0 +1,75 @@ +// @ts-check +const { promises: fs } = require('fs') +const path = require('path') +const { cwd } = require('process') + +const { warn } = require('../../utils/command-helpers') +const { getPathInProject } = require('../settings') + +const { INTERNAL_EDGE_FUNCTIONS_FOLDER } = require('./consts') + +/** + * Reads an import map from a path and returns the parsed data, if it exists + * and is valid. Otherwise, it returns null. + * + * @param {string} importMapPath + * @returns {Promise} + */ +const getImportMap = async (importMapPath) => { + try { + const data = await fs.readFile(importMapPath) + const importMap = JSON.parse(data) + + return importMap + } catch { + warn(`Could not read the import map file for Edge Functions at ${importMapPath}`) + + return null + } +} + +const getInternalFunctions = async () => { + const internalPath = path.join(cwd(), getPathInProject([INTERNAL_EDGE_FUNCTIONS_FOLDER])) + + try { + const stats = await fs.stat(internalPath) + + if (!stats.isDirectory()) { + throw new Error('Path is not a directory') + } + + const manifestPath = path.join(internalPath, 'manifest.json') + // eslint-disable-next-line import/no-dynamic-require, n/global-require + const manifest = require(manifestPath) + + if (manifest.version !== 1) { + throw new Error('Unsupported manifest format') + } + + const data = { + functions: manifest.functions, + path: internalPath, + } + + if (manifest.import_map) { + const importMapPath = path.resolve(path.dirname(manifestPath), manifest.import_map) + const importMap = await getImportMap(importMapPath) + + if (importMap !== null) { + return { + ...data, + importMap, + } + } + } + + return data + } catch { + return { + functions: [], + path: null, + } + } +} + +module.exports = { getInternalFunctions } diff --git a/src/lib/edge-functions/proxy.js b/src/lib/edge-functions/proxy.js new file mode 100644 index 00000000000..f7f661694fb --- /dev/null +++ b/src/lib/edge-functions/proxy.js @@ -0,0 +1,133 @@ +// @ts-check +const { env } = require('process') + +const getAvailablePort = require('get-port') +const { v4: generateUUID } = require('uuid') + +const { NETLIFYDEVERR, chalk } = require('../../utils/command-helpers') +const { getPathInProject } = require('../settings') +const { startSpinner, stopSpinner } = require('../spinner') + +const { DIST_IMPORT_MAP_PATH } = require('./consts') +const headers = require('./headers') +const { getInternalFunctions } = require('./internal') +const { EdgeFunctionsRegistry } = require('./registry') + +const headersSymbol = Symbol('Edge Functions Headers') + +const LOCAL_HOST = '127.0.0.1' + +const getDownloadUpdateFunctions = () => { + let spinner + + const onAfterDownload = () => { + stopSpinner({ spinner }) + } + + const onBeforeDownload = () => { + spinner = startSpinner({ text: 'Setting up the Edge Functions environment. This may take a couple of minutes.' }) + } + + return { + onAfterDownload, + onBeforeDownload, + } +} + +const handleProxyRequest = (req, proxyReq) => { + Object.entries(req[headersSymbol]).forEach(([header, value]) => { + proxyReq.setHeader(header, value) + }) +} + +const initializeProxy = async ({ config, configPath, getUpdatedConfig, settings }) => { + const { functions: internalFunctions, importMap, path: internalFunctionsPath } = await getInternalFunctions() + const { port: mainPort } = settings + const userFunctionsPath = config.build.edge_functions + const isolatePort = await getAvailablePort() + + // Initializes the server, bootstrapping the Deno CLI and downloading it from + // the network if needed. We don't want to wait for that to be completed, or + // the command will be left hanging. + const server = prepareServer({ + config, + configPath, + directories: [internalFunctionsPath, userFunctionsPath].filter(Boolean), + getUpdatedConfig, + importMaps: [importMap].filter(Boolean), + internalFunctions, + port: isolatePort, + }) + const hasEdgeFunctions = userFunctionsPath !== undefined || internalFunctions.length !== 0 + + return async (req) => { + if (req.headers[headers.Passthrough] !== undefined || !hasEdgeFunctions) { + return + } + + const { registry } = await server + + await registry.initialize() + + const manifest = await registry.getManifest() + const url = new URL(req.url, `http://${LOCAL_HOST}:${mainPort}`) + const routes = manifest.routes.map((route) => ({ + ...route, + pattern: new RegExp(route.pattern), + })) + const matchingFunctions = routes.filter(({ pattern }) => pattern.test(url.pathname)).map((route) => route.function) + + if (matchingFunctions.length === 0) { + return + } + + req[headersSymbol] = { + [headers.Functions]: matchingFunctions.join(','), + [headers.PassHost]: `${LOCAL_HOST}:${mainPort}`, + [headers.Passthrough]: 'passthrough', + [headers.RequestID]: generateUUID(), + } + + return `http://${LOCAL_HOST}:${isolatePort}` + } +} + +const isEdgeFunctionsRequest = (req) => req[headersSymbol] !== undefined + +const prepareServer = async ({ + config, + configPath, + directories, + getUpdatedConfig, + importMaps, + internalFunctions, + port, +}) => { + const bundler = await import('@netlify/edge-bundler') + const distImportMapPath = getPathInProject([DIST_IMPORT_MAP_PATH]) + const runIsolate = await bundler.serve({ + ...getDownloadUpdateFunctions(), + debug: env.NETLIFY_DENO_DEBUG === 'true', + distImportMapPath, + formatExportTypeError: (name) => + `${NETLIFYDEVERR} ${chalk.red('Failed')} to load Edge Function ${chalk.yellow( + name, + )}. The file does not seem to have a function as the default export.`, + formatImportError: (name) => `${NETLIFYDEVERR} ${chalk.red('Failed')} to run Edge Function ${chalk.yellow(name)}:`, + importMaps, + port, + }) + const registry = new EdgeFunctionsRegistry({ + bundler, + config, + configPath, + directories, + getUpdatedConfig, + internalFunctions, + runIsolate, + }) + + return { registry, runIsolate } +} + +module.exports = { handleProxyRequest, initializeProxy, isEdgeFunctionsRequest } diff --git a/src/lib/edge-functions/registry.js b/src/lib/edge-functions/registry.js new file mode 100644 index 00000000000..b92c7ea6058 --- /dev/null +++ b/src/lib/edge-functions/registry.js @@ -0,0 +1,312 @@ +// @ts-check +const { NETLIFYDEVERR, NETLIFYDEVLOG, chalk, log, warn, watchDebounced } = require('../../utils/command-helpers') + +/** + * @typedef EdgeFunction + * @type {object} + * @property {string} name + * @property {string} path + */ + +/** + * @typedef EdgeFunctionDeclaration + * @type {object} + * @property {string} function + * @property {string} path + */ + +class EdgeFunctionsRegistry { + /** + * @param {Object} opts + * @param {import('@netlify/edge-bundler')} opts.bundler + * @param {object} opts.config + * @param {string} opts.configPath + * @param {string[]} opts.directories + * @param {() => Promise} opts.getUpdatedConfig + * @param {EdgeFunction[]} opts.internalFunctions + * @param {(functions: EdgeFunction[]) => Promise} opts.runIsolate + */ + constructor({ bundler, config, configPath, directories, getUpdatedConfig, internalFunctions, runIsolate }) { + /** + * @type {import('@netlify/edge-bundler')} + */ + this.bundler = bundler + + /** + * @type {string} + */ + this.configPath = configPath + + /** + * @type {string[]} + */ + this.directories = directories + + /** + * @type {() => Promise} + */ + this.getUpdatedConfig = getUpdatedConfig + + /** + * @type {EdgeFunction[]} + */ + this.internalFunctions = internalFunctions + + /** + * @type {(functions: EdgeFunction[]) => Promise} + */ + this.runIsolate = runIsolate + + /** + * @type {Error | null} + */ + this.buildError = null + + /** + * @type {EdgeFunctionDeclaration[]} + */ + this.declarations = this.getDeclarations(config) + + /** + * @type {Map} + */ + this.directoryWatchers = new Map() + + /** + * @type {Map} + */ + this.dependencyPaths = new Map() + + /** + * @type {Map} + */ + this.functionPaths = new Map() + + /** + * @type {Promise} + */ + this.initialScan = this.scan(directories) + + this.setupWatchers() + } + + /** + * @param {EdgeFunction[]} functions + */ + async build(functions) { + try { + const { graph, success } = await this.runIsolate(functions) + + if (!success) { + throw new Error('Build error') + } + + this.buildError = null + + this.processGraph(graph) + } catch (error) { + this.buildError = error + + throw error + } + } + + async checkForAddedOrDeletedFunctions() { + const functionsFound = await this.bundler.find(this.directories) + const newFunctions = functionsFound.filter((func) => { + const functionExists = this.functions.some( + (existingFunc) => func.name === existingFunc.name && func.path === existingFunc.path, + ) + + if (functionExists) { + return + } + + const hasDeclaration = this.declarations.some((declaration) => declaration.function === func.name) + + // We only load the function if there's a config declaration for it. + return hasDeclaration + }) + const deletedFunctions = this.functions.filter((existingFunc) => { + const functionExists = functionsFound.some( + (func) => func.name === existingFunc.name && func.path === existingFunc.path, + ) + + return !functionExists + }) + + this.functions = functionsFound + + if (newFunctions.length === 0 && deletedFunctions.length === 0) { + return + } + + try { + await this.build(functionsFound) + + deletedFunctions.forEach((func) => { + EdgeFunctionsRegistry.logDeletedFunction(func) + }) + + newFunctions.forEach((func) => { + EdgeFunctionsRegistry.logAddedFunction(func) + }) + } catch { + // no-op + } + } + + getDeclarations(config) { + const { edge_functions: userFunctions = [] } = config + const declarations = [...this.internalFunctions, ...userFunctions] + + return declarations + } + + getManifest() { + return this.bundler.generateManifest({ declarations: this.declarations, functions: this.functions }) + } + + async handleFileChange(path) { + const matchingFunctions = new Set( + [this.functionPaths.get(path), ...(this.dependencyPaths.get(path) || [])].filter(Boolean), + ) + + // If the file is not associated with any function, there's no point in + // building. However, it might be that the path is in fact associated with + // a function but we just haven't registered it due to a build error. So if + // there was a build error, let's always build. + if (matchingFunctions.size === 0 && this.buildError === null) { + return + } + + log(`${NETLIFYDEVLOG} ${chalk.magenta('Reloading')} edge functions...`) + + try { + await this.build(this.functions) + + const functionNames = [...matchingFunctions] + + if (functionNames.length === 0) { + log(`${NETLIFYDEVLOG} ${chalk.green('Reloaded')} edge functions`) + } else { + functionNames.forEach((functionName) => { + log(`${NETLIFYDEVLOG} ${chalk.green('Reloaded')} edge function ${chalk.yellow(functionName)}`) + }) + } + } catch { + log(`${NETLIFYDEVERR} ${chalk.red('Failed')} reloading edge function`) + } + } + + initialize() { + this.initialization = + this.initialization || + // eslint-disable-next-line promise/prefer-await-to-then + this.initialScan.then(async (functions) => { + try { + await this.build(functions) + } catch { + // no-op + } + + return null + }) + + return this.initialization + } + + static logAddedFunction(func) { + log(`${NETLIFYDEVLOG} ${chalk.green('Loaded')} edge function ${chalk.yellow(func.name)}`) + } + + static logDeletedFunction(func) { + log(`${NETLIFYDEVLOG} ${chalk.magenta('Removed')} edge function ${chalk.yellow(func.name)}`) + } + + processGraph(graph) { + if (!graph) { + warn('Could not process edge functions dependency graph. Live reload will not be available.') + + return + } + + // Creating a Map from `this.functions` that map function paths to function + // names. This allows us to match modules against functions in O(1) time as + // opposed to O(n). + // eslint-disable-next-line unicorn/prefer-spread + const functionPaths = new Map(Array.from(this.functions, (func) => [func.path, func.name])) + + // Mapping file URLs to names of functions that use them as dependencies. + const dependencyPaths = new Map() + + graph.modules.forEach(({ dependencies = [], specifier }) => { + const functionMatch = functionPaths.get(specifier) + + if (!functionMatch) { + return + } + + dependencies.forEach((dependency) => { + // We're interested in tracking local dependencies, so we only look at + // specifiers with the `file:` protocol. + if ( + dependency.code === undefined || + typeof dependency.code.specifier !== 'string' || + !dependency.code.specifier.startsWith('file://') + ) { + return + } + + const { specifier: dependencyURL } = dependency.code + const functions = dependencyPaths.get(dependencyURL) || [] + + dependencyPaths.set(dependencyURL, [...functions, functionMatch]) + }) + }) + + this.dependencyPaths = dependencyPaths + this.functionPaths = functionPaths + } + + async scan(directories) { + const functions = await this.bundler.find(directories) + + functions.forEach((func) => { + EdgeFunctionsRegistry.logAddedFunction(func) + }) + + this.functions = functions + + return functions + } + + async setupWatchers() { + // Creating a watcher for the config file. When it changes, we update the + // declarations and see if we need to register or unregister any functions. + this.configWatcher = await watchDebounced(this.configPath, { + onChange: async () => { + const newConfig = await this.getUpdatedConfig() + + this.declarations = this.getDeclarations(newConfig) + + await this.checkForAddedOrDeletedFunctions() + }, + }) + + // Creating a watcher for each source directory. + await Promise.all(this.directories.map((directory) => this.setupWatcherForDirectory(directory))) + } + + async setupWatcherForDirectory(directory) { + const watcher = await watchDebounced(directory, { + onAdd: () => this.checkForAddedOrDeletedFunctions(), + onChange: (path) => this.handleFileChange(path), + onUnlink: () => this.checkForAddedOrDeletedFunctions(), + }) + + this.directoryWatchers.set(directory, watcher) + } +} + +module.exports = { EdgeFunctionsRegistry } diff --git a/src/lib/functions/registry.js b/src/lib/functions/registry.js index 09e5e2f265e..8119bb8f7f5 100644 --- a/src/lib/functions/registry.js +++ b/src/lib/functions/registry.js @@ -71,7 +71,7 @@ class FunctionsRegistry { ) } - async buildFunctionAndWatchFiles(func, { verbose } = {}) { + async buildFunctionAndWatchFiles(func, { verbose = false } = {}) { if (verbose) { log(`${NETLIFYDEVLOG} ${chalk.magenta('Reloading')} function ${chalk.yellow(func.name)}...`) } diff --git a/src/recipes/vscode/index.js b/src/recipes/vscode/index.js new file mode 100644 index 00000000000..f4d5de91fb7 --- /dev/null +++ b/src/recipes/vscode/index.js @@ -0,0 +1,61 @@ +const { join } = require('path') + +const inquirer = require('inquirer') + +const { NETLIFYDEVLOG, NETLIFYDEVWARN, chalk, error, log } = require('../../utils/command-helpers') + +const { applySettings, getSettings, writeSettings } = require('./settings') + +const description = 'Create VS Code settings for an optimal experience with Netlify projects' + +const getPrompt = ({ fileExists, path }) => { + const formattedPath = chalk.underline(path) + const message = fileExists + ? `There is a VS Code settings file at ${formattedPath}. Can we update it?` + : `A new VS Code settings file will be created at ${formattedPath}` + + return inquirer.prompt({ + type: 'confirm', + name: 'confirm', + message, + default: true, + }) +} + +const getEdgeFunctionsPath = ({ config, repositoryRoot }) => + config.build.edge_functions || join(repositoryRoot, 'netlify', 'edge-functions') + +const getSettingsPath = (repositoryRoot) => join(repositoryRoot, '.vscode', 'settings.json') + +const run = async ({ config, repositoryRoot }) => { + const { DenoBridge } = await import('@netlify/edge-bundler') + const deno = new DenoBridge({ + onBeforeDownload: () => + log(`${NETLIFYDEVWARN} Setting up the Edge Functions environment. This may take a couple of minutes.`), + }) + const denoBinary = await deno.getBinaryPath() + const settingsPath = getSettingsPath(repositoryRoot) + const edgeFunctionsPath = getEdgeFunctionsPath({ config, repositoryRoot }) + const { fileExists, settings: existingSettings } = await getSettings(settingsPath) + const settings = applySettings(existingSettings, { denoBinary, edgeFunctionsPath, repositoryRoot }) + const { confirm } = await getPrompt({ fileExists, path: settingsPath }) + + if (!confirm) { + return + } + + try { + await writeSettings({ settings, settingsPath }) + + log(`${NETLIFYDEVLOG} VS Code settings file ${fileExists ? 'updated' : 'created'}.`) + log( + `${NETLIFYDEVWARN} If you don't have the Deno VS Code extension, install it by visiting ${chalk.blue( + 'https://ntl.fyi/deno-vscode', + )}.`, + ) + } catch { + error('Could not write VS Code settings file.') + } +} + +module.exports = { description, run } diff --git a/src/recipes/vscode/settings.js b/src/recipes/vscode/settings.js new file mode 100644 index 00000000000..c2e22714870 --- /dev/null +++ b/src/recipes/vscode/settings.js @@ -0,0 +1,66 @@ +const { promises: fs } = require('fs') +const { dirname, relative } = require('path') + +const unixify = require('unixify') + +const applySettings = (existingSettings, { denoBinary, edgeFunctionsPath, repositoryRoot }) => { + const relativeEdgeFunctionsPath = unixify(relative(repositoryRoot, edgeFunctionsPath)) + const settings = { + ...existingSettings, + 'deno.enable': true, + 'deno.enablePaths': existingSettings['deno.enablePaths'] || [], + 'deno.unstable': true, + 'deno.importMap': '.netlify/edge-functions-import-map.json', + } + + // If the Edge Functions path isn't already in `deno.enabledPaths`, let's add + // it. + if (!settings['deno.enablePaths'].includes(relativeEdgeFunctionsPath)) { + settings['deno.enablePaths'].push(relativeEdgeFunctionsPath) + } + + // If the Deno CLI binary isn't globally installed, we need to set the path + // to it in the settings file or the extension won't know where to find it. + // The only exception is when `deno.path` has already been defined, because + // we don't want to override that. + if (!denoBinary.global && settings['deno.path'] === undefined) { + settings['deno.path'] = denoBinary.path + } + + return settings +} + +const getSettings = async (settingsPath) => { + try { + const stats = await fs.stat(settingsPath) + + if (!stats.isFile()) { + throw new Error(`${settingsPath} is not a valid file.`) + } + + const file = await fs.readFile(settingsPath) + + return { + fileExists: true, + settings: JSON.parse(file), + } + } catch (error) { + if (error.code !== 'ENOENT') { + throw new Error(`Could not open VS Code settings file: ${error.message}`) + } + + return { + fileExists: false, + settings: {}, + } + } +} + +const writeSettings = async ({ settings, settingsPath }) => { + const serializedSettings = JSON.stringify(settings, null, 2) + + await fs.mkdir(dirname(settingsPath), { recursive: true }) + await fs.writeFile(settingsPath, serializedSettings) +} + +module.exports = { applySettings, getSettings, writeSettings } diff --git a/src/utils/command-helpers.js b/src/utils/command-helpers.js index 4f3f5dfb1ae..6bc15869208 100644 --- a/src/utils/command-helpers.js +++ b/src/utils/command-helpers.js @@ -205,6 +205,16 @@ const normalizeConfig = (config) => const DEBOUNCE_WAIT = 100 +/** + * Adds a file watcher to a path or set of paths and debounces the events. + * + * @param {string | string[]} target + * @param {Object} opts + * @param {number} [opts.depth] + * @param {() => any} [opts.onAdd] + * @param {() => any} [opts.onChange] + * @param {() => any} [opts.onUnlink] + */ const watchDebounced = async (target, { depth, onAdd = () => {}, onChange = () => {}, onUnlink = () => {} }) => { const watcher = chokidar.watch(target, { depth, ignored: /node_modules/, ignoreInitial: true }) diff --git a/src/utils/deploy/deploy-site.js b/src/utils/deploy/deploy-site.js index 8aca7ae0c29..71a8494d1dc 100644 --- a/src/utils/deploy/deploy-site.js +++ b/src/utils/deploy/deploy-site.js @@ -1,6 +1,7 @@ const cleanDeep = require('clean-deep') const tempy = require('tempy') +const edgeFunctions = require('../../lib/edge-functions') const { rmdirRecursiveAsync } = require('../../lib/fs') const { warn } = require('../command-helpers') @@ -53,9 +54,18 @@ const deploySite = async ( phase: 'start', }) + const edgeFunctionsDistPath = await edgeFunctions.getDistPathIfExists() const [{ files, filesShaMap }, { fnShaMap, functionSchedules, functions, functionsWithNativeModules }] = await Promise.all([ - hashFiles(dir, configPath, { concurrentHash, hashAlgorithm, assetType, statusCb, filter }), + hashFiles({ + assetType, + concurrentHash, + directories: [configPath, dir, edgeFunctionsDistPath].filter(Boolean), + filter, + hashAlgorithm, + normalizer: edgeFunctions.deployFileNormalizer, + statusCb, + }), hashFns(fnDir, { functionsConfig, tmpDir, @@ -69,13 +79,18 @@ const deploySite = async ( siteEnv, }), ]) - const filesCount = Object.keys(files).length + const edgeFunctionsCount = Object.keys(files).filter(edgeFunctions.isEdgeFunctionFile).length + const filesCount = Object.keys(files).length - edgeFunctionsCount const functionsCount = Object.keys(functions).length - const hasFunctionDirectories = fnDir.length !== 0 + const stats = buildStatsString([ + filesCount > 0 && `${filesCount} files`, + functionsCount > 0 && `${functionsCount} functions`, + edgeFunctionsCount > 0 && 'edge functions', + ]) statusCb({ type: 'hashing', - msg: `Finished hashing ${filesCount} files${hasFunctionDirectories ? ` and ${functionsCount} functions` : ''}`, + msg: `Finished hashing ${stats}`, phase: 'stop', }) @@ -165,4 +180,11 @@ For more information, visit https://ntl.fyi/cli-native-modules.`) return deployManifest } +const buildStatsString = (possibleParts) => { + const parts = possibleParts.filter(Boolean) + const message = parts.slice(0, -1).join(', ') + + return parts.length > 1 ? `${message} and ${parts[parts.length - 1]}` : message +} + module.exports = { deploySite } diff --git a/src/utils/deploy/hash-files.js b/src/utils/deploy/hash-files.js index ba76fb68dca..e30138b2644 100644 --- a/src/utils/deploy/hash-files.js +++ b/src/utils/deploy/hash-files.js @@ -5,16 +5,21 @@ const pump = promisify(require('pump')) const { fileFilterCtor, fileNormalizerCtor, hasherCtor, manifestCollectorCtor } = require('./hasher-segments') -const hashFiles = async ( - dir, - configPath, - { assetType = 'file', concurrentHash, filter, hashAlgorithm = 'sha1', statusCb }, -) => { +const hashFiles = async ({ + assetType = 'file', + concurrentHash, + directories, + filter, + hashAlgorithm = 'sha1', + normalizer, + statusCb, +}) => { if (!filter) throw new Error('Missing filter function option') - const fileStream = walker([configPath, dir], { filter }) + + const fileStream = walker(directories, { filter }) const fileFilter = fileFilterCtor() const hasher = hasherCtor({ concurrentHash, hashAlgorithm }) - const fileNormalizer = fileNormalizerCtor({ assetType }) + const fileNormalizer = fileNormalizerCtor({ assetType, normalizer }) // Written to by manifestCollector // normalizedPath: hash (wanted by deploy API) diff --git a/src/utils/deploy/hasher-segments.js b/src/utils/deploy/hasher-segments.js index 42666b4801e..b64ee2bcfa3 100644 --- a/src/utils/deploy/hasher-segments.js +++ b/src/utils/deploy/hasher-segments.js @@ -24,8 +24,16 @@ const hasherCtor = ({ concurrentHash, hashAlgorithm }) => { } // Inject normalized file names into normalizedPath and assetType -const fileNormalizerCtor = ({ assetType }) => - map((fileObj) => ({ ...fileObj, assetType, normalizedPath: normalizePath(fileObj.relname) })) +const fileNormalizerCtor = ({ assetType, normalizer: normalizeFunction }) => + map((fileObj) => { + const normalizedFile = { ...fileObj, assetType, normalizedPath: normalizePath(fileObj.relname) } + + if (normalizeFunction !== undefined) { + return normalizeFunction(normalizedFile) + } + + return normalizedFile + }) // A writable stream segment ctor that normalizes file paths, and writes shaMap's const manifestCollectorCtor = (filesObj, shaMap, { assetType, statusCb }) => { diff --git a/src/utils/functions/edge-handlers.js b/src/utils/functions/edge-handlers.js deleted file mode 100644 index 56533c47789..00000000000 --- a/src/utils/functions/edge-handlers.js +++ /dev/null @@ -1,88 +0,0 @@ -// @ts-check -const fs = require('fs').promises -const path = require('path') - -const { cancelDeploy, uploadEdgeHandlers } = require('../../lib/api') -const { readFileAsyncCatchError } = require('../../lib/fs') -const { startSpinner, stopSpinner } = require('../../lib/spinner') -const { error } = require('../command-helpers') - -const MANIFEST_FILENAME = 'manifest.json' -const EDGE_HANDLERS_FOLDER = '.netlify/edge-handlers' - -const validateEdgeHandlerFolder = async ({ site }) => { - try { - const resolvedFolder = path.resolve(site.root, EDGE_HANDLERS_FOLDER) - const stat = await fs.stat(resolvedFolder) - if (!stat.isDirectory()) { - error(`Edge Handlers folder ${EDGE_HANDLERS_FOLDER} must be a path to a directory`) - } - return resolvedFolder - } catch { - // ignore errors at the moment - // TODO: report error if 'edge_handlers' config exists after - // https://github.com/netlify/build/pull/1829 is published - } -} - -const readBundleAndManifest = async ({ edgeHandlersResolvedFolder }) => { - const manifestPath = path.resolve(edgeHandlersResolvedFolder, MANIFEST_FILENAME) - const { content: manifest, error: manifestError } = await readFileAsyncCatchError(manifestPath) - if (manifestError) { - error(`Could not read Edge Handlers manifest file ${manifestPath}: ${manifestError.message}`) - } - - let manifestJson - try { - manifestJson = JSON.parse(manifest) - } catch (error_) { - error(`Edge Handlers manifest file is not a valid JSON file: ${error_.message}`) - } - - if (!manifestJson.sha) { - error(`Edge Handlers manifest file is missing the 'sha' property`) - } - - const bundlePath = path.resolve(edgeHandlersResolvedFolder, manifestJson.sha) - const { content: bundleBuffer, error: bundleError } = await readFileAsyncCatchError(bundlePath) - - if (bundleError) { - error(`Could not read Edge Handlers bundle file ${bundlePath}: ${bundleError.message}`) - } - - return { bundleBuffer, manifest: manifestJson } -} - -const deployEdgeHandlers = async ({ api, deployId, silent, site }) => { - const edgeHandlersResolvedFolder = await validateEdgeHandlerFolder({ site }) - if (edgeHandlersResolvedFolder) { - let spinner - try { - spinner = silent - ? null - : startSpinner({ text: `Deploying Edge Handlers from directory ${edgeHandlersResolvedFolder}` }) - - const { bundleBuffer, manifest } = await readBundleAndManifest({ edgeHandlersResolvedFolder }) - // returns false if the bundle exists, true on success, throws on error - const success = await uploadEdgeHandlers({ - api, - deployId, - bundleBuffer, - manifest, - }) - - const text = success - ? `Finished deploying Edge Handlers from directory: ${edgeHandlersResolvedFolder}` - : `Skipped deploying Edge Handlers since the bundle already exists` - stopSpinner({ spinner, text, error: false }) - } catch (error_) { - const text = `Failed deploying Edge Handlers: ${error_.message}` - stopSpinner({ spinner, text, error: true }) - await cancelDeploy({ api, deployId }) - // no need to report the error again - error('') - } - } -} - -module.exports = { deployEdgeHandlers } diff --git a/src/utils/functions/index.js b/src/utils/functions/index.js index b5952f47014..6d1a74f19d0 100644 --- a/src/utils/functions/index.js +++ b/src/utils/functions/index.js @@ -1,11 +1,12 @@ +const edgeFunctions = require('../../lib/edge-functions') + const constants = require('./constants') -const edgeHandlers = require('./edge-handlers') const functions = require('./functions') const getFunctions = require('./get-functions') module.exports = { ...constants, ...functions, - ...edgeHandlers, + ...edgeFunctions, ...getFunctions, } diff --git a/src/utils/index.js b/src/utils/index.js index 32655a07bfe..0b3807a8dde 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -17,7 +17,6 @@ const proxy = require('./proxy') const readRepoURL = require('./read-repo-url') const StateConfig = require('./state-config') const telemetry = require('./telemetry') -const trafficMesh = require('./traffic-mesh') module.exports = { ...commandHelpers, @@ -36,7 +35,6 @@ module.exports = { ...readRepoURL, ...StateConfig, ...telemetry, - ...trafficMesh, execa, getGlobalConfig, } diff --git a/src/utils/proxy.js b/src/utils/proxy.js index ad82abc814e..39ac7e76813 100644 --- a/src/utils/proxy.js +++ b/src/utils/proxy.js @@ -8,6 +8,7 @@ const path = require('path') const contentType = require('content-type') const cookie = require('cookie') const { get } = require('dot-prop') +const generateETag = require('etag') const httpProxy = require('http-proxy') const { createProxyMiddleware } = require('http-proxy-middleware') const jwtDecode = require('jwt-decode') @@ -17,6 +18,7 @@ const pEvent = require('p-event') const pFilter = require('p-filter') const toReadableStream = require('to-readable-stream') +const edgeFunctions = require('../lib/edge-functions') const { fileExistsAsync, isFileAsync } = require('../lib/fs') const { NETLIFYDEVLOG, NETLIFYDEVWARN } = require('./command-helpers') @@ -24,6 +26,8 @@ const { createStreamPromise } = require('./create-stream-promise') const { headersForPath, parseHeaders } = require('./headers') const { createRewriter, onChanges } = require('./rules-proxy') +const shouldGenerateETag = Symbol('Internal: response should generate ETag') + const isInternal = function (url) { return url.startsWith('/.netlify/') } @@ -303,8 +307,22 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir } }) - proxy.on('error', (err) => console.error('error while proxying request:', err.message)) + proxy.on('error', (_, req, res) => { + res.writeHead(500, { + 'Content-Type': 'text/plain', + }) + + const message = edgeFunctions.isEdgeFunctionsRequest(req) + ? 'There was an error with an Edge Function. Please check the terminal for more details.' + : 'Could not proxy request.' + + res.end(message) + }) proxy.on('proxyReq', (proxyReq, req) => { + if (edgeFunctions.isEdgeFunctionsRequest(req)) { + edgeFunctions.handleProxyRequest(req, proxyReq) + } + // eslint-disable-next-line no-underscore-dangle if (req.__expectHeader) { // eslint-disable-next-line no-underscore-dangle @@ -330,16 +348,44 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir return serveRedirect({ req, res, proxy: handlers, match: null, options: req.proxyOptions }) } + const responseData = [] const requestURL = new URL(req.url, `http://${req.headers.host || 'localhost'}`) const headersRules = headersForPath(headers, requestURL.pathname) - Object.entries(headersRules).forEach(([key, val]) => { - res.setHeader(key, val) - }) - res.writeHead(req.proxyOptions.status || proxyRes.statusCode, proxyRes.headers) + proxyRes.on('data', function onData(data) { - res.write(data) + responseData.push(data) }) + proxyRes.on('end', function onEnd() { + const responseBody = Buffer.concat(responseData) + + let responseStatus = req.proxyOptions.status || proxyRes.statusCode + + // `req[shouldGenerateETag]` may contain a function that determines + // whether the response should have an ETag header. + if ( + typeof req[shouldGenerateETag] === 'function' && + req[shouldGenerateETag]({ statusCode: responseStatus }) === true + ) { + const etag = generateETag(responseBody, { weak: true }) + + if (req.headers['if-none-match'] === etag) { + responseStatus = 304 + } + + res.setHeader('etag', etag) + } + + Object.entries(headersRules).forEach(([key, val]) => { + res.setHeader(key, val) + }) + + res.writeHead(responseStatus, proxyRes.headers) + + if (responseStatus !== 304) { + res.write(responseBody) + } + res.end() }) }) @@ -359,11 +405,17 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir return handlers } -const onRequest = async ({ addonsUrls, functionsServer, proxy, rewriter, settings }, req, res) => { +const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings }, req, res) => { req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method) ? null : await createStreamPromise(req, BYTES_LIMIT) + const edgeFunctionsProxyURL = await edgeFunctionsProxy(req, res) + + if (edgeFunctionsProxyURL !== undefined) { + return proxy.web(req, res, { target: edgeFunctionsProxyURL }) + } + if (isFunction(settings.functionsPort, req.url)) { return proxy.web(req, res, { target: functionsServer }) } @@ -384,7 +436,17 @@ const onRequest = async ({ addonsUrls, functionsServer, proxy, rewriter, setting framework: settings.framework, } - if (match) return serveRedirect({ req, res, proxy, match, options }) + if (match) { + // We don't want to generate an ETag for 3xx redirects. + req[shouldGenerateETag] = ({ statusCode }) => statusCode < 300 || statusCode >= 400 + + return serveRedirect({ req, res, proxy, match, options }) + } + + // The request will be served by the framework server, which means we want to + // generate an ETag unless we're rendering an error page. The only way for + // us to know that is by looking at the status code + req[shouldGenerateETag] = ({ statusCode }) => statusCode >= 200 && statusCode < 300 const ct = req.headers['content-type'] ? contentType.parse(req).type : '' if ( @@ -399,9 +461,14 @@ const onRequest = async ({ addonsUrls, functionsServer, proxy, rewriter, setting proxy.web(req, res, options) } -const startProxy = async function (settings, addonsUrls, configPath, projectDir) { +const startProxy = async function ({ addonsUrls, config, configPath, getUpdatedConfig, projectDir, settings }) { const functionsServer = settings.functionsPort ? `http://localhost:${settings.functionsPort}` : null - + const edgeFunctionsProxy = await edgeFunctions.initializeProxy({ + config, + configPath, + getUpdatedConfig, + settings, + }) const proxy = await initializeProxy({ port: settings.frameworkPort, distDir: settings.dist, @@ -417,7 +484,14 @@ const startProxy = async function (settings, addonsUrls, configPath, projectDir) configPath, }) - const onRequestWithOptions = onRequest.bind(undefined, { proxy, rewriter, settings, addonsUrls, functionsServer }) + const onRequestWithOptions = onRequest.bind(undefined, { + proxy, + rewriter, + settings, + addonsUrls, + functionsServer, + edgeFunctionsProxy, + }) const server = settings.https ? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions) : http.createServer(onRequestWithOptions) @@ -436,4 +510,4 @@ const startProxy = async function (settings, addonsUrls, configPath, projectDir) const BYTES_LIMIT = 30 -module.exports = { startProxy } +module.exports = { shouldGenerateETag, startProxy } diff --git a/src/utils/traffic-mesh.js b/src/utils/traffic-mesh.js deleted file mode 100644 index 484f503f5b4..00000000000 --- a/src/utils/traffic-mesh.js +++ /dev/null @@ -1,219 +0,0 @@ -// @ts-check -const { EOL } = require('os') -const path = require('path') -const process = require('process') -const rl = require('readline') - -const { getBinaryPath } = require('@netlify/routing-local-proxy') -const waitPort = require('wait-port') - -const { getPathInProject } = require('../lib/settings') -const { clearSpinner, startSpinner, stopSpinner } = require('../lib/spinner') - -const { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, log } = require('./command-helpers') -const { createDeferred } = require('./deferred') -const execa = require('./execa') - -const EDGE_HANDLERS_BUNDLER_CLI_PATH = path.resolve(require.resolve('@netlify/plugin-edge-handlers'), '..', 'cli.js') - -const startForwardProxy = async ({ - debug, - frameworkPort, - functionsPort, - jwtRolesPath, - jwtSecret, - locationDb, - port, - publishDir, -}) => { - const args = [ - 'run', - '--port', - port, - '--forward-proxy', - `http://localhost:${frameworkPort}`, - '--watch', - publishDir, - '--bundler', - EDGE_HANDLERS_BUNDLER_CLI_PATH, - '--log-file', - getPathInProject(['logs', 'traffic-mesh.log']), - '--progress', - ] - - if (functionsPort) { - args.push('--local-services-uri', `http://localhost:${functionsPort}`) - } - - if (debug) { - args.push('--debug') - } - - if (locationDb) { - args.push('--geo', locationDb) - } - - if (jwtRolesPath) { - args.push('--jwt-roles-path', jwtRolesPath) - } - - if (jwtSecret) { - args.push('--signature-secret', jwtSecret) - } - - const { subprocess } = runProcess({ args }) - const { firstBundleReady, forwarder } = forwardMessagesToLog({ subprocess }) - - subprocess.on('close', process.exit) - subprocess.on('SIGINT', process.exit) - subprocess.on('SIGTERM', process.exit) - ;['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP', 'exit'].forEach((signal) => { - process.on(signal, () => { - forwarder.close() - - const sig = signal === 'exit' ? 'SIGTERM' : signal - subprocess.kill(sig, { - forceKillAfterTimeout: PROXY_EXIT_TIMEOUT, - }) - }) - }) - - // Wait until the first traffic-mesh bundle is ready - // - // In case of errors, this delays the startup process until the errors are fixed - await firstBundleReady - - try { - const open = await waitPort({ port, output: 'silent', timeout: PROXY_READY_TIMEOUT }) - if (!open) { - throw new Error(`Timed out waiting for forward proxy to be ready on port '${port}'`) - } - return `http://localhost:${port}` - } catch (error) { - log(`${NETLIFYDEVERR}`, error) - } -} - -const forwardMessagesToLog = ({ subprocess }) => { - const { promise: firstBundleReady, reject: firstBundleReject, resolve: firstBundleResolve } = createDeferred() - - let currentId = null - let lastError = null - let lastWasSuccess = false - let spinner = null - - const reset = () => { - currentId = null - spinner = null - } - - const forwarder = rl.createInterface({ - input: subprocess.stderr, - }) - - forwarder - .on('line', (line) => { - let data - try { - data = JSON.parse(line.trim()) - } catch (error) { - log(`${NETLIFYDEVERR} Cannot parse log line as JSON: ${line.trim()}${EOL}${EOL}${error}`) - return - } - - const { error, id, type } = data - switch (type) { - case 'bundle:start': - currentId = id - if (!spinner) { - spinner = startSpinner({ text: 'Processing request remaps, header rules and Edge Handlers...' }) - } - break - - case 'bundle:success': - if (currentId !== id) { - return - } - - // Clear spinner if there already is a log line indicating success above, - // instead of appending another line of "Yay, your project was bundled!" - if (lastWasSuccess) { - clearSpinner({ spinner }) - } else { - stopSpinner({ - spinner, - error: false, - text: 'Done processing request remaps, header rules and Edge Handlers', - }) - } - lastWasSuccess = true - lastError = null - - firstBundleResolve() - reset() - break - - case 'bundle:fail': { - if (currentId !== id) { - return - } - - // Only show the error if it's new - const errorMsg = (error && error.msg) || 'Failed processing request remaps, header rules or Edge Handlers' - if (errorMsg === lastError) { - clearSpinner({ spinner }) - } else { - stopSpinner({ - spinner, - error: true, - text: errorMsg, - }) - log( - `${NETLIFYDEVLOG} Change any project configuration file (netlify.toml, _headers, _redirects) or any Edge Handlers file to trigger a re-bundle`, - ) - } - - lastWasSuccess = false - lastError = errorMsg - reset() - break - } - - default: - log(`${NETLIFYDEVWARN} Unknown routing-local-proxy event '${type}'`) - break - } - }) - .on('close', () => { - if (spinner) { - // Hide the spinner - spinner.stop() - } - - reset() - }) - .on('error', (err) => { - stopSpinner({ - spinner, - error: true, - text: `${NETLIFYDEVERR} An error occurred while bundling processing the messages from routing-local-proxy: ${err}`, - }) - - firstBundleReject(err) - reset() - }) - - return { forwarder, firstBundleReady } -} - -// 30 seconds -const PROXY_READY_TIMEOUT = 3e4 -// 2 seconds -const PROXY_EXIT_TIMEOUT = 2e3 - -const runProcess = ({ args }) => { - const subprocess = execa(getBinaryPath(), args, { stdio: ['inherit', 'inherit', 'pipe'] }) - return { subprocess } -} - -module.exports = { runProcess, startForwardProxy } diff --git a/tests/integration/0.command.dev.test.js b/tests/integration/0.command.dev.test.js index adfd0c4ac57..a53c90bf120 100644 --- a/tests/integration/0.command.dev.test.js +++ b/tests/integration/0.command.dev.test.js @@ -4,6 +4,7 @@ const http = require('http') // eslint-disable-next-line ava/use-test const avaTest = require('ava') const { isCI } = require('ci-info') +const fetch = require('node-fetch') const { withDevServer } = require('./utils/dev-server') const { startExternalServer } = require('./utils/external-server') @@ -12,305 +13,343 @@ const { withSiteBuilder } = require('./utils/site-builder') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest -const testMatrix = [ - { args: [] }, +test('should return 404.html if exists for non existing routes', async (t) => { + await withSiteBuilder('site-with-shadowing-404', async (builder) => { + builder.withContentFile({ + path: '404.html', + content: '

404 - Page not found

', + }) - // some tests are still failing with this enabled - // { args: ['--edgeHandlers'] } -] + await builder.buildAsync() -const testName = (title, args) => (args.length <= 0 ? title : `${title} - ${args.join(' ')}`) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/non-existent`, { throwHttpErrors: false }) + t.is(response.headers.etag, undefined) + t.is(response.body, '

404 - Page not found

') + }) + }) +}) -testMatrix.forEach(({ args }) => { - test(testName('should return 404.html if exists for non existing routes', args), async (t) => { - await withSiteBuilder('site-with-shadowing-404', async (builder) => { - builder.withContentFile({ - path: '404.html', - content: '

404 - Page not found

', +test('should return 404.html from publish folder if exists for non existing routes', async (t) => { + await withSiteBuilder('site-with-shadowing-404-in-publish-folder', async (builder) => { + builder + .withContentFile({ + path: 'public/404.html', + content: '

404 - My Custom 404 Page

', + }) + .withNetlifyToml({ + config: { + build: { + publish: 'public/', + }, + }, }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/non-existent`, { throwHttpErrors: false }) - t.is(response.body, '

404 - Page not found

') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/non-existent`, { throwHttpErrors: false }) + t.is(response.statusCode, 404) + t.is(response.headers.etag, undefined) + t.is(response.body, '

404 - My Custom 404 Page

') }) }) +}) - test(testName('should return 404.html from publish folder if exists for non existing routes', args), async (t) => { - await withSiteBuilder('site-with-shadowing-404-in-publish-folder', async (builder) => { - builder - .withContentFile({ - path: 'public/404.html', - content: '

404 - My Custom 404 Page

', - }) - .withNetlifyToml({ - config: { - build: { - publish: 'public/', - }, - }, - }) +test('should return 404 for redirect', async (t) => { + await withSiteBuilder('site-with-shadowing-404-redirect', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/test-404', to: '/foo', status: 404 }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/non-existent`, { throwHttpErrors: false }) - t.is(response.statusCode, 404) - t.is(response.body, '

404 - My Custom 404 Page

') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/test-404`, { throwHttpErrors: false }) + t.truthy(response.headers.etag) + t.is(response.statusCode, 404) + t.is(response.body, '

foo') }) }) +}) - test(testName('should return 404 for redirect', args), async (t) => { - await withSiteBuilder('site-with-shadowing-404-redirect', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/test-404', to: '/foo', status: 404 }], - }, - }) +test('should ignore 404 redirect for existing file', async (t) => { + await withSiteBuilder('site-with-shadowing-404-redirect-existing', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: 'test-404.html', + content: '

This page actually exists', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/test-404', to: '/foo', status: 404 }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/test-404`, { throwHttpErrors: false }) - t.is(response.statusCode, 404) - t.is(response.body, '

foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/test-404`) + + t.is(response.statusCode, 200) + t.is(response.body, '

This page actually exists') }) }) +}) - test(testName('should ignore 404 redirect for existing file', args), async (t) => { - await withSiteBuilder('site-with-shadowing-404-redirect-existing', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: 'test-404.html', - content: '

This page actually exists', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/test-404', to: '/foo', status: 404 }], - }, - }) +test('should follow 404 redirect even with existing file when force=true', async (t) => { + await withSiteBuilder('site-with-shadowing-404-redirect-force', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: 'test-404.html', + content: '

This page actually exists', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/test-404', to: '/foo', status: 404, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/test-404`) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/test-404`, { throwHttpErrors: false }) - t.is(response.statusCode, 200) - t.is(response.body, '

This page actually exists') - }) + t.is(response.statusCode, 404) + t.is(response.body, '

foo') }) }) +}) - test(testName('should follow 404 redirect even with existing file when force=true', args), async (t) => { - await withSiteBuilder('site-with-shadowing-404-redirect-force', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: 'test-404.html', - content: '

This page actually exists', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/test-404', to: '/foo', status: 404, force: true }], - }, - }) +test('should source redirects file from publish directory', async (t) => { + await withSiteBuilder('site-redirects-file-inside-publish', async (builder) => { + builder + .withContentFile({ + path: 'public/index.html', + content: 'index', + }) + .withRedirectsFile({ + pathPrefix: 'public', + redirects: [{ from: '/*', to: `/index.html`, status: 200 }], + }) + .withNetlifyToml({ + config: { + build: { publish: 'public' }, + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/test-404`, { throwHttpErrors: false }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/test`) - t.is(response.statusCode, 404) - t.is(response.body, '

foo') - }) + t.is(response.statusCode, 200) + t.is(response.body, 'index') }) }) +}) - test(testName('should source redirects file from publish directory', args), async (t) => { - await withSiteBuilder('site-redirects-file-inside-publish', async (builder) => { - builder - .withContentFile({ - path: 'public/index.html', - content: 'index', - }) - .withRedirectsFile({ - pathPrefix: 'public', - redirects: [{ from: '/*', to: `/index.html`, status: 200 }], - }) - .withNetlifyToml({ - config: { - build: { publish: 'public' }, - }, - }) +test('should redirect requests to an external server', async (t) => { + await withSiteBuilder('site-redirects-file-to-external', async (builder) => { + const externalServer = startExternalServer() + const { port } = externalServer.address() + builder.withRedirectsFile({ + redirects: [{ from: '/api/*', to: `http://localhost:${port}/:splat`, status: 200 }], + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/test`) + await withDevServer({ cwd: builder.directory }, async (server) => { + const getResponse = await got(`${server.url}/api/ping`).json() + t.deepEqual(getResponse, { body: {}, method: 'GET', url: '/ping' }) - t.is(response.statusCode, 200) - t.is(response.body, 'index') - }) + const postResponse = await got + .post(`${server.url}/api/ping`, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: 'param=value', + }) + .json() + t.deepEqual(postResponse, { body: { param: 'value' }, method: 'POST', url: '/ping' }) }) + + externalServer.close() }) +}) - test(testName('should redirect requests to an external server', args), async (t) => { - await withSiteBuilder('site-redirects-file-to-external', async (builder) => { - const externalServer = startExternalServer() - const { port } = externalServer.address() - builder.withRedirectsFile({ - redirects: [{ from: '/api/*', to: `http://localhost:${port}/:splat`, status: 200 }], - }) +test('should follow 301 redirect to an external server', async (t) => { + await withSiteBuilder('site-redirects-file-to-external-301', async (builder) => { + const externalServer = startExternalServer() + const { port } = externalServer.address() + builder.withRedirectsFile({ + redirects: [{ from: '/api/*', to: `http://localhost:${port}/:splat`, status: 301 }], + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const getResponse = await got(`${server.url}/api/ping`).json() - t.deepEqual(getResponse, { body: {}, method: 'GET', url: '/ping' }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/api/ping`).json() + t.deepEqual(response, { body: {}, method: 'GET', url: '/ping' }) + }) + + externalServer.close() + }) +}) + +test('should redirect POST request if content-type is missing', async (t) => { + await withSiteBuilder('site-with-post-no-content-type', async (builder) => { + builder.withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/other/:splat', status: 200 }], + }, + }) - const postResponse = await got - .post(`${server.url}/api/ping`, { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: 'param=value', + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const options = { + host: server.host, + port: server.port, + path: '/api/echo', + method: 'POST', + } + let data = '' + await new Promise((resolve) => { + const callback = (response) => { + response.on('data', (chunk) => { + data += chunk }) - .json() - t.deepEqual(postResponse, { body: { param: 'value' }, method: 'POST', url: '/ping' }) + response.on('end', resolve) + } + const req = http.request(options, callback) + req.write('param=value') + req.end() }) - externalServer.close() + // we're testing Netlify Dev didn't crash + t.is(data, 'Method Not Allowed') }) }) +}) - test(testName('should follow 301 redirect to an external server', args), async (t) => { - await withSiteBuilder('site-redirects-file-to-external-301', async (builder) => { - const externalServer = startExternalServer() - const { port } = externalServer.address() - builder.withRedirectsFile({ - redirects: [{ from: '/api/*', to: `http://localhost:${port}/:splat`, status: 301 }], +test('should return .html file when file and folder have the same name', async (t) => { + await withSiteBuilder('site-with-same-name-for-file-and-folder', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: 'foo/file.html', + content: '

file in folder', }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/api/ping`).json() - t.deepEqual(response, { body: {}, method: 'GET', url: '/ping' }) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo`) - externalServer.close() + t.is(response.statusCode, 200) + t.is(response.body, '

foo') }) }) +}) - test(testName('should redirect POST request if content-type is missing', args), async (t) => { - await withSiteBuilder('site-with-post-no-content-type', async (builder) => { - builder.withNetlifyToml({ +test('should not shadow an existing file that has unsafe URL characters', async (t) => { + await withSiteBuilder('site-with-unsafe-url-file-names', async (builder) => { + builder + .withContentFile({ + path: 'public/index.html', + content: 'index', + }) + .withContentFile({ + path: 'public/files/file with spaces.html', + content: 'file with spaces', + }) + .withContentFile({ + path: 'public/files/[file_with_brackets].html', + content: 'file with brackets', + }) + .withNetlifyToml({ config: { - functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/other/:splat', status: 200 }], + build: { publish: 'public' }, + redirects: [{ from: '/*', to: '/index.html', status: 200 }], }, }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const options = { - host: server.host, - port: server.port, - path: '/api/echo', - method: 'POST', - } - let data = '' - await new Promise((resolve) => { - const callback = (response) => { - response.on('data', (chunk) => { - data += chunk - }) - response.on('end', resolve) - } - const req = http.request(options, callback) - req.write('param=value') - req.end() - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const [spaces, brackets] = await Promise.all([ + got(`${server.url}/files/file with spaces`).text(), + got(`${server.url}/files/[file_with_brackets]`).text(), + ]) - // we're testing Netlify Dev didn't crash - t.is(data, 'Method Not Allowed') - }) + t.is(spaces, 'file with spaces') + t.is(brackets, 'file with brackets') }) }) +}) - test(testName('should return .html file when file and folder have the same name', args), async (t) => { - await withSiteBuilder('site-with-same-name-for-file-and-folder', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: 'foo/file.html', - content: '

file in folder', - }) +test('should generate an ETag for static assets', async (t) => { + await withSiteBuilder('site-with-static-assets', async (builder) => { + builder + .withContentFile({ + path: 'public/index.html', + content: 'index', + }) + .withNetlifyToml({ + config: { + build: { publish: 'public' }, + redirects: [{ from: '/*', to: '/index.html', status: 200 }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo`) + await withDevServer({ cwd: builder.directory }, async (server) => { + const res1 = await fetch(`${server.url}`) + const etag = res1.headers.get('etag') - t.is(response.statusCode, 200) - t.is(response.body, '

foo') - }) - }) - }) - - test(testName('should not shadow an existing file that has unsafe URL characters', args), async (t) => { - await withSiteBuilder('site-with-unsafe-url-file-names', async (builder) => { - builder - .withContentFile({ - path: 'public/index.html', - content: 'index', - }) - .withContentFile({ - path: 'public/files/file with spaces.html', - content: 'file with spaces', - }) - .withContentFile({ - path: 'public/files/[file_with_brackets].html', - content: 'file with brackets', - }) - .withNetlifyToml({ - config: { - build: { publish: 'public' }, - redirects: [{ from: '/*', to: '/index.html', status: 200 }], - }, - }) + t.truthy(etag) + t.is(res1.status, 200) + t.truthy(await res1.text()) - await builder.buildAsync() + const res2 = await fetch(`${server.url}`, { + headers: { + 'if-none-match': etag, + }, + }) - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const [spaces, brackets] = await Promise.all([ - got(`${server.url}/files/file with spaces`).text(), - got(`${server.url}/files/[file_with_brackets]`).text(), - ]) + t.is(res2.status, 304) + t.falsy(await res2.text()) - t.is(spaces, 'file with spaces') - t.is(brackets, 'file with brackets') + const res3 = await fetch(`${server.url}`, { + headers: { + 'if-none-match': 'stale-etag', + }, }) + + t.truthy(res3.headers.get('etag')) + t.is(res3.status, 200) + t.truthy(await res3.text()) }) }) }) diff --git a/tests/integration/100.command.dev.test.js b/tests/integration/100.command.dev.test.js index da7e5bf8926..273e3bcf0e9 100644 --- a/tests/integration/100.command.dev.test.js +++ b/tests/integration/100.command.dev.test.js @@ -7,6 +7,7 @@ const avaTest = require('ava') const { isCI } = require('ci-info') const dotProp = require('dot-prop') const jwt = require('jsonwebtoken') +const { Response } = require('node-fetch') const { withDevServer } = require('./utils/dev-server') const got = require('./utils/got') @@ -14,15 +15,6 @@ const { withSiteBuilder } = require('./utils/site-builder') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest -const testMatrix = [ - { args: [] }, - - // some tests are still failing with this enabled - // { args: ['--edgeHandlers'] } -] - -const testName = (title, args) => (args.length <= 0 ? title : `${title} - ${args.join(' ')}`) - const JWT_EXPIRY = 1_893_456_000 const getToken = ({ jwtRolePath = 'app_metadata.authorization.roles', jwtSecret = 'secret', roles }) => { const payload = { @@ -50,11 +42,11 @@ const setupRoleBasedRedirectsSite = (builder) => { return builder } -const validateRoleBasedRedirectsSite = async ({ args, builder, jwtRolePath, jwtSecret, t }) => { +const validateRoleBasedRedirectsSite = async ({ builder, jwtRolePath, jwtSecret, t }) => { const adminToken = getToken({ jwtSecret, jwtRolePath, roles: ['admin'] }) const editorToken = getToken({ jwtSecret, jwtRolePath, roles: ['editor'] }) - await withDevServer({ cwd: builder.directory, args }, async (server) => { + await withDevServer({ cwd: builder.directory }, async (server) => { const unauthenticatedResponse = await got(`${server.url}/admin`, { throwHttpErrors: false }) t.is(unauthenticatedResponse.statusCode, 404) t.is(unauthenticatedResponse.body, 'Not Found') @@ -78,321 +70,310 @@ const validateRoleBasedRedirectsSite = async ({ args, builder, jwtRolePath, jwtS }) } -testMatrix.forEach(({ args }) => { - test(testName('should follow redirect for fully qualified rule', args), async (t) => { - await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { - const publicDir = 'public' - builder - .withNetlifyToml({ - config: { - build: { publish: publicDir }, - }, - }) - .withContentFiles([ - { - path: path.join(publicDir, 'index.html'), - content: 'index', - }, - { - path: path.join(publicDir, 'local-hello.html'), - content: 'hello', - }, - ]) - .withRedirectsFile({ - redirects: [{ from: `http://localhost/hello-world`, to: `/local-hello`, status: 200 }], - }) +test('should follow redirect for fully qualified rule', async (t) => { + await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { + const publicDir = 'public' + builder + .withNetlifyToml({ + config: { + build: { publish: publicDir }, + }, + }) + .withContentFiles([ + { + path: path.join(publicDir, 'index.html'), + content: 'index', + }, + { + path: path.join(publicDir, 'local-hello.html'), + content: 'hello', + }, + ]) + .withRedirectsFile({ + redirects: [{ from: `http://localhost/hello-world`, to: `/local-hello`, status: 200 }], + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/hello-world`) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/hello-world`) - t.is(response.statusCode, 200) - t.is(response.body, 'hello') - }) + t.is(response.statusCode, 200) + t.is(response.body, 'hello') }) }) +}) - test(testName('should return 202 ok and empty response for background function', args), async (t) => { - await withSiteBuilder('site-with-background-function', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ - path: 'hello-background.js', - handler: () => { - console.log("Look at me I'm a background task") - }, - }) +test('should return 202 ok and empty response for background function', async (t) => { + await withSiteBuilder('site-with-background-function', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'hello-background.js', + handler: () => { + console.log("Look at me I'm a background task") + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/hello-background`) - t.is(response.statusCode, 202) - t.is(response.body, '') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/hello-background`) + t.is(response.statusCode, 202) + t.is(response.body, '') }) }) +}) - test(testName('background function clientContext,identity should be null', args), async (t) => { - await withSiteBuilder('site-with-background-function', async (builder) => { - await builder - .withNetlifyToml({ config: { functions: { directory: 'functions' } } }) - .withFunction({ - path: 'hello-background.js', - handler: (_, context) => { - console.log(`__CLIENT_CONTEXT__START__${JSON.stringify(context)}__CLIENT_CONTEXT__END__`) - }, - }) - .buildAsync() +test('background function clientContext,identity should be null', async (t) => { + await withSiteBuilder('site-with-background-function', async (builder) => { + await builder + .withNetlifyToml({ config: { functions: { directory: 'functions' } } }) + .withFunction({ + path: 'hello-background.js', + handler: (_, context) => { + console.log(`__CLIENT_CONTEXT__START__${JSON.stringify(context)}__CLIENT_CONTEXT__END__`) + }, + }) + .buildAsync() - await withDevServer({ cwd: builder.directory, args }, async ({ outputBuffer, url }) => { - await got(`${url}/.netlify/functions/hello-background`) + await withDevServer({ cwd: builder.directory }, async ({ outputBuffer, url }) => { + await got(`${url}/.netlify/functions/hello-background`) - const output = outputBuffer.toString() - const context = JSON.parse(output.match(/__CLIENT_CONTEXT__START__(.*)__CLIENT_CONTEXT__END__/)[1]) - t.is(context.clientContext, null) - t.is(context.identity, null) - }) + const output = outputBuffer.toString() + const context = JSON.parse(output.match(/__CLIENT_CONTEXT__START__(.*)__CLIENT_CONTEXT__END__/)[1]) + t.is(context.clientContext, null) + t.is(context.identity, null) }) }) +}) - test(testName('should enforce role based redirects with default secret and role path', args), async (t) => { - await withSiteBuilder('site-with-default-role-based-redirects', async (builder) => { - setupRoleBasedRedirectsSite(builder) - await builder.buildAsync() - await validateRoleBasedRedirectsSite({ builder, args, t }) - }) +test('should enforce role based redirects with default secret and role path', async (t) => { + await withSiteBuilder('site-with-default-role-based-redirects', async (builder) => { + setupRoleBasedRedirectsSite(builder) + await builder.buildAsync() + await validateRoleBasedRedirectsSite({ builder, t }) }) +}) - test(testName('should enforce role based redirects with custom secret and role path', args), async (t) => { - await withSiteBuilder('site-with-custom-role-based-redirects', async (builder) => { - const jwtSecret = 'custom' - const jwtRolePath = 'roles' - setupRoleBasedRedirectsSite(builder).withNetlifyToml({ - config: { - dev: { - jwtSecret, - jwtRolePath, - }, +test('should enforce role based redirects with custom secret and role path', async (t) => { + await withSiteBuilder('site-with-custom-role-based-redirects', async (builder) => { + const jwtSecret = 'custom' + const jwtRolePath = 'roles' + setupRoleBasedRedirectsSite(builder).withNetlifyToml({ + config: { + dev: { + jwtSecret, + jwtRolePath, }, - }) - await builder.buildAsync() - await validateRoleBasedRedirectsSite({ builder, args, t, jwtSecret, jwtRolePath }) + }, }) + await builder.buildAsync() + await validateRoleBasedRedirectsSite({ builder, t, jwtSecret, jwtRolePath }) }) +}) - test(testName('routing-local-proxy serves edge handlers with --edgeHandlers flag', args), async (t) => { - await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { - const publicDir = 'public' - builder - .withNetlifyToml({ - config: { - build: { - publish: publicDir, - edge_handlers: 'netlify/edge-handlers', - }, - 'edge-handlers': [ - { - handler: 'smoke', - path: '/edge-handler', - }, - ], - }, - }) - .withContentFiles([ - { - path: path.join(publicDir, 'index.html'), - content: 'index', +test('Serves an Edge Function that terminates a response', async (t) => { + await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { + const publicDir = 'public' + builder + .withNetlifyToml({ + config: { + build: { + publish: publicDir, + edge_functions: 'netlify/edge-functions', }, - ]) - .withEdgeHandlers({ - fileName: 'smoke.js', - handlers: { - onRequest: (event) => { - event.replaceResponse( - // eslint-disable-next-line no-undef - new Response(null, { - headers: { - Location: 'https://google.com/', - }, - status: 301, - }), - ) + edge_functions: [ + { + function: 'hello', + path: '/edge-function', }, - }, - }) + ], + }, + }) + .withContentFiles([ + { + path: path.join(publicDir, 'index.html'), + content: 'index', + }, + ]) + .withEdgeFunction({ + handler: () => new Response('Hello world'), + name: 'hello', + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args: [...args, '--edgeHandlers'] }, async (server) => { - const response = await got(`${server.url}/edge-handler`, { - followRedirect: false, - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/edge-function`) - t.is(response.statusCode, 301) - t.is(response.headers.location, 'https://google.com/') - }) + t.is(response.statusCode, 200) + t.is(response.body, 'Hello world') }) }) +}) - test(testName('routing-local-proxy serves edge handlers with deprecated --trafficMesh flag', args), async (t) => { - await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { - const publicDir = 'public' - builder - .withNetlifyToml({ - config: { - build: { - publish: publicDir, - edge_handlers: 'netlify/edge-handlers', - }, - 'edge-handlers': [ - { - handler: 'smoke', - path: '/edge-handler', - }, - ], - }, - }) - .withContentFiles([ - { - path: path.join(publicDir, 'index.html'), - content: 'index', +test('Serves an Edge Function with a rewrite', async (t) => { + await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { + const publicDir = 'public' + builder + .withNetlifyToml({ + config: { + build: { + publish: publicDir, + edge_functions: 'netlify/edge-functions', }, - ]) - .withEdgeHandlers({ - fileName: 'smoke.js', - handlers: { - onRequest: (event) => { - event.replaceResponse( - // eslint-disable-next-line no-undef - new Response(null, { - headers: { - Location: 'https://google.com/', - }, - status: 301, - }), - ) + edge_functions: [ + { + function: 'hello', + path: '/edge-function', }, - }, - }) + ], + }, + }) + .withContentFiles([ + { + path: path.join(publicDir, 'goodbye.html'), + content: 'goodbye', + }, + ]) + .withEdgeFunction({ + handler: (_, context) => context.rewrite('/goodbye'), + name: 'hello', + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args: [...args, '--trafficMesh'] }, async (server) => { - const response = await got(`${server.url}/edge-handler`, { - followRedirect: false, - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/edge-function`) - t.is(response.statusCode, 301) - t.is(response.headers.location, 'https://google.com/') - }) + t.is(response.statusCode, 200) + t.is(response.body, 'goodbye') }) }) +}) - test(testName('routing-local-proxy builds projects w/o edge handlers', args), async (t) => { - await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { - const publicDir = 'public' - builder - .withNetlifyToml({ - config: { - build: { publish: publicDir }, - }, - }) - .withContentFiles([ - { - path: path.join(publicDir, 'index.html'), - content: 'index', +test('Serves an Edge Function that transforms the response', async (t) => { + await withSiteBuilder('site-with-fully-qualified-redirect-rule', async (builder) => { + const publicDir = 'public' + builder + .withNetlifyToml({ + config: { + build: { + publish: publicDir, + edge_functions: 'netlify/edge-functions', }, - ]) + edge_functions: [ + { + function: 'yell', + path: '/*', + }, + ], + }, + }) + .withContentFiles([ + { + path: path.join(publicDir, 'hello.html'), + content: 'hello', + }, + ]) + .withEdgeFunction({ + handler: async (_, context) => { + const resp = await context.next() + const text = await resp.text() - await builder.buildAsync() + return new Response(text.toUpperCase(), resp) + }, + name: 'yell', + }) - await withDevServer({ cwd: builder.directory, args: [...args, '--edgeHandlers'] }, async (server) => { - const response = await got(`${server.url}/index.html`) + await builder.buildAsync() - t.is(response.statusCode, 200) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/hello`) + + t.is(response.statusCode, 200) + t.is(response.body, 'HELLO') }) }) +}) - test(testName('redirect with country cookie', args), async (t) => { - await withSiteBuilder('site-with-country-cookie', async (builder) => { - builder - .withContentFiles([ - { - path: 'index.html', - content: 'index', - }, - { - path: 'index-es.html', - content: 'index in spanish', - }, - ]) - .withRedirectsFile({ - redirects: [{ from: `/`, to: `/index-es.html`, status: '200!', condition: 'Country=ES' }], - }) +test('redirect with country cookie', async (t) => { + await withSiteBuilder('site-with-country-cookie', async (builder) => { + builder + .withContentFiles([ + { + path: 'index.html', + content: 'index', + }, + { + path: 'index-es.html', + content: 'index in spanish', + }, + ]) + .withRedirectsFile({ + redirects: [{ from: `/`, to: `/index-es.html`, status: '200!', condition: 'Country=ES' }], + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/`, { - headers: { - cookie: `nf_country=ES`, - }, - }) - t.is(response.statusCode, 200) - t.is(response.body, 'index in spanish') + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/`, { + headers: { + cookie: `nf_country=ES`, + }, }) + t.is(response.statusCode, 200) + t.is(response.body, 'index in spanish') }) }) +}) - test(testName(`doesn't hang when sending a application/json POST request to function server`, args), async (t) => { - await withSiteBuilder('site-with-functions', async (builder) => { - const functionsPort = 6666 - await builder - .withNetlifyToml({ config: { functions: { directory: 'functions' }, dev: { functionsPort } } }) - .buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async ({ port, url }) => { - const response = await got(`${url.replace(port, functionsPort)}/test`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: '{}', - throwHttpErrors: false, - }) - t.is(response.statusCode, 404) - t.is(response.body, 'Function not found...') +test(`doesn't hang when sending a application/json POST request to function server`, async (t) => { + await withSiteBuilder('site-with-functions', async (builder) => { + const functionsPort = 6666 + await builder + .withNetlifyToml({ config: { functions: { directory: 'functions' }, dev: { functionsPort } } }) + .buildAsync() + + await withDevServer({ cwd: builder.directory }, async ({ port, url }) => { + const response = await got(`${url.replace(port, functionsPort)}/test`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: '{}', + throwHttpErrors: false, }) + t.is(response.statusCode, 404) + t.is(response.body, 'Function not found...') }) }) +}) - test(testName(`catches invalid function names`, args), async (t) => { - await withSiteBuilder('site-with-functions', async (builder) => { - const functionsPort = 6667 - await builder - .withNetlifyToml({ config: { functions: { directory: 'functions' }, dev: { functionsPort } } }) - .withFunction({ - path: 'exclamat!on.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - .buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async ({ port, url }) => { - const response = await got(`${url.replace(port, functionsPort)}/exclamat!on`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: '{}', - throwHttpErrors: false, - }) - t.is(response.statusCode, 400) - t.is(response.body, 'Function name should consist only of alphanumeric characters, hyphen & underscores.') +test(`catches invalid function names`, async (t) => { + await withSiteBuilder('site-with-functions', async (builder) => { + const functionsPort = 6667 + await builder + .withNetlifyToml({ config: { functions: { directory: 'functions' }, dev: { functionsPort } } }) + .withFunction({ + path: 'exclamat!on.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) + .buildAsync() + + await withDevServer({ cwd: builder.directory }, async ({ port, url }) => { + const response = await got(`${url.replace(port, functionsPort)}/exclamat!on`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: '{}', + throwHttpErrors: false, }) + t.is(response.statusCode, 400) + t.is(response.body, 'Function name should consist only of alphanumeric characters, hyphen & underscores.') }) }) }) diff --git a/tests/integration/200.command.dev.test.js b/tests/integration/200.command.dev.test.js index fd884f03eb5..c9d0e5bd90b 100644 --- a/tests/integration/200.command.dev.test.js +++ b/tests/integration/200.command.dev.test.js @@ -16,12 +16,7 @@ const { withSiteBuilder } = require('./utils/site-builder') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest -const testMatrix = [ - { args: [] }, - - // some tests are still failing with this enabled - // { args: ['--edgeHandlers'] } -] +const testMatrix = [{ args: [] }] const testName = (title, args) => (args.length <= 0 ? title : `${title} - ${args.join(' ')}`) @@ -363,9 +358,11 @@ export const handler = async function () { await withDevServer({ cwd: builder.directory, args }, async (server) => { const response = await got(`${server.url}/.netlify/functions/custom-headers`) + t.falsy(response.headers.etag) t.is(response.headers['single-value-header'], 'custom-value') t.is(response.headers['multi-value-header'], 'custom-value1, custom-value2') const builderResponse = await got(`${server.url}/.netlify/builders/custom-headers`) + t.falsy(builderResponse.headers.etag) t.is(builderResponse.headers['single-value-header'], 'custom-value') t.is(builderResponse.headers['multi-value-header'], 'custom-value1, custom-value2') }) diff --git a/tests/integration/210.command.deploy.test.js b/tests/integration/210.command.deploy.test.js index 7cf0cc4fe1f..e888d0d9130 100644 --- a/tests/integration/210.command.deploy.test.js +++ b/tests/integration/210.command.deploy.test.js @@ -3,17 +3,13 @@ const { join } = require('path') const process = require('process') const test = require('ava') -const omit = require('omit.js').default - -const { supportsEdgeHandlers } = require('../../src/lib/account') -const { getToken } = require('../../src/utils/command-helpers') +const { Response } = require('node-fetch') const callCli = require('./utils/call-cli') const { createLiveTestSite, generateSiteName } = require('./utils/create-live-test-site') const got = require('./utils/got') const { withSiteBuilder } = require('./utils/site-builder') -const EDGE_HANDLER_MIN_LENGTH = 50 const SITE_NAME = generateSiteName('netlify-test-deploy-') const validateContent = async ({ content, path, siteUrl, t }) => { @@ -117,13 +113,10 @@ if (process.env.NETLIFY_TEST_DISABLE_LIVE !== 'true') { }) }) - test.serial('should deploy edge handlers when directory exists', async (t) => { - if (!supportsEdgeHandlers(t.context.account)) { - console.warn(`Skipping edge handlers deploy test for account ${t.context.account.slug}`) - return - } + // TODO: Re-add when feature flag is no longer needed. + test.serial.skip('should deploy Edge Functions when directory exists', async (t) => { await withSiteBuilder('site-with-public-folder', async (builder) => { - const content = '

⊂◉‿◉つ

' + const content = '

loud

' builder .withContentFile({ path: 'public/index.html', @@ -131,15 +124,18 @@ if (process.env.NETLIFY_TEST_DISABLE_LIVE !== 'true') { }) .withNetlifyToml({ config: { - build: { publish: 'public', command: 'echo "no op"', edge_handlers: 'netlify/edge-handlers' }, + build: { publish: 'public', command: 'echo "no op"' }, + edge_functions: [{ function: 'yell', path: '/*' }], }, }) - .withEdgeHandlers({ - handlers: { - onRequest: (event) => { - console.log(`Incoming request for ${event.request.url}`) - }, + .withEdgeFunction({ + handler: async (_, context) => { + const resp = await context.next() + const text = await resp.text() + + return new Response(text.toUpperCase(), resp) }, + name: 'yell', }) await builder.buildAsync() @@ -148,31 +144,11 @@ if (process.env.NETLIFY_TEST_DISABLE_LIVE !== 'true') { cwd: builder.directory, env: { NETLIFY_SITE_ID: t.context.siteId }, } - // build the edge handlers first + await callCli(['build'], options) const deploy = await callCli(['deploy', '--json'], options).then((output) => JSON.parse(output)) - await validateDeploy({ deploy, siteName: SITE_NAME, content, t }) - - // validate edge handlers - // use this until we can use `netlify api` - const [apiToken] = await getToken() - const { content_length: contentLength, ...rest } = await got( - `https://api.netlify.com/api/v1/deploys/${deploy.deploy_id}/edge_handlers`, - { - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${apiToken}`, - }, - }, - ).json() - - t.deepEqual(omit(rest, ['created_at', 'sha']), { - content_type: 'application/javascript', - handlers: ['index'], - valid: true, - }) - t.is(contentLength > EDGE_HANDLER_MIN_LENGTH, true) + await validateDeploy({ deploy, siteName: SITE_NAME, content: content.toUpperCase(), t }) }) }) diff --git a/tests/integration/300.command.dev.test.js b/tests/integration/300.command.dev.test.js index d9179cc608b..98dd4025d76 100644 --- a/tests/integration/300.command.dev.test.js +++ b/tests/integration/300.command.dev.test.js @@ -13,180 +13,196 @@ const { withSiteBuilder } = require('./utils/site-builder') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest -const testMatrix = [ - { args: [] }, +test('should return index file when / is accessed', async (t) => { + await withSiteBuilder('site-with-index-file', async (builder) => { + builder.withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) - // some tests are still failing with this enabled - // { args: ['--edgeHandlers'] } -] + await builder.buildAsync() -const testName = (title, args) => (args.length <= 0 ? title : `${title} - ${args.join(' ')}`) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(server.url).text() + t.is(response, '

⊂◉‿◉つ

') + }) + }) +}) -testMatrix.forEach(({ args }) => { - test(testName('should return index file when / is accessed', args), async (t) => { - await withSiteBuilder('site-with-index-file', async (builder) => { - builder.withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) +test('should return user defined headers when / is accessed', async (t) => { + await withSiteBuilder('site-with-headers-on-root', async (builder) => { + builder.withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) - await builder.buildAsync() + const headerName = 'X-Frame-Options' + const headerValue = 'SAMEORIGIN' + builder.withHeadersFile({ headers: [{ path: '/*', headers: [`${headerName}: ${headerValue}`] }] }) - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(server.url).text() - t.is(response, '

⊂◉‿◉つ

') - }) + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const { headers } = await got(server.url) + t.is(headers[headerName.toLowerCase()], headerValue) }) }) +}) - test(testName('should return user defined headers when / is accessed', args), async (t) => { - await withSiteBuilder('site-with-headers-on-root', async (builder) => { - builder.withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) +test('should return user defined headers when non-root path is accessed', async (t) => { + await withSiteBuilder('site-with-headers-on-non-root', async (builder) => { + builder.withContentFile({ + path: 'foo/index.html', + content: '

⊂◉‿◉つ

', + }) - const headerName = 'X-Frame-Options' - const headerValue = 'SAMEORIGIN' - builder.withHeadersFile({ headers: [{ path: '/*', headers: [`${headerName}: ${headerValue}`] }] }) + const headerName = 'X-Frame-Options' + const headerValue = 'SAMEORIGIN' + builder.withHeadersFile({ headers: [{ path: '/*', headers: [`${headerName}: ${headerValue}`] }] }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const { headers } = await got(server.url) - t.is(headers[headerName.toLowerCase()], headerValue) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const { headers } = await got(`${server.url}/foo`) + t.is(headers[headerName.toLowerCase()], headerValue) }) }) +}) - test(testName('should return user defined headers when non-root path is accessed', args), async (t) => { - await withSiteBuilder('site-with-headers-on-non-root', async (builder) => { - builder.withContentFile({ - path: 'foo/index.html', - content: '

⊂◉‿◉つ

', - }) - - const headerName = 'X-Frame-Options' - const headerValue = 'SAMEORIGIN' - builder.withHeadersFile({ headers: [{ path: '/*', headers: [`${headerName}: ${headerValue}`] }] }) +test('should return response from a function with setTimeout', async (t) => { + await withSiteBuilder('site-with-set-timeout-function', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'timeout.js', + handler: async () => { + console.log('ding') + // Wait for 4 seconds + const FUNCTION_TIMEOUT = 4e3 + await new Promise((resolve) => { + setTimeout(resolve, FUNCTION_TIMEOUT) + }) + return { + statusCode: 200, + body: 'ping', + metadata: { builder_function: true }, + } + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const { headers } = await got(`${server.url}/foo`) - t.is(headers[headerName.toLowerCase()], headerValue) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/timeout`).text() + t.is(response, 'ping') + const builderResponse = await got(`${server.url}/.netlify/builders/timeout`).text() + t.is(builderResponse, 'ping') }) }) +}) - test(testName('should return response from a function with setTimeout', args), async (t) => { - await withSiteBuilder('site-with-set-timeout-function', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ - path: 'timeout.js', - handler: async () => { - console.log('ding') - // Wait for 4 seconds - const FUNCTION_TIMEOUT = 4e3 - await new Promise((resolve) => { - setTimeout(resolve, FUNCTION_TIMEOUT) - }) - return { - statusCode: 200, - body: 'ping', - metadata: { builder_function: true }, - } - }, - }) +test('should fail when no metadata is set for builder function', async (t) => { + await withSiteBuilder('site-with-misconfigured-builder-function', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'builder.js', + handler: async () => ({ + statusCode: 200, + body: 'ping', + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/timeout`).text() - t.is(response, 'ping') - const builderResponse = await got(`${server.url}/.netlify/builders/timeout`).text() - t.is(builderResponse, 'ping') + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/builder`) + t.is(response.body, 'ping') + t.is(response.statusCode, 200) + const builderResponse = await got(`${server.url}/.netlify/builders/builder`, { + throwHttpErrors: false, }) + t.is( + builderResponse.body, + `{"message":"Function is not an on-demand builder. See https://ntl.fyi/create-builder for how to convert a function to a builder."}`, + ) + t.is(builderResponse.statusCode, 400) }) }) +}) - test(testName('should fail when no metadata is set for builder function', args), async (t) => { - await withSiteBuilder('site-with-misconfigured-builder-function', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ - path: 'builder.js', - handler: async () => ({ - statusCode: 200, - body: 'ping', - }), - }) +test('should serve function from a subdirectory', async (t) => { + await withSiteBuilder('site-with-from-subdirectory', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: path.join('echo', 'echo.js'), + handler: async () => ({ + statusCode: 200, + body: 'ping', + metadata: { builder_function: true }, + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/builder`) - t.is(response.body, 'ping') - t.is(response.statusCode, 200) - const builderResponse = await got(`${server.url}/.netlify/builders/builder`, { - throwHttpErrors: false, - }) - t.is( - builderResponse.body, - `{"message":"Function is not an on-demand builder. See https://ntl.fyi/create-builder for how to convert a function to a builder."}`, - ) - t.is(builderResponse.statusCode, 400) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/echo`).text() + t.is(response, 'ping') + const builderResponse = await got(`${server.url}/.netlify/builders/echo`).text() + t.is(builderResponse, 'ping') }) }) +}) - test(testName('should serve function from a subdirectory', args), async (t) => { - await withSiteBuilder('site-with-from-subdirectory', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ - path: path.join('echo', 'echo.js'), +test('should pass .env.development vars to function', async (t) => { + await withSiteBuilder('site-with-env-development', async (builder) => { + builder + .withNetlifyToml({ config: { functions: { directory: 'functions' } } }) + .withEnvFile({ path: '.env.development', env: { TEST: 'FROM_DEV_FILE' } }) + .withFunction({ + path: 'env.js', handler: async () => ({ statusCode: 200, - body: 'ping', + body: `${process.env.TEST}`, metadata: { builder_function: true }, }), }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/echo`).text() - t.is(response, 'ping') - const builderResponse = await got(`${server.url}/.netlify/builders/echo`).text() - t.is(builderResponse, 'ping') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'FROM_DEV_FILE') + const builderResponse = await got(`${server.url}/.netlify/builders/env`).text() + t.is(builderResponse, 'FROM_DEV_FILE') }) }) +}) - test(testName('should pass .env.development vars to function', args), async (t) => { - await withSiteBuilder('site-with-env-development', async (builder) => { - builder - .withNetlifyToml({ config: { functions: { directory: 'functions' } } }) - .withEnvFile({ path: '.env.development', env: { TEST: 'FROM_DEV_FILE' } }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}`, - metadata: { builder_function: true }, - }), - }) +test('should pass process env vars to function', async (t) => { + await withSiteBuilder('site-with-process-env', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'env.js', + handler: async () => ({ + statusCode: 200, + body: `${process.env.TEST}`, + metadata: { builder_function: true }, + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'FROM_DEV_FILE') - const builderResponse = await got(`${server.url}/.netlify/builders/env`).text() - t.is(builderResponse, 'FROM_DEV_FILE') - }) + await withDevServer({ cwd: builder.directory, env: { TEST: 'FROM_PROCESS_ENV' } }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'FROM_PROCESS_ENV') + const builderResponse = await got(`${server.url}/.netlify/builders/env`).text() + t.is(builderResponse, 'FROM_PROCESS_ENV') }) }) +}) - test(testName('should pass process env vars to function', args), async (t) => { - await withSiteBuilder('site-with-process-env', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ +test('should pass [build.environment] env vars to function', async (t) => { + await withSiteBuilder('site-with-build-environment', async (builder) => { + builder + .withNetlifyToml({ + config: { build: { environment: { TEST: 'FROM_CONFIG_FILE' } }, functions: { directory: 'functions' } }, + }) + .withFunction({ path: 'env.js', handler: async () => ({ statusCode: 200, @@ -195,101 +211,74 @@ testMatrix.forEach(({ args }) => { }), }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, env: { TEST: 'FROM_PROCESS_ENV' }, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'FROM_PROCESS_ENV') - const builderResponse = await got(`${server.url}/.netlify/builders/env`).text() - t.is(builderResponse, 'FROM_PROCESS_ENV') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'FROM_CONFIG_FILE') + const builderResponse = await got(`${server.url}/.netlify/builders/env`).text() + t.is(builderResponse, 'FROM_CONFIG_FILE') }) }) +}) - test(testName('should pass [build.environment] env vars to function', args), async (t) => { - await withSiteBuilder('site-with-build-environment', async (builder) => { - builder - .withNetlifyToml({ - config: { build: { environment: { TEST: 'FROM_CONFIG_FILE' } }, functions: { directory: 'functions' } }, - }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}`, - metadata: { builder_function: true }, - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'FROM_CONFIG_FILE') - const builderResponse = await got(`${server.url}/.netlify/builders/env`).text() - t.is(builderResponse, 'FROM_CONFIG_FILE') +test('[context.dev.environment] should override [build.environment]', async (t) => { + await withSiteBuilder('site-with-build-environment', async (builder) => { + builder + .withNetlifyToml({ + config: { + build: { environment: { TEST: 'DEFAULT_CONTEXT' } }, + context: { dev: { environment: { TEST: 'DEV_CONTEXT' } } }, + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'env.js', + handler: async () => ({ + statusCode: 200, + body: `${process.env.TEST}`, + }), }) - }) - }) - - test(testName('[context.dev.environment] should override [build.environment]', args), async (t) => { - await withSiteBuilder('site-with-build-environment', async (builder) => { - builder - .withNetlifyToml({ - config: { - build: { environment: { TEST: 'DEFAULT_CONTEXT' } }, - context: { dev: { environment: { TEST: 'DEV_CONTEXT' } } }, - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}`, - }), - }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'DEV_CONTEXT') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'DEV_CONTEXT') }) }) +}) - test(testName('should inject env vars based on [dev].envFiles file order', args), async (t) => { - await withSiteBuilder('site-with-env-files', async (builder) => { - builder - .withNetlifyToml({ - config: { - dev: { envFiles: ['.env.production', '.env.development', '.env'] }, - functions: { directory: 'functions' }, - }, - }) - .withEnvFile({ path: '.env.production', env: { TEST: 'FROM_PRODUCTION_FILE' } }) - .withEnvFile({ - path: '.env.development', - env: { TEST: 'FROM_DEVELOPMENT_FILE', TEST2: 'FROM_DEVELOPMENT_FILE' }, - }) - .withEnvFile({ path: '.env', env: { TEST: 'FROM_DEFAULT_FILE', TEST2: 'FROM_DEFAULT_FILE' } }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}__${process.env.TEST2}`, - }), - }) +test('should inject env vars based on [dev].envFiles file order', async (t) => { + await withSiteBuilder('site-with-env-files', async (builder) => { + builder + .withNetlifyToml({ + config: { + dev: { envFiles: ['.env.production', '.env.development', '.env'] }, + functions: { directory: 'functions' }, + }, + }) + .withEnvFile({ path: '.env.production', env: { TEST: 'FROM_PRODUCTION_FILE' } }) + .withEnvFile({ + path: '.env.development', + env: { TEST: 'FROM_DEVELOPMENT_FILE', TEST2: 'FROM_DEVELOPMENT_FILE' }, + }) + .withEnvFile({ path: '.env', env: { TEST: 'FROM_DEFAULT_FILE', TEST2: 'FROM_DEFAULT_FILE' } }) + .withFunction({ + path: 'env.js', + handler: async () => ({ + statusCode: 200, + body: `${process.env.TEST}__${process.env.TEST2}`, + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'FROM_PRODUCTION_FILE__FROM_DEVELOPMENT_FILE') - t.true(server.output.includes('Ignored .env.development file')) - t.true(server.output.includes('Ignored .env file')) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'FROM_PRODUCTION_FILE__FROM_DEVELOPMENT_FILE') + t.true(server.output.includes('Ignored .env.development file')) + t.true(server.output.includes('Ignored .env file')) }) }) }) diff --git a/tests/integration/400.command.dev.test.js b/tests/integration/400.command.dev.test.js index 1cad70f44b1..3ff476f3f97 100644 --- a/tests/integration/400.command.dev.test.js +++ b/tests/integration/400.command.dev.test.js @@ -14,668 +14,654 @@ const { withSiteBuilder } = require('./utils/site-builder') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest -const testMatrix = [ - { args: [] }, - - // some tests are still failing with this enabled - // { args: ['--edgeHandlers'] } -] - -const testName = (title, args) => (args.length <= 0 ? title : `${title} - ${args.join(' ')}`) - -testMatrix.forEach(({ args }) => { - test(testName('should use [build.environment] and not [context.production.environment]', args), async (t) => { - await withSiteBuilder('site-with-build-environment', async (builder) => { - builder - .withNetlifyToml({ - config: { - build: { environment: { TEST: 'DEFAULT_CONTEXT' } }, - context: { production: { environment: { TEST: 'PRODUCTION_CONTEXT' } } }, - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}`, - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'DEFAULT_CONTEXT') +test('should use [build.environment] and not [context.production.environment]', async (t) => { + await withSiteBuilder('site-with-build-environment', async (builder) => { + builder + .withNetlifyToml({ + config: { + build: { environment: { TEST: 'DEFAULT_CONTEXT' } }, + context: { production: { environment: { TEST: 'PRODUCTION_CONTEXT' } } }, + functions: { directory: 'functions' }, + }, }) - }) - }) - - test(testName('should override .env.development with process env', args), async (t) => { - await withSiteBuilder('site-with-override', async (builder) => { - builder - .withNetlifyToml({ config: { functions: { directory: 'functions' } } }) - .withEnvFile({ path: '.env.development', env: { TEST: 'FROM_DEV_FILE' } }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}`, - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, env: { TEST: 'FROM_PROCESS_ENV' }, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'FROM_PROCESS_ENV') + .withFunction({ + path: 'env.js', + handler: async () => ({ + statusCode: 200, + body: `${process.env.TEST}`, + }), }) - }) - }) - test(testName('should override [build.environment] with process env', args), async (t) => { - await withSiteBuilder('site-with-build-environment-override', async (builder) => { - builder - .withNetlifyToml({ - config: { build: { environment: { TEST: 'FROM_CONFIG_FILE' } }, functions: { directory: 'functions' } }, - }) - .withFunction({ - path: 'env.js', - handler: async () => ({ - statusCode: 200, - body: `${process.env.TEST}`, - }), - }) + await builder.buildAsync() - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, env: { TEST: 'FROM_PROCESS_ENV' }, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'FROM_PROCESS_ENV') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'DEFAULT_CONTEXT') }) }) +}) - test(testName('should override value of the NETLIFY_DEV env variable', args), async (t) => { - await withSiteBuilder('site-with-netlify-dev-override', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ +test('should override .env.development with process env', async (t) => { + await withSiteBuilder('site-with-override', async (builder) => { + builder + .withNetlifyToml({ config: { functions: { directory: 'functions' } } }) + .withEnvFile({ path: '.env.development', env: { TEST: 'FROM_DEV_FILE' } }) + .withFunction({ path: 'env.js', handler: async () => ({ statusCode: 200, - body: `${process.env.NETLIFY_DEV}`, + body: `${process.env.TEST}`, }), }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer( - { cwd: builder.directory, env: { NETLIFY_DEV: 'FROM_PROCESS_ENV' }, args }, - async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'true') - }, - ) + await withDevServer({ cwd: builder.directory, env: { TEST: 'FROM_PROCESS_ENV' } }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'FROM_PROCESS_ENV') }) }) +}) - test(testName('should set value of the CONTEXT env variable', args), async (t) => { - await withSiteBuilder('site-with-context-override', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ +test('should override [build.environment] with process env', async (t) => { + await withSiteBuilder('site-with-build-environment-override', async (builder) => { + builder + .withNetlifyToml({ + config: { build: { environment: { TEST: 'FROM_CONFIG_FILE' } }, functions: { directory: 'functions' } }, + }) + .withFunction({ path: 'env.js', handler: async () => ({ statusCode: 200, - body: `${process.env.CONTEXT}`, + body: `${process.env.TEST}`, }), }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`).text() - t.is(response, 'dev') - }) + await withDevServer({ cwd: builder.directory, env: { TEST: 'FROM_PROCESS_ENV' } }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'FROM_PROCESS_ENV') }) }) +}) - test(testName('should replicate Lambda behaviour for synchronous return values', args), async (t) => { - await withSiteBuilder('site-replicate-aws-sync-behaviour', async (builder) => { - builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ - path: 'env.js', - handler: () => ({ - statusCode: 200, - }), - }) +test('should replicate Lambda behaviour for synchronous return values', async (t) => { + await withSiteBuilder('site-replicate-aws-sync-behaviour', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'env.js', + handler: () => ({ + statusCode: 200, + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/.netlify/functions/env`, { - throwHttpErrors: false, - }) - t.true(response.body.startsWith('no lambda response.')) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`, { + throwHttpErrors: false, }) + t.true(response.body.startsWith('no lambda response.')) }) }) +}) - test(testName('should redirect using a wildcard when set in netlify.toml', args), async (t) => { - await withSiteBuilder('site-with-redirect-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], - }, - }) - .withFunction({ - path: 'ping.js', - handler: async () => ({ - statusCode: 200, - body: 'ping', - }), - }) +test('should override value of the NETLIFY_DEV env variable', async (t) => { + await withSiteBuilder('site-with-netlify-dev-override', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'env.js', + handler: async () => ({ + statusCode: 200, + body: `${process.env.NETLIFY_DEV}`, + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/api/ping`).text() - t.is(response, 'ping') - }) + await withDevServer({ cwd: builder.directory, env: { NETLIFY_DEV: 'FROM_PROCESS_ENV' } }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'true') }) }) +}) - test(testName('should pass undefined body to functions event for GET requests when redirecting', args), async (t) => { - await withSiteBuilder('site-with-get-echo-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], - }, - }) - .withFunction({ - path: 'echo.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) +test('should set value of the CONTEXT env variable', async (t) => { + await withSiteBuilder('site-with-context-override', async (builder) => { + builder.withNetlifyToml({ config: { functions: { directory: 'functions' } } }).withFunction({ + path: 'env.js', + handler: async () => ({ + statusCode: 200, + body: `${process.env.CONTEXT}`, + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/api/echo?ding=dong`).json() - t.is(response.body, undefined) - t.is(response.headers.host, `${server.host}:${server.port}`) - t.is(response.httpMethod, 'GET') - t.is(response.isBase64Encoded, true) - t.is(response.path, '/api/echo') - t.deepEqual(response.queryStringParameters, { ding: 'dong' }) - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/.netlify/functions/env`).text() + t.is(response, 'dev') }) }) +}) - test(testName('should pass body to functions event for POST requests when redirecting', args), async (t) => { - await withSiteBuilder('site-with-post-echo-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], - }, - }) - .withFunction({ - path: 'echo.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) +test('should redirect using a wildcard when set in netlify.toml', async (t) => { + await withSiteBuilder('site-with-redirect-function', async (builder) => { + builder + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], + }, + }) + .withFunction({ + path: 'ping.js', + handler: async () => ({ + statusCode: 200, + body: 'ping', + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got - .post(`${server.url}/api/echo?ding=dong`, { - headers: { - 'content-type': 'application/x-www-form-urlencoded', - }, - body: 'some=thing', - }) - .json() - - t.is(response.body, 'some=thing') - t.is(response.headers.host, `${server.host}:${server.port}`) - t.is(response.headers['content-type'], 'application/x-www-form-urlencoded') - t.is(response.headers['content-length'], '10') - t.is(response.httpMethod, 'POST') - t.is(response.isBase64Encoded, false) - t.is(response.path, '/api/echo') - t.deepEqual(response.queryStringParameters, { ding: 'dong' }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/api/ping`).text() + t.is(response, 'ping') + }) + }) +}) + +test('should pass undefined body to functions event for GET requests when redirecting', async (t) => { + await withSiteBuilder('site-with-get-echo-function', async (builder) => { + builder + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], + }, + }) + .withFunction({ + path: 'echo.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), }) + + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/api/echo?ding=dong`).json() + t.is(response.body, undefined) + t.is(response.headers.host, `${server.host}:${server.port}`) + t.is(response.httpMethod, 'GET') + t.is(response.isBase64Encoded, true) + t.is(response.path, '/api/echo') + t.deepEqual(response.queryStringParameters, { ding: 'dong' }) }) }) +}) - test(testName('should return an empty body for a function with no body when redirecting', args), async (t) => { - await withSiteBuilder('site-with-no-body-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], - }, - }) - .withFunction({ - path: 'echo.js', - handler: async () => ({ - statusCode: 200, - }), - }) +test('should pass body to functions event for POST requests when redirecting', async (t) => { + await withSiteBuilder('site-with-post-echo-function', async (builder) => { + builder + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], + }, + }) + .withFunction({ + path: 'echo.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got.post(`${server.url}/api/echo?ding=dong`, { + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got + .post(`${server.url}/api/echo?ding=dong`, { headers: { 'content-type': 'application/x-www-form-urlencoded', }, body: 'some=thing', }) + .json() - t.is(response.body, '') - t.is(response.statusCode, 200) - }) + t.is(response.body, 'some=thing') + t.is(response.headers.host, `${server.host}:${server.port}`) + t.is(response.headers['content-type'], 'application/x-www-form-urlencoded') + t.is(response.headers['content-length'], '10') + t.is(response.httpMethod, 'POST') + t.is(response.isBase64Encoded, false) + t.is(response.path, '/api/echo') + t.deepEqual(response.queryStringParameters, { ding: 'dong' }) }) }) +}) - test(testName('should handle multipart form data when redirecting', args), async (t) => { - await withSiteBuilder('site-with-multi-part-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], - }, - }) - .withFunction({ - path: 'echo.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const form = new FormData() - form.append('some', 'thing') - - const expectedBoundary = form.getBoundary() - const expectedResponseBody = form.getBuffer().toString('base64') +test('should return an empty body for a function with no body when redirecting', async (t) => { + await withSiteBuilder('site-with-no-body-function', async (builder) => { + builder + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], + }, + }) + .withFunction({ + path: 'echo.js', + handler: async () => ({ + statusCode: 200, + }), + }) - const response = await got - .post(`${server.url}/api/echo?ding=dong`, { - body: form, - }) - .json() + await builder.buildAsync() - t.is(response.headers.host, `${server.host}:${server.port}`) - t.is(response.headers['content-type'], `multipart/form-data; boundary=${expectedBoundary}`) - t.is(response.headers['content-length'], '164') - t.is(response.httpMethod, 'POST') - t.is(response.isBase64Encoded, true) - t.is(response.path, '/api/echo') - t.deepEqual(response.queryStringParameters, { ding: 'dong' }) - t.is(response.body, expectedResponseBody) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got.post(`${server.url}/api/echo?ding=dong`, { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + body: 'some=thing', }) + + t.is(response.body, '') + t.is(response.statusCode, 200) }) }) +}) - test(testName('should return 404 when redirecting to a non existing function', args), async (t) => { - await withSiteBuilder('site-with-missing-function', async (builder) => { - builder.withNetlifyToml({ +test('should handle multipart form data when redirecting', async (t) => { + await withSiteBuilder('site-with-multi-part-function', async (builder) => { + builder + .withNetlifyToml({ config: { functions: { directory: 'functions' }, redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], }, }) + .withFunction({ + path: 'echo.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got - .post(`${server.url}/api/none`, { - body: 'nothing', - }) - .catch((error) => error.response) + await withDevServer({ cwd: builder.directory }, async (server) => { + const form = new FormData() + form.append('some', 'thing') - t.is(response.statusCode, 404) - }) + const expectedBoundary = form.getBoundary() + const expectedResponseBody = form.getBuffer().toString('base64') + + const response = await got + .post(`${server.url}/api/echo?ding=dong`, { + body: form, + }) + .json() + + t.is(response.headers.host, `${server.host}:${server.port}`) + t.is(response.headers['content-type'], `multipart/form-data; boundary=${expectedBoundary}`) + t.is(response.headers['content-length'], '164') + t.is(response.httpMethod, 'POST') + t.is(response.isBase64Encoded, true) + t.is(response.path, '/api/echo') + t.deepEqual(response.queryStringParameters, { ding: 'dong' }) + t.is(response.body, expectedResponseBody) }) }) +}) - test(testName('should parse function query parameters using simple parsing', args), async (t) => { - await withSiteBuilder('site-with-multi-part-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'echo.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) +test('should return 404 when redirecting to a non existing function', async (t) => { + await withSiteBuilder('site-with-missing-function', async (builder) => { + builder.withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response1 = await got(`${server.url}/.netlify/functions/echo?category[SOMETHING][]=something`).json() - const response2 = await got(`${server.url}/.netlify/functions/echo?category=one&category=two`).json() + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got + .post(`${server.url}/api/none`, { + body: 'nothing', + }) + .catch((error) => error.response) - t.deepEqual(response1.queryStringParameters, { 'category[SOMETHING][]': 'something' }) - t.deepEqual(response2.queryStringParameters, { category: 'one, two' }) - }) + t.is(response.statusCode, 404) }) }) +}) - test(testName('should handle form submission', args), async (t) => { - await withSiteBuilder('site-with-form', async (builder) => { - builder - .withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'submission-created.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const form = new FormData() - form.append('some', 'thing') - const response = await got - .post(`${server.url}/?ding=dong`, { - body: form, - }) - .json() - - const body = JSON.parse(response.body) - - t.is(response.headers.host, `${server.host}:${server.port}`) - t.is(response.headers['content-length'], '276') - t.is(response.headers['content-type'], 'application/json') - t.is(response.httpMethod, 'POST') - t.is(response.isBase64Encoded, false) - t.is(response.path, '/') - t.deepEqual(response.queryStringParameters, { ding: 'dong' }) - t.deepEqual(body, { - payload: { - created_at: body.payload.created_at, - data: { - ip: '::ffff:127.0.0.1', - some: 'thing', - user_agent: 'got (https://github.com/sindresorhus/got)', - }, - human_fields: { - Some: 'thing', - }, - ordered_human_fields: [ - { - name: 'some', - title: 'Some', - value: 'thing', - }, - ], - site_url: '', - }, - }) +test('should parse function query parameters using simple parsing', async (t) => { + await withSiteBuilder('site-with-multi-part-function', async (builder) => { + builder + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, }) + .withFunction({ + path: 'echo.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) + + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const response1 = await got(`${server.url}/.netlify/functions/echo?category[SOMETHING][]=something`).json() + const response2 = await got(`${server.url}/.netlify/functions/echo?category=one&category=two`).json() + + t.deepEqual(response1.queryStringParameters, { 'category[SOMETHING][]': 'something' }) + t.deepEqual(response2.queryStringParameters, { category: 'one, two' }) }) }) +}) - test(testName('should handle form submission with a background function', args), async (t) => { - await withSiteBuilder('site-with-form-background-function', async (builder) => { - await builder - .withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'submission-created-background.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - .buildAsync() +test('should handle form submission', async (t) => { + await withSiteBuilder('site-with-form', async (builder) => { + builder + .withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'submission-created.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) + + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const form = new FormData() - form.append('some', 'thing') - const response = await got.post(`${server.url}/?ding=dong`, { + await withDevServer({ cwd: builder.directory }, async (server) => { + const form = new FormData() + form.append('some', 'thing') + const response = await got + .post(`${server.url}/?ding=dong`, { body: form, }) - t.is(response.statusCode, 202) - t.is(response.body, '') + .json() + + const body = JSON.parse(response.body) + + t.is(response.headers.host, `${server.host}:${server.port}`) + t.is(response.headers['content-length'], '276') + t.is(response.headers['content-type'], 'application/json') + t.is(response.httpMethod, 'POST') + t.is(response.isBase64Encoded, false) + t.is(response.path, '/') + t.deepEqual(response.queryStringParameters, { ding: 'dong' }) + t.deepEqual(body, { + payload: { + created_at: body.payload.created_at, + data: { + ip: '::ffff:127.0.0.1', + some: 'thing', + user_agent: 'got (https://github.com/sindresorhus/got)', + }, + human_fields: { + Some: 'thing', + }, + ordered_human_fields: [ + { + name: 'some', + title: 'Some', + value: 'thing', + }, + ], + site_url: '', + }, }) }) }) +}) - test(testName('should not handle form submission when content type is `text/plain`', args), async (t) => { - await withSiteBuilder('site-with-form-text-plain', async (builder) => { - builder - .withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'submission-created.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - - await builder.buildAsync() +test('should handle form submission with a background function', async (t) => { + await withSiteBuilder('site-with-form-background-function', async (builder) => { + await builder + .withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'submission-created-background.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) + .buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got - .post(`${server.url}/?ding=dong`, { - body: 'Something', - headers: { - 'content-type': 'text/plain', - }, - }) - .catch((error) => error.response) - t.is(response.body, 'Method Not Allowed') + await withDevServer({ cwd: builder.directory }, async (server) => { + const form = new FormData() + form.append('some', 'thing') + const response = await got.post(`${server.url}/?ding=dong`, { + body: form, }) + t.is(response.statusCode, 202) + t.is(response.body, '') }) }) +}) - test(testName('should return existing local file even when rewrite matches when force=false', args), async (t) => { - await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: false }], +test('should not handle form submission when content type is `text/plain`', async (t) => { + await withSiteBuilder('site-with-form-text-plain', async (builder) => { + builder + .withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'submission-created.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) + + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got + .post(`${server.url}/?ding=dong`, { + body: 'Something', + headers: { + 'content-type': 'text/plain', }, }) + .catch((error) => error.response) + t.is(response.body, 'Method Not Allowed') + }) + }) +}) - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo?ping=pong`).text() - t.is(response, '

foo') +test('should return existing local file even when rewrite matches when force=false', async (t) => { + await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: false }], + }, }) + + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo?ping=pong`).text() + t.is(response, '

foo') }) }) +}) - test(testName('should return existing local file even when redirect matches when force=false', args), async (t) => { - await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo', to: '/not-foo', status: 301, force: false }], - }, - }) +test('should return existing local file even when redirect matches when force=false', async (t) => { + await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo', to: '/not-foo', status: 301, force: false }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo?ping=pong`).text() - t.is(response, '

foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo?ping=pong`).text() + t.is(response, '

foo') }) }) +}) - test(testName('should ignore existing local file when redirect matches and force=true', args), async (t) => { - await withSiteBuilder('site-with-shadowing-force-true', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: true }], - }, - }) +test('should ignore existing local file when redirect matches and force=true', async (t) => { + await withSiteBuilder('site-with-shadowing-force-true', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo`).text() - t.is(response, '

not-foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo`).text() + t.is(response, '

not-foo') }) }) +}) - test(testName('should use existing file when rule contains file extension and force=false', args), async (t) => { - await withSiteBuilder('site-with-shadowing-file-extension-force-false', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: false }], - }, - }) +test('should use existing file when rule contains file extension and force=false', async (t) => { + await withSiteBuilder('site-with-shadowing-file-extension-force-false', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: false }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo.html`).text() - t.is(response, '

foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo.html`).text() + t.is(response, '

foo') }) }) +}) - test(testName('should redirect when rule contains file extension and force=true', args), async (t) => { - await withSiteBuilder('site-with-shadowing-file-extension-force-true', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: true }], - }, - }) +test('should redirect when rule contains file extension and force=true', async (t) => { + await withSiteBuilder('site-with-shadowing-file-extension-force-true', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo.html`).text() - t.is(response, '

not-foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo.html`).text() + t.is(response, '

not-foo') }) }) +}) - test(testName('should redirect from sub directory to root directory', args), async (t) => { - await withSiteBuilder('site-with-shadowing-sub-to-root', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/not-foo', to: '/foo', status: 200, force: true }], - }, - }) +test('should redirect from sub directory to root directory', async (t) => { + await withSiteBuilder('site-with-shadowing-sub-to-root', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/not-foo', to: '/foo', status: 200, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response1 = await got(`${server.url}/not-foo`).text() - const response2 = await got(`${server.url}/not-foo/`).text() + await withDevServer({ cwd: builder.directory }, async (server) => { + const response1 = await got(`${server.url}/not-foo`).text() + const response2 = await got(`${server.url}/not-foo/`).text() - // TODO: check why this doesn't redirect - const response3 = await got(`${server.url}/not-foo/index.html`).text() + // TODO: check why this doesn't redirect + const response3 = await got(`${server.url}/not-foo/index.html`).text() - t.is(response1, '

foo') - t.is(response2, '

foo') - t.is(response3, '

not-foo') - }) + t.is(response1, '

foo') + t.is(response2, '

foo') + t.is(response3, '

not-foo') }) }) }) diff --git a/tests/integration/410.command.dev.trace.test.js b/tests/integration/410.command.dev.trace.test.js deleted file mode 100644 index 68c0b92fae5..00000000000 --- a/tests/integration/410.command.dev.trace.test.js +++ /dev/null @@ -1,31 +0,0 @@ -const test = require('ava') - -const callCli = require('./utils/call-cli') -const { withSiteBuilder } = require('./utils/site-builder') - -test('routing-local-proxy does not match redirect for empty site', async (t) => { - await withSiteBuilder('empty-site', async (builder) => { - await builder.buildAsync() - - const output = await callCli(['dev:trace', 'http://localhost/routing-path'], { - cwd: builder.directory, - }) - - t.is(output.includes("request didn't match any rule"), true) - }) -}) - -test('routing-local-proxy matches redirect when url matches', async (t) => { - await withSiteBuilder('site-with-redirects', async (builder) => { - builder.withRedirectsFile({ - redirects: [{ from: '/*', to: `/index.html`, status: 200 }], - }) - await builder.buildAsync() - - const output = await callCli(['dev:trace', 'http://localhost/routing-path'], { - cwd: builder.directory, - }) - - t.is(output.includes('mapped remap found'), true) - }) -}) diff --git a/tests/integration/500.command.dev.test.js b/tests/integration/500.command.dev.test.js index c26810b24e8..7d050f4b20b 100644 --- a/tests/integration/500.command.dev.test.js +++ b/tests/integration/500.command.dev.test.js @@ -13,361 +13,350 @@ const { withSiteBuilder } = require('./utils/site-builder') const test = isCI ? avaTest.serial.bind(avaTest) : avaTest -const testMatrix = [ - { args: [] }, +test('should return 404 when redirecting to a non existing function', async (t) => { + await withSiteBuilder('site-with-missing-function', async (builder) => { + builder.withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], + }, + }) + + await builder.buildAsync() - // some tests are still failing with this enabled - // { args: ['--edgeHandlers'] } -] + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got + .post(`${server.url}/api/none`, { + body: 'nothing', + }) + .catch((error) => error.response) -const testName = (title, args) => (args.length <= 0 ? title : `${title} - ${args.join(' ')}`) + t.is(response.statusCode, 404) + }) + }) +}) -testMatrix.forEach(({ args }) => { - test(testName('should return 404 when redirecting to a non existing function', args), async (t) => { - await withSiteBuilder('site-with-missing-function', async (builder) => { - builder.withNetlifyToml({ +test('should parse function query parameters using simple parsing', async (t) => { + await withSiteBuilder('site-with-multi-part-function', async (builder) => { + builder + .withNetlifyToml({ config: { functions: { directory: 'functions' }, - redirects: [{ from: '/api/*', to: '/.netlify/functions/:splat', status: 200 }], }, }) + .withFunction({ + path: 'echo.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got - .post(`${server.url}/api/none`, { - body: 'nothing', - }) - .catch((error) => error.response) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response1 = await got(`${server.url}/.netlify/functions/echo?category[SOMETHING][]=something`).json() + const response2 = await got(`${server.url}/.netlify/functions/echo?category=one&category=two`).json() - t.is(response.statusCode, 404) - }) + t.deepEqual(response1.queryStringParameters, { 'category[SOMETHING][]': 'something' }) + t.deepEqual(response2.queryStringParameters, { category: 'one, two' }) }) }) +}) - test(testName('should parse function query parameters using simple parsing', args), async (t) => { - await withSiteBuilder('site-with-multi-part-function', async (builder) => { - builder - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'echo.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response1 = await got(`${server.url}/.netlify/functions/echo?category[SOMETHING][]=something`).json() - const response2 = await got(`${server.url}/.netlify/functions/echo?category=one&category=two`).json() - - t.deepEqual(response1.queryStringParameters, { 'category[SOMETHING][]': 'something' }) - t.deepEqual(response2.queryStringParameters, { category: 'one, two' }) +test('should handle form submission', async (t) => { + await withSiteBuilder('site-with-form', async (builder) => { + builder + .withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'submission-created.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), }) - }) - }) - test(testName('should handle form submission', args), async (t) => { - await withSiteBuilder('site-with-form', async (builder) => { - builder - .withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', + await builder.buildAsync() + + await withDevServer({ cwd: builder.directory }, async (server) => { + const form = new FormData() + form.append('some', 'thing') + const response = await got + .post(`${server.url}/?ding=dong`, { + body: form, }) - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, + .json() + + const body = JSON.parse(response.body) + + t.is(response.headers.host, `${server.host}:${server.port}`) + t.is(response.headers['content-length'], '276') + t.is(response.headers['content-type'], 'application/json') + t.is(response.httpMethod, 'POST') + t.is(response.isBase64Encoded, false) + t.is(response.path, '/') + t.deepEqual(response.queryStringParameters, { ding: 'dong' }) + t.deepEqual(body, { + payload: { + created_at: body.payload.created_at, + data: { + ip: '::ffff:127.0.0.1', + some: 'thing', + user_agent: 'got (https://github.com/sindresorhus/got)', }, - }) - .withFunction({ - path: 'submission-created.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - - await builder.buildAsync() - - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const form = new FormData() - form.append('some', 'thing') - const response = await got - .post(`${server.url}/?ding=dong`, { - body: form, - }) - .json() - - const body = JSON.parse(response.body) - - t.is(response.headers.host, `${server.host}:${server.port}`) - t.is(response.headers['content-length'], '276') - t.is(response.headers['content-type'], 'application/json') - t.is(response.httpMethod, 'POST') - t.is(response.isBase64Encoded, false) - t.is(response.path, '/') - t.deepEqual(response.queryStringParameters, { ding: 'dong' }) - t.deepEqual(body, { - payload: { - created_at: body.payload.created_at, - data: { - ip: '::ffff:127.0.0.1', - some: 'thing', - user_agent: 'got (https://github.com/sindresorhus/got)', - }, - human_fields: { - Some: 'thing', - }, - ordered_human_fields: [ - { - name: 'some', - title: 'Some', - value: 'thing', - }, - ], - site_url: '', + human_fields: { + Some: 'thing', }, - }) + ordered_human_fields: [ + { + name: 'some', + title: 'Some', + value: 'thing', + }, + ], + site_url: '', + }, }) }) }) +}) - test(testName('should handle form submission with a background function', args), async (t) => { - await withSiteBuilder('site-with-form-background-function', async (builder) => { - await builder - .withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'submission-created-background.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) - .buildAsync() +test('should handle form submission with a background function', async (t) => { + await withSiteBuilder('site-with-form-background-function', async (builder) => { + await builder + .withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'submission-created-background.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) + .buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const form = new FormData() - form.append('some', 'thing') - const response = await got.post(`${server.url}/?ding=dong`, { - body: form, - }) - t.is(response.statusCode, 202) - t.is(response.body, '') + await withDevServer({ cwd: builder.directory }, async (server) => { + const form = new FormData() + form.append('some', 'thing') + const response = await got.post(`${server.url}/?ding=dong`, { + body: form, }) + t.is(response.statusCode, 202) + t.is(response.body, '') }) }) +}) - test(testName('should not handle form submission when content type is `text/plain`', args), async (t) => { - await withSiteBuilder('site-with-form-text-plain', async (builder) => { - builder - .withContentFile({ - path: 'index.html', - content: '

⊂◉‿◉つ

', - }) - .withNetlifyToml({ - config: { - functions: { directory: 'functions' }, - }, - }) - .withFunction({ - path: 'submission-created.js', - handler: async (event) => ({ - statusCode: 200, - body: JSON.stringify(event), - }), - }) +test('should not handle form submission when content type is `text/plain`', async (t) => { + await withSiteBuilder('site-with-form-text-plain', async (builder) => { + builder + .withContentFile({ + path: 'index.html', + content: '

⊂◉‿◉つ

', + }) + .withNetlifyToml({ + config: { + functions: { directory: 'functions' }, + }, + }) + .withFunction({ + path: 'submission-created.js', + handler: async (event) => ({ + statusCode: 200, + body: JSON.stringify(event), + }), + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got - .post(`${server.url}/?ding=dong`, { - body: 'Something', - headers: { - 'content-type': 'text/plain', - }, - }) - .catch((error) => error.response) - t.is(response.body, 'Method Not Allowed') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got + .post(`${server.url}/?ding=dong`, { + body: 'Something', + headers: { + 'content-type': 'text/plain', + }, + }) + .catch((error) => error.response) + t.is(response.body, 'Method Not Allowed') }) }) +}) - test(testName('should return existing local file even when rewrite matches when force=false', args), async (t) => { - await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: false }], - }, - }) +test('should return existing local file even when rewrite matches when force=false', async (t) => { + await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: false }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo?ping=pong`).text() - t.is(response, '

foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo?ping=pong`).text() + t.is(response, '

foo') }) }) +}) - test(testName('should return existing local file even when redirect matches when force=false', args), async (t) => { - await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo', to: '/not-foo', status: 301, force: false }], - }, - }) +test('should return existing local file even when redirect matches when force=false', async (t) => { + await withSiteBuilder('site-with-shadowing-force-false', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo', to: '/not-foo', status: 301, force: false }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo?ping=pong`).text() - t.is(response, '

foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo?ping=pong`).text() + t.is(response, '

foo') }) }) +}) - test(testName('should ignore existing local file when redirect matches and force=true', args), async (t) => { - await withSiteBuilder('site-with-shadowing-force-true', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: true }], - }, - }) +test('should ignore existing local file when redirect matches and force=true', async (t) => { + await withSiteBuilder('site-with-shadowing-force-true', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo', to: '/not-foo', status: 200, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo`).text() - t.is(response, '

not-foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo`).text() + t.is(response, '

not-foo') }) }) +}) - test(testName('should use existing file when rule contains file extension and force=false', args), async (t) => { - await withSiteBuilder('site-with-shadowing-file-extension-force-false', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: false }], - }, - }) +test('should use existing file when rule contains file extension and force=false', async (t) => { + await withSiteBuilder('site-with-shadowing-file-extension-force-false', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: false }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo.html`).text() - t.is(response, '

foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo.html`).text() + t.is(response, '

foo') }) }) +}) - test(testName('should redirect when rule contains file extension and force=true', args), async (t) => { - await withSiteBuilder('site-with-shadowing-file-extension-force-true', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: true }], - }, - }) +test('should redirect when rule contains file extension and force=true', async (t) => { + await withSiteBuilder('site-with-shadowing-file-extension-force-true', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/foo.html', to: '/not-foo', status: 200, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response = await got(`${server.url}/foo.html`).text() - t.is(response, '

not-foo') - }) + await withDevServer({ cwd: builder.directory }, async (server) => { + const response = await got(`${server.url}/foo.html`).text() + t.is(response, '

not-foo') }) }) +}) - test(testName('should redirect from sub directory to root directory', args), async (t) => { - await withSiteBuilder('site-with-shadowing-sub-to-root', async (builder) => { - builder - .withContentFile({ - path: 'foo.html', - content: '

foo', - }) - .withContentFile({ - path: path.join('not-foo', 'index.html'), - content: '

not-foo', - }) - .withNetlifyToml({ - config: { - redirects: [{ from: '/not-foo', to: '/foo', status: 200, force: true }], - }, - }) +test('should redirect from sub directory to root directory', async (t) => { + await withSiteBuilder('site-with-shadowing-sub-to-root', async (builder) => { + builder + .withContentFile({ + path: 'foo.html', + content: '

foo', + }) + .withContentFile({ + path: path.join('not-foo', 'index.html'), + content: '

not-foo', + }) + .withNetlifyToml({ + config: { + redirects: [{ from: '/not-foo', to: '/foo', status: 200, force: true }], + }, + }) - await builder.buildAsync() + await builder.buildAsync() - await withDevServer({ cwd: builder.directory, args }, async (server) => { - const response1 = await got(`${server.url}/not-foo`).text() - const response2 = await got(`${server.url}/not-foo/`).text() + await withDevServer({ cwd: builder.directory }, async (server) => { + const response1 = await got(`${server.url}/not-foo`).text() + const response2 = await got(`${server.url}/not-foo/`).text() - // TODO: check why this doesn't redirect - const response3 = await got(`${server.url}/not-foo/index.html`).text() + // TODO: check why this doesn't redirect + const response3 = await got(`${server.url}/not-foo/index.html`).text() - t.is(response1, '

foo') - t.is(response2, '

foo') - t.is(response3, '

not-foo') - }) + t.is(response1, '

foo') + t.is(response2, '

foo') + t.is(response3, '

not-foo') }) }) }) diff --git a/tests/integration/640.command.recipes.test.js b/tests/integration/640.command.recipes.test.js new file mode 100644 index 00000000000..721a3bf3517 --- /dev/null +++ b/tests/integration/640.command.recipes.test.js @@ -0,0 +1,103 @@ +const { resolve } = require('path') + +const test = require('ava') +const execa = require('execa') + +const { readFileAsyncCatchError } = require('../../src/lib/fs') + +const callCli = require('./utils/call-cli') +const cliPath = require('./utils/cli-path') +const { CONFIRM, answerWithValue, handleQuestions } = require('./utils/handle-questions') +const { withSiteBuilder } = require('./utils/site-builder') +const { normalize } = require('./utils/snapshots') + +test('Shows a list of all the available recipes', async (t) => { + const cliResponse = await callCli(['recipes:list']) + + t.snapshot(normalize(cliResponse)) +}) + +test('Generates a new VS Code settings file if one does not exist', async (t) => { + await withSiteBuilder('repo', async (builder) => { + await builder.buildAsync() + + const childProcess = execa(cliPath, ['recipes', 'vscode'], { + cwd: builder.directory, + }) + const settingsPath = resolve(builder.directory, '.vscode', 'settings.json') + + handleQuestions(childProcess, [ + { + question: `A new VS Code settings file will be created at ${settingsPath}`, + answer: answerWithValue(CONFIRM), + }, + ]) + + await childProcess + + const { content, error } = await readFileAsyncCatchError(`${builder.directory}/.vscode/settings.json`) + const settings = JSON.parse(content) + + t.is(error, undefined) + t.is(settings['deno.enable'], true) + t.is(settings['deno.importMap'], '.netlify/edge-functions-import-map.json') + t.deepEqual(settings['deno.enablePaths'], ['netlify/edge-functions']) + }) +}) + +test('Updates an existing VS Code settings file', async (t) => { + await withSiteBuilder('repo', async (builder) => { + await builder + .withContentFile({ + path: '.vscode/settings.json', + content: JSON.stringify({ 'deno.enablePaths': ['/some/path'], someSetting: 'value' }), + }) + .buildAsync() + + const childProcess = execa(cliPath, ['recipes', 'vscode'], { + cwd: builder.directory, + }) + const settingsPath = resolve(builder.directory, '.vscode', 'settings.json') + + handleQuestions(childProcess, [ + { + question: `There is a VS Code settings file at ${settingsPath}. Can we update it?`, + answer: answerWithValue(CONFIRM), + }, + ]) + + await childProcess + + const { content, error } = await readFileAsyncCatchError(`${builder.directory}/.vscode/settings.json`) + const settings = JSON.parse(content) + + t.is(error, undefined) + t.is(settings.someSetting, 'value') + t.is(settings['deno.enable'], true) + t.is(settings['deno.importMap'], '.netlify/edge-functions-import-map.json') + t.deepEqual(settings['deno.enablePaths'], ['/some/path', 'netlify/edge-functions']) + }) +}) + +test('Does not generate a new VS Code settings file if the user does not confirm the prompt', async (t) => { + await withSiteBuilder('repo', async (builder) => { + await builder.buildAsync() + + const childProcess = execa(cliPath, ['recipes', 'vscode'], { + cwd: builder.directory, + }) + const settingsPath = resolve(builder.directory, '.vscode', 'settings.json') + + handleQuestions(childProcess, [ + { + question: `A new VS Code settings file will be created at ${settingsPath}`, + answer: answerWithValue('n'), + }, + ]) + + await childProcess + + const { error } = await readFileAsyncCatchError(`${builder.directory}/.vscode/settings.json`) + t.is(error.code, 'ENOENT') + }) +}) diff --git a/tests/integration/snapshots/320.command.help.test.js.md b/tests/integration/snapshots/320.command.help.test.js.md index 219dc1d6082..feb44efe11d 100644 --- a/tests/integration/snapshots/320.command.help.test.js.md +++ b/tests/integration/snapshots/320.command.help.test.js.md @@ -1,4 +1,4 @@ -# Snapshot report for `tests/320.command.help.test.js` +# Snapshot report for `tests/integration/320.command.help.test.js` The actual snapshot is saved in `320.command.help.test.js.snap`. @@ -23,6 +23,8 @@ Generated by [AVA](https://avajs.dev). $ dev Local dev server␊ $ env (Beta) Control environment variables for the current site␊ $ functions Manage netlify functions␊ + $ recipes (Beta) Create and modify files in a project using pre-defined␊ + recipes␊ $ graph (Beta) Control the Netlify Graph functions for the current␊ site␊ $ init Configure continuous deployment for a new or existing site. To␊ diff --git a/tests/integration/snapshots/320.command.help.test.js.snap b/tests/integration/snapshots/320.command.help.test.js.snap index fcfaeed952664445e4d3f7ec6e905f52f8658204..0823a8166e82abe74014e8783e80cd143237763a 100644 GIT binary patch literal 963 zcmV;!13dgeRzV-f zd$2u8y9EA#HJh^KC%M=5Jkq3s*(A2leVucCeN$X2lYepFe}k7^fzsfWEUsAzs+Lak z+Lgw;Z#P14&p+(_xxe#ZhrWAzI}dk%?Y*6x&5uq`GRBhOC|B~C2j@piuudAy!os-t ztBrv6B+Jg{2Zs~1ebidBi}C4ndT{dcW0s|V^Kj0EFxs*BJ$?b6KVeg@`2yHUGCdGt zgqR4gCF{PkMl-Ijd*JMdRp3h_0`{_zO0ad;FTx%se{CAekRh&E#q&~X2sXK?YK4p; zqO&;!4VHUg4!Ki9h|8_4eJ~VID|4NKjV%zKWA&@{q_C!9z67+_9<+DN6o@E{5@3^y zWnbHINR74}*kwY19w1V7V{~VYqBCiYuFy4Gax3|z0*CHx4BA*rCr?V{^KE*cvJk-9OBOIigE$!!!6|G<@Wo~j{V`|OR` zjFJyECm35vY{kZJ_x}{>0rn|TzCCI8JUaapvR6`n>Dz-AJTe%_4p-#FSFi15xc#Zn1p7>*Ku}P*NBxk0kE7A3cG7G8u)};kT4|lA!=6P-!9WM)7 zcW8D>3kRN(?9~j}Qpq65)v$*LS0=D@D_v@S;yTv5o~QHNH?6_UO1cqoOKOZ<1!zQ~ zdU@N9^SB80aBRCJY%QzN1C7q(qSYvA5~cv}th?4+@je=R7Z$`ss38pyWC3rHbY+%C z`f51R2V-e-y6^s6o9;h$|97%&8RP@dg{cFzIMYvOZ}7FCkv=M)ve77{^p8(SS1X>< zr)tr4g&L9*92u9*;$I#*5d(TbUB0d(CgOcPv*rq4Abe^pIQQ`mKZJ?1mL()nZt(^K z-mtF?zH+!z;>M!fU-vx*>t!Kxr1BNcLCq^*7c>!Ltif@ZljN6f|Ek2!$LXN)(o*hm zV1@zO<&tGDC-d>yQQ$X=Z=NruYsn&C4gl+R-Zq1g7@9Tcx}Rl}_XpG2@nn97lF!MS lD|PE_-UMvdplu_!*+G3O_zo0+7g)rkvcJ#yaLJ(v003pk)_ni~ literal 928 zcmV;R17G|>RzVJu00000000AxRn2Z2HxPCm7zOs$H{hX%7Kq$SPq{g=>Kd?Y!E*j!1PHyH z)w1D|TmDG)vB?|s4bmsg49WeGCBxl=v?RZo`DW(h?6>Mpnewyy@*jBV6(|i}$?AdC zpjzoPZ(VJ?`{$bw-184d(-#Ln9?0cWG-APfrS)QED(Dvufn%z#X=JS)w(~m`w-G|a~c>XJ!bIn)4 zF0<*05EH~Ccq>`|TnEj#ei(p@bJl>bjfmL0AeCU-u3yJJB>!N7WmqAuSi{R&YKS(a zXevb?RI2uiNI>Yqj2;P+AJf<1nEE>cV1@1pBUu7XX4k~)~+at&i{ z0*hFG@N`~{`Yy=LB^YPYGQB6mYw_8c%sGdlQ_YoUh1UvP`fn}d*?nUz$wC>UDiWUw$ksP`i*;2|N$kkX|BPqu!J)%pZq*|wZw|P3x zedr7pR+3WFmed%ziO__^?v`g1^QIFoFMc1R;lXyFMZ{16C!-r_> zU0hHlVh;IYV-+e?u&awaYB%FiI~o_eQ}^)St*QI<@c&MnJp*NyX66C-*>D&OuS67jxWSaXkG2K)qA zaPH$1eh8ChAj?Q9xy2g{c*Fh<`1Qe^8aGz;@wV?NST8GCVk!TS3N&wk-B$RPVvUX& z?UG-*{hJz4q z`+8gyv-cv-L?>U7HCO7 Snapshot 1 + + `.----------------------------------------------------------------------------------.␊ + | Usage: netlify generate |␊ + |----------------------------------------------------------------------------------|␊ + | Name | Description |␊ + |--------|-------------------------------------------------------------------------|␊ + | vscode | Create VS Code settings for an optimal experience with Netlify projects |␊ + '----------------------------------------------------------------------------------'` + +## shows a list of all the available recipes + +> Snapshot 1 + + `.----------------------------------------------------------------------------------.␊ + | Usage: netlify generate |␊ + |----------------------------------------------------------------------------------|␊ + | Name | Description |␊ + |--------|-------------------------------------------------------------------------|␊ + | vscode | Create VS Code settings for an optimal experience with Netlify projects |␊ + '----------------------------------------------------------------------------------'` diff --git a/tests/integration/snapshots/640.command.generate.test.js.snap b/tests/integration/snapshots/640.command.generate.test.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..a15103a58cd70e122dd28f1e2eae8517fb536826 GIT binary patch literal 310 zcmV-60m=SBRzVIR%mawnBy|ddg5_jy?rwCmyX*`} zglqIo;*+{3a@ZU;Tjnc=`SUUSPR-VO^Cq8Pq^y>XH=E8M1Q0BXf^Pt=1?>oMk8E*k z2_hK|BrFbtbYA7-RM)8ZQsS(*Dh4hti|g{ST-;`7G4ElLC&8BPz>!*R-k~K&5tZQH z;f@}r=lXe{-?Sf0*XeNDKYjX#6^V%)l)d|>^N(ph<-v3>#@Ccgmyw2-J#Sz+6ogdS zwE~TgfDU}J+@S?J28vA15FA)LSpWV!ME^=gC7D*)1V^edrgDyH9?mh%COA@k17>1B I Snapshot 1 + + `.----------------------------------------------------------------------------------.␊ + | Usage: netlify recipes |␊ + |----------------------------------------------------------------------------------|␊ + | Name | Description |␊ + |--------|-------------------------------------------------------------------------|␊ + | vscode | Create VS Code settings for an optimal experience with Netlify projects |␊ + '----------------------------------------------------------------------------------'` diff --git a/tests/integration/snapshots/640.command.recipes.test.js.snap b/tests/integration/snapshots/640.command.recipes.test.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..cb5be4cc62b223817d2f73ae53c03927ca7138cd GIT binary patch literal 291 zcmV+;0o?vURzVkG0+D~N_kQo2@p$R$$zwbzMp(-S3bHoJ$$f4g2k#SS;oulMu?~x`KTkQnvNJ8x>1e>8rk~(-Ve_y80039{hA{vD literal 0 HcmV?d00001 diff --git a/tests/integration/utils/dev-server.js b/tests/integration/utils/dev-server.js index 6b42f163ce6..8f38301075c 100644 --- a/tests/integration/utils/dev-server.js +++ b/tests/integration/utils/dev-server.js @@ -8,6 +8,7 @@ const pTimeout = require('p-timeout') const seedrandom = require('seedrandom') const cliPath = require('./cli-path') +const { handleQuestions } = require('./handle-questions') const { killProcess } = require('./process') // each process gets a starting port based on the pid @@ -32,7 +33,7 @@ const getExecaOptions = ({ cwd, env }) => ({ encoding: 'utf8', }) -const startServer = async ({ cwd, offline = true, env = {}, args = [], expectFailure = false }) => { +const startServer = async ({ cwd, offline = true, env = {}, args = [], expectFailure = false, prompt }) => { const tryPort = currentPort currentPort += 1 const port = await getPort({ port: tryPort }) @@ -44,6 +45,13 @@ const startServer = async ({ cwd, offline = true, env = {}, args = [], expectFai ['dev', offline ? '--offline' : '', '-p', port, '--staticServerPort', port + FRAMEWORK_PORT_SHIFT, ...args], getExecaOptions({ cwd, env }), ) + + const promptHistory = [] + + if (prompt) { + handleQuestions(ps, prompt, promptHistory) + } + const outputBuffer = [] const serverPromise = new Promise((resolve, reject) => { let selfKilled = false @@ -60,6 +68,7 @@ const startServer = async ({ cwd, offline = true, env = {}, args = [], expectFai selfKilled = true await killProcess(ps) }, + promptHistory, }) } }) diff --git a/tests/integration/utils/handle-questions.js b/tests/integration/utils/handle-questions.js index 3bfc3baa03c..51a68aad466 100644 --- a/tests/integration/utils/handle-questions.js +++ b/tests/integration/utils/handle-questions.js @@ -5,18 +5,20 @@ const { Buffer } = require('buffer') * questions correctly typed or the process will keep waiting for input. * @param {ExecaChildProcess} process * @param {Array<{question: string, answer: string}>} questions + * @param {Array} prompts * - questions that you know the CLI will ask and respective answers to mock */ -const handleQuestions = (process, questions) => { - const remainingQuestions = [...questions] +const handleQuestions = (process, questions, prompts = []) => { let buffer = '' process.stdout.on('data', (data) => { - buffer += data - const index = remainingQuestions.findIndex(({ question }) => buffer.includes(question)) + buffer = (buffer + data).replace(/\n/g, '') + const index = questions.findIndex( + ({ question }, questionIndex) => buffer.includes(question) && !prompts.includes(questionIndex), + ) if (index >= 0) { + prompts.push(index) buffer = '' - process.stdin.write(Buffer.from(remainingQuestions[index].answer)) - remainingQuestions.splice(index, 1) + process.stdin.write(Buffer.from(questions[index].answer)) } }) } diff --git a/tests/integration/utils/site-builder.js b/tests/integration/utils/site-builder.js index 88a63858b51..af3dbad9d76 100644 --- a/tests/integration/utils/site-builder.js +++ b/tests/integration/utils/site-builder.js @@ -66,12 +66,10 @@ const createSiteBuilder = ({ siteName }) => { }) return builder }, - withEdgeHandlers: ({ fileName = 'index.js', handlers }) => { - const dest = path.join(directory, 'netlify/edge-handlers', fileName) + withEdgeFunction: ({ handler, name = 'function' }) => { + const dest = path.join(directory, 'netlify/edge-functions', `${name}.js`) tasks.push(async () => { - const content = Object.entries(handlers) - .map(([event, handler]) => `export const ${event} = ${handler.toString()}`) - .join(os.EOL) + const content = `export default ${handler.toString()}` await ensureDir(path.dirname(dest)) await writeFile(dest, content) }) diff --git a/tests/unit/utils/deploy/hash-files.test.js b/tests/unit/utils/deploy/hash-files.test.js index 830101ad8a2..b90dd080322 100644 --- a/tests/unit/utils/deploy/hash-files.test.js +++ b/tests/unit/utils/deploy/hash-files.test.js @@ -15,7 +15,8 @@ test('Hashes files in a folder', async (t) => { .buildAsync() const expectedFiles = ['netlify.toml', 'public/index.html'] - const { files, filesShaMap } = await hashFiles(builder.directory, `${builder.directory}/netlify.toml`, { + const { files, filesShaMap } = await hashFiles({ + directories: [builder.directory, `${builder.directory}/netlify.toml`], filter: () => true, concurrentHash: DEFAULT_CONCURRENT_HASH, statusCb() {},